@@ -378,9 +378,64 @@ function main(argv) {
378378// handshake is a flag rather than a returned sentinel.
379379let selfTestReachedVerdict = false ;
380380
381+ // ── The self-test's own battery roster and floor (#13489) ──────────────────
382+ //
383+ // `cases.filter((c) => !c.ok)` used to be this self-test's ONLY success
384+ // condition, so "every case
385+ // held" and "the cases never ran" printed the same line. Closed the way
386+ // PR #13487 validated on check-doc-authoring: what is pinned is the registered
387+ // NAMES, not a number. The floor requires the OPENED set to equal the DECLARED
388+ // set with each battery at or above its own count.
389+ //
390+ // This file declares ONE battery, opened at the top of the self-test body. It
391+ // carries exactly ONE named section banner (`The carve-out machinery, driven by
392+ // a SYNTHETIC exclusion`), which is fewer than the two the sectioning criterion
393+ // needs, and ⛔ a single banner is NOT split on — sectioning on it would leave
394+ // every case above it in an unnamed remainder battery this transplant would
395+ // have to invent a name for. The hoisted single battery is the shape PR #14896,
396+ // PR #15003 and PR #15217 landed for exactly this case.
397+ //
398+ // ⛔ A pinned TOTAL is not the repair: a battery dropping from 9 cases to 3
399+ // keeps a total "right" the moment a sibling grows.
400+ //
401+ // The count is a FLOOR, not an equality — adding cases is ordinary work and must
402+ // not red. A battery BELOW its floor means cases stopped running; the remedy is
403+ // to find what stopped registering.
404+ const SELF_TEST_BATTERIES = Object . freeze ( {
405+ 'check-docs-single-h1 self-test' : 20 ,
406+ } ) ;
407+
408+ // DELETING an entry silences that battery's floor exactly as effectively as
409+ // zeroing it, so the roster's own size is pinned too.
410+ const SELF_TEST_BATTERY_FLOOR = 1 ;
411+
412+ // The key an assertion is filed under when no battery is open. It is not a
413+ // declared battery, so it reds by the same set difference rather than silently
414+ // inflating whichever battery happened to run last.
415+ const UNATTRIBUTED_BATTERY = '(no battery open)' ;
416+
381417export function selfTest ( ) {
418+ // The battery ledger this self-test's floor is evaluated against (#13489).
419+ // `battery()` opens a battery; every assertion below is attributed to the one
420+ // most recently opened, so a section that stops running stops registering and
421+ // names ITSELF at the floor rather than going quiet.
422+ const batterySeen = new Map ( ) ;
423+ let openBattery = null ;
424+ const battery = ( name ) => {
425+ openBattery = name ;
426+ } ;
427+ const registerCase = ( ) => {
428+ const b = openBattery ?? UNATTRIBUTED_BATTERY ;
429+ batterySeen . set ( b , ( batterySeen . get ( b ) ?? 0 ) + 1 ) ;
430+ } ;
431+ battery ( 'check-docs-single-h1 self-test' ) ;
382432 const cases = [ ] ;
383- const t = ( name , ok , detail ) => cases . push ( { name, ok : Boolean ( ok ) , detail } ) ;
433+ // The concise arrow gains a BLOCK body so the case can be registered before
434+ // it is recorded; `cases.push` is unchanged, so no assertion is rewritten.
435+ const t = ( name , ok , detail ) => {
436+ registerCase ( ) ;
437+ cases . push ( { name, ok : Boolean ( ok ) , detail } ) ;
438+ } ;
384439
385440 const dir = mkdtempSync ( join ( tmpdir ( ) , 'docs-single-h1-' ) ) ;
386441 try {
@@ -493,6 +548,53 @@ export function selfTest() {
493548 rmSync ( dir , { recursive : true , force : true } ) ;
494549 }
495550
551+ // ── The floor: every declared battery RAN, and ran its cases (#13489) ────
552+ //
553+ // Evaluated after every battery has had its chance and BEFORE the verdict, so
554+ // the success line below can only be printed by a run in which the set of
555+ // batteries that registered assertions EQUALS the set declared. A set
556+ // difference names WHICH battery stopped; a count says only that something did.
557+ // This file's sink IS the `cases` ledger, so the floor speaks its idiom: a
558+ // breach is recorded as a failing case and reds through the existing verdict
559+ // below. It bypasses `t()` deliberately — a floor message is not a case.
560+ const floorFailure = ( message ) => { cases . push ( { name : message , ok : false } ) ; } ;
561+ const declaredBatteries = Object . keys ( SELF_TEST_BATTERIES ) ;
562+ let floorBreached = false ;
563+ if ( declaredBatteries . length < SELF_TEST_BATTERY_FLOOR ) {
564+ floorBreached = true ;
565+ floorFailure (
566+ `SELF_TEST_BATTERIES declares ${ declaredBatteries . length } batteries, below the pinned `
567+ + `${ SELF_TEST_BATTERY_FLOOR } — a battery deleted from the roster takes its own floor with it.` ,
568+ ) ;
569+ }
570+ for ( const [ name , count ] of batterySeen ) {
571+ if ( declaredBatteries . includes ( name ) ) continue ;
572+ floorBreached = true ;
573+ floorFailure (
574+ `self-test battery "${ name } " registered ${ count } case(s) but is not declared in `
575+ + 'SELF_TEST_BATTERIES — an assertion attributed to no declared battery is one nothing floors.' ,
576+ ) ;
577+ }
578+ for ( const name of declaredBatteries ) {
579+ const count = batterySeen . get ( name ) ?? 0 ;
580+ if ( count >= SELF_TEST_BATTERIES [ name ] ) continue ;
581+ floorBreached = true ;
582+ floorFailure (
583+ count === 0
584+ ? `self-test battery "${ name } " DID NOT RUN — 0 cases registered, ${ SELF_TEST_BATTERIES [ name ] } pinned. `
585+ + 'The verdict below would have claimed those cases hold.'
586+ : `self-test battery "${ name } " registered ${ count } case(s), below its pinned floor of `
587+ + `${ SELF_TEST_BATTERIES [ name ] } — cases that used to run no longer do.` ,
588+ ) ;
589+ }
590+ if ( floorBreached ) {
591+ floorFailure (
592+ 'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the '
593+ + 'number. Find what stopped registering (an early return, a deleted block, a guard that now '
594+ + 'skips) and restore it.' ,
595+ ) ;
596+ }
597+
496598 const failed = cases . filter ( ( c ) => ! c . ok ) ;
497599 for ( const c of failed ) console . error ( ` ✗ ${ c . name } ${ c . detail ? ` — ${ c . detail } ` : '' } ` ) ;
498600 if ( failed . length ) {
0 commit comments