@@ -406,9 +406,63 @@ async function main() {
406406// as one that passed (#13798).
407407const SELF_TEST_VERDICT = 'check-declaration-mirrors self-test reached its verdict' ;
408408
409+ // ── The self-test's own battery roster and floor (#13489) ──────────────────
410+ //
411+ // `cases.filter((c) => !c.cond)` used to be this self-test's ONLY success
412+ // condition, so "every case
413+ // held" and "the cases never ran" printed the same line. Closed the way
414+ // PR #13487 validated on check-doc-authoring: what is pinned is the registered
415+ // NAMES, not a number. The floor requires the OPENED set to equal the DECLARED
416+ // set with each battery at or above its own count.
417+ //
418+ // This file declares ONE battery, opened at the top of the self-test body. Its
419+ // blocks are headed by unmarked prose comments, so it carries fewer than the two
420+ // named section banners the sectioning criterion needs, and ⛔ a comment is NOT
421+ // promoted to a section head — that is a judgement per comment this transplant
422+ // does not make. The hoisted single battery is the shape PR #14896, PR #15003
423+ // and PR #15217 landed for exactly this case.
424+ //
425+ // ⛔ A pinned TOTAL is not the repair: a battery dropping from 9 cases to 3
426+ // keeps a total "right" the moment a sibling grows.
427+ //
428+ // The count is a FLOOR, not an equality — adding cases is ordinary work and must
429+ // not red. A battery BELOW its floor means cases stopped running; the remedy is
430+ // to find what stopped registering.
431+ const SELF_TEST_BATTERIES = Object . freeze ( {
432+ 'check-declaration-mirrors self-test' : 23 ,
433+ } ) ;
434+
435+ // DELETING an entry silences that battery's floor exactly as effectively as
436+ // zeroing it, so the roster's own size is pinned too.
437+ const SELF_TEST_BATTERY_FLOOR = 1 ;
438+
439+ // The key an assertion is filed under when no battery is open. It is not a
440+ // declared battery, so it reds by the same set difference rather than silently
441+ // inflating whichever battery happened to run last.
442+ const UNATTRIBUTED_BATTERY = '(no battery open)' ;
443+
409444async function selfTest ( ) {
445+ // The battery ledger this self-test's floor is evaluated against (#13489).
446+ // `battery()` opens a battery; every assertion below is attributed to the one
447+ // most recently opened, so a section that stops running stops registering and
448+ // names ITSELF at the floor rather than going quiet.
449+ const batterySeen = new Map ( ) ;
450+ let openBattery = null ;
451+ const battery = ( name ) => {
452+ openBattery = name ;
453+ } ;
454+ const registerCase = ( ) => {
455+ const b = openBattery ?? UNATTRIBUTED_BATTERY ;
456+ batterySeen . set ( b , ( batterySeen . get ( b ) ?? 0 ) + 1 ) ;
457+ } ;
458+ battery ( 'check-declaration-mirrors self-test' ) ;
410459 const cases = [ ] ;
411- const ok = ( label , cond ) => cases . push ( { label, cond } ) ;
460+ // The concise arrow gains a BLOCK body so the case can be registered before
461+ // it is recorded; `cases.push` is unchanged, so no assertion is rewritten.
462+ const ok = ( label , cond ) => {
463+ registerCase ( ) ;
464+ cases . push ( { label, cond } ) ;
465+ } ;
412466 const dir = mkdtempSync ( join ( tmpdir ( ) , 'os-decl-mirror-' ) ) ;
413467 let seq = 0 ;
414468
@@ -549,6 +603,53 @@ async function selfTest() {
549603 mirrorFiles ( ) . every ( ( f ) => f . endsWith ( '.d.mts' ) ) ,
550604 ) ;
551605
606+ // ── The floor: every declared battery RAN, and ran its cases (#13489) ────
607+ //
608+ // Evaluated after every battery has had its chance and BEFORE the verdict, so
609+ // the success line below can only be printed by a run in which the set of
610+ // batteries that registered assertions EQUALS the set declared. A set
611+ // difference names WHICH battery stopped; a count says only that something did.
612+ // This file's sink IS the `cases` ledger, so the floor speaks its idiom: a
613+ // breach is recorded as a failing case and reds through the existing verdict
614+ // below. It bypasses `ok()` deliberately — a floor message is not a case.
615+ const floorFailure = ( message ) => { cases . push ( { label : message , cond : false } ) ; } ;
616+ const declaredBatteries = Object . keys ( SELF_TEST_BATTERIES ) ;
617+ let floorBreached = false ;
618+ if ( declaredBatteries . length < SELF_TEST_BATTERY_FLOOR ) {
619+ floorBreached = true ;
620+ floorFailure (
621+ `SELF_TEST_BATTERIES declares ${ declaredBatteries . length } batteries, below the pinned `
622+ + `${ SELF_TEST_BATTERY_FLOOR } — a battery deleted from the roster takes its own floor with it.` ,
623+ ) ;
624+ }
625+ for ( const [ name , count ] of batterySeen ) {
626+ if ( declaredBatteries . includes ( name ) ) continue ;
627+ floorBreached = true ;
628+ floorFailure (
629+ `self-test battery "${ name } " registered ${ count } case(s) but is not declared in `
630+ + 'SELF_TEST_BATTERIES — an assertion attributed to no declared battery is one nothing floors.' ,
631+ ) ;
632+ }
633+ for ( const name of declaredBatteries ) {
634+ const count = batterySeen . get ( name ) ?? 0 ;
635+ if ( count >= SELF_TEST_BATTERIES [ name ] ) continue ;
636+ floorBreached = true ;
637+ floorFailure (
638+ count === 0
639+ ? `self-test battery "${ name } " DID NOT RUN — 0 cases registered, ${ SELF_TEST_BATTERIES [ name ] } pinned. `
640+ + 'The verdict below would have claimed those cases hold.'
641+ : `self-test battery "${ name } " registered ${ count } case(s), below its pinned floor of `
642+ + `${ SELF_TEST_BATTERIES [ name ] } — cases that used to run no longer do.` ,
643+ ) ;
644+ }
645+ if ( floorBreached ) {
646+ floorFailure (
647+ 'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the '
648+ + 'number. Find what stopped registering (an early return, a deleted block, a guard that now '
649+ + 'skips) and restore it.' ,
650+ ) ;
651+ }
652+
552653 const failed = cases . filter ( ( c ) => ! c . cond ) ;
553654 for ( const c of cases ) console . log ( `${ c . cond ? 'ok ' : 'FAIL' } ${ c . label } ` ) ;
554655 if ( failed . length ) {
0 commit comments