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

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude
, '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 13 more self-tests a battery roster and floor - #15003

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor
Sep 3, 2026
Merged

test(scripts): give 13 more self-tests a battery roster and floor#15003
baozhoutao merged 5 commits into
mainfrom
claude/issue-13799-batch2-roster-floor

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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;
  • 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 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.

readingPM parking note 5527609175measured here on 5bc2f272
files defining a selfTest (.mjs/.mts)173175
with a verdict handshake (union of the three landed spellings)160160
with a roster floor (SELF_TEST_BATTERIES)9292
⇒ dispatchable (handshake ✓, roster ✗)6969
⇒ blocked by #13798 (no handshake)1214

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 selfTest and 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)

filebatteriescases
scripts/check-filter-alias-parity.mjs718
scripts/check-i18n-bundles.mjs4 (first battery hoisted)77
scripts/check-i18n-coverage.mjs4 (first battery hoisted)71
scripts/check-page-declaration-shape.mjs819
scripts/check-skill-identifier-liveness.mjs1075
scripts/check-type-source-resolution.mjs1179
scripts/docs-audit/check-audit-scope.mjs2 (first battery hoisted)26
scripts/measure-stall-guard-headroom.mjs1535
scripts/pm/check-governed-merges.mjs22243
scripts/pm/check-governed-prose.mjs628
scripts/pm/check-governed-queue-guard.mjs17129
scripts/pm/ci-failure.mjs14136
scripts/pm/git-history.mjs337

Three 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.mjs prints ✓ check-audit-scope self-test: ${total} cases pass. and measure-stall-guard-headroom.mjs prints ${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.mjs and check-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

filemeasured reason
scripts/ablation-dist-preflight.mjsclass-1 — no single in-body assertion helper: the failed sink is written at 6 inline site(s).
scripts/check-adr-links.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-agent-model-declared.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-console-intercept-disarm.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed here: class-1 concise-arrow sink const ok = (label, cond) => cases.push({ label, cond });, no block body for registerCase(). (Also 0 named section banners.)
scripts/check-doc-anchors.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-docs-single-h1.mjsclass-1 concise-arrow sink t — 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body (needs 2).
scripts/check-durability-degradation-log-level.mjsTier C by the card: a multi-entry dispatch combining several self-test callees. Excluded by construction. (Also 0 named section banners in the body.)
scripts/check-error-code-casing.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mtsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-kernel-hook-pairs.mjsclass-1 — assertions go through a module-level assert, so the self-test body holds no block-bodied assertion helper.
scripts/check-logger-receiver-detach.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1; both below the floor).
scripts/check-meta-type-normalized.mjsclass-1 — no single in-body assertion helper: the problems sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-optional-error-sink-contract.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-override-consistency.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/check-platform-checklist.mjsTier C by the card: a multi-entry dispatch combining several self-test callees, so there is no single selfTest body to floor. Excluded by construction.
scripts/check-pnpm-acquisition.mjsclass-1 concise-arrow sink t — 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.mjsclass-1 — no single in-body assertion helper: the failures sink is written at 7 inline site(s).
scripts/check-refd-timer-probe.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failures sink 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.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below two; and no block-bodied in-body assertion helper (the failed sink is written at 7 inline sites).
scripts/check-skill-frame-freshness.mjscarried forward from PR #14896, re-confirmed: no in-body assertion helper at all — cases is pushed at 12 separate inline sites, so there is no single block body for registerCase().
scripts/check-skill-frame-sync.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: no named section banner in the self-test body — its comments label individual cases, not sections.
scripts/check-stack-collection-maps.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/check-startup-registry-verdict.mjscarried forward from PR #14896, re-confirmed: 1 named section banner, below the two the criterion needs.
scripts/check-tenant-chokepoint.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — three unmarked prose comments head its blocks, and promoting one to a section head is a judgement per comment this transplant does not make.
scripts/check-test-completeness.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/check-turbo-task-graph.mjscarried forward from PR #14896, re-confirmed: class-3 — no body-level verdict site (selfTest() returns a failures array; the verdict is printed by a separate runSelfTest()). Also 0 named section banners.
scripts/check-whole-set-label-write.mjscarried forward from PR #14896, re-confirmed: below the two named section banners the criterion needs (this instrument reads 0, b1c read 1).
scripts/check-widget-option-census.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjscarried forward from PR #14896, re-confirmed: 0 named section banners — four unmarked prose comments head its blocks.
scripts/check-workspace-manifest-cycles.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict.
scripts/checklist-select.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/js-comment-mask.mjscarried forward from PR #14896, re-confirmed: 0 named section banners in the self-test body.
scripts/measure-position-name-fold-census.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the problems sink 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.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/partition-test-shards.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict).
scripts/pm/check-clause2-carriers.mjsclass-1 concise-arrow sink t — no block body to hold registerCase().
scripts/pm/check-half-states.mjsclass-1 concise-arrow sink — const 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.mjs mis-scans it at ~17 kloc and blanks the function keyword, so the reading above is by hand.)
scripts/pm/check-label-desc-cap.mjsclass-2 — 1 named section banner(s) in the body, below the two the criterion needs.
scripts/pm/check-skill-id-lint.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsclass-1 — no single in-body assertion helper: the failed sink 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.mjsshape ✓, behaviour ✗ — measured, not guessed. 74 banners / 73 live batteries / 1288 cases, and the transplant renders cleanly, but this self-test READS ITS OWN SOURCE: with the roster in place node scripts/pm/dispatch-gates.mjs --self-test prints declare 26 literal(s) where the base tree prints 23, and 3116 tracked files where the base prints 2992. 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.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/publish-smoke-pack.mjscarried forward from PR #14896, re-confirmed: no comment at statement position in the self-test body at all, so no section banner.
scripts/render-release-coverage-anchor.mjsclass-1 — no in-body assertion sink at all (bare throw / table-driven verdict); class-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/run-with-stall-guard.mjsclass-2 — 0 named section banner(s) in the body, below the two the criterion needs.
scripts/typecheck-configs.mjsclass-3 — no body-level verdict site, so there is no place inside the body to evaluate a floor before the verdict; class-1 — no single in-body assertion helper: the failures sink 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), REPLAYS and GOVERNED_SURFACES (check-governed-merges), PROSE_SURFACES (check-governed-prose), GOVERNED_SURFACES, GOVERNED_APPROVERS, REPLAYS and GENERATED_SURFACE_EXCEPTIONS (check-governed-queue-guard). None is shrink-only:

  • REPLAYS is a set of incident replays and only grows; GOVERNED_SURFACES, PROSE_SURFACES and GENERATED_SURFACE_EXCEPTIONS are registers that grow as surfaces and generators are governed;
  • FAILURE_BRANCHES is the gate's own branch set, whose length the verdict line already prints;
  • GOVERNED_APPROVERS is a pinned two-account set — the assertion immediately above the loop is the-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-test before 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 two check:i18n* readings are from the tree after pnpm 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:

base 5bc2f272this branch dc3e2815
ROSTER91104
COUNT42
NONE7261

Three set assertions, computed in python, not read by eye:

  1. every one of the 13 worklist files reads ROSTER after — True; before, 11 read NONE and 2 read COUNT (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);
  2. the set of files whose class changed equals the worklist exactly (symmetric difference empty) — True;
  3. git diff --name-only equals the worklist exactly — True.

Ablations — four, each from the committed implementation

Each leg carries a trap … EXIT INT TERM restore on absolute paths. The mutation is proved on disk by an anchored count andgit hash-object against the HEAD blob (an empty hash is read as FAILURE, not as "nothing to compare"), and the restore by an empty git diff HEAD — never by an exit code. The anchor is required to match exactly one line or the leg aborts. No dist is on the resolution path of any of these four files, so no rebuild leg applies.

  1. A battery's cases deletedscripts/pm/check-governed-prose.mjs, the 3 cases under battery('codeSpansIn') (5575ba248f4b0d32). Exit 0 → 1: self-test battery "codeSpansIn" DID NOT RUN — 0 cases registered, 3 pinned. The verdict below would have claimed those cases hold.
  2. A roster entry deletedscripts/docs-audit/check-audit-scope.mjs, the 'the injection contract (#13591)': 1, row (anchored count 1 → 0; 60debd41db15d005). 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.
  3. The introduced registerCase() removed from the sink helperscripts/check-filter-alias-parity.mjs (anchored count 1 → 0; f54a07e3568fd046). 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.
  4. One battery() opener deletedscripts/check-page-declaration-shape.mjs, battery('Comment masking, both directions'); (anchored count 1 → 0; 00b6c350deb47921). 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/objectstack from 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 from governed-surface-guard.yml, not lint.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.

  • 39 RAN-PASS (exit 0) of the 40, including 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) and check:nul-bytes (exit 0).
  • check-test-completenessexit 3, NOT MEASURED by the gate's own instruction (PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named). Not a pass and not a red.
  • Three first-pass readings that were container state, all cleared and re-run green: 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; check:i18n and check:i18n-coverage exit 3 (PREREQUISITE NOT MET — the workspace CLI is not built, with both --self-test halves already printing their ✓ line) → 0 each after pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* under scripts/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 on dc3e2815, 82 s. No narrowing claimed.
  • Control-byte scan over the 13 changed files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — no hits; check:nul-bytes exit 0.

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

scripts/** publishes nothing ⇒ skip-changeset.

Post-merge: origin/main merged 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 on dc3e2815 and 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 by 5d4d55aec"tooling(pm): govern hotcrm in check-governed-merges (#14867) (#14987)". The other 12 are untouched by the merge (git diff --stat dc3e2815 HEAD over 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 of four-governed-repos-declared with five-governed-repos-declared plus a new hotcrm-is-a-governed-repo-with-its-slug (#14867) assertion. The resolution keeps the opener and both of main's assertions; nothing of main's hotcrm governance 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 empty git diff HEAD) reports:

  • declared set equals opened set — 22 / 22, symmetric difference empty;
  • exactly one battery moved: 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 own 245 assertions verdict line;
  • that entry's floor was re-read to 17. Every other floor is unchanged, and SELF_TEST_BATTERY_FLOOR stays 22.

Re-verified on the merge result 8d6d40e6:

  • Behaviour byte-identical, measured in place rather than from a copy: origin/main's own version of the file swapped into the worktree (7486320e8f1afdf2, proved equal to the origin/main blob), run, then restored to an empty git diff HEAD. Both sides exit 0 with stdout and stderr byte-identical. ⚠️ A first reading of this file exited 1 with the battery below its floor; that was the fresh worktree having no node_modules, so the real-generator battery could not run — container state, not a case deletion, and it cleared to exit 0 after pnpm install. It is recorded rather than quietly re-run.
  • A fifth ablation leg, on the merged file: main's own assert('five-governed-repos-declared', …) line deleted (anchored count 1 → 0, 0585ed5acee9dfa2). 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 empty git diff HEAD. So the re-read floor is load-bearing over main's change, not merely satisfied by it.
  • Gates re-derived and re-run on 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-completeness exit 3). check:pm-governed-merges exit 0; check:pm-dispatch-gates exit 0 (1288 cases). The two check:i18n* gates again needed the workspace build in this fresh worktree (exit 3, both --self-test halves green) and were 0 each after it, under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 425s).
  • pnpm lint whole repo — exit 0 on 8d6d40e6, 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

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
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@github-actions

github-actionsBot commented Sep 3, 2026

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 15725f3eeb58eea0a3779cd095e88f757fa086a8packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 3, 2026 17:24
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
@github-merge-queue
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
@baozhoutao
baozhoutao added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8a96e66Sep 3, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch2-roster-floor branch September 3, 2026 19:22
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.

2 participants

@baozhoutao@claude