# Oracle cross-file CATCH measured — S9/C02 self-deal sink in an imported helper (#44)

audience: AI coding agents first. Optimize for activation, not prose.

**BLUF: the founding oracle class (C02 self-deal) is now CATCH-measured ACROSS files, not just reach-verified.**
Gate scans a caller that holds NO sink; `collect_deps` resolves the imported helper that BUILDS the money-move
sink; `run_oracle_set` runs the oracle on the resolved helper → the canonical self-deal pair `owner|referee`
is flagged (RED). The fixed helper → not flagged (GREEN). The caller scanned ALONE is oracle-SILENT — so
cross-file resolution, not the caller, is what surfaces the catch. Closes the
`2026-06-17-band2-delivery-shipped.md` gap: "reach restored, **not catch measured**". Deterministic, no LLM.

## What this closes (self-named gap)

`band2-delivery-shipped.md:80-83`: post-#42 `run_oracle_set` runs the oracle PER in-scope file, so an intra-dep
complete-mediation (C02/C09) sink IS scanned — BUT "the xfile cell is oracle-silent (auth), and NO corpus cell
yet has an imported-helper C02 sink. A dedicated cross-file imported-sink C02 cell is the proper measurement
(fast-follow, tie to #40); until then claim 'reach restored', not 'catch measured'." This cell IS that
measurement.

## The cell — real canonical, cross-file topology

`domains/security/detectors/oracle/cells/` (band-3 cells live WITH the detector, not under `corpus/`):
- `caller_vuln.ts` / `caller_safe.ts` — the scanned TARGET (models `payments/finalize.ts` importing the accrual
  service). Carries NO money-move sink. Imports `accrueAffiliateCommission` from `./service_{vuln,safe}`.
- `service_vuln.ts` / `service_safe.ts` — the imported helper that BUILDS the sink. Faithful reconstruction of
  multideal `apps/web/src/server/referrals/service.ts` @ `c2d8b4195` (RAW git). Self-contained: the
  `isSelfVendorPurchase` identity-predicate is inlined so the oracle resolves it in-file → `unresolved-imports: 0`.
- `canonical.json` — class S9, band 3, `fix_sha c2d8b4195`, `canonical_symbol "owner|referee"`.

C02 shape: `accrueAffiliateCommission` blocks the affiliate commission only when the REFERRER is the deal's
vendor owner; pre-fix it does NOT block when the BUYER (referee) owns the vendor → a buyer who owns the deal's
vendor self-deals a commission into their own wallet. `c2d8b4195` added the `isSelfVendorPurchase(referee, owner)`
guard.

## Measured (deterministic, `tests/test_oracle_xfile.py`, 3 tests, in the 27-pass suite)

```
RED   gate scan caller_vuln.ts → collect_deps resolves ['service_vuln.ts']
        service_vuln.ts : owner|referee = YES   (oracle INTRA-SINK GAP — CATCH)
        caller_vuln.ts  : owner|referee = no    (silent — the sink is cross-file only)
GREEN gate scan caller_safe.ts → collect_deps resolves ['service_safe.ts']
        service_safe.ts : owner|referee = no    (buyer self-deal now mediated — silent on canonical)
LOAD-BEARING  oracle on caller_vuln.ts ALONE (no resolution) → "(none — oracle SILENT)"
        → without cross-file resolution this C02 is a SILENT FALSE-CLEAN
```

Discriminator = the specific pair `owner|referee` (the exact pair `c2d8b4195` added a guard for): present in
RED, absent in GREEN. This is the project's recall definition (canonical_symbol substring in the finding).

## Measured on the REAL canonical (not only the reconstruction)

The RED catch is no longer reconstruction-only. The oracle was run on the REAL pre-fix file
`c2d8b4195~1:apps/web/src/server/referrals/service.ts` (via `git worktree` so the `./commission` siblings
resolve → `unresolved-imports: 0`):

```
fn accrueAffiliateCommission (L247)
  [INTRA-SINK GAP] accrueAffiliateCommission :: affiliate_commission @L356
      guards {owner|referrer} but NOT {owner|referee} — incomplete mediation on same sink
value-positive sinks: 2   flags: 3   unresolved-imports: 0
```

`owner|referee` IS flagged on the real ground-truth code — the reconstruction `service_vuln.ts` reproduces the
real canonical's catch faithfully. (The real fixed HEAD `service.ts` was likewise run → `owner|referee` is NOT a
FLAGS gap there, matching `service_safe.ts`.) The checked-in reconstruction cells are the permanent regression
fixture; this one-time real-repo run is the fidelity proof that the fixture matches ground truth.

## Discriminator semantics (right-reason hardening)

`owner|referee` is SEMANTICALLY AMBIGUOUS across the oracle's two output sections, so the test reads the section
it means:
- in **FLAGS** the pair means an UNMEDIATED gap → RED;
- in an EXTRACTED **`[gated:...]`** line the pair means MEDIATED → GREEN (verified: the safe helper emits
  `[gated:owner|referrer,owner|referee]`).

`gate.run_oracle` deliberately returns only the FLAGS section (triage-ready), which is why the simple substring
test discriminates — but that is a section-stripping side effect, not a guarantee. The tests now assert the
semantics directly (`tests/test_oracle_xfile.py`): RED → `owner|referee` is a FLAGS gap AND appears in NO
`[gated:]` line; GREEN → `owner|referee` is absent from FLAGS AND PRESENT in a `[gated:]` line. The GREEN
`[gated:]` assertion is load-bearing: it proves GREEN is green because the pair is MEDIATED, not because a fix
that DELETED the referee principal made the pair vanish (which would also pass a bare FLAGS-absence check — for
the wrong reason).

## Honest scope (no-false-coverage)

- **The oracle also emits a separate `referee|referrer` INTRA-SINK over-flag in BOTH RED and GREEN.** That pair
  is mediated UPSTREAM by `isSelfReferral` in the attribution path, not inside `accrue` — so the oracle, lacking
  that context, flags it on the real fixed code too (verified: running the oracle on the REAL HEAD `service.ts`
  emits exactly this `referee|referrer` flag). It is NOT the C02 canonical; the specific-pair `canonical_symbol`
  excludes it. Using the real fix's residual rather than fabricating a fully-silent GREEN keeps the cell faithful
  to ground truth. (This residual is a known oracle precision item, separate from this catch.)
- **n=1 cross-file CATCH proof.** Coverage/resolution is the ENABLER; recall-at-rate is the downstream #24 sweep.
  This cell proves the cross-file oracle path delivers a CATCH on a real canonical — it is not a recall rate.
- **Single-function reconstruction.** The cell isolates `accrueAffiliateCommission`; the sibling
  `qualifyRefereeFirstPaid` (C09, same fix) is not reconstructed here — INTER-SINK behavior is out of scope for
  this CATCH proof.

## Why it matters

C02/C09 are oracle-ONLY (no LLM backstop — `[MEASURED]` no unseeded LLM config ever caught C02). Before #42,
scanning a route never pulled the accrual helper into scope, so a C02 sink built inside that helper was an
unrecoverable silent false-clean. #42 restored the reach; #44 proves the reach delivers the catch end-to-end.
