# Band-2 consolidation + verification-stage — CANDIDATE (items #9/#13/#14)

date: 2026-06-20 · status: **resolver/barrel/degraded-emit SHIPPED; verification-stage = CANDIDATE (not in live orchestrator)** · parent: `docs/validation/2026-06-17-band2-trigger-gap-shipped.md` · source defect: `docs/validation/2026-06-19-live-fire-precision-3repos.md:40` (defect #2) · gate to apply: k≥3 measurement (below)

## BLUF
Band-2's cross-file MECHANISM is built and tested. The one open band-2 CODE item is **defect #2** (`...live-fire-precision-3repos.md:40`): the orchestrator's LLM emit raises **confident per-finding criticals** (`sev=critical, rolls=3, of=3`) on code whose decisive guard lives in an **unresolved import the gate never saw** — the trance TOCTOU (3/3) + itemIds IDOR (2/3) false-alarms whose real guard (CAS `UPDATE...WHERE status IN(...)`; order scoped by `userId`) sat in an unresolved predicate import. Its precise fix is a **verification stage** (#14) that makes the LLM self-report cross-file dependence and downgrade. That is an LLM-behavior change with no deterministic core → its recall/precision effect is knowable ONLY by rolling → **CANDIDATE**, same shape as #15, NOT a live orchestrator edit this session.

## Reconciliation — band-2 mechanism is SHIPPED (correcting "band-2 not yet started")
Orientation evidence overturns the earlier "highest lever, not yet started" framing. Already shipped + tested:
- **Cross-file resolver (#36) + barrel-following (#13):** `orchestrator/resolver.py:262 first_party_value_imports` pulls ALL first-party value imports (not payment-named); `:217 resolve_through_barrel` follows named re-exports + `export *` to the definition site with a local-def short-circuit (no false-clean); `:293 collect_deps` is budget-capped, `dropped` never silently skipped. Trigger gap CLOSED (`2026-06-17-band2-trigger-gap-shipped.md` §RESOLVED); budget invariant E2E-tested (`tests/test_gate_emit.py::test_over_budget_fanin_drops_real_and_emit_is_degraded`).
- **no-false-clean DUAL at RESULT level — shipped on BOTH sides:** the emit sets `status="degraded"` + lists `coverage.unresolved` whenever a dep is dropped / merge degrades / the oracle is unreliable (`orchestrator/gate.py:292`); the PREVENT consumer treats any `status in (degraded,error)` as COVERAGE-INCOMPLETE — surfaced, **never blocks** (`prevent/runner.py:100-102` + docstring `:12-13`).

What is genuinely OPEN is narrower than "build band-2": it is defect #2's **per-finding** reliability under degraded scope (below) + the corpus-blocked recall RATE.

## Block-safety is established — defect #2 is triage-legibility, not a block hole
A grep decides whether defect #2 is a block-safety defect or an audit-legibility one:
- `build_emit_dict` (the orchestrator LLM emit) is referenced ONLY in `orchestrator/gate.py` + `orchestrator/semantic_merge.py`. **No `prevent/` code reads it.**
- PREVENT's block ladder (`prevent/runner.py:103-109`) operates on findings from its OWN registry detectors run as subprocesses (`_run_detector`), emitting the `contract.py` shape directly — it does NOT consume `gate.py --emit`. The orchestrator emit is the band-2 **audit artifact** (human / fix-agent / `bench.py` read), not a block input.

⇒ The confident-critical-under-degraded-scope is a **triage-legibility** miss in the audit artifact (a fix-agent wastes a cycle on a false alarm), NOT a path that blocks a commit on unseen-guard code. This is why the fix is a precision refinement (downgrade for legibility), not an emergency block-safety patch — and why it can be measurement-gated rather than rushed live.

## Why NOT a coarse deterministic marker (the rejected shortcut)
The tempting "deterministic" move — when `status=degraded`, tag EVERY LLM finding `unverified-cross-file` — is REJECTED:
1. **It does not satisfy defect #2.** The defect is per-finding ("a finding *whose decisive predicate is in an unresolved import*"). A flag firing on every finding under degraded scope marks a rock-solid in-file `sql.raw(userInput)` finding as unreliable merely because some unrelated import was budget-dropped — a **false reliability signal**.
2. **Oracle-symmetry breaks on presence-vs-absence.** The oracle's UNRELIABLE is conservative on a *negative/silent* result (free — it was not going to block). Marking a *positive* finding unreliable has real cost: it trains the consumer to discount TRUE positives. Conservative-on-negatives ≠ conservative-on-positives.
The discriminating axis is **absence-class-vs-presence + which predicate the verdict hinges on** — which is NOT deterministically available without the LLM emitting a "this finding depends on cross-file context I could not resolve" flag. That flag is the verification stage; it is LLM behavior → measurement-blocked.

## The candidate — verification stage (#14), mechanism specified, NOT applied
After the k-union, a verification sub-prompt asks the orchestrator, per surviving finding:
```
For each finding, decide: is your verdict DECIDED by a predicate (guard, atomicity, scope check,
signature/secret verify) whose body is in coverage.unresolved (a dropped/unresolved import the
review did not contain)? If YES → emit reliability="cross-file-unverified" and downgrade the
finding off block-eligibility (it becomes a WARN-tier lead to verify, not a confident critical).
NEVER downgrade an ABSENCE-CLASS finding (a missing guard whose absence IS the defect — there is
no cross-file body that could exonerate it). NEVER downgrade a finding whose decisive predicate is
IN the reviewed code (in-file sink, present here).
```
Design properties that bound the recall risk:
- **Downgrade, never withhold** — preserves no-false-clean (`baseline.prompt.txt:83` absence-class rule untouched). The finding stays in the emit, re-tiered with a visible `reliability` reason.
- **Absence-class never-downgrade** — the load-bearing recall guard. A missing-authz / missing-CSRF / fail-open finding has no exonerating cross-file body, so degraded scope NEVER lowers it.
- **In-file-predicate never-downgrade** — kills the coarse-marker failure: a finding decided by code present in the review is full-confidence regardless of unrelated dropped imports.

## A/B measurement cells (build at neutral path, RAW-git provenance from the real fix commits)
| id | shape | expected under candidate | role |
|----|-------|--------------------------|------|
| B1 | trance TOCTOU: status-transition critical whose CAS guard `UPDATE...WHERE status IN(...)` is in an UNRESOLVED import | finding KEPT, `reliability=cross-file-unverified`, downgraded off block-eligibility | precision target (the live-fire defect #2 false-alarm) |
| B2 | itemIds IDOR: order-access critical whose `userId` scoping is in an UNRESOLVED import | KEPT, downgraded + reliability note | precision target |
| B3 | in-file `sql.raw(userInput)` injection + ONE unrelated budget-dropped import (status=degraded) | **stays full confidence — NO downgrade** (decisive predicate is in-file) | **precision tripwire** (the coarse-marker failure the rule must avoid) |
| B4 | absence-class: missing authz check on a mutating route, under degraded scope | **stays full confidence — NO downgrade** (absence-class) | **recall-regression tripwire** |
B3/B4 are load-bearing: if the candidate ever downgrades them it is REJECTED. B1/B2 downgraded + B3/B4 held is the precision win.

## Apply-gate (the one blocked step — do NOT wire the verification stage until ALL green)
1. **Recall no-regression** — k≥3 union over the 17 LLM corpus cells, OLD vs NEW orchestrator; NEW drops no right-reason catch. B4 (absence-class) stays full every roll.
2. **Precision** — B1/B2 downgraded + B3 held, n≥3, on the real trance/itemIds live-fire files.
3. **Discriminator** — safe.ts 17/17 unchanged.
Wire the verification stage into the orchestrator ONLY after 1+2+3 are measured green. Record a validation doc; update CLAUDE.md "Measured state".

## Status / done-bar
- **SHIPPED + green (real completion):** resolver #36 + barrel #13 + result-level degraded-emit no-false-clean dual (both sides), all deterministically tested.
- **CANDIDATE (rate-pending, this doc):** the verification stage #14 — mechanism + absence-class/in-file guardrails + A/B cells + apply-gate fully specified; recall/precision UNMEASURED this session (no rolls). Identical shape to the #15 executable-stub candidate.
- **Corpus-blocked residual (shared with #8/#10):** the n≥3 Shape-B recall RATE across non-payments domains (Shape-B n=1/85; synthesis FORBIDDEN) + the #9 flaky-tail (7×2/3 cells, the k=1 production-orchestrator recall) — both await real harvested fix commits, not orchestrator code.

This is "real completion" under the locked done-bar (mechanism built + green on available cells + documented measurement gap), NOT a deferral.
