# Template -- Probe Finding Record

**Type:** Template
**Owner:** Blind-Spot Mapper (E5)
**Emitted to:** Reopen Authority Enforcer (E7), Self-Audit Resistance Monitor (E9), Evaluator Search Ledger (writer: E5; owner: E4)

---

## Per-probe record

Every probe emits one record per (claim, probe) pair, fired or null. Silent omission is a NEVER rule.

```json
{
  "record_type": "probe_finding",
  "record_schema_version": "1.0",
  "run_id": "<string>",
  "claim_id": "<string>",
  "probe_id": "BSP-01-MONOCULTURE | BSP-02-COVERT-TIER-BIAS | BSP-03-FORCED-CLOSURE | BSP-04-PUB-BIAS-MISS | BSP-05-RETRACTION-MISS | BSP-06-AI-CONTAMINATION-MISS",
  "probe_version": "<string>",
  "fired": true | false | null,
  "null_reason": "probe_unavailable | registry_offline | insufficient_evidence | null",
  "severity": "low | medium | high | critical | null",
  "evidence": {
    "_probe_specific": "<structured per probe reference>"
  },
  "taxonomy_entry_candidate": "<existing entry id | new | PROPOSED-NEW-PROBE>",
  "criterion_hash": "<string; immutable across the run>",
  "frame_registry_ref": "<string>",
  "ledger_ref": "<string>",
  "source": "production | seeded",
  "seeded_case_id": "<string or null>"
}
```

Invariants:

- `fired: null` ONLY if `null_reason` is set. A null record with no reason is a structural error.
- `severity` is `null` iff `fired` is `false` or `null`.
- `criterion_hash` is identical across all records emitted in the same run; mismatch invalidates the run.
- `source: "seeded"` REQUIRES a non-null `seeded_case_id`.

---

## Per-signal record

The 5-signal integrity inventory emits one record per signal per run:

```json
{
  "record_type": "signal_finding",
  "record_schema_version": "1.0",
  "run_id": "<string>",
  "signal_id": "SIG-01 | SIG-02 | SIG-03 | SIG-04 | SIG-05",
  "signal_version": "1.0",
  "fired": true | false,
  "severity": "low | medium | high | critical | null",
  "evaluated_at_phase": "A | C/D",
  "evidence": { "_signal_specific": "<structured per signal>" },
  "absolute_counts": { "<optional for SIG-01>": "..." },
  "halted_run": true | false
}
```

Invariants:

- `halted_run: true` ONLY for `signal_id: "SIG-03"` with `fired: true`. Any other signal cannot halt.
- `severity` is `null` iff `fired` is `false`.

---

## Run summary record

Emitted once per run, after probes and signals complete:

```json
{
  "record_type": "run_summary",
  "record_schema_version": "1.0",
  "run_id": "<string>",
  "criterion_hash": "<string>",
  "criterion_hash_at_run_end": "<string; MUST equal criterion_hash>",
  "probes_run_count": <int>,
  "probes_fired_count": <int>,
  "nulls_emitted": <int>,
  "signals_fired": ["<signal_id>", ...],
  "severity_max": "low | medium | high | critical | null",
  "taxonomy_version_at_run_start": "<semver>",
  "taxonomy_version_at_run_end": "<semver>",
  "entries_touched": ["<entry_id>", ...],
  "delta_metrics": { "<SIG-01 context>": "..." },
  "halted": true | false,
  "halt_reason": "<string or null>"
}
```

The run summary is the ONLY record E9 requires to compute over / under-report externally. Per-probe and per-signal records provide the disaggregation E9 uses for precision computation.

---

## Emission rules

1. Write each record to the Evaluator Search Ledger as it is produced; do not batch.
2. Emit per-probe records and per-signal records to E9 co-emission channel simultaneously with ledger write.
3. Emit run summary to E7 (findings) and E9 (diagnostic metadata) AFTER all per-probe and per-signal records are written.
4. If a ledger write fails, HALT the run; do not emit findings on an incomplete ledger.
