--- name: signalgraph-evidence-check description: Run SignalGraph's deterministic conversion-delivery or marketing-journey-health check against a sanitized fixture and, when DataHub is configured, attach validated owner and downstream-lineage context to the finding. Use when a marketing or growth pipeline shows a suspected missing offline conversion, a tracking/consent gap, or when an agent needs to know who owns a DataHub-tracked asset and what depends on it before proposing a fix. license: Apache-2.0 compatibility: Requires Python 3.11+ and a local checkout of github.com/Atroci/signalgraph. Live DataHub context additionally requires `uv` (for `uvx`) on PATH and a reachable DataHub GMS instance. metadata: repository: "https://github.com/Atroci/signalgraph" --- # SignalGraph evidence check SignalGraph turns a small sanitized aggregate (counts, never raw identifiers) into a deterministic finding, then optionally reads DataHub for the owner and downstream impact of the asset involved. It never guesses: a failed DataHub read is an error, not a fallback. ## When to use this skill - A conversion, booking, or lead count looks like it stopped arriving at a destination (ad platform, CRM, booking system) and you need a reproducible, non-anecdotal finding before opening an incident. - You have (or can produce) a sanitized aggregate contract — counts only — for click-context capture, consent enforcement, or destination delivery across a marketing journey, and want a deterministic health read instead of an eyeballed dashboard. - An agent already has a DataHub asset URN and needs the validated owner and degree-1 downstream assets before proposing or routing a fix. Do not use this skill to fetch raw event rows, resolve identity, compute attribution, or mutate any system. SignalGraph accepts operator-supplied or locally-derived aggregate counts only, and its only optional write is one idempotent DataHub incident (see Boundaries below). ## Decision: which evaluator | Evidence you have | Flag | Module | | --- | --- | --- | | Eligible vs. received/success/pending counts for one delivery | `--conversion-delivery` or a positional fixture | `signalgraph.rules` / `signalgraph.conversion_delivery` | | Local sanitized status CSVs instead of typed-in counts | `--fixture-context` + `--source-csv` + `--destination-csv` | `signalgraph.csv_input` | | Aggregate click/consent/journey counts across a marketing path | `--marketing-health` | `signalgraph.marketing_health` | | A marketing signal of unknown trustworthiness | `--signal` | `signalgraph.signal_contract` | ## Running it Offline (no DataHub, no credentials, deterministic): ```sh python3 -m signalgraph.cli \ --offline \ --markdown-out /tmp/evidence.md \ --json-out /tmp/evidence.json \ demo/fixtures/healthy.json demo/fixtures/missing_upload.json ``` With DataHub context, through the official read-only MCP path (requires `DATAHUB_GMS_URL`, optionally `DATAHUB_TOKEN`): ```sh export DATAHUB_GMS_URL=http://localhost:8080 python3 -m signalgraph.cli \ --mcp \ --markdown-out /tmp/evidence.md \ --json-out /tmp/evidence.json \ path/to/fixture.json ``` To also write DataHub context back — one Custom Assertion result per run, `SUCCESS` or `FAILURE` — add `--apply-assertion` to the `--mcp` command above (one fixture only). Add `--apply-incident` instead (or as well) to raise a DataHub incident, but only when the finding is not healthy. Never invent a fixture's `lineage` URNs. They must name real DataHub dataset URNs the operator controls; SignalGraph fails closed on a missing, ambiguous, or under-owned asset rather than guessing. ## Reading the result From the JSON document: - `mode` — `offline_fixture`, `datahub_readback`, or `datahub_mcp_readonly`. Only the latter two carry live DataHub evidence. - `results[].finding.failure_code` — one of `HEALTHY`, `NO_RECENT_UPLOAD`, `HIGH_MISMATCH`, `MISSING_DELIVERY`, `PENDING_OVER_TOLERANCE`. - `results[].finding.declared_exposure_estimate` — an operator-declared value, not measured loss. Say so if you relay it. - `results[].action_context.owners[].name` — who owns the destination asset. - `results[].action_context.blast_radius.downstream_count` — how many DataHub-tracked assets sit one hop downstream. Treat `datahub_evidence: false` as proof of the deterministic rule only, never as proof that a live DataHub instance holds these assets. ## Boundaries - Aggregate evidence only. No raw `gclid`/`fbclid`, cookies, customer identifiers, or probabilistic attribution ever enters this path. - Read-only against DataHub by default. Two independent, opt-in writes exist, each only after a validated MCP run and only for conversion fixtures: `--apply-incident` (one idempotent `OPERATIONAL` incident, only when the finding is not healthy) and `--apply-assertion` (one DataHub Custom Assertion, upserted and reported for every finding, including a healthy one). - No LLM, autonomy, or planning inside SignalGraph itself. It is a deterministic evaluator an agent calls, not an agent that decides on its own initiative. - Today's evaluators accept an operator-produced sanitized JSON aggregate or local sanitized CSV rows. They do not query a warehouse, ClickHouse, BigQuery, HubSpot, Typeform, or an ad platform directly; see `docs/roadmap.md` in the repository for that boundary. Full reference: `README.md`, `docs/architecture.md`, `docs/datahub.md`, and `docs/hackathon-demo.md` in the repository root.