Uh oh!
There was an error while loading. Please reload this page.
test(scripts): give 13 more self-tests a battery roster and floor - #15003
Merged
Conversation
Part of #13799 (batch 2, Tier B — the batch-1 shape). PR #13487's roster-and-floor shape as batches 1/1b/1c landed it, transplanted onto four `scripts/**` self-tests that already carry that shape. ⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned — the roster pins registered NAMES. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Part of #13799 (batch 2, Tier B — the batch-1 shape). ⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned — the roster pins registered NAMES. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Part of #13799 (batch 2, Tier B — the batch-1 shape). ⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned — the roster pins registered NAMES. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Contributor
📓 Docs Drift CheckNothing 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
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
baozhoutao
marked this pull request as ready for review
September 3, 2026 17:24
baozhoutao
enabled auto-merge
September 3, 2026 17:24
github-merge-queueBot
removed this pull request from the merge queue due to a conflict with the base branch
Sep 3, 2026
# Conflicts: # scripts/pm/check-governed-merges.mjs
…merge `origin/main`'s #14867 change (`hotcrm` added to `GOVERNED_REPOS`) grows the `multi-repo scope (#9619)` battery from 15 cases to 17: one assertion becomes two, and the new register row adds one more through the section's own loop. Re-read from a probe run rather than assumed — the declared set still equals the opened set (22/22), and the file's self-test output stays byte-identical to `origin/main`'s version of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13799 (batch 2, Tier B — the batch-1 shape).
PR #13487's roster-and-floor shape, exactly as batches 1/1b/1c landed it (PRs #14851, #14872, #14896), transplanted onto the
scripts/**self-tests that already carry that shape. 123 batteries / 973 cases pinned across 13 files.Per file, and nothing else:
SELF_TEST_BATTERIESroster of names with a per-battery floor,SELF_TEST_BATTERY_FLOORpinning the roster's own size, andUNATTRIBUTED_BATTERY, placed after the import block;battery('BANNER TEXT')at each existing section banner, named verbatim from the banner;registerCase()at the head of the existing in-body assertion helper;⛔ No case is rewritten, none reordered, no assertion changes meaning. ⛔ No TOTAL is pinned.
The population, re-derived on a fresh tree
Triage's rule (
5478879048) — 「#13798 first, per file」 — makes this batch the unfloored set that already has the handshake, not what remains: a floor on a handshake-less file cannot fire, because the floor never runs either.55276091755bc2f272selfTest(.mjs/.mts)SELF_TEST_BATTERIES)69 + 14 = 83 = 175 − 92, reconciled. The dispatchable set matches at 69; the whole delta sits inside the blocked set, which this batch excludes by construction (two extra files define a
selfTestand carry no handshake:check-adr-symbol-anchors.mjs,symbol-anchors.mjs).The file surface: 13 floored, 56 deferred with a measured reason
The batch-1 criterion, measured on all three halves: a block-bodied in-body assertion helper, at least two named section banners at statement position (innermost open bracket a brace, never a square bracket or a paren), and a body-level verdict site. 13 of the 69 qualify.
A named section banner carries a marker — a horizontal rule, a box, or an enumerator (
// 1. name,// G1: name). An unmarked comment explains the next statement; ⛔ promoting one to a section head is a judgement per comment, which this transplant does not make.The instrument used to classify all 69 was cross-validated against PR #14896's 15 measured drops: it reproduces every one of them (two differ by a single banner, 0 vs 1, both far below the floor of 2).
Floored (13)
scripts/check-filter-alias-parity.mjsscripts/check-i18n-bundles.mjsscripts/check-i18n-coverage.mjsscripts/check-page-declaration-shape.mjsscripts/check-skill-identifier-liveness.mjsscripts/check-type-source-resolution.mjsscripts/docs-audit/check-audit-scope.mjsscripts/measure-stall-guard-headroom.mjsscripts/pm/check-governed-merges.mjsscripts/pm/check-governed-prose.mjsscripts/pm/check-governed-queue-guard.mjsscripts/pm/ci-failure.mjsscripts/pm/git-history.mjsThree files run cases before their first banner (
check-i18n-bundles,check-i18n-coverage,docs-audit/check-audit-scope); 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. That applies to exactly one banner in this batch (measure-stall-guard-headroom, 16 banners → 15 batteries).⭐ Two of the 13 read as already-floored and were not
docs-audit/check-audit-scope.mjsprints✓ check-audit-scope self-test: ${total} cases pass.andmeasure-stall-guard-headroom.mjsprints${checked} assertion(s) passed.— both derive a case count and print it, and nothing compares either. If a case array shrinks, the printed number shrinks with it and the gate stays green. Both now carry a real roster floor. (The pair the card names by identifier,typecheck-configs.mjsandcheck-comment-mask-corpus.mjs, is not in the floored set — both are class-1/class-2 and appear in the table below.)Deferred (56) — left for a later batch rather than improvised
scripts/ablation-dist-preflight.mjsfailedsink is written at 6 inline site(s).scripts/check-adr-links.mjsassert, so the self-test body holds no block-bodied assertion helper.scripts/check-agent-model-declared.mjsfailedsink is written at 7 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-comment-mask-corpus.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-console-intercept-disarm.mjsfailuressink is written at 2 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-declaration-mirrors.mjsconst ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)scripts/check-doc-anchors.mjsassert, so the self-test body holds no block-bodied assertion helper.scripts/check-docs-single-h1.mjst— no block body to hold registerCase(); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.scripts/check-dts-emitted.mjsscripts/check-durability-degradation-log-level.mjsscripts/check-error-code-casing.mjsfailedsink is written at 3 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-examples-live-imports.mjsfailedsink is written at 1 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-exported-any-returns.mtsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-kernel-hook-pairs.mjsassert, so the self-test body holds no block-bodied assertion helper.scripts/check-logger-receiver-detach.mjsscripts/check-meta-type-normalized.mjsproblemssink is written at 4 inline site(s); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.scripts/check-objectql-double-limit.mjsscripts/check-optional-error-sink-contract.mjsfailuressink is written at 7 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-org-identifier.mjsfailedsink is written at 2 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-osv-exemptions.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-override-consistency.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-platform-checklist.mjsselfTestbody to floor. Excluded by construction.scripts/check-pnpm-acquisition.mjst— no block body to hold registerCase(); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-published-files.mjsfailuressink is written at 7 inline site(s).scripts/check-refd-timer-probe.mjsfailedsink is written at 5 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-sdui-manifest.mjsfailuressink is written at 1 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-skill-compatibility-version.mjsfailedsink is written at 7 inline sites).scripts/check-skill-frame-freshness.mjscasesis pushed at 12 separate inline sites, so there is no single block body for registerCase().scripts/check-skill-frame-sync.mjsfailedsink is written at 5 inline site(s); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.scripts/check-skills-token-ratchet.mjsfailedsink is written at 1 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/check-spec-parsed-alias.mjsscripts/check-stack-collection-maps.mjsscripts/check-startup-registry-verdict.mjsscripts/check-tenant-chokepoint.mjsscripts/check-test-completeness.mjsthrow/ table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.scripts/check-turbo-task-graph.mjsselfTest()returns a failures array; the verdict is printed by a separaterunSelfTest()). Also 0 named section banners.scripts/check-whole-set-label-write.mjsscripts/check-widget-option-census.mjsfailedsink is written at 5 inline site(s); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.scripts/check-wildcard-fallthrough.mjsscripts/check-workspace-manifest-cycles.mjsscripts/checklist-select.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/js-comment-mask.mjsscripts/measure-position-name-fold-census.mjsproblemssink is written at 15 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/measure-test-shard-timings.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/partition-test-shards.mjsthrow/ table-driven verdict).scripts/pm/check-clause2-carriers.mjst— no block body to hold registerCase().scripts/pm/check-half-states.mjsconst t = (name, actual, expected) => cases.push([name, actual, expected]);(L11941) has no block body to hold registerCase(). (The analyzer could not resolve this file's body automatically either:js-comment-mask.mjsmis-scans it at ~17 kloc and blanks thefunctionkeyword, so the reading above is by hand.)scripts/pm/check-label-desc-cap.mjsscripts/pm/check-skill-id-lint.mjsfailedsink is written at 1 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/pm/check-skill-line-ratchet.mjsfailedsink is written at 1 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/pm/dispatch-gates.mjsnode scripts/pm/dispatch-gates.mjs --self-testprintsdeclare 26 literal(s)where the base tree prints23, and3116 tracked fileswhere the base prints2992. Four battery names carry path-shaped text (e.g.The scripts/** blind spot, closed at the source (#10784)) and the gate's own path-population extractor reads them as declared populations. That is a change of meaning, not a no-op, so it is deferred rather than improvised past. (Its self-test also costs ~288 s per run, twice per verification.)scripts/pm/release-rehearsal-clone.mjsscripts/publish-smoke-pack.mjsscripts/render-release-coverage-anchor.mjsthrow/ table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.scripts/run-with-stall-guard.mjsscripts/typecheck-configs.mjsfailuressink is written at 2 inline site(s); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.Shrink-only ledgers: scanned, none found in this batch
Every battery that drives its cases off a module-level constant was enumerated inside the 13 self-test bodies and each underlying list read:
FAILURE_BRANCHES(check-i18n-coverage),WORKSPACE_PARENT_GLOBS(check-type-source-resolution),REPLAYSandGOVERNED_SURFACES(check-governed-merges),PROSE_SURFACES(check-governed-prose),GOVERNED_SURFACES,GOVERNED_APPROVERS,REPLAYSandGENERATED_SURFACE_EXCEPTIONS(check-governed-queue-guard). None is shrink-only:REPLAYSis a set of incident replays and only grows;GOVERNED_SURFACES,PROSE_SURFACESandGENERATED_SURFACE_EXCEPTIONSare registers that grow as surfaces and generators are governed;FAILURE_BRANCHESis the gate's own branch set, whose length the verdict line already prints;GOVERNED_APPROVERSis a pinned two-account set — the assertion immediately above the loop isthe-authorized-set-is-exactly-the-ruled-two-accounts, so an edit to it already reds by design and the floor adds no new friction.So no floor in this batch moves with a list a legitimate edit shortens.
Evidence
Behaviour is unchanged, per file
For all 13:
node FILE --self-testbefore and after, exit code captured by redirect before any pipe. 13/13 exit 0 both sides, with stdout and stderr byte-identical on every one (compared in full, not sampled). The twocheck:i18n*readings are from the tree afterpnpm installand a workspace build; without the build both gates exit 3 on a missing-CLI prerequisite, which is container state, not a verdict.Census
node scripts/measure-self-test-floor.mjs --json:5bc2f272dc3e2815Three set assertions, computed in python, not read by eye:
ROSTERafter — True; before, 11 readNONEand 2 readCOUNT(the instrument's own high-recall "candidate to read" class, which its header says is not a verdict — both were hand-read and are the false floors described above);git diff --name-onlyequals the worklist exactly — True.Ablations — four, each from the committed implementation
Each leg carries a
trap … EXIT INT TERMrestore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-objectagainst the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an emptygit diff HEAD— never by an exit code. The anchor is required to match exactly one line or the leg aborts. Nodistis on the resolution path of any of these four files, so no rebuild leg applies.scripts/pm/check-governed-prose.mjs, the 3 cases underbattery('codeSpansIn')(5575ba24→8f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.scripts/docs-audit/check-audit-scope.mjs, the'the injection contract (#13591)': 1,row (anchored count 1 → 0;60debd41→db15d005). Exit 0 → 1, naming both halves: SELF_TEST_BATTERIES declares 1 batteries, below the pinned 2andbattery "the injection contract ([finding] Adding a NEW hand-written page under content/docs/ makes a PR human-merge-only — always, and invisibly until the gate runs #13591)" registered 1 case(s) but is not declared in SELF_TEST_BATTERIES.registerCase()removed from the sink helper —scripts/check-filter-alias-parity.mjs(anchored count 1 → 0;f54a07e3→568fd046). Exit 0 → 1 with every original case still passing: all 7 batteries report DID NOT RUN, so the file's own green verdict is exactly what the floor refuses.battery()opener deleted —scripts/check-page-declaration-shape.mjs,battery('Comment masking, both directions');(anchored count 1 → 0;00b6c350→deb47921). Exit 0 → 1: battery "Comment masking, both directions" DID NOT RUN — 0 cases registered, 3 pinned.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom this worktree after the edits (no paths passed; the script reads the change set from git — 13 paths). 38 commands derived +node scripts/pm/check-governed-queue-guard.mjs --self-test(that gate's self-test runs fromgoverned-surface-guard.yml, notlint.yml, so the lint-derived list does not name it) +pnpm check:declared-population-live= 40 run. Every exit code captured by redirect before any pipe.check:pm-dispatch-gates(exit 0, dispatch-gates self-test: 1288 cases pass),check:declared-population-live(exit 0),check:ratchet-remedy-authority(exit 0) andcheck:nul-bytes(exit 0).check-test-completeness— exit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a savedturbo run testlog, and no log was named). Not a pass and not a red.check-engine-split-ratioexit 2 (this clone is shallow … a ratio derived here would be real, plausible and WRONG) → 0 aftergit fetch --shallow-since=2026-05-29 origin main;check:i18nandcheck:i18n-coverageexit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both--self-testhalves already printing their ✓ line) → 0 each afterpnpm exec turbo run build --filter=./packages/* --filter=./packages/*/*underscripts/pm/os-verify-lock.sh(VERDICT command-exit 0, held 453s). 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 ondc3e2815, 82 s. No narrowing claimed.grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits;check:nul-bytesexit 0.The build left the tracked tree unchanged (
git status --porcelainempty).scripts/**publishes nothing ⇒skip-changeset.Post-merge:
origin/mainmerged in, one conflict resolved (2026-09-03)PR evicted from the merge queue at 17:59:29Z on a merge conflict, not a test failure (
mergeable_state: dirty; its own CI was green ondc3e2815and no merge-group build ever ran). Resolved by a real merge commit — ⛔ no rebase, no amend, no force-push.Exactly one file conflicted:
scripts/pm/check-governed-merges.mjs, changed on main by5d4d55aec"tooling(pm): governhotcrmin check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEADover the 13 lists that one file and nothing else).Both sides kept. The hunk was my
battery('multi-repo scope (#9619)');opener against main's replacement offour-governed-repos-declaredwithfive-governed-repos-declaredplus a newhotcrm-is-a-governed-repo-with-its-slug (#14867)assertion. The resolution keeps the opener and both of main's assertions; nothing of main'shotcrmgovernance is dropped, and no floor is loosened. Main's added comment is unmarked prose explaining the next statement, ⛔ not promoted to a section head, so the file gains no battery.The battery numbers moved, and were re-read rather than assumed. A probe run over the merged file (dump inserted, mutation proved by
git hash-object, restored to an emptygit diff HEAD) reports:multi-repo scope (#9619)15 → 17 (main's one-assertion-becomes-two, plus one more case the new register row adds through that section's own loop); total 243 → 245, matching the file's own245 assertionsverdict line;SELF_TEST_BATTERY_FLOORstays 22.Re-verified on the merge result
8d6d40e6:origin/main's own version of the file swapped into the worktree (7486320e→8f1afdf2, proved equal to theorigin/mainblob), run, then restored to an emptygit diff HEAD. Both sides exit 0 with stdout and stderr byte-identical.node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 afterpnpm install. It is recorded rather than quietly re-run.assert('five-governed-repos-declared', …)line deleted (anchored count 1 → 0,0585ed5a→cee9dfa2). Exit 0 → 1: self-test battery "multi-repo scope (check-governed-merges cannot answer its own question where it is actually run: sibling repos are out of scope, and merged_by is UNRESOLVED without a token #9619)" registered 16 case(s), below its pinned floor of 17. Restored to an emptygit diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.8d6d40e6— the derived family is byte-identical to the pre-merge one (38 commands), and the same 40 ran with the same result: 39 RAN-PASS, 1 NOT MEASURED (check-test-completenessexit 3).check:pm-governed-mergesexit 0;check:pm-dispatch-gatesexit 0 (1288 cases). The twocheck:i18n*gates again needed the workspace build in this fresh worktree (exit 3, both--self-testhalves green) and were 0 each after it, underscripts/pm/os-verify-lock.sh(VERDICT command-exit 0, held 425s).pnpm lintwhole repo — exit 0 on8d6d40e6, 79 s. Control-byte scan clean; build left the tracked tree unchanged.git diff --stat origin/main HEAD -- scripts/is still exactly the 13 files, 1365 insertions / 1 deletion — the same net shape as before the merge, now purely additive over current main.⛔ Left as a draft with no auto-merge armed, per the coordinator.
🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code