Uh oh!
There was an error while loading. Please reload this page.
test(scripts): pin a battery roster floor on 18 class-1 scripts/** self-tests (#13799 batch 1b) - #14872
test(scripts): pin a battery roster floor on 18 class-1 scripts/** self-tests (#13799 batch 1b)#14872claude[bot] wants to merge 1 commit into
Conversation
Batch 1b of #13799: the PR #13487 roster-floor shape transplanted onto the `scripts/**` self-tests whose assertion sink is NOT a block-bodied helper inside the self-test body -- a concise arrow, or a module-scope function -- so batch 1 (PR #14851) could not transplant it verbatim. Per the batch-1 review ruling, the roster machinery lives at MODULE scope (SELF_TEST_BATTERIES / SELF_TEST_BATTERY_FLOOR / UNATTRIBUTED_BATTERY / battery() / registerCase() / batteryFloorFailures()), and each file's existing assertion sink is given a minimal block body that calls registerCase() and returns the original expression unchanged. No case is rewritten, none is reordered, and no assertion changes meaning: all 18 self-tests exit with the same code and byte-identical output before and after. What is pinned is the registered NAMES, not a total: every existing section banner opens a battery, every assertion is attributed to the battery most recently opened, the floor requires the OPENED set to equal the DECLARED set with each battery at or above its own count, and the roster's own size is pinned so deleting an entry cannot silence a floor quietly. None of the introduced helpers is named with a self-test spelling. That is deliberate and recorded beside them: `check:pm-dispatch-gates` anchors on a top-level declaration whose NAME spells self-test, and every such name owes a row in that gate's COMPOUND_ANCHOR_LEDGER. These helpers hold no fixtures to mask and read no path literal, so the accurate name is the one that says `battery`. One battery is pinned at its structural invariant rather than at today's count, with the reason written over the entry: check-plugin-teardown-shape's exclusions battery runs exactly one case per DELIBERATELY_EXCLUDED row, and promoting a name onto the teardown roster is a legitimate edit that shrinks that list. Census (`node scripts/measure-self-test-floor.mjs --json`): ROSTER 3 -> 21, NONE 158 -> 140; the set of files whose class changed equals this worklist exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015k1DVWthZyPS7xi1Q72YpK
a888d1f to
ca1e17bComparePM note ( Generated by Claude Code |
Correction to the note above (same seat): the Generated by Claude Code |
Part of #13799 (batch 1b, Tier B class 1)
Batch 1b of the assertion-floor card: the PR #13487 roster-floor shape transplanted onto the
scripts/**self-tests that batch 1 (PR #14851) could not take verbatim because their assertion sink is not a block-bodied helper inside the self-test body — it is a concise arrow (const t = (name, ok, detail) => cases.push({ ... });) or a module-scope function, so there was no{ ... }to thread a per-run ledger through.Per the batch-1 review ruling (comment 5521234092, class 1): the roster machinery lives at module scope, and each file's existing assertion sink is given a minimal block body that calls
registerCase()and then returns the original expression unchanged.--self-testruns exit with the same code (0) and byte-identical stdout and stderr before and afterThe shape, identical in all 18 files
Inserted after the import block (uniformly, so no dispatch can read a
constbefore its initialiser — the TDZ trap batch 1 measured oncheck-adr-anchors):SELF_TEST_BATTERIES— a frozen roster of battery NAMES, each with its own case floorSELF_TEST_BATTERY_FLOOR— the roster's own size, so deleting an entry cannot silence a floor quietlyUNATTRIBUTED_BATTERY— the key an assertion is filed under with no battery open; undeclared on purpose, so it reds by the same set differencebattery()/registerCase()/batteryFloorFailures()check:pm-dispatch-gatesanchors on a top-level declaration whose NAME spells self-test, and every such name owes a row in that gate'sCOMPOUND_ANCHOR_LEDGER. The first draft called the floor evaluatorselfTestFloorFailures()and reddened that gate on all 18 files. The ledger row is the right remedy for a pre-existing accidental name — the gate says so — butscripts/pm/dispatch-gates.mjsis on this dispatch's do-not-edit list (PR #14765 in flight), and this is a new helper whose name was being chosen for the first time. These helpers hold no fixtures to mask and read no path literal, sobattery…is simply the accurate name for what they are. Flagged for the PM in the report in case a ledger row is preferred instead.In the body: one
battery('NAME')at each existing section banner, named verbatim from the banner text; oneregisterCase()in the sink; and the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the existing report prints them.Files, and the sink each one grew a helper at
185 batteries, 968 cases pinned across 18 files.
registerCase()was added toscripts/check-cli-command-ids.mjsconst t = (name, ok, detail = '') => cases.push({ ... })scripts/check-cli-test-child-env.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-cross-package-test-inputs.mjsconst ok = (label, cond) => cases.push({ label, cond })scripts/check-dual-build-cjs-loads.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-entry-guard.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-live-db-isolation.mjsconst check = (label, ok) => cases.push({ label, ok })scripts/check-parse-guard.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-partof-closing-keyword.mjsconst t = (name, actual, expected) => cases.push([ ... ])scripts/check-plugin-teardown-shape.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-published-list-mirrors.mjsconst ok = (label, cond) => cases.push({ label, cond })scripts/check-runner-env-posture.mjsconst t = (name, actual, expected) => cases.push([ ... ])scripts/check-single-claim-paths.mjsconst t = (name, actual, expected) => cases.push([ ... ])scripts/check-tenant-audit-census.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/check-watch-hint-literal.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/import-prerequisite.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/invoked-as.mjsconst t = (name, ok, detail) => cases.push({ ... })scripts/qa/qa-rollup.mjsfunction assert(cond, msg, failures)— called only fromselfTest(), verifiedscripts/ts-parse.mjsconst t = (name, ok, detail) => cases.push({ ... })Every concise arrow became:
The
returnis load-bearing: it preserves the sink's value exactly, so the conversion is a wrap and not a rewrite.Two files (
check-cross-package-test-inputs,check-tenant-audit-census) run cases before their first section banner, so their first battery is opened at the top of the body — the PR #13487 precedent's own shape — and that banner then carries no second opener.The shrink-only ruling, applied
Three batteries in this batch run one case per row of a list. Each was read by hand:
qa-rollup/every RETIRED phrasing is rejected, by the right reason(16 =RETIRED_TITLES) — pinned at 16. That list only grows; removing a row means un-retiring a phrasing, which is the regression it exists to catch.check-plugin-teardown-shape/every roster name reds(4 =TEARDOWN_ALIASES) — pinned at 4. A move onto the roster grows it.check-plugin-teardown-shape/the exclusions, pinned as cases rather than asserted in prose(18 =DELIBERATELY_EXCLUDED) — ⛔ NOT pinned at 18. It has no structural case of its own, and the roster it reads is complementary toTEARDOWN_ALIASES: promoting a name onto the teardown roster is a legitimate edit that shrinks this list while growing the sibling battery. Pinned instead at the part that does not move with the list — this battery ran and at least one excluded name was audited — with the reason written over the entry.The two genuinely shrink-only ledgers this batch touches (
KNOWN_TEARDOWN_UNREACHED,TYPED_EXEMPTIONSand the dual-build baseline) are asserted structurally —every shipped X …, one case regardless of row count — so no floor here moves with them.Census
node scripts/measure-self-test-floor.mjs --json, merge base2263ca4d6→ this branch:Three set-equality assertions, computed in python, all true:
NONEbefore andROSTERafter;NONEdecompose exactly: 113 = 68 + 40 + 2 + 3 — 68 of the batch-1 remainder this batch does not take, 40 in flight on PR test(scripts): pin a battery roster floor on 40 morescripts/**self-tests #14851,check-i18n-coverageandcheck-i18n-bundles(honoured exclusions), and 3 handshake-carrying files outside batch 1's declared Tier-B population of 126.The dispatch put the class-1 surface at 48 and asked for the class to be re-derived from the tree. It was, and the number does not reproduce. 45 of the batch-1 report's 86
remainder_declaredfiles do have a block-bodied assertion helper inside the self-test body — for examplecheck-adr-0087-registration.mjs:3236isconst assert = (cond, msg) => { checked++; if (!cond) failures.push(msg); };, three lines belowfunction selfTest(). Those files are not class 1 under the stated criterion, whatever kept them out of batch 1.Applying the dispatch's criterion strictly — a resolvable entry body, no block-bodied in-body assertion helper, ≥2 named section banners all before the verdict, and a body-level
if (SINK)verdict site — yields 23, of which 5 are excluded for shapes the class-1 ruling does not cover, leaving 18.The direction of the difference is the safe one: this batch is a strict subset of any wider reading, so it cannot collide with batch 1c (classes 2 and 3). Under batch 1's own class ordering a file with no in-body helper is class 1, never 2 or 3, so nothing 1c owns is taken here.
The 68 batch-1 remainder files this batch does NOT take, with the measured reason
check-adr-0087-registration,check-auth-mount-ledger,check-ci-filter-parity,check-comment-mask-adoption,check-console-injection,check-cross-repo-closer-outcome,check-declaration-mirrors,check-dev-prereqs,check-dispatcher-error-vocabulary,check-doc-frontmatter,check-docs-locale-catch-all,check-docs-section-name,check-dts-emitted,check-engine-split-ratio,check-error-status-conformance,check-i18n-stale-fill,check-init-service-contract,check-keyed-text-bounds,check-logger-receiver-detach,check-merge-queue-triage-outcome,check-objectql-double-limit,check-overlay-whitelist-table,check-quick-reference-counts,check-ratchet-remedy-authority,check-required-contexts,check-route-envelope,check-section-landing-index,check-skill-compatibility-version,check-skill-frame-freshness,check-spec-parsed-alias,check-stack-collection-maps,check-stall-guard-budget,check-startup-registry-verdict,check-system-context-census,check-tenant-chokepoint,check-turbo-task-graph,check-undeclared-dep-imports,check-vendor-version-stamps,check-whole-set-label-write,check-wildcard-fallthrough,docs-audit/affected-docs,js-comment-mask,publish-smoke-pack,release-github-releases,sync-template-versions.check-agent-model-declared,check-comment-mask-corpus,check-console-intercept-disarm,check-docs-single-h1,check-error-code-casing,check-optional-error-sink-contract,check-pnpm-acquisition,check-sdui-manifest,check-skill-frame-sync,check-widget-option-census,measure-position-name-fold-census,measure-test-shard-timings,render-release-coverage-anchor.if (SINK)verdict site (class 3, batch 1c):check-adr-links,check-doc-anchors,check-kernel-hook-pairs,check-override-consistency,partition-test-shards.ablation-dist-preflightandcheck-published-files— no single assertion sink; the sink is repeated inline in about six separateforloops, so "a minimal helper at the existing sink" would mean rewriting the reporting of every case.check-examples-live-importsandcheck-org-identifier— table-driven, with every section banner inside thecasesarray literal, where nobattery()statement can go. The card names this as Tier C.check-durability-degradation-log-level— multi-entry dispatch, named as Tier C in the batch-1 report.Verification
node GATE --self-test— 18/18 identical exit code (0) and byte-identical stdout and stderr, captured by redirect before any pipe. (check-plugin-teardown-shapeneeded the clone deepened to reach its pinned fixture commit; both readings are from the deepened tree.)traprestore, mutation proved on disk by anchoredgrep -cplus agit hash-objectcomparison against the HEAD blob, and restore proved by an emptygit diff HEAD— never by an exit code:invoked-as, onet(...)line removed): exit 0 → 1,battery "the predicate, directly" registered 4 case(s), below its pinned floor of 5.invoked-as): exit 1 naming both halves —SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "the fixture: a probe reached three ways" registered 6 case(s) but is not declared.registerCase()line removed from the sink (check-runner-env-posture) — the class-1-specific leg, proving the introduced helper is load-bearing: exit 1, every batteryDID NOT RUN — 0 cases registered, N pinned, with every original case still passing.distis on the resolution path of any of the three, so no rebuild leg applies to them; the dist-dependent gates were re-run after a real build.scripts/check-nul-bytes.mjsexit 0;grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over the 18 changed files: no hits.Gates, on
ca1e17bfnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed — the script derives the change set itself) reconciles this card at 34 families: 32 by path + 2 by change kind. All 34 were run, pluscheck:declared-population-live, which the dispatch names as mandatory and which the derivation does not include — 35 commands. Exit codes captured by redirect before any pipe; every result below quotes the gate's own verdict line, never a bare$?.pnpm check:ratchet-remedy-authority= 0 andpnpm check:declared-population-live= 0.pnpm check:pm-dispatch-gates= 0 —✓ dispatch-gates self-test: 1241 cases pass.It was red on the first head for the compound-anchor reason above (✗ every compound self-test NAME the anchor matches is classified in COMPOUND_ANCHOR_LEDGER — unlisted: … ×18), and green after the helpers were namedbattery….node scripts/check-partof-closing-keyword.mjsandnode scripts/check-single-claim-paths.mjsexit 2 printingNOT WIRED — neither PR_BODY nor PR_NUMBER is set … This is a wiring or usage failure, NOT a verdict. Theirpnpm check:*aliases — what CI runs — both exit 0.node scripts/check-test-completeness.mjsexits 3: "That list names this script with NO argument… There is no local log to hand it, so the local reading for this gate is NOT MEASURED. ⛔ It is not a red."dist. ⛔ Never read as a pass:pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/*ran underscripts/pm/os-verify-lock.sh— VERDICT command-exit 0, 7m15s — and three of the four then exit 0 (check:dual-build-cjs-loads, and the two@objectstack/lintdoc gates); the fourth is the NOT MEASURED one above. The build left the tracked tree unchanged (git statusempty).pnpm lint(whole repo,eslint . --no-inline-config): exit 0. No narrowing claimed.Generated by Claude Code