@@ -1420,6 +1420,141 @@ function report({ wide = false } = {}) {
14201420 }
14211421}
14221422
1423+ // ── The assertion floor, per battery (#13489) ───────────────────────────────
1424+ //
1425+ // One battery per NAMED SECTION of `selfTest()`, each key byte-equal to the
1426+ // box-drawing banner it stands for, so a battery that stops registering names
1427+ // the banner a reader can go find instead of a number that says only that
1428+ // something moved.
1429+ //
1430+ // The counts are FLOORS MEASURED ON A RUN, never static `t(` site counts: eight
1431+ // of this body's sites sit inside loops — four over the recorded spellings and
1432+ // four over the DECLARED-NARROWER rows of `TRIAGE` — so two of these batteries
1433+ // run several times their static site count, and a floor planned from the
1434+ // source would sit far below what actually runs and would floor nothing.
1435+ //
1436+ // ⛔ A pinned TOTAL is not the repair: one battery falling from 60 cases to 3
1437+ // keeps a total "right" the moment a sibling grows. That is what six batteries
1438+ // buy over one number.
1439+ //
1440+ // The counts are a FLOOR, not an equality — adding cases is ordinary work and
1441+ // must not red. A battery BELOW its floor means cases stopped running; the
1442+ // remedy is to find what stopped registering.
1443+ //
1444+ // ⚠️ The seven cases that run BEFORE the first banner have no section head of
1445+ // their own. They are attributed to the FIRST banner's battery, whose opener is
1446+ // hoisted to the top of the body so that banner carries no second opener —
1447+ // PR #13487's shape, as batches 1b and 2 landed it. Promoting their comment to
1448+ // a section head would be a source change this batch does not make, and leaving
1449+ // them unattributed reds by the set difference below, which is the point.
1450+ const SELF_TEST_BATTERIES = Object . freeze ( {
1451+ 'The FOLD: one row per literal, however many invocations reach it' : 14 ,
1452+ 'The triage coupling, both directions' : 6 ,
1453+ 'The MECHANISM a repaired reason turns on, held mechanically' : 4 ,
1454+ 'The RECORDED SPELLINGS, pinned: LIVENESS and PRECISION' : 65 ,
1455+ "The DECLARATION a row describes, read from the gate's own SOURCE" : 43 ,
1456+ 'CENSUS_REFUSE_WIDE, pinned on its OWN terms (#14695)' : 5 ,
1457+ } ) ;
1458+
1459+ // DELETING an entry silences that battery's floor exactly as effectively as
1460+ // zeroing it, so the roster's own size is pinned too.
1461+ const SELF_TEST_BATTERY_FLOOR = 6 ;
1462+
1463+ // The key a case is filed under when no battery is open. It is not a declared
1464+ // battery, so it reds by the same set difference rather than silently inflating
1465+ // whichever battery happened to run last.
1466+ const UNATTRIBUTED_BATTERY = '(no battery open)' ;
1467+
1468+ // ── Why the CHECK sits inside `selfTest()`, at its verdict site ─────────────
1469+ //
1470+ // This body both REGISTERS and DECIDES: it prints its own verdict and exits 1
1471+ // itself, so the success line and the floor are in the same frame and the floor
1472+ // goes immediately above that line — the only place a run that registered
1473+ // nothing can still be stopped from reporting that every case held.
1474+ //
1475+ // The landed recipe refuses a floor placed before a plain `return`, because an
1476+ // early return above it skips the check. That hole is not open here, and the
1477+ // reason is mechanical rather than argued: this body's only exit that a caller
1478+ // accepts is the `SELF_TEST_VERDICT` sentinel returned BELOW the success line
1479+ // (#13798), and the dispatch refuses anything else. An early return therefore
1480+ // reds at the HANDSHAKE, not silently — while a section that keeps running to
1481+ // the bottom with its cases gone reds at the FLOOR. The two holes stay
1482+ // orthogonal, each with its own guard, which is how that card ruled them.
1483+
1484+ // The battery ledger, read by `batteryFloorFailures()` at `selfTest()`'s verdict
1485+ // site. `battery()` opens a battery; every case registered after that line is
1486+ // attributed to the one most recently opened, so a section that stops running
1487+ // stops registering and names ITSELF at the floor rather than going quiet.
1488+ //
1489+ // ⚠️ Named for the roster's role, deliberately NOT with a self-test spelling:
1490+ // `check:pm-dispatch-gates` anchors on a top-level declaration whose NAME spells
1491+ // self-test and every such name owes a row in its COMPOUND_ANCHOR_LEDGER. This
1492+ // machinery holds no fixtures to mask and reads no path literal, so the accurate
1493+ // name is the one that says `battery`.
1494+ const batterySeen = new Map ( ) ;
1495+ let openBattery = null ;
1496+
1497+ /** Open a battery. Every case registered after this line is attributed to it. */
1498+ function battery ( name ) {
1499+ openBattery = name ;
1500+ }
1501+
1502+ /** Called by `selfTest()`'s own case sink, once per case. */
1503+ function registerCase ( ) {
1504+ const name = openBattery ?? UNATTRIBUTED_BATTERY ;
1505+ batterySeen . set ( name , ( batterySeen . get ( name ) ?? 0 ) + 1 ) ;
1506+ }
1507+
1508+ /**
1509+ * The floor: every declared battery RAN, and ran its cases (#13489).
1510+ *
1511+ * Guards the registrations made by `selfTest()` — the body whose case sink
1512+ * `t()` routes through `registerCase()`. It is called at that body's verdict
1513+ * site, after every battery has had its chance and before the success line, so
1514+ * that line can only be printed by a run in which the set of batteries that
1515+ * registered cases EQUALS the set declared, each at or above its own count. A
1516+ * set difference says WHICH battery stopped; a count says only that something
1517+ * did.
1518+ *
1519+ * @returns {string[] } floor breaches; empty means the floor held
1520+ */
1521+ function batteryFloorFailures ( ) {
1522+ const declared = Object . keys ( SELF_TEST_BATTERIES ) ;
1523+ const problems = [ ] ;
1524+ if ( declared . length < SELF_TEST_BATTERY_FLOOR ) {
1525+ problems . push (
1526+ `SELF_TEST_BATTERIES declares ${ declared . length } batteries, below the pinned `
1527+ + `${ SELF_TEST_BATTERY_FLOOR } — a battery deleted from the roster takes its own floor with it.` ,
1528+ ) ;
1529+ }
1530+ for ( const [ name , count ] of batterySeen ) {
1531+ if ( declared . includes ( name ) ) continue ;
1532+ problems . push (
1533+ `self-test battery "${ name } " registered ${ count } case(s) but is not declared in `
1534+ + 'SELF_TEST_BATTERIES — a case attributed to no declared battery is one nothing floors.' ,
1535+ ) ;
1536+ }
1537+ for ( const name of declared ) {
1538+ const count = batterySeen . get ( name ) ?? 0 ;
1539+ if ( count >= SELF_TEST_BATTERIES [ name ] ) continue ;
1540+ problems . push (
1541+ count === 0
1542+ ? `self-test battery "${ name } " DID NOT RUN — 0 cases registered, ${ SELF_TEST_BATTERIES [ name ] } pinned. `
1543+ + 'The verdict below would have claimed those cases hold.'
1544+ : `self-test battery "${ name } " registered ${ count } case(s), below its pinned floor of `
1545+ + `${ SELF_TEST_BATTERIES [ name ] } — cases that used to run no longer do.` ,
1546+ ) ;
1547+ }
1548+ if ( problems . length ) {
1549+ problems . push (
1550+ 'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the '
1551+ + 'number. Find what stopped registering (an early return, a deleted block, a guard that now '
1552+ + 'skips, a loop that no longer reaches it) and restore it.' ,
1553+ ) ;
1554+ }
1555+ return problems ;
1556+ }
1557+
14231558// Returned by `selfTest()` only after its verdict is printed. The dispatch
14241559// refuses anything else: a `return` that leaves the function above that line
14251560// prints nothing and still exits 0 — a self-test that never finished, reported
@@ -1428,7 +1563,17 @@ const SELF_TEST_VERDICT = 'bare-root-worklist self-test reached its verdict';
14281563
14291564function selfTest ( ) {
14301565 const failures = [ ] ;
1431- const t = ( label , ok ) => { if ( ! ok ) failures . push ( label ) ; } ;
1566+ // The one case sink, unchanged in what it judges: the only addition is that a
1567+ // case is COUNTED whether it holds or not, which is what lets the floor at the
1568+ // verdict site tell "held" from "never ran".
1569+ const t = ( label , ok ) => {
1570+ registerCase ( ) ;
1571+ if ( ! ok ) failures . push ( label ) ;
1572+ } ;
1573+ // Cases run before the first banner, so the first battery is opened at the
1574+ // top of the body and that banner carries no second opener — PR #13487's own
1575+ // shape, as batches 1b and 2 landed it.
1576+ battery ( 'The FOLD: one row per literal, however many invocations reach it' ) ;
14321577
14331578 const files = trackedFiles ( ) ;
14341579 const dirs = topLevelDirs ( files ) ;
@@ -1479,6 +1624,11 @@ function selfTest() {
14791624 //
14801625 // Every (invocation, file, constant, word) the derivation reaches, walked
14811626 // through the same predicates the sweep uses and with no dedupe of its own.
1627+ //
1628+ // ⚠️ This section's battery is opened at the TOP of the body, not here: the
1629+ // seven cases above run before any banner and have no section head of their
1630+ // own, so they are attributed to THIS battery rather than left unattributed.
1631+ // This banner therefore carries no second opener.
14821632 const perInvocation = new Set ( ) ;
14831633 for ( const [ check , entry ] of families ) {
14841634 for ( const file of entry . files ?? [ ] ) {
@@ -1563,6 +1713,7 @@ function selfTest() {
15631713 // takes a declaration, or a family is renamed, the verdict must come out with
15641714 // it. A verdict describing a row the sweep no longer finds is the shape that
15651715 // rots into an allowlist nobody re-reads, which #10840 refused by name.
1716+ battery ( 'The triage coupling, both directions' ) ;
15661717 const stale = [ ...TRIAGE . keys ( ) ] . filter ( ( k ) => ! keys . has ( k ) ) . sort ( ) ;
15671718 t ( `no recorded verdict outlives its row${ stale . length ? ` — STALE: ${ stale . join ( ' · ' ) } . `
15681719 + 'Delete the entry; do not re-point it at another row.' : '' } `, stale . length === 0 ) ;
@@ -1664,6 +1815,7 @@ function selfTest() {
16641815 // are joined rather than spelled, for the same reason the probes above take
16651816 // their root from the tree: a glob literal here would hand this file a
16661817 // population of its own.
1818+ battery ( 'The MECHANISM a repaired reason turns on, held mechanically' ) ;
16671819 const PKG = 'packages' ;
16681820 const seg = ( f ) => f . split ( '/' ) ;
16691821 const underPkg = files . filter ( ( f ) => seg ( f ) [ 0 ] === PKG ) ;
@@ -1712,6 +1864,7 @@ function selfTest() {
17121864 // zero-segment forms of `**`). A divergence means the record stopped
17131865 // describing the tree. ⛔ The remedy is to re-measure the ROW, never to relax
17141866 // `holds` until it agrees again.
1867+ battery ( 'The RECORDED SPELLINGS, pinned: LIVENESS and PRECISION' ) ;
17151868 const spellingRows = [ ...TRIAGE . entries ( ) ] . filter ( ( [ , v ] ) => v . spelling ) ;
17161869 // The two verdicts whose whole content is a claim only a spelling records, so
17171870 // a record without one records nothing for the pins to hold. SPELLABLE-
@@ -1805,6 +1958,7 @@ function selfTest() {
18051958 // been removed. ⛔ When this reds the remedy is to re-measure
18061959 // the ROW -- never to extend `omits` until it agrees again, which is the same
18071960 // move as relaxing `holds`, refused above in as many words.
1961+ battery ( "The DECLARATION a row describes, read from the gate's own SOURCE" ) ;
18081962 const declaredHintsAt = ( file , root ) => {
18091963 const abs = join ( ROOT , file ) ;
18101964 if ( ! existsSync ( abs ) ) return null ;
@@ -1871,6 +2025,7 @@ function selfTest() {
18712025 // battery skips out of laziness. What CAN be held mechanically instead:
18722026 // every row's own internal shape, and that this table never collides with
18732027 // `TRIAGE`'s key space or contributes a population hint of its own.
2028+ battery ( 'CENSUS_REFUSE_WIDE, pinned on its OWN terms (#14695)' ) ;
18742029 {
18752030 const overlap = [ ...CENSUS_REFUSE_WIDE . keys ( ) ] . filter ( ( k ) => TRIAGE . has ( k ) ) . sort ( ) ;
18762031 t ( `no CENSUS_REFUSE_WIDE key collides with a TRIAGE key${ overlap . length
@@ -1904,9 +2059,16 @@ function selfTest() {
19042059 + 'each row was actually measured at instead of one shared field.' : '' } `, bases . size === 1 ) ;
19052060 }
19062061
2062+ // ── The assertion floor, at the verdict site (#13489) ─────────────────────
2063+ // The batteries above REGISTER but do not decide, so the floor over their
2064+ // registrations is evaluated here, into the same sink the cases use — the
2065+ // only place a run that registered nothing can still be stopped from
2066+ // reporting that every case held.
2067+ for ( const breach of batteryFloorFailures ( ) ) failures . push ( breach ) ;
2068+
19072069 if ( failures . length ) {
19082070 for ( const f of failures ) console . error ( ` x self-test: ${ f } ` ) ;
1909- console . error ( `\nbare-root-worklist --self-test: ${ failures . length } failure(s).\n` ) ;
2071+ console . error ( `\nbare-root-worklist --self-test: ${ failures . length } failure(s) (cases and floor) .\n` ) ;
19102072 process . exit ( 1 ) ;
19112073 }
19122074 console . log (
0 commit comments