STOP — do NOT treat the next push as acceptance. I am HOLDING the IR-146 land. Your classifier has a field defect, found by the push that landed IR-147 itself. MEASURED, post-merge main run 35998753683 at 9aa011ac, changes job 107629922177: CLASSIFY_BEFORE: c185326bd2b08e152cc33aa975fcea2240ca1cc8 CLASSIFY_FORCED: false CLASSIFY code=true reason=before-not-ancestor UNIT_REUSE run-unit=false reason=exact-pr-proof run=35996160079 attempt=1 sha=9aa011ac... before-not-ancestor is FALSE. c185326b IS an ancestor of 9aa011ac — I measured it myself immediately before pushing, from my full clone: `git merge-base --is-ancestor origin/main 9aa011ac` exit 0, with origin/main == c185326b at that moment, and `git log origin/main..9aa011ac` listing exactly 0854bbe8 and 9aa011ac. The SHAs are right; the ancestry VERDICT is wrong. MECHANISM (my read, yours to confirm at source): classify_push conflates "NO" with "CANNOT TELL". Two links: 1. The reachability probe is `cat-file -e before^{commit}` — that tests OBJECT PRESENCE, not HISTORY CONNECTIVITY. Self-hosted runners reuse their workspace, so a stale object from an earlier run can make the probe succeed while the CURRENT depth-2 shallow history does not link before..sha. Presence then short-circuits the deepen loop at step 0 and the history is never completed. c185326b sits at depth 3 here (9aa011ac <- 0854bbe8 <- c185326b), so a clean depth-2 checkout should NOT have had it — which is itself evidence the object was stale. 2. `merge-base --is-ancestor` returns non-zero both for "not an ancestor" AND for "cannot decide on this shallow graph". You map every non-zero to before-not-ancestor. CONSEQUENCE, and why I am holding: the direction is safe — it fell back to code=true, and IR-144's exact-pr-proof skipped units anyway, so nothing was wasted today. But if before-not-ancestor is what a self-hosted push reliably produces, the docs-only push path NEVER fires in the field, and IR-147 is built but inert. Your pre-registered prediction for IR-146 (code=false reason=docs-only) would then red — and it would red for THIS reason, not for the one the prediction is about. That is a burned acceptance, which is exactly what the pre-registration existed to prevent. It worked; use it. Also note IR-146's own PR is docs-only, so its PR run skips units, so there is NO exact-pr-proof at its sha. If it lands while the ancestry probe is broken, the fallback runs BOTH full unit legs on a Markdown-only commit — the precise cost IR-147 exists to remove, paid on IR-147's own acceptance run. And the box is not free: todlando's W3 window is live on hfenduleam right now. WHAT I NEED: 1. Confirm or refute the mechanism at source, from that job's log and the runner's checkout, not from reasoning. If the object was stale, say how you determined it. 2. Fix the probe so presence is not mistaken for connectivity: deepen until `merge-base --is-ancestor` SUCCEEDS (or the bound is hit), rather than until `cat-file` succeeds. And split the outcomes — a shallow graph that cannot decide is its own named reason (before-undecidable or similar), not before-not-ancestor. Both still run units; the point is that the log must say which happened, or the next person reads a real non-ancestor into a shallow artefact. 3. A selftest arm for it: a fake git where cat-file SUCCEEDS and is-ancestor fails, asserting the deepen still runs and the reason is the new one. That arm must red before your fix and green after — negative control first, as before. 4. Re-run the local dry-run for the IR-146 range against the FIXED classifier, and re-register the prediction. IR-146 (c) @eb5de50f stays unlanded until that lands. It is still the right acceptance vehicle — just not yet. Nothing about the gate verdict changes: the four conditions held, and this is a defect the gate could not have caught, because it only exists on a real self-hosted shallow checkout. Good pre-registration is why we are catching it as a finding instead of as a mystery red.