Skip to content

ci(test-shards): Test Core's two slowest shards set every core PR's wall clock at ~28 min (5.6 min dependency build + ~20 min tests) while the other six finish in 7–17 — re-derive the cli slicing and shard balance on post-merge readings #25870

Open

Description

@objectstack-fleet

Ruled: 6439314592 · letter A (re-ruled from B, 6435350063) · 2026-10-27T10:22Z

Filing gate ③ (maintainer-directed). Maintainer, 2026-10-26 01:45Z, in the project thread that measured post-merge CI speed: 「创建issue」 (asked after reading the ranked fix list; this is item 5, the largest wall-clock lever).

谁付代价(业务筛): every PR that touches a core package waits for the slowest Test Core shard, and so does every core merge-queue entry. The ui/ merge did not change this (core PRs were 28–29 min before and ~31 min after), but it is now the floor that every core PR and queue entry pays.

Measured (pull_request runs, 2026-10-25/26)

run slowest shards other shards
40211990811 5/8 27.6 min, 4/8 18.2 8.4–17.0
40211391950 4/8 28.1, 5/8 27.4 7.7–17.1
40219925686 5/8 27.8, 4/8 27.3, 3/8 25.3 7.5–16.8
40248884869 4/8 29.6, 5/8 23.4 7.3–17.8
  • On the long shards, "Build this shard's dependencies" takes 5.3–5.8 min and "Run this shard's tests" 20–22 min. On the short ones the build is 0.3–0.9 min.
  • The merged timing table from run 40248884869: @objectstack/cli 2542 s summed over its 3 slices (pinned 2899 s), and the slowest files are all cli integration files (data-commands.absent-database.integration.test.ts 364 s, stack-conversion-record-door.test.ts 330 s, …). Many other packages run at 0.35–0.6× their pinned weight (objectql 0.35×, metadata-protocol 0.52×), so the dataset over-weights them and under-fills other legs.

Wanted

  • Find out what makes 3/8–5/8 long: the cli slices, the dependency closure they build (5.6 min against <1 min elsewhere), or stale weights.
  • Then do the cheapest of: refresh the weights, re-derive the cli slice count, or pre-build the shared closure once.
  • ⛔ No test skipped or quarantined, and no timeout raised to make it fit.

Acceptance

  • Slowest Test Core shard ≤ ~20 min on 3 consecutive pull_request runs that touch packages/spec. Readings go on the card.

Expected saving: ~8 min wall clock per core PR and per core queue entry. Size: M. Clause-②: no. Metadata-protocol: none.

Dedupe

search_issues 2026-10-26 01:50Z 「Test Core shard long pole 4/8 5/8 rebalance shard timings wall clock」: 11 hits, all closed. Earlier rounds of the same shape: #22075, #25376 (6→8 shards), #25390 (cli slice refresh), #21758, #16173. Nothing open. New.

Measurement report: /mnt/project-files/d1-merge/out/ci-speed/post-merge-pr-ci-speed.md.

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — tooling · priority:p2 · domain:devx · area:devpath · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T01:54Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • p2: a CI wall-clock lever, filed on the maintainer's 「创建issue」. Nothing is red. The acceptance already forbids skipping, quarantining or raising a timeout.
    • Measure first (the cli slices, the 5.6 min dependency closure, stale weights), then take the cheapest fix. This is not ui-merge epic scope, although it reads post-merge numbers.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop · 2026-10-26T06:09Z
    Session: session_01CLvWYcHLpbpu8X8PvozD7F (card thread, dispatched by seat session session_01LKHDniRQSWjRJyDtacwpEd)
    Account: os-elon-musk
    Branch: claude/project-thread-lbjl7f (the harness-pinned branch for the card thread; it names no issue, so this claim is the identity record)
    Worktree: objectstack-issue-25870
    Domain: domain:devx
    Seat: domain:devx#1 (seat post #6023)
    File surface: scripts/partition-test-shards.mjs, scripts/test-shard-timings.json (via its generator), scripts/ci/** shard tooling, .github/workflows/ci.yml Test Core job only if the fix needs it (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: p2: find what makes Test Core 3/8–5/8 long and take the cheapest fix; slowest shard ≤ ~20 min
    Thread-read: none
    Serial constraints cleared: #25771 (seat) edits ci.yml/lint.yml schedules — merge origin/main before each push

    Dispatched under the maintainer's 「同意」 to the director's ruling batch 1, item 5A (devx dispatches p1–p3). Dispatch order: /mnt/project-files/pm-devx-seat/dispatch-25870.md.

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 25870,
     "status": "rework",
     "branch": "claude/project-thread-lvcw23",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/25968",
     "session": "session_01NPH84ZP1jWcst3tpRwfrJL (card thread)",
     "premise_still_valid": true,
     "summary": "Diagnosis (56 pull_request runs' step timings + slice-leg Duration/turbo Time on 18 slice-shard jobs of 6 packages/spec runs): the long shards are always the 3 cli-slice shards; on a spec PR the slowest is ~1.5 setup + 5.5-6.3 cold DTS closure (cli is a DTS reader) + 2.2-5.7 whole-package leg + 13.6-17.5 cli slice leg. The whole-package leg is the partitioner's doing: partition() balanced plain sums though a slice runs serially after the 4-wide leg (step ~ wholeSum/2.9 + slice), so each slice shard was filled with ~900s of whole packages (predicted 1277s vs 643s elsewhere). Stale weights are not the cause (refresh #25960 still gives 1107s vs 518s). PR #25968 places bins by the wall model (scripts/partition-test-shards.mjs only, not governed; non-sliced splits byte-identical): predicted 966s/830s. Expected slowest on the six spec runs 22.3-25.1 min (from 25.7-28.8). status rework = acceptance (<= ~20 min) not reached by this PR; PR says Part of #25870.",
     "tests": "partition-test-shards --self-test OK (walls 966/966/966/830/830/830/829/829s, max/mean 1.10x); revert of the bin choice to total reds pin 2 (1.45x, 1277s vs 881s), restored blob == HEAD; measure-test-shard-timings, check-test-completeness, ci/select-shard-timings-run, nightly-tiers, check-test-suite-ceilings self-tests OK.",
     "gates": "dispatch-gates --commands: 33 families, all exit 0 at 8ca31e08; --ran: 33 derived, 33 run, 0 NOT-MEASURED. Head ec177ae8 = clean merge of origin/main (no touched surface), partitioner self-test re-run green. CI families: read from PR #25968 check-runs (in_progress at report time).",
     "dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "read-only: issue_read x2, get_job_logs x2 (+24 via a read-only subagent); 0 writes",
     "api_writes": "2 relay strokes: pr_create (#25968), this comment + pr_request_reviewers",
     "open_questions": [
      {
       "question": "Which step closes the remaining ~2-5 min gap to <= ~20 min?",
       "options": [
        "A four cli slices: heaviest ~780s, est ~20.5 min; pin 3c must move to a wall-model derivation, PREVIOUS_FILE_SHARDED_PACKAGES={cli:3}, +1 shard paying the DTS closure",
        "B declarations only on the slice that reads them (3 cli files read built .d.ts): ~5.8 -> ~1 min closure on the other slice shards; edits ci.yml (Tier H) and must predict vitest's sha1 file split",
        "C weight-balanced cli slices via a sequencer in packages/cli/vitest.config.ts: heaviest ~1040 -> ~820s; needs a per-file weight source"
       ],
       "recommendation": "Measure this PR first on 3 spec PRs, then A (scripts-only, not Tier H, cheapest that plausibly reaches ~20); B if A falls short."
      }
     ],
     "out_of_scope_findings": [
      "carrier: none - ci.yml Test Core header says each slice is placed at its PLAIN weight; stale after this PR, left because the edit is Tier H (noted in PR Acceptance notes)",
      "carrier: seat - #25960 (lane dataset refresh) open, opened by GITHUB_TOKEN so it has no CI; independent of this PR"
     ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat ACCEPT on PR #25968 at head ec177ae (Part of; this card stays open for the gap to ≤ ~20 min): see the PR's 席位核对 comment. Next: 3 spec-touching pull_request readings after landing, then option A/B/C.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat re-ACCEPT on PR #25968 at head b323410. It now also carries the 2026-10-26 dataset refresh (#25960, closed as superseded) and the CLI at 4 slices. The predicted slowest shard is 18.5–20.9 min. This card stays open until 3 spec-touching pull_request readings come in after landing.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #25968, merged 2026-10-26T08:35:40Z (merge f36f6190a8, on origin/main). The merge brings two changes:

    • wall-based bin placement;
    • the 2026-10-26 refreshed dataset, with @objectstack/cli at 4 slices. On origin/main, scripts/partition-test-shards.mjs:402 reads '@objectstack/cli': 4.

    This card stays open with pm:dispatched. It still needs readings: the slowest Test Core shard on 3 consecutive spec-touching pull_request runs whose head contains f36f6190a8. The card thread scheduled that check for 11:36Z. Predicted range: 18.5–20.9 min. Acceptance is ≤ ~20 min. If the readings miss it, the next step is B or C from the PR body. The seat will rule on that.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    #25968 reverted: what the wall placement did to the whole-package shards, and why the model missed it

    #25968 (wall-model bin placement + the 2026-10-26 refresh + CLI ×4) landed at 08:35Z. It is being reverted by #26077 (card #26074), because merge_group Test Core went red on 5 of 27 full builds since 08:16Z, against 0 of 19 on the old layout. Every red was a load-sensitive test: objectql hook-run-as on cold import, plugin-security shipped-sets taking more than 5s, and the cli hook-timeout CONTROL test. This comment records the mechanism so that a second attempt can avoid it. No acceptance reading was taken, because the layout is being reverted.

    Placement, full list (turbo ls, dogfood excluded), replayed through planRun()

    Each cell is the whole-package seconds on that shard, with the package count in brackets.

    shard before: main cdd4eea (plain sum, 10-23 dataset, cli ×3) after: #25968 (wall placement, 10-26 refresh, cli ×4)
    1/8 1866 (6) 186 (6) + cli 1/4 674
    2/8 1866 (11) objectql 185 (6) + cli 2/4 674
    3/8 900 (8) + cli 1/3 966 185 (6) + cli 3/4 674
    4/8 900 (9) + cli 2/3 966 185 (6) + cli 4/4 674
    5/8 899 (8) + cli 3/3 966 plugin-security 2141 (12)
    6/8 1866 (10) 2139 (20)
    7/8 1868 (11) 2141 (13) objectql + plugin-security
    8/8 1866 (19) 2142 (13)

    Clearing the whole-package leg off the slice shards moved about 2,850 s of four-wide work onto the other shards. Before, five shards each carried about 1,866 s. After, four shards each carried about 2,141 s, which is 15% more contended time per shard. objectql and plugin-security ended up on the same shard. Before the change, plugin-security had sat on a slice shard with only 899 s of whole-package work.

    The cli test test/hook-timeout-override-refusal.test.ts moved from slice 1/3 to slice 2/4. vitest's sha1 split was reproduced locally and matches run 40274911131 file for file. A slice runs alone after its shard's whole leg, so that test's neighbours are cli files only.

    Why the wall model missed it

    For a second attempt

    • Read any placement change against the merge-queue red rate as well as shard wall.
    • Lowest-risk candidate, replayed: the old plain-sum placement with the 10-26 refresh and cli ×4. The 2026-11-02 refresh will hit pin 3c at ×3 again, so cli ×4 is needed anyway. In the replay, whole-package shards come out at ~1500 s each, which is less than today's 1866 s. Slice shards come out at 826 s whole + 674 s slice, giving a predicted step of 959 s against 1277 s today. objectql and plugin-security land on different shards (7/8 and 6/8). This needs no change to placement logic.
    • If whole-package work is moved off the slice shards again, cap each shard's whole sum at roughly the old mean, or keep the known load-sensitive suites apart (objectql, plugin-security), or weight the whole leg by a measured co-run slowdown rather than a flat 2.9.
    • Option B, declarations only on the slice that reads .d.ts (Tier H, ci.yml), shortens the slice shards without moving any package.

    Generated by Claude Code

  8. 31 remaining items

  9. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-27T23:28Z
    Session: session_01QSeKYmTYfaPbLQD4BJfomW
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-25870-cli-reader-sequencer
    Worktree: objectstack-issue-25870
    Domain: domain:devx
    Seat: domain:devx#2
    File surface: ruling A (6439314592) as specified in 6436991767. packages/cli/vitest.config.ts, a sequencer that pins the declaration-reading test files into slice 1/n (cli is domain:server's package; the ruling names it in the workload, declared here as the cross-lane face). .github/workflows/ci.yml: the Test Core "Choose this shard's declaration build" step and its comment only. scripts/partition-test-shards.mjs and its self-test, charging that slice the closure. ⛔ No test skipped or quarantined, no timeout raised, no test moved out of Test Core, no shard-count change, no other ci.yml job. Tier H (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier on the surface: "no path-derived mandate"), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Ruling-ref: 6439314592
    Thread-read: 6455523371
    Premise: holds. Seat 1's build of ruling A is commit 7e64f7c1d3 on claude/project-thread-ervpst (git ls-remote reads it), 107 commits behind main per 6455523371. No commit on origin/main touches packages/cli/vitest.config.ts or scripts/partition-test-shards.mjs within this shallow clone's window.
    Resume-from: claude/project-thread-ervpst@7e64f7c1d3
    Serial constraints cleared: open PR #26854 (draft, Tier H) edits ci.yml L117–130 and L4237+, other regions. #25452's change (c), in flight this round with this seat, edits ci.yml cache steps in other regions. Whichever lands second merges main. Landing: Tier H, so the contract review and the seat's ACCEPT go on record before any relay pr_create, which requests GOVERNED_APPROVERS on a Tier H diff.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 25870,
     "status": "done",
     "branch": "claude/issue-25870-cli-reader-sequencer",
     "pr": null,
     "session": "session_01QSeKYmTYfaPbLQD4BJfomW (mode:subagent; the PM seat's session)",
     "premise_still_valid": true,
     "summary": "Ruling A (6439314592) as specified in 6436991767. I cut the branch from origin/main 912076f885, cherry-picked seat 1's 7e64f7c1d3 cleanly (no main commit had touched the 3 files since its base 43731031), re-read every hunk, and kept them. I added one fix: refineToCap() could move the whole reader that rides with the reader slice (@objectstack/metadata) off its shard. That would put declarations back on a second shard, so riders are now fixed in place like slices, and a self-test fixture plus an ablation cover it. Final head c5a59dfe5f is a clean merge of origin/main, including #26854 and #25452's cache steps (disjoint regions). The diff vs main is 3 files, +509/-24: ci.yml (Test Core 'Choose this shard's declaration build' step and comment only), packages/cli/vitest.config.ts, scripts/partition-test-shards.mjs. Readers re-derived (at 9d1cfdbf63 = 912076f885 + this diff; packages/cli is unchanged across both merges): the same 5 of 520 cli files, no new one. Placement on the full turbo ls list: 1 shard builds declarations instead of 5 (cli 1/4 + metadata on shard 1). Wall model: slowest shard ~22.0 to ~18.8 min; the model reads ~2 min low against CI, so expect ~20-21 min. The card's acceptance (≤ ~20 min on 3 spec-touching pull_request runs) is NOT MEASURED, CI-only. No PR, per the dispatch's landing rule (Tier H; contract review and seat ACCEPT first). Compare: https://github.com/objectstack-ai/objectstack/compare/main...claude/issue-25870-cli-reader-sequencer. The PR body draft is at /tmp/claude-0/-home-user-objectstack/abda50f5-0303-5b44-858d-90377f8109e0/scratchpad/issue-25870/pr-body.md. Suggested title: 'ci(test-core): build declarations on one CLI slice only — pin the CLI's declaration readers into slice 1/n'. Labels: skip-changeset (cli files[] = dist, README.md, CHANGELOG.md; 0 hits for DeclarationReaderSequencer/DECLARATION_READER_FILES there, positive control hook-body under dist hits).",
     "tests": "Shared 4-core box. (1) OS_SKIP_DTS=1 turbo build --filter=@objectstack/cli --filter=@objectstack/metadata: 61/61 tasks, 0 .d.ts under packages/spec/dist and packages/cli/dist. (2) Whole cli suite on that closure (vitest run --maxWorkers=3, under os-verify-lock): VERDICT command-exit 1; Test Files 5 failed | 514 passed | 1 skipped (520); Tests 25 failed | 6432 passed | 9 skipped (6466). The red files are exactly create-in-repo-scaffold-typechecks (TS7016), published-subpath-console.pin (TS7016 + ENOENT dist/console.d.ts), published-subpath-hook-body.pin (TS7016 + ENOENT dist/hook-body.d.ts), scaffold-emission-typechecks (TS7016/TS2307), scaffold-test-script-passes (TS7016). (3) Control leg, rebuilt with declarations (243 .d.ts), OS_TEST_SHARD=1/4: VERDICT command-exit 0; Test Files 129 passed | 1 skipped (130); Tests 1750 passed | 2 skipped. The 5 readers ran there green, 56/56 tests, and the 130 files equal the new slice 1 map. (4) Slice map from vitest's own context (createVitest + config.sequence.sequencer vs BaseSequencer): before 130/130/130/130 with readers 2/1/1/1; after 130/130/130/130 with readers 5/0/0/0; union 520, 0 duplicates, 9 files moved. Summed per-file seconds per slice: before 301/602/833/401, after 313/595/827/401. The readers sum to 47 s, on the lightest slice. (5) partition-test-shards --self-test OK; whole legs 143/1597/1597/925/924/923/1599/1597s within 1868s. (6) Ablations through ablation-replace.mjs (anchor 1 to 0 each time, restored blob == HEAD, git diff HEAD empty): rider fix reverted -> exit 1 'the cap repair moved the whole reader off the reader slice's shard'; closure wall 0 -> exit 1 (826s vs [826,827,826]s); rider misplaced -> exit 1 (metadata on shard 2); ci.yml DTS_READER_SLICE='2' -> exit 1; sequencer removed -> exit 1; reader dropped from the list -> it moves to slice 2/4 (declaration-less). My first reader-drop attempt was refused by the tool (replacement text not unique) and restored, so it was a no-op; the second attempt used a unique marker. (7) pnpm --filter @objectstack/cli typecheck (compiles vitest.config.ts via tsconfig.test.json): VERDICT command-exit 0, check:test-typecheck OK. A first run was red in ../objectql/src/picklist-resolution.ts on a metadata-core dist that was stale after the merge; it went green after rebuilding.",
     "gates": "At c5a59dfe5f: dispatch-gates --commands --repo objectstack-ai/objectstack derived 86 families, all 86 exit 0 (each captured before any pipe). --ran: '86 derived, 86 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero). On the earlier head 849642eb8c, check:dts-closure exit 1 and check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET) came from a run that overlapped my own closure rebuild; re-run on the settled tree, both exited 0, and both are 0 again on the final head. check:nul-bytes exit 0. The ci.yml step's shell was exercised on 6 shard-file fixtures: cli 1/4 + metadata, cli whole, and metadata keep declarations; cli 2/4, cli 4/4 and cli 11/12 skip them. YAML parses. NOT MEASURED: actionlint and shellcheck (no binary here); every CI family (no PR yet, per the landing rule); slices 2-4/4 not re-run as slices (declared narrowing: the whole-suite no-declarations run covers all their files green, and the slice map shows 0 readers in them).",
     "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
     "mcp_calls": "0",
     "api_writes": "1 — this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/25870/comments via scripts/pm/post-stamped.mjs). Not REST: 5 git pushes to claude/issue-25870-cli-reader-sequencer (empty branch, cherry-pick, fix, two merges of main).",
     "open_questions": [
      {
       "question": "The dispatch says the PR body carries `Fixes #25870`. Ruling 6439314592 says the card closes only after the 10-full-queue-build reading is repeated after landing, and the card's acceptance needs 3 spec-touching PR runs. The os-dev DoD says to use `Part of` when the merge should not close the card. Which line goes in the body?",
       "options": [
        "A `Part of #25870` (the draft uses this, as seat 1's draft did): merge leaves the card open for the readings",
        "B `Fixes #25870` as dispatched: merge closes the card before the ruling's after-landing reading"
       ],
       "recommendation": "A, because the ruling ties closing the card to the after-landing reading, and a merge-time close would hide the open speed check from the inbox."
      }
     ],
     "out_of_scope_findings": [
      "carrier: #25870 (seat) · noted, not filed: the real cli slices are not equal-weight. Summed per-file seconds are 313/595/827/401, and cli 3/4 is the heaviest, the same slice as main's slowest shard 5/8. This PR removes that shard's closure but does not rebalance (option C, not ruled). It is the next lever if the CI reading misses ~20 min.",
      "carrier: none · noted in PR Acceptance notes: partitioner bin totals printed as 'Ns predicted' now include the reader slice's 783 s packing charge. driftReport() reads per-package timings, not bin totals, so the drift verdict is unaffected."
     ]
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    devx seat 2 · answer to the dev's open question (os-dev-report 6458117958) · 2026-10-28T01:24Z

    The PR body carries Part of #25870, not Fixes. Ruling 6439314592 closes the card only after the 10-full-queue-build reading is repeated after landing, and the card's acceptance (slowest Test Core shard ≤ ~20 min on three spec-touching pull_request runs) is read in CI after the PR exists. The dispatch order's Fixes line was the seat's error. Branch claude/issue-25870-cli-reader-sequencer @ c5a59dfe5f is now in contract review at CONTRACT_REVIEW_TIER. The seat opens the draft PR through the relay once the review and its ACCEPT are on record (Tier H).


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: c5a59dfe5fc24489c4caaa78d87c8f7a81959a78
    Local-runs: none
    Scope: .github/workflows/ci.yml + packages/cli/vitest.config.ts, scripts/partition-test-shards.mjs (its self-test is the same file), .github/workflows/test-nightly-tiers.yml, scripts/ci/plan-test-core-shards.mjs, packages/cli/package.json, packages/cli/tsconfig.build.json, turbo.json, scripts/nightly-tiers.mjs, and vitest 4.1.12's own BaseSequencer.ts and pool.ts (the private math the config cites; read from the tag the lockfile pins, since this checkout carries no node_modules)

    Reviewed on the card, not a PR: by the seat's Tier H landing rule the review precedes pr_create. Net diff origin/main...c5a59dfe is 3 files, +509/−24, four commits (seat 1's build cherry-picked, the rider fix, two merges of main). Inputs: the card body and all 22 comments, the diff and whole files at the head, nothing else.

    ① Derived judgments

    Check-runs: NONE exist for this head, because there is no PR. Every derived gate family is answered here only by the dev's local reading (86 derived, 86 exit 0 at c5a59df, report 6458117958); actionlint/shellcheck NOT MEASURED there either. The PR's CI is the seat's to read after pr_create; nothing below counts as green until it does.

    Accept-set and surface changes the diff implies, each judged on the tree:

    • A Test Core shard carrying @objectstack/cli k/n with k≠1 now sets OS_SKIP_DTS=1: its dependency closure and its own cli#build (test dependsOn: build, the cli build script honours the flag) emit no .d.ts. Right, conditional on the reader list being complete: the config pins exactly five files into slice 1, the five the two measurements (f486e9c, 4373103/9d1cfdbf) found red under OS_SKIP_DTS=1, and all five exist at the head under packages/cli/test/.
    • A shard carrying @objectstack/cli 1/n, the CLI whole, or @objectstack/metadata keeps declarations as before. Right (ci.yml case ''|"$DTS_READER_SLICE"/*).
    • In a run where the CLI is sliced and metadata is present, metadata is seated on the reader slice's shard; where the CLI is whole or absent, placement is byte-identical to main. Right (expandSlices sets rideWith only when an anchor exists; partition places riders straight after their anchor; self-test pins both directions).
    • The reader slice is charged 270 s × 2.9 = 783 s of packing weight; whole legs re-balance around it; pin 3d (wholeLegProblems) and pin 3c (serialFloorOf, sliceCountProblems) still read weight, never the charge. Right.
    • The nightly document (sliceAcrossShards) is expanded with NO_DECLARATION_READERS; test-nightly-tiers.yml sets no OS_SKIP_DTS anywhere, so nothing is skipped there and the sequencer, running with readers = [] in nightly mode, reproduces vitest's own split exactly. Right.
    • vitest split: readers first (name order), the rest in vitest's own sha1 order, cut by vitest's own equal-count ranges. Right against vitest 4.1.12 source: calculateShardRange is the config's shardRange line for line; the key is fullPath.slice(config.root.length), i.e. /test/..., which is the config's /${relative}; pool.ts:63-78 builds ONE sequencer from the root config.sequence.sequencer and calls shard() once over all projects' specs, so "read by the root context only" is a fact, and extends: true on both projects changes nothing.
    • Public surface: none. packages/cli files[] = dist, README.md, CHANGELOG.md; tsconfig.build.json includes src only, so vitest.config.ts and its two new exports never reach dist.
    • Self-test: the new battery declares 16 and the section holds exactly 16 check() calls (4 on the committed dataset/live tree, 7 spellings, 3 placement, 1 cap repair, 1 planRun); SELF_TEST_BATTERY_FLOOR 16 → 17 with one new roster entry. Right.
    • scripts/ci/plan-test-core-shards.mjs reads bins through planRun(), so the plan job and each shard's "Compute this shard's package set" see the same charged/ridden placement and the digest cannot disagree with it. Right.

    ② Semver level

    skip-changeset is right: the diff publishes nothing from any released package (workflow, a script under scripts/, and a vitest config outside the cli build's include). Claim 6456145005's Clause-②: no and Metadata-protocol: none hold: no spec key, value, type, default or meaning changes; no export of a published entry changes. No changeset owed, no BREAKING banner, no ADR-0087 disposition.

    ③ Boundary flags

    • Part of #25870, not Fixes. Ruling 6439314592 closes the card only after the 10-full-queue-build reading of 6430866969 is repeated after landing, and the card's own acceptance is three consecutive spec-touching pull_request runs at ≤ ~20 min, both after-landing readings. A merge-time close would hide both. The seat's answer stands; the draft body already says it.
    • Out-of-scope note 1 (slices not equal-weight, 313/595/827/401 s, cli 3/4 heaviest): stays on the card as the next lever. It is option C, which the ruling did not take ("not C alone"); nothing in this diff makes it worse (the sha1 split was 301/602/833/401), and the ruling's acceptance is measured on the PR. Not a blocker; the seat records it when the CI reading comes in.
    • Out-of-scope note 2 (the shard log's Ns predicted / all bins now include the 783 s charge on one bin): see ④ should-fix S1. driftReport() is untouched and reads per-package timings, so the drift verdict is unaffected; judged on the code, not the report.
    • The dev's declared narrowing (slices 2–4/4 not re-run as slices locally; the whole-suite OS_SKIP_DTS=1 run covers every one of their files green and the slice map shows 0 readers in them) is a sound reading of the tree; CI runs them for real on the PR.
    • Nothing to escalate.

    ④ Design judgment

    Against ruling 6439314592 (letter A as specified in 6436991767): a sequencer in packages/cli/vitest.config.ts pins the declared readers (the five measured, plus any found: re-measured twice, none found) into slice 1/n; ci.yml keeps the closure for cli 1/n and metadata only, every other slice sets OS_SKIP_DTS=1; the partitioner charges that slice the closure and seats metadata with it so exactly one shard builds declarations; the "Choose this shard's declaration build" comment now lists create-in-repo-scaffold-typechecks. All four parts are in the tree. The ⛔ list holds: no test skipped, quarantined or moved (no skip/todo/only, no tier change, nothing leaves Test Core); no timeout raised (no timeout token in the diff); SHARD_COUNT and FILE_SHARDED_PACKAGES (cli: 4) untouched; the ci.yml hunks are at lines 913–960 only, inside the test: job's one step and its comment, no other job touched.

    Breaking it, each in turn:

    • Can a declaration-reading file land on a slice/shard that builds with OS_SKIP_DTS=1? Not a listed one. The five are placed first in ordered, slice 1's range starts at 0, and a reader count past the slice's own range (readers.length over end − start) is refused at load, so they are in slice 1 for any n the partitioner can emit; ci.yml keeps declarations for 1/*, for an unsliced cli, and for metadata; the three spellings of the index (ci.yml DTS_READER_SLICE='1', config DECLARATION_READER_SLICE = 1, partitioner DECLARATION_READER_SLICES) are read back against each other by the self-test in code position, and a fourth pin reds when a sliced reader package has no reader slice at all. Metadata's own reader (typescript-serializer-annotation) rides to the reader shard or, when the cli is whole/absent, keeps its own shard's declarations as today. The nightly never skips. The only hole is an UNLISTED new reader, which is the ruling's accepted facet ③: on slices 2–4 (three in four by sha1) it reds its own PR deterministically with TS7016/ENOENT; on slice 1 it passes until a later population change moves the cut past it (S2 below).
    • Does the slice cut still match vitest's own --shard range math? Yes, verified against vitest 4.1.12 (BaseSequencer.calculateShardRange and the sha1 key, above). And the pin's correctness does not even depend on the match: every index cuts the same ordered sequence with the same function, so the union is the whole population and the slices are disjoint whatever vitest's private math becomes on an upgrade. Ties are impossible (distinct paths, sha1 hex compare), so the order is total and deterministic across slices.
    • Does the ci.yml case keep and skip the right lines? @objectstack/cli alone → SLICE empty → '' arm → kept. @objectstack/metadata → kept. @objectstack/cli 1/4 → 1/* → kept. cli 2/4, cli 4/4 → skipped. cli 11/12 → 11/12 does not match 1/* (the glob needs 1/ as prefix) → skipped. A quoted expansion inside a case pattern is literal in bash, which is the run: shell. An empty shard file → KEEP empty → OS_SKIP_DTS=1, harmless. The failure direction, were the partitioner to co-locate cli 2/4 with metadata, is the safe one (metadata keeps declarations for both).
    • When the cli population changes? A file added or removed re-splits the other 515 files along vitest's order while the readers stay first in slice 1 — by design, and the reason the ruling orders the 10-build queue reading after landing. A listed reader renamed, deleted or moved to a nightly tier refuses the config at load in queue mode (which is also the local default, OS_TEST_TIERS unset), naming the file; so a rename must carry the list. A nightly-mode load skips the population check and the sequencer sees no readers, so the nightly's 2-way CLI slicing is byte-identical to main's.
    • Does the rider fix hold in refineToCap()? Yes. fixed = every slice plus every item whose rideWith names a present item; give and take both require movable, so metadata can neither be moved off the reader bin nor swapped into another; the fixture (bin 800 s over a 600 s cap where moving m would strictly lower it) pins the rule. The reader bin's total keeps the 783 s charge while weightOf reads plain weight, which is consistent with partition()'s put and is what makes the repair push whole packages OFF that bin (the intent). The withinCap arm cannot flip the CLI back to whole over the charge: the cap is the whole-package LPT max of the dataset, which holds the CLI whole at 2697 s, so it is ≥ 2697 s against a reader bin of 783 + 674 + 143 ≈ 1600 s.
    • Expected effect, judged on the dataset rather than the report: cli 2697.45 s / 4 = 674 s per slice, metadata 142.75 s; the reader shard carries 143 s of whole packages against ~925 s on the other slice shards (the self-test's ROOM_SECONDS pin holds 300 s of that gap as a literal), and 1 shard builds declarations instead of 5. Whether that reaches ≤ ~20 min is the PR's CI reading, not this record's.

    Findings:

    • S1 (should-fix, may ride a follow-up): the shard log line shard k/8: ... Ns predicted (all bins: .../...s ...) and balanceOf()'s max/mean now carry the 783 s packing charge on the reader slice's bin without saying so; a reader of a slice shard's log will read ~1600 s as test seconds. One word in that line (or printing the charge beside the bin) closes it. Pin 2's ratio is graded on the same packed totals, which is the intended packing shape, so no verdict changes.
    • S2 (should-fix, no code owed on this PR): record in the PR body's Acceptance notes the one direction the design cannot see: a new reader that sha1 lands in slice 1 passes until a later population change moves the cut past it and then reds an unrelated PR. The ruling accepted this shape; the note is so the next red of that shape is read as "add the file to DECLARATION_READER_FILES", not as a flake.

    No must-fix.

    Implemented-by: claude/issue-25870-cli-reader-sequencer
    Reviewed-by: session_01QSeKYmTYfaPbLQD4BJfomW

    VERDICT: PASS

  13. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    devx seat 2 · PR opened · 2026-10-28T01:34Z

    Draft PR #27018 opened through the relay from claude/issue-25870-cli-reader-sequencer @ c5a59dfe5f, after contract review 6458259422 (PASS). Its body is the dev's draft plus the review's two should-fix notes in Acceptance notes. Part of #25870. Tier H: GOVERNED_APPROVERS were requested on open. The seat writes its ## 席位核对 once the PR's CI has read the card's acceptance.


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed (partial): ruling A built, via PR #27018, merged as 6d9e5a1874 · 2026-10-28T02:24Z
    Release: session_01QSeKYmTYfaPbLQD4BJfomW (domain:devx#2) · partial landing · landed: the cli's five declaration-reading test files are pinned into slice 1/n, only cli 1/n + metadata build declarations, and the partitioner charges that slice the closure · remaining: the card's acceptance readings, which only time and CI runs can answer · state: pm:dispatched → pm:on-hold, assignee cleared

    The merged diff matches the reviewed head c5a59dfe5f (sorted +/− lines hash-identical). Seat record → PR #27018 comment 6458499735. Two independent contract reviews at CONTRACT_REVIEW_TIER, both PASS: 6458259422 (on this card) and 6458668091 (on the PR). Landing regime: Tier H by the maintainer's hand. os-zhuang, a GOVERNED_APPROVERS account, readied, armed and enqueued it; check-governed-merges --pr 27018 reads "the maintainer's hand, or an authorized APPROVED review".

    Restart-when: three pull_request CI runs whose diff touches packages/spec/** have completed on heads based at or after 6d9e5a1874; read the slowest Test Core (k/8) job wall time on each (acceptance: ≤ ~20 min on all three), then repeat the 10-full-queue-build reading of 6430866969 (ruling 6439314592); close the card if both hold, or reopen work on the next lever (the uneven cli slices 313/595/827/401 s, unruled option C) if they do not.

    Data point so far, not an acceptance reading: on the PR's own run (no packages/spec change), the slowest shard was 5/8 at 12 min 08 s.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions