test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

test(scripts): give 30 more self-tests a battery roster and floor - #14896

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c
Sep 3, 2026
Merged

test(scripts): give 30 more self-tests a battery roster and floor#14896
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-self-test-roster-floor-b1c

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 1c, Tier B — batch-1 shape)

PR #13487's roster-and-floor shape, exactly as batch 1 landed it in PR #14851, transplanted onto the scripts/** self-tests that already carry that shape. 432 batteries / 2591 cases pinned across 30 files.

Per file, and nothing else:

  • a module-level frozen SELF_TEST_BATTERIES roster of names with a per-battery floor, SELF_TEST_BATTERY_FLOOR pinning the roster's own size, and UNATTRIBUTED_BATTERY, placed after the import block (batch 1b's uniform placement — TDZ-safe by construction);
  • battery('BANNER TEXT') at each existing section banner, named verbatim from the banner;
  • one registerCase() at the head of the existing in-body assertion helper;
  • the floor evaluated immediately before the existing verdict site, its messages entering the file's own failure sink so the report the file already prints carries them.

⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.

The file surface: 30 floored, 15 dropped with the measured reason

The dispatch named 45 files (the batch-1b report's "HAS a block-bodied in-body assertion helper" list). That list was derived on the helper half of the batch-1 criterion only. Re-measured against the tree on all three halves — a block-bodied in-body assertion helper and at least two named section banners and a body-level verdict site — 30 qualify.

The banner criterion, as measured

A named section banner is a comment block at statement position inside the self-test body (innermost open bracket is a brace, never a square bracket or a paren) whose head carries a section marker: a horizontal rule, a box (a bare rule line, then the title, then a rule), or an enumerator (// 1. name, // 3 — name, // G1: name, // TSO-6048: name). A comment with no marker is a paragraph explaining the next statement, not a section head; reading one as a section head is a judgement per comment, which a verbatim transplant does not make.

The bracket half of that rule is load-bearing and was measured: in scripts/docs-audit/affected-docs.mjs a brace-only depth count put four banners inside an array literal, where a battery() statement is a syntax error — the Tier-C shape the batch-1b report names. The probe pass caught it; the renderer now refuses that position.

Floored (30)

filebatteriescases
scripts/check-adr-0087-registration.mjs48292
scripts/check-auth-mount-ledger.mjs1842
scripts/check-ci-filter-parity.mjs742
scripts/check-comment-mask-adoption.mjs623
scripts/check-console-injection.mjs1023
scripts/check-cross-repo-closer-outcome.mjs581
scripts/check-dev-prereqs.mjs1651
scripts/check-dispatcher-error-vocabulary.mjs2 (first battery hoisted)282
scripts/check-doc-frontmatter.mjs1185
scripts/check-docs-locale-catch-all.mjs1528
scripts/check-docs-section-name.mjs2285
scripts/check-engine-split-ratio.mjs216
scripts/check-error-status-conformance.mjs2340
scripts/check-i18n-stale-fill.mjs2 (first battery hoisted)27
scripts/check-init-service-contract.mjs1926
scripts/check-keyed-text-bounds.mjs967
scripts/check-merge-queue-triage-outcome.mjs7126
scripts/check-overlay-whitelist-table.mjs1970
scripts/check-quick-reference-counts.mjs2237
scripts/check-ratchet-remedy-authority.mjs2027
scripts/check-required-contexts.mjs22150
scripts/check-route-envelope.mjs27 (first battery hoisted)88
scripts/check-section-landing-index.mjs1231
scripts/check-stall-guard-budget.mjs1061
scripts/check-system-context-census.mjs1743
scripts/check-undeclared-dep-imports.mjs950
scripts/check-vendor-version-stamps.mjs6 (first battery hoisted)64
scripts/docs-audit/affected-docs.mjs28 (first battery hoisted)545
scripts/release-github-releases.mjs1049
scripts/sync-template-versions.mjs840

Five files run cases before their first banner (check-dispatcher-error-vocabulary, check-i18n-stale-fill, check-route-envelope, check-vendor-version-stamps, docs-audit/affected-docs); their first battery is opened at the top of the body and that banner then carries no second opener — the PR #13487 precedent's own shape, as batch 1b did it. Banners that registered no case are not declared as batteries and get no opener: a battery is a section that actually runs cases.

Dropped (15) — left for a later batch rather than improvised

filemeasured reason
scripts/check-declaration-mirrors.mjsthe in-body assertion sink is a CONCISE arrow — const ok = (label, cond) => cases.push({ label, cond }); (L411) — with no block body to hold registerCase(). That is the class-1 blocker, not the batch-1 shape.
scripts/check-dts-emitted.mjsno named section banner in the self-test body (0 of the 2 the criterion needs): the body carries one prose comment and no ruled, boxed or enumerated section head.
scripts/check-logger-receiver-detach.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-objectql-double-limit.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-compatibility-version.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-skill-frame-freshness.mjsno in-body assertion helper at all: cases are pushed inline at ~14 separate cases.push({ ... }) sites, so there is no single block body for registerCase(). The only block-bodied helper, linear(), is a fixture builder.
scripts/check-spec-parsed-alias.mjsno named section banner in the self-test body: its comments label individual cases (// GOOD:, // BAD (rule 1)), not sections.
scripts/check-stack-collection-maps.mjsno named section banner in the self-test body.
scripts/check-startup-registry-verdict.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjsno named section banner in the self-test body: three unmarked prose comments head its blocks, and reading one as a section head rather than an explanation of the next statement is a judgement per comment, which this transplant does not make.
scripts/check-turbo-task-graph.mjsno body-level verdict site: selfTest() returns a failures array and the verdict is printed by a SEPARATE runSelfTest() (L892). That is the class-3 shape.
scripts/check-whole-set-label-write.mjsone named section banner in the self-test body, below the two the criterion needs.
scripts/check-wildcard-fallthrough.mjsno named section banner in the self-test body: four unmarked prose comments head its blocks.
scripts/js-comment-mask.mjsno named section banner in the self-test body.
scripts/publish-smoke-pack.mjsno comment at statement position in the self-test body at all, so no section banner.

Shrink-only ledgers: scanned, none found in this batch

Every battery that iterates a module-level constant was enumerated (28 battery/ledger pairs across 13 files) and each underlying list read: CATEGORIES, SHAPES, MUTATIONS, ROOTS, TEXT_STAMPS, EXPECTED_TEXT_FAMILY, FLOORS, REQUIRED_CONTEXTS, INSTRUCTION_SURFACES, RETIRED_CONTEXT_NAMES, EXPRESS_RESPONSE_MODULES, DECLARED_COUNTS, UNENFORCED_TEXT_COUNTS, ROOT_DIR_WATCH_HINTS, YAML_CENSUS_ANCHORS. None is shrink-only, and the two that read closest to it are not one-case-per-row: UNENFORCED_TEXT_COUNTS is asserted structurally (two cases, with the row count inside the case rather than as case multiplicity), and RETIRED_CONTEXT_NAMES only ever grows. So no floor in this batch moves with a list a legitimate edit shortens.

Evidence

Behaviour is unchanged, per file

For all 30: node FILE --self-test before and after, exit code captured by redirect before any pipe. 30/30 exit 0 both sides, and cmp -s reports stdout and stderr byte-identical on every one. (Both readings are from the tree after pnpm install; without it seven files exit 3 on a missing-dist prerequisite and two on ERR_MODULE_NOT_FOUND, which is a container state, not a verdict.)

Census

node scripts/measure-self-test-floor.mjs --json:

merge base 2263ca4d6this branch f248bc953
ROSTER333
COUNT44
NONE158128

Three set-equality assertions, computed in python, all True:

  1. every one of the 30 worklist files reads NONE before and ROSTER after;
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty);
  3. git diff --name-only equals the worklist exactly.

And the 128 still NONE decompose exactly — a disjoint partition whose union is the set, asserted in python, not read by eye:

128 = 40 PR #14851 (batch 1, unmerged)
+ 18 PR #14872 (batch 1b, unmerged)
+ 23 PR #14853 (issue #13798 batch 2, unmerged)
+ 15 this batch's measured drops
+ 2 honoured i18n exclusions (PR #14856)
+ 13 class 2 — fewer than two banners, re-derived from the tree
+ 5 class 3 — no body-level verdict site
+ 5 Tier C / shape-blocked
+ 3 honoured open-PR exclusions (check-type-check-coverage, pm/dispatch-gates, pm/bare-root-worklist)
+ 4 outside the declared Tier-B population (check-platform-checklist, check-regen-pending, git-merge-regen, setup-git-hooks)

The 30 floored here intersect PR #14851's 40, PR #14872's 18, PR #14853's 24, the i18n pair and the open-PR exclusions in zero files.

Ablations — four, each from the committed implementation

Each leg carries a trap restore on absolute paths; the mutation is proved on disk by an anchored grep count plus git hash-object against the HEAD blob, and the restore by an empty git diff HEAD — never by an exit code. No dist is on the resolution path of any of the four, so no rebuild leg applies to them.

  1. A battery's cases deletedscripts/check-auth-mount-ledger.mjs, the 2 ok(deriveBasePath( cases (grep 2 → 0; cd7b24abb8493fe3). Exit 0 → 1: battery "The base path is DERIVED, and its absence is not an empty population." DID NOT RUN — 0 cases registered, 2 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/check-engine-split-ratio.mjs (grep 1 → 0; d92d218606deaef8). Exit 1 naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "pure rendering" registered 5 case(s) but is not declared in SELF_TEST_BATTERIES.
  3. The introduced registerCase() removed from the sink helperscripts/check-quick-reference-counts.mjs (grep 1 → 0; ce2b2de3a29feeba). Exit 1 with every original case still passing: all 22 batteries report DID NOT RUN.
  4. One battery() opener deletedscripts/docs-audit/affected-docs.mjs (grep 1 → 0; 965c95f0255698df). Exit 1: battery "anchor PROVENANCE ([decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824)" DID NOT RUN — 0 cases registered, 12 pinned.

A fifth attempt aborted before running — the anchor matched zero lines and the guard refused rather than reporting a clean measurement, which is the failure shape the ablation contract exists to catch.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; the script reads the change set from git — 30 paths vs merge base 2263ca4d6). 55 commands derived + check:declared-population-live + check:pm-dispatch-gates + check:nul-bytes = 58 run. Exit codes captured by redirect before any pipe.

  • 57 RAN-PASS (exit 0) of the 58 run, including both mandatory gates: check:ratchet-remedy-authority 0, check:declared-population-live 0 (158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8079 tracked file(s)).
  • check:pm-dispatch-gatesexit 0, dispatch-gates self-test: 1241 cases pass. No compound-anchor red: this batch introduces no top-level function declaration at all, so the SELF_TEST_DECL anchor sees nothing new. The battery/registerCase closures are function-scoped and the three new module-level names are consts, which the anchor does not match.
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction, not a red.
  • Two first-pass readings that were container state, both cleared and re-run green: check-dev-prereqs exit 1 (The workspace is not built — 1 unmet precondition, not a list of problems) → 0 after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 6m32s); check-engine-split-ratio exit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 after git fetch --shallow-since=2026-05-29 origin main. Neither is a verdict about this diff, and neither was read as a pass before it was re-run.
  • pnpm lint (whole repo, eslint . --no-inline-config) — exit 0 on f248bc953. No narrowing claimed.
  • Control-byte scan over the 30 changed files (grep -naP) clean; check:nul-bytes exit 0.

The build left the tracked tree unchanged (git status --porcelain empty).

scripts/** only ⇒ skip-changeset.


Generated by Claude Code

Batch 1c of #13799: PR #13487's roster-and-floor shape, exactly as batch 1
landed it, transplanted onto the `scripts/**` self-tests that already carry
its shape -- a block-bodied assertion helper inside the self-test body, at
least two named section banners, and a body-level verdict site.
Per file: a module-level frozen `SELF_TEST_BATTERIES` roster of NAMES with a
per-battery floor, `SELF_TEST_BATTERY_FLOOR` pinning the roster's own size,
`UNATTRIBUTED_BATTERY`, a `battery('<banner text>')` opener at each existing
section banner, one `registerCase()` at the head of the existing assertion
helper, and the floor evaluated immediately before the existing verdict so
its messages enter the file's own failure sink. 432 batteries, 2591 cases.
No case is rewritten, none reordered and no assertion changes meaning: every
file's `--self-test` exits 0 with byte-identical stdout AND stderr before and
after. The roster block goes after the import block in every file, which is
TDZ-safe by construction.
15 of the 45 files the dispatch named do not meet that criterion when measured
against the tree and are left for a later batch rather than improvised; the
reason per file is in the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBXxmS9sXHoqnozSNwHnE
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 11:01
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit a610775Sep 3, 2026
42 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-self-test-roster-floor-b1c branch September 3, 2026 12:00
os-litant pushed a commit that referenced this pull request Sep 3, 2026
Two conflicts, both against main commits that landed after this branch's
merge base 5ff5f95:
- .claude/skills/pm-dispatch/references/lanes/services.md: main's
365141f (#14856) edited the very bullet this branch deletes (the
bullet moved to references/platform-readings.md). Settled to OUR side:
the bullet stays deleted and the move stands. The FACT main corrected in
that bullet (the i18n gates answer PREREQUISITE NOT MET with exit 3, not
1) is carried into the moved text by the follow-up commit, so this merge
commit's non-conflict content stays a pure merge of the two parents.
- scripts/check-ratchet-remedy-authority.mjs: main's a610775 (#14896)
added the self-test battery roster and floor at the spot where this
branch's section (21) sits. Settled by keeping BOTH: section (21) opens
with battery('(21) ...'), is declared in SELF_TEST_BATTERIES at its case
count (2), and sits before the floor-evaluation block; the roster's own
size pin SELF_TEST_BATTERY_FLOOR moves 20 -> 21 by the header's own
convention (the roster size is pinned at the declared count). The
exception phrase stays assembled, never spelled, in author-facing text,
and the gate's run line is byte-identical to main's.
scripts/pm/check-skill-line-ratchet.mjs auto-merged with main's c47a5ac
(#14853) verdict handshake; the two run-path verdict lines this branch adds
are outside that handshake, which covers selfTest()'s sentinel return only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@baozhoutao