@@ -582,7 +582,17 @@ function classify(type: string, path: string, status: string, led: any, cat: any
582582
583583// Reverse integrity: every `@proof:` tag declared under the dogfood proof tree
584584// must be registered in proof-registry.mts. An orphan tag means a proof was
585- // written but never wired into the high-risk-class list — flag it (warning).
585+ // written but never wired into the high-risk-class list.
586+ //
587+ // RED since 2026-08-26, having been a ⚠ before. The warning was calibrated for
588+ // a backlog era — it reported 13 orphan tags at once, then 11 — and a signal
589+ // that never fails the build cannot close the class it names: the 11 were
590+ // registered in one round, a 12th arrived with the next dogfood proof, and the
591+ // second card was written from the same ⚠ line as the first. The census that
592+ // licenses the flip is that round's own arithmetic: the list is at ZERO on the
593+ // commit this changes, so the gate starts green and only a NEW unregistered tag
594+ // can red it — the same "a check that starts at zero can be red" reasoning the
595+ // key-mention half was switched on under.
586596function scanOrphanProofs ( ) {
587597 const proofDir = join ( repoRoot , 'packages/qa/dogfood/test' ) ;
588598 if ( ! existsSync ( proofDir ) ) return ; // spec may be consumed standalone (published)
@@ -820,6 +830,10 @@ const failed =
820830 // be red; that is the whole reason the census came first.
821831 report . keyMentionUnanchored . length > 0 ||
822832 report . keyMentionStale . length > 0 ||
833+ // A dogfood `@proof:` tag the registry never learned about. Red rather than ⚠
834+ // since 2026-08-26 — see scanOrphanProofs for why the warning could not close
835+ // the class, and for the zero-census that lets this start green.
836+ report . orphanProofs . length > 0 ||
823837 report . orphanEntries . length > 0 ||
824838 report . verification . errors . length > 0 ||
825839 report . producers . errors . length > 0 ||
@@ -937,8 +951,29 @@ if (asJson) {
937951 ) ;
938952 }
939953 if ( report . orphanProofs . length ) {
940- console . log ( `\n⚠ ${ report . orphanProofs . length } unregistered dogfood proof tag(s) — add to proof-registry.mts:` ) ;
954+ console . log ( `\n✗ ${ report . orphanProofs . length } unregistered dogfood proof tag(s) — add to proof-registry.mts:` ) ;
941955 report . orphanProofs . forEach ( ( s : string ) => console . log ( ` ${ s } ` ) ) ;
956+ console . log (
957+ '\n A `@proof:` tag on disk that the registry does not know is a proof no ledger entry\n' +
958+ ' can cite: `BOUND_PROOF_PATHS` is built from HIGH_RISK_CLASSES, so an unregistered\n' +
959+ ' proof cannot bind a `live` verdict however thoroughly it runs.\n\n' +
960+ ' Add a HIGH_RISK_CLASSES entry in proof-registry.mts. Registering is mechanical;\n' +
961+ ' the judgment half is `bound`. Read the proof file and ask: is there an AUTHORABLE\n' +
962+ ' property whose `live` status it actually gates?\n' +
963+ ' • yes → `bound: true` + the `ledgerBindings` entry, and put the same `proof` ref\n' +
964+ ' on that ledger row (the wiring test in proof-registry.test.ts holds both ends);\n' +
965+ ' • no → `bound: false` + a `blockedReason` naming what it guards INSTEAD (a\n' +
966+ ' runtime/service invariant, a breadth sweep, or an entry already spoken for —\n' +
967+ ' a ledger row carries one `proof` ref). Registered-and-honestly-unbound is a\n' +
968+ ' first-class outcome; most of the registry is exactly that.\n' +
969+ ' ⛔ Do not bind a proof to a property it does not AUTHOR just to reach `bound: true`\n' +
970+ ' — a citation for a property the proof never exercises is the false comfort the\n' +
971+ ' whole ledger exists to end.\n\n' +
972+ ' This was a ⚠ until 2026-08-26. It reported 13 tags, then 11, and a warning nothing\n' +
973+ ' fails on cannot close a class: the 11 were registered in one round and a 12th\n' +
974+ ' arrived with the next dogfood proof, its card written off the same ⚠ line. The list\n' +
975+ ' was at zero when this became red, so a hit here is a NEW tag, not a backlog.' ,
976+ ) ;
942977 }
943978 if ( report . proofMissing . length ) {
944979 console . log ( `\n✗ ${ report . proofMissing . length } high-risk 'live' propert(ies) missing a runtime proof:` ) ;
@@ -1168,7 +1203,8 @@ if (asJson) {
11681203 'every container inheritance is declared, every `live` entry\'s repo-local evidence path ' +
11691204 'resolves, every `path:NNN` citation names a line that file actually has and every cited ' +
11701205 'file names the property it is evidence for (or is a recorded exemption), all bound ' +
1171- 'high-risk proofs resolve, and the README state table carries a row ' +
1206+ 'high-risk proofs resolve, every dogfood `@proof:` tag on disk is registered in ' +
1207+ 'proof-registry.mts, and the README state table carries a row ' +
11721208 `for each of the ${ report . readmeRowCount } governed type(s) it claims to index.` ,
11731209 ) ;
11741210 console . log (
0 commit comments