Skip to content

feat(scripts): a third test-budget class, "compiles the package type graph once" - #23897

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23821-type-graph-budget-class
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23821-type-graph-budget-class

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23821
Clause-②: no

The refresh diff's closed list of test-budget classes (TEST_BUDGET_CLASSES in scripts/measure-test-shard-timings.mjs) gains its third value, compiles the package type graph once. A test file whose irreducible cost is one compile of its package's type graph can now declare its own measured budget, under the same grammar, number rule and refusals as the first two classes. One file changed: +107 / −16.

The ruling

Ruling record 6212133431 (letter A, the maintainer's 「同意」), which extends ruling record 6181973363 on #23534 by one class. Verbatim:

  1. The class name is compiles the package type graph once. It is the third value of TEST_BUDGET_CLASSES (scripts/measure-test-shard-timings.mjs:1255-1258 at this read, two values); the refusal at :1295 and its text at :1269 list three classes; the self-test at :2997 pins three.
  2. The number stays ruling 6181973363 item 2: the measured CI reading × 1.25, rounded up to the next 10 s, rising only by a PR that re-measures and says why in the line. The three prohibitions (item 5) stand: no deletion without a named duplicate, no timeout raise, no move to a slower or skipped project.
  3. No AGENTS.md edit: AGENTS.md:129-130 names the ruling record and no class list.

Ruling item 3 (the two declarations themselves) is the spec lane's. The two header lines in packages/spec/src/contracts/scoped-context.test.ts and packages/spec/src/integration/connector-author-shape.test.ts follow on #23180 in the spec lane once this lands. This PR touches no packages/** file, no workflow and no AGENTS.md.

Every place in the script that changed

Line numbers are at origin/main 497518c3f. They match the ruling's read.

Where (origin/main) Before After
:1225-1231, the readTestBudget docblock "(ruling record 6181973363, letter B)"; "Two classes …"; "A file of either class …" Cites both records. "Three classes …" names the third (a single compile of the package's type graph, every probe after the first reading that one program; ruling record 6212133431, letter A, which adds this class and changes nothing else). "A file of any class …"
:1239, the grammar's CLASS row "spelled as the ruling names it" "spelled as its ruling names it"
:1255-1258, TEST_BUDGET_CLASSES two values a third value, 'compiles the package type graph once'
:1268-1269, the refusal's text "(ruling record 6181973363)"; CLASS is "a" or "b" "(ruling records 6181973363 and 6212133431)"; CLASS is one of "a", "b", "c", so every refusal lists all three classes
:1295, the class refusal the class "X" is neither class the ruling names the class "X" is none of the 3 classes the rulings name (the count is read from the list)
:1662-1664, the battery roster 'per-file budget declarations (ruling 6181973363)': 14 18, and the comment names ruling record 6212133431's cases
:2982-2986, self-test fixtures [producerClass, wholePackageClass] adds typeGraphClass; ruledClasses (the three spellings as literals); specFileWith (the two spec files' real header, declaration on line 2); typeGraphLine (the ruling's line)
:2996-2999, the class pin length !== 2, two spellings length !== 3, three spellings in order, against the literals
:3019-3021, the off-list class case "a class naming neither" "a class naming none of them" (wording only)

The only other places that cite the mechanism name no class and list none, so they are unchanged:

  • :212-217 (FILE_BUDGET_SECONDS' doc);
  • :1545 (the rendered "Held to the budget it declares" line prints each file's own class);
  • the self-test section banner at :2980.

A tree-wide grep for TEST_BUDGET_CLASSES, either class phrase and test-budget outside this script found only the 12 declaring test files. It found nothing in docs/, content/, .claude/, AGENTS.md or .github/workflows/.

Proof the new value is read end to end

Four new self-test cases are in battery per-file budget declarations (ruling 6181973363), which grows from 14 to 18:

  1. Accepted. The ruling's line, // test-budget: 30 — compiles the package type graph once: …, sits under the exact header of the two spec files (copyright line, then the declaration on line 2, where all 12 declarations in the tree sit). It reads as { seconds: 30, cls: 'compiles the package type graph once', line: 2 }.
  2. The two earlier classes still read in that same header, at 40 s each. The third class took nothing from them.
  3. Near misses are refused loudly. Six spellings are refused: type-graph, a dropped once, a dropped package, packages, a capital C, and a trailing space before the colon. Each refusal starts with f.test.ts:3: , quotes the bad spelling, and names all three classes.
  4. On disk, through --diff. A file carrying the ruling's line goes through declaredBudgetInTree and the real diffMain, with the same CLI path as the existing round trip.
    • At the card's slowest CI reading (18.1 s), it is held, not listed: `src/integration/graph.test.ts` (`spec`) 18.10 s of its 30 s, compiles the package type graph once.
    • At 31 s it is listed against its own budget: | ... | 31.00 (declared 30) | 1 / 1 |.

Ablation. This was one-off, on f8bacd05b (the head), through scripts/ablation-replace.mjs in WRAP mode, with a trap backstop on absolute paths. No permanent mutation test remains. All four legs restored to blob 5e2b82584d38, which equals HEAD, and git diff HEAD was empty after each.

Leg Mutation (anchor 1 → 0, blob changed) Self-test reading
0 battery pin 18 → 19 exit 1: registered 18 case(s), below its pinned floor of 19. The battery runs exactly 18.
1 delete the third value exit 1 at the pin: budget: the classes read ["spawns the real producer once per single-cause fixture","whole-package import"]
2 control: the check thunk catches each failure and prints RED instead of aborting; the value is present exit 0, zero RED lines
3 delete the third value and the leg-2 instrumentation exactly four RED lines; every other case stayed green

The four RED lines in leg 3:

  • the pin;
  • case 1 (scoped-context.test.ts:2: the class "compiles the package type graph once" is none of the 2 classes the rulings name);
  • case 3 (the first near miss: the refusal no longer names a third class);
  • case 4 (the on-disk --diff refuses graph.test.ts:2).

Case 2 stayed green, as a control should.

The 12 declarations on main read unchanged. The script has no dry-run mode, so a read-only probe imported the script's own readTestBudget and read every file in packages/, apps/ and examples/ that carries a // test-budget: line. The reading is the same 12 files (10 producer-class, 2 whole-package), with identical seconds, class, line and reason. The rows digest is f1975b9e4af0… at both 497518c3f (before) and f8bacd05b (after). The two spec files read null on disk today. With the ruling's line spliced in at line 2 in memory only, each reads as the third class at 30 s.

Tests

node scripts/measure-test-shard-timings.mjs --self-test printed measure-test-shard-timings: self-test OK, exit 0, at f8bacd05b.
pnpm exec eslint --no-inline-config scripts/measure-test-shard-timings.mjs exited 0. The control-byte scan found nothing.

Gates (local, at f8bacd05b, the final head)

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 32 commands from git, against merge base 497518c3f.
  • All 32 ran and all 32 exited 0, each exit captured before any pipe. They include:
    • pnpm check:pm-dispatch-gates, run detached with its exit written to a file: ✓ dispatch-gates self-test (fast tier): 1884 cases pass;
    • check:nul-bytes, check:entry-guard and check:cross-package-test-inputs;
    • the self-test wiring and anchor gates with their self-tests;
    • the three shard-timing self-tests (measure-test-shard-timings, partition-test-shards, ci/select-shard-timings-run).
  • --ran: ✓ dispatch-gates --ran: 32 derived famil(ies) accounted for — 32 run, 0 NOT-MEASURED (a DERIVED zero — all 32 recorded an exit code and none of them is 3).
  • node scripts/pm/check-governed-merges.mjs --branch claude/issue-23821-type-graph-budget-class reported 0 of 1 path(s) hit the register (NOT governed), with 123 changed lines, under the 3,000 threshold.
  • Every family CI runs is read from this PR's check-runs.

scripts/** ships in no package, so no changeset.

Acceptance notes (not filed)

  • The battery's name still reads (ruling 6181973363). Renaming it would only churn the roster. Its comment names both records. Carrier: none.

  • No PR-time parse of a declaration (as in PR feat(scripts): a test file of either ruled class is listed over its own declared budget, not the 10 s line #23595). The spec lane's two lines are parsed only by the next weekly refresh. The spec lane can check them locally before pushing:

    node -e "import('./scripts/measure-test-shard-timings.mjs').then((m) => console.log(m.readTestBudget(require('fs').readFileSync(process.argv[1], 'utf8'), process.argv[1])))" packages/spec/src/contracts/scoped-context.test.ts

Generated by Claude Code

…graph once"

TEST_BUDGET_CLASSES gains its third value, as ruling record 6212133431
(letter A) names it. The number rule and the three prohibitions of ruling
record 6181973363 are unchanged. The refusal now lists every class
("one of ...") and says "none of the 3 classes the rulings name" instead of
"neither class". The self-test pins the three spellings as literals and
reads the third end to end: the ruling's line under the spec files' header,
the two earlier classes in that same header, six near misses refused naming
all three classes, and a --diff run from disk that holds the file at 18.10 s
of its 30 s and lists it at 31 s. Battery pin 14 -> 18.

Claude-Session: https://claude.ai/code/session_016PVjjuVPte5XEJvaQx1E4t
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · PR #23897 (draft, head f8bacd05b, Fixes #23821) · domain:devx seat 2 · session_016PVjjuVPte5XEJvaQx1E4t · 2026-10-16T12:04Z

Checked on GitHub and against the sources, not on the report's say-so.

  • Shape:
    • 1 file, scripts/measure-test-shard-timings.mjs, +107 / −16. This is the claim's whole surface (6214640541).
    • Not governed: check-governed-merges --pr 23897, run by this seat, reads 0 of 1 paths.
    • The body opens Fixes #23821, then Clause-②: no.
    • scripts/** ships in no package, so the seat applied skip-changeset in this act.
  • Against the ruling 6212133431, read on the diff:
    • Item 1. TEST_BUDGET_CLASSES gains 'compiles the package type graph once' as its third value, spelled exactly as ruled.
    • The refusal text now cites both ruling records and lists CLASS is one of all three. A class refusal reads "none of the 3 classes the rulings name", and the count comes from the list.
    • The self-test pins the three spellings as literals, in order, with no fourth. Reading them from the list instead would hide a deleted value.
    • Item 2. The number rule and the prohibitions are untouched.
    • Items 3–4. No packages/** and no AGENTS.md in the diff.
  • Proof, by the dev:
    • Four new cases:
      • the ruling's line under the spec files' real header reads 30 s and the third class;
      • the two earlier classes still read;
      • six near-miss spellings are each refused, naming all three classes;
      • an on-disk --diff holds the file at 18.10 s of its 30 s and lists it at 31 s.
    • Battery floor 14 → 18.
    • Ablation: deleting the value turns exactly those four cases red, and the control stays green.
    • The 12 declarations on main read identically before and after (rows digest f1975b9e4af0).
  • Gates: local, 32 derived, 32 exit 0, --ran 0 NOT-MEASURED.
  • Next, in the spec lane: the two // test-budget: <n> — compiles the package type graph once: … header lines ride test budget (domain:spec): 26 test file(s) over 10 s of wall in the hourly full battery (Part of #23151) #23180 at that day's CI reading × 1.25 (ruling item 3). The PR body carries the one-line local check for them.
  • Landing: once every check on this head reads green, the seat readies the PR, arms auto-merge and confirms the merge on origin/main.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Decision] Two spec test files compile the package's type graph once and read 14-18 s on CI: a third test-budget class, or they stay listed

2 participants