# The artifact outranks the summary — the §2.5 structural-scrub gate

_Source: `system/cure/lib/run-driver/gate-graph.json` (the §2.5 gate node) and
`system/cure/lib/investigator-output-referential-integrity-gate.mjs` (the gate implementation). No
redaction required — framework gate topology and gate logic, no secrets or customer data. The one
run-id retained (`atomic-crm-20260525T153327Z`) is a Cure sandbox run, not a customer identifier._

## The gate

The Cure v2 operation carries a binding pre-aggregator gate. From `gate-graph.json`:

```json
{
  "gate_id": "§2.5",
  "title": "Pre-Aggregator Structural Scrub Gate (binding; both modes; FIX-RUN7-003)",
  "applicability": { "always": true },
  "prerequisites": ["§2.X.1", "§2.9"],
  "ledger_artifact": "gates/operator-only/investigator-output-referential-integrity.json",
  "clean_rule": { "kind": "presence", "rationale": "The phase-level gate (5 checks incl. C98 CB-3,
     4-way cardinality, per-shard RI, anchor-pseudonym consistency) emits …investigator-output-
     referential-integrity.json on PASS; a FAIL throws and §3 MUST NOT proceed." },
  "enforcement_tier": "mechanical"
}
```

It runs after the §2.X dir-hygiene passes and the §2.9 admissibility filter, and **before §3** (the
aggregator). A FAIL throws and §3 must not proceed — the aggregator never sees an investigation whose
outputs don't reconcile.

## What "the artifact outranks the summary" means

The gate's implementation (`investigator-output-referential-integrity-gate.mjs`) runs five checks.
The load-bearing one for this claim is **Check 1.5 — status ↔ findings.length consistency (the
silent-loss guard):**

> Catches the failure class where an investigator subagent reports `status: complete_with_findings`
> in its **return summary** AND advertises a findings count via a verbal summary, but the **persisted
> manifest's `findings` array is empty** (emit-time bug, transient write error, an agent flow that
> builds the envelope first but skips the `findings.push()` loop).

When a shard's status says `complete_with_findings` but `findings.length === 0`, the gate raises a
**blocker** (`per_claim_status_findings_silent_loss`) with this message:

> "This is a SILENT-LOSS failure — the agent reported finding(s) in its return summary, but the
> persisted manifest carries none. … The aggregator would otherwise see zero findings from this shard
> and silently drop the intended evidence."

That is the principle in one line: **a finding reported in the agent's conversational summary but
absent from the on-disk artifact is treated as a defect that blocks advancement — not as a finding.**
The persisted manifest (the artifact) is authoritative; the return summary is not. The check is
symmetric — `complete_clean` with a non-empty `findings` array is *also* a blocker
(`per_claim_status_findings_inverse_inconsistency`), so the status label and the artifact must agree
in both directions.

## Why the gate exists — a real loss it now prevents

The guard cites the run that motivated it (from the source comment): cure-v2 run
`atomic-crm-20260525T153327Z` "lost 3 P1 `check_constraint_missing_for_required_field` findings … agent
return summary cited 3 findings; persisted manifest had `findings: []`." The schema-enum check passed
(the status string was valid); the toxic-token scan passed (nothing toxic in an empty array); "but the
cluster never made it to the aggregator and would have stayed lost into the run report." Check 1.5
closes exactly that gap — the run now halts at §2.5 instead of silently under-reporting.

## Enforcement tier

`§2.5` is `enforcement_tier: "mechanical"` — enforced by code (the gate throws), not by a procedural
forcing function. It is one of the 36 mechanical gates in the Cure v2 operation
(`publications/chassis-reference/METRIC_PROVENANCE.md`, the 36-mechanical / 13-forcing-function
partition of the 49 gates).
