@@ -277,18 +277,25 @@ export const REQUIRED_CONTEXTS = [
277277 * cannot be forgotten (self-test: 'the ledger cannot be forgotten').
278278 * - `staleSites` is a per-file OCCURRENCE BUDGET, not a ban: the occurrence
279279 * counts at rename time. Above budget = red (the dead name written
280- * FRESH); at or below = green with a notice. A ban would be wrong even
281- * for the fix PRs — the checklist's own fix keeps one `ESLint` as a
282- * deliberate historical mention ("改名前的 PR 仍列旧名"), and history is
280+ * FRESH); at or below = green with a notice. A ban would be wrong while
281+ * the fix PRs are in flight — a fix may legitimately keep the dead name
282+ * as a historical mention ("改名前的 PR 仍列旧名"), and history is
283283 * legitimate prose everywhere. Budgets only ever ratchet down, by hand,
284284 * notice-driven; a row whose budgets have been trimmed away is a standing
285- * ban on writing that dead name fresh anywhere in the scan set.
285+ * ban on writing that dead name fresh anywhere in the scan set. The
286+ * `ESLint` row reached that state on 2026-08-18: its checklist fix was
287+ * expected to keep one historical mention and dropped the name outright,
288+ * the trim notice fired, and the budget was deleted — measured, not
289+ * assumed, which is the whole point of the notice being notice-driven.
286290 * - `renameInFlight: true` lets the OLD literal satisfy a `mustName`
287291 * requirement while the instruction fixes are in flight. Once every
288292 * required-set surface names the new literal itself, a notice asks for
289293 * the flip to false. Flipping early is safe by construction: the flip PR
290294 * goes red while any surface still leans on the grace, so it cannot merge
291- * before the fixes do — it self-orders, it never races.
295+ * before the fixes do — it self-orders, it never races. (The pin runs in
296+ * the `Lint & Repo Gates` job with no `if:`, asserted in the wiring block
297+ * below, so "red" there means the required context is red — that is what
298+ * makes the self-ordering hold rather than merely being claimed.)
292299 *
293300 * ## What this scan can and cannot recognise, measured before it was built
294301 *
@@ -353,15 +360,19 @@ export const RETIRED_CONTEXT_NAMES = [
353360 name : 'ESLint' ,
354361 replacedBy : 'Lint & Repo Gates' ,
355362 authorized : '#9325 maintainer ruling 2026-08-17; workflow + registry half landed via #9421 on 2026-08-18' ,
356- // The checklist's gate-clearance line: stale when this ledger row was
357- // written (the fix was in flight as its own PR), and that fix keeps one
358- // deliberate historical `ESLint` mention on the same line — the budget is
359- // 1 across both states on purpose.
360- staleSites : { '.claude/skills/pm-dispatch/references/review-checklist.md' : 1 } ,
361- // While true, the old literal still satisfies mustName — the split-PR
362- // window. Flip to false once every required-set surface names
363- // 'Lint & Repo Gates' itself; the completion notice below says when.
364- renameInFlight : true ,
363+ // NO budgets: the rename is complete on every surface. The checklist's
364+ // gate-clearance line was the one budgeted site (1 occurrence, in flight
365+ // as its own PR when this row was written) and its fix was expected to
366+ // keep that mention as deliberate history; it dropped the name entirely
367+ // instead, the trim notice fired, and the budget was deleted on
368+ // 2026-08-18. This row is therefore now a standing ban: writing `ESLint`
369+ // fresh into ANY scanned surface is red. A future deliberate historical
370+ // mention is still legitimate prose — it just has to re-record a budget
371+ // here, in the same PR, saying why.
372+ // The grace is closed for the same reason: every required-set surface
373+ // names 'Lint & Repo Gates' itself, so the retired literal no longer
374+ // satisfies mustName (self-test: "the shipped ledger's grace is closed").
375+ renameInFlight : false ,
365376 } ,
366377 {
367378 // Not a rename — the CHECK itself retired (2026-08-18 ruling: a human
@@ -1143,23 +1154,35 @@ async function selfTest() {
11431154 ) ;
11441155
11451156 // A retired name written FRESH (beyond budget) ⇒ red, naming the file, the
1146- // budget and the replacement. Additive on purpose: the budgeted file holds
1147- // 1 occurrence before its fix PR and 1 after (the fix keeps a historical
1148- // mention), and two appended mentions exceed the budget from either base.
1149- const freshStale = judgeSurfaces ( {
1150- files : surfaceMap ( {
1151- [ CHECKLIST_SURFACE ] : surfaceSources [ CHECKLIST_SURFACE ] + '\n- 入队前亲核 ESLint job;确认 ESLint 已绿。\n' ,
1152- } ) ,
1153- } ) ;
1157+ // budget and the replacement. Additive on purpose: no anchor into a region
1158+ // an in-flight PR edits. The `ESLint` row's budgets have been trimmed away,
1159+ // so the checklist tolerates ZERO occurrences and one appended mention is
1160+ // already the red — the standing-ban state, asserted rather than described.
1161+ const freshChecklistText = surfaceSources [ CHECKLIST_SURFACE ] + '\n- 入队前亲核 ESLint job 是否已绿。\n' ;
1162+ const freshStale = judgeSurfaces ( { files : surfaceMap ( { [ CHECKLIST_SURFACE ] : freshChecklistText } ) } ) ;
11541163 assert (
11551164 freshStale . problems . some (
11561165 ( p ) =>
11571166 p . includes ( CHECKLIST_SURFACE ) &&
11581167 p . includes ( "retired required context 'ESLint'" ) &&
1159- p . includes ( 'budgeted: 1 ' ) &&
1168+ p . includes ( 'budgeted: 0 ' ) &&
11601169 p . includes ( "'Lint & Repo Gates'" ) ,
11611170 ) ,
1162- 'a retired name written beyond its budget ⇒ red, naming the file, the budget and the replacement' ,
1171+ 'a retired name written fresh into a trimmed row\'s surface ⇒ red, naming the file, the budget and the replacement' ,
1172+ ) ;
1173+ // …and that red is the TRIM's doing, not something the scan would say
1174+ // anyway: the identical text under a row that still budgets 1 for this file
1175+ // is green. Without this ablation the assertion above keeps passing on the
1176+ // day someone restores the budget, and the standing ban would be untested.
1177+ const budgetRestored = judgeSurfaces ( {
1178+ retired : RETIRED_CONTEXT_NAMES . map ( ( row ) =>
1179+ row . name === 'ESLint' ? { ...row , staleSites : { [ CHECKLIST_SURFACE ] : 1 } } : row ,
1180+ ) ,
1181+ files : surfaceMap ( { [ CHECKLIST_SURFACE ] : freshChecklistText } ) ,
1182+ } ) ;
1183+ assert (
1184+ budgetRestored . problems . length === 0 ,
1185+ `restoring a budget of 1 makes the same single mention green — the red above is the trimmed budget, nothing else — got ${ JSON . stringify ( budgetRestored . problems ) } ` ,
11631186 ) ;
11641187 const staleInAgents = judgeSurfaces ( {
11651188 files : surfaceMap ( { 'AGENTS.md' : surfaceSources [ 'AGENTS.md' ] + '\nConfirm the ESLint job is green before arming.\n' } ) ,
@@ -1169,36 +1192,54 @@ async function selfTest() {
11691192 'a retired name in a zero-budget surface ⇒ red (budgets tolerate only the sites recorded at rename time)' ,
11701193 ) ;
11711194
1172- // The post-fix state, synthesised from the fix PR's own line shape: current
1173- // names present, ONE historical `ESLint` mention within budget ⇒ green —
1174- // the fix itself must not be blocked by this scan — and the completion
1175- // notice asks for the renameInFlight flip.
1176- const postFix = judgeSurfaces ( {
1177- files : surfaceMap ( {
1178- [ CHECKLIST_SURFACE ] :
1179- '- 入队前亲核 Lint & Repo Gates 与 TypeScript Type Check 两个 job 的 `conclusion` 已为 `success`(必需检查认 check-run 名,改名前的 PR 仍列旧名 `ESLint`)。\n' ,
1180- } ) ,
1181- } ) ;
1195+ // The SHIPPED state of the #9325 rename, both halves of the housekeeping
1196+ // the notices drove (#9505). The grace is closed: a checklist that reverts
1197+ // to naming only the retired literal no longer satisfies mustName. Pinning
1198+ // this against the REAL ledger is the point — the synthetic pair further
1199+ // down proves the mechanism, this proves the mechanism is switched on in
1200+ // the row that ships.
1201+ const revertedText = '- 入队前亲核 ESLint 与 TypeScript Type Check 两个 job 的 `conclusion` 已为 `success`。\n' ;
1202+ const graceClosed = judgeSurfaces ( { files : surfaceMap ( { [ CHECKLIST_SURFACE ] : revertedText } ) } ) ;
11821203 assert (
1183- postFix . problems . length === 0 ,
1184- `the post-rename checklist (current names + one budgeted historical mention) ⇒ green — got ${ JSON . stringify ( postFix . problems ) } ` ,
1204+ graceClosed . problems . some (
1205+ ( p ) => p . includes ( CHECKLIST_SURFACE ) && p . includes ( "'Lint & Repo Gates'" ) && p . includes ( 'no longer names' ) ,
1206+ ) ,
1207+ "the shipped ledger's grace is closed: a surface naming only 'ESLint' is red on the required literal (#9505)" ,
11851208 ) ;
1209+ // Single-variable ablation of exactly that flip: re-open the grace on the
1210+ // real row and change NOTHING else (the budget stays trimmed, so the
1211+ // budget half still reds) — the NAMING red disappears. So the red above is
1212+ // renameInFlight: false, not the trim and not the file's other content.
1213+ const graceReopened = judgeSurfaces ( {
1214+ retired : RETIRED_CONTEXT_NAMES . map ( ( row ) => ( row . name === 'ESLint' ? { ...row , renameInFlight : true } : row ) ) ,
1215+ files : surfaceMap ( { [ CHECKLIST_SURFACE ] : revertedText } ) ,
1216+ } ) ;
11861217 assert (
1187- postFix . notices . some ( ( n ) => n . includes ( 'renameInFlight to false ') ) ,
1188- 'once every required-set surface names the current literal itself, the flip-to-false notice fires ' ,
1218+ ! graceReopened . problems . some ( ( p ) => p . includes ( "'Lint & Repo Gates'" ) && p . includes ( 'no longer names ') ) ,
1219+ 'flipping ONLY renameInFlight back to true clears the naming red — the red above is the flip, isolated ' ,
11891220 ) ;
11901221
1191- // A rewording that keeps the current literals and drops the historical
1192- // mention ⇒ green, with the trim notice (budgets only ever ratchet down).
1193- const reworded = judgeSurfaces ( {
1194- files : surfaceMap ( { [ CHECKLIST_SURFACE ] : '- 翻 ready 前确认 Lint & Repo Gates 与 TypeScript Type Check 均已 success。\n' } ) ,
1222+ // The two notices that drove this housekeeping must go SILENT once it is
1223+ // done: a completion notice that keeps firing after the work is finished
1224+ // trains the seat reading it to ignore the next one. Read from the real
1225+ // ledger against the real surfaces — the same pair the pin prints.
1226+ const shipped = judgeSurfaces ( ) ;
1227+ assert (
1228+ ! shipped . notices . some ( ( n ) => n . includes ( "'ESLint'" ) || n . includes ( 'renameInFlight to false' ) ) ,
1229+ 'after the flip and the trim, the ESLint row is silent — neither the trim notice nor the flip notice fires (#9505)' ,
1230+ ) ;
1231+ // The notice LOGIC outlives this rename, so it keeps its coverage through a
1232+ // synthetic in-flight row: the real ledger no longer has one, and an
1233+ // untested notice is the next rename's silent no-op.
1234+ const inFlightAgain = judgeSurfaces ( {
1235+ retired : [ { name : 'ESLint' , replacedBy : 'Lint & Repo Gates' , renameInFlight : true , staleSites : { [ CHECKLIST_SURFACE ] : 1 } } ] ,
11951236 } ) ;
11961237 assert (
1197- reworded . problems . length === 0 ,
1198- `a rewording that keeps the current literals ⇒ green — got ${ JSON . stringify ( reworded . problems ) } ` ,
1238+ inFlightAgain . notices . some ( ( n ) => n . includes ( 'renameInFlight to false' ) ) ,
1239+ 'the flip-completion notice still fires for an in-flight row whose surfaces have all moved to the current literal' ,
11991240 ) ;
12001241 assert (
1201- reworded . notices . some ( ( n ) => n . includes ( "'ESLint'" ) && n . includes ( 'trimmed' ) ) ,
1242+ inFlightAgain . notices . some ( ( n ) => n . includes ( "'ESLint'" ) && n . includes ( 'trimmed' ) ) ,
12021243 'a budget larger than the surviving occurrence count ⇒ the trim notice' ,
12031244 ) ;
12041245
0 commit comments