Repository navigation
ci(test-shards): widen Test Core from 6 to 8 shards once @objectstack/spec is file-sharded — the "6 is enough" arithmetic predates the cli slices (full-battery slowest shard ≈ 1937 s → ≈ 1452 s) #25376
Description
Filing gate: ③ maintainer-directed task (CI performance programme, 2026-10-23). Reader: the domain:devx execution seat, dispatch step — one os-dev, one PR, after the spec-slicing card lands. Dedup: search_issues on objectstack-ai/objectstack, closed included, "SHARD_COUNT 6 to 8 test shards widen partition" → 3 hits, all closed (#22075, #16473, #15208); none open. Session: session_01GVTBi44LAWbPWg4evKfE1T.
Blocked-by: #25372
One-sentence problem
The six-way split of objectstack's test suite was sized when the largest indivisible block was 1773 s; the cli package has since been sliced into three and (with the sibling card) spec into two, so the arithmetic that said "a seventh or eighth shard buys nothing" no longer holds — a full-battery run's slowest shard drops from ≈ 1937 s to ≈ 1452 s at eight.
Evidence (file lines at objectstack commit 303aef0)
scripts/partition-test-shards.mjs:127—export const SHARD_COUNT = 6;;:61-62andci.yml:468-473carry the standing reasoning for 6, written against max 1773 s / spec 1147 s.scripts/test-shard-timings.json(2026-10-13): 73 packages sum 11,619 s; cli 2206 s (3 slices), spec 1331 s (to be 2 slices), objectql 700, runtime 632, metadata-protocol 588, rest 531.- Local LPT replay over the 76 packages with a
testscript: 6 bins ≈ 1936–1938 s (max/mean 1.00); 8 bins ≈ 1452 s; 10 bins hit the spec floor at 1331 s — hence this card waits for the spec slicing. ci.yml:557Test Coretimeout-minutes: 50;:563the matrixshard: [1, 2, 3, 4, 5, 6];:577-585and:602-610shard-scoped Turbo cache keys; theTest Coreaggregator (ci.yml:1428-1480) verifies a roster of six.- Measured full-battery shard tests step 24–27 min today (PR 39891259937 shard 3/6 26.6 min; schedule runs median 28.1 min wall, n=24). Per-shard fixed overhead (checkout, node, pnpm, restore, install) measured 1.3–1.5 min, so two more shards cost ≈ 3 runner-min per run.
Governing text
ci.yml:468-473/partition-test-shards.mjs:61-62: the recorded reasoning this card supersedes; the PR must rewrite those comments with the new numbers, not delete them.platform-readings.md(pm-dispatch references): "单容器重验证并发甜点 ≈3,排批按它定上限" concerns the PM's local re-verification, not CI shard width — no conflict.
Change
SHARD_COUNT6 → 8 and the partition self-test pins (the 1.3× balance ratio pin must be re-derived from the new weights, not loosened).ci.yml: matrix 1..8; the aggregator roster andcheck-aggregator-rosterexpectations; the shard-scoped cache key namespace is already per-shard. Re-estimatetimeout-minutesfrom the new slowest predicted shard × the drift ceiling (ci: Test Core compares each shard's measured duration with its predicted weight — warning at 1.3x, red at 70% of the timeout (maintainer-directed, drift alarm) #16465 lineage), do not leave 50.shard-timings-refresh.ymlandmeasure-test-shard-timings.mjs: wherever the shard count is read by name or pinned, follow the in-tree pattern for "the count changed" (the refresh header documents a NOT MEASURED transition window).
Acceptance
- Full-battery run after landing: slowest
Test Coreshard tests step ≤ 25 min → target ≈ 17 min with the spec slicing in; no shard over 70% of its timeout (ci: Test Core compares each shard's measured duration with its predicted weight — warning at 1.3x, red at 70% of the timeout (maintainer-directed, drift alarm) #16465 red line). - Aggregator roster,
check:ci-filter-parity, partition self-test green; the first Monday refresh completes with eight shard rows.
Risks and pins
- Same files as the spec-slicing card (partition pins, timings, ci.yml matrix): land strictly after it — hence
Blocked-by:above, not a parallel dispatch. - Two more runners per run ≈ +3 runner-min/run (≈ +16 runner-h/day at today's volume) — accepted by the maintainer directive below.
Work estimate
Lane domain:devx · 1 PR (scripts/partition-test-shards.mjs, .github/workflows/ci.yml, possibly shard-timings-refresh.yml) · precedent: the last widening is the one ci.yml:468-473 argues against; its PR and +/− lines are not reachable from this depth-50 clone. Clause-②: no · Metadata-protocol: none · Tier H (.github/workflows/ci.yml is a governed surface — the PR waits for a GOVERNED_APPROVERS approval before ready).
Prior rulings read: shard, partition, shard_count → docs/adr 3 hits, AGENTS.md 0, packages/spec/src 21 (none named for this mechanism); ADR none; thread: none.
Related: #22075 (closed), #16465 (closed), #16473 (closed), #22917 (closed — drift red on shard 3/6).
Maintainer directive (verbatim, untranslated)
同意,立卡
— the maintainer, 2026-10-23, in reply to the director seat's offer 「(a) 我按 PM 流程把 A1–A5、B1–B3 立成卡进队列(英文卡面、带 Governing text: 与工作量列),由 os-dev 派发」. The CI performance analysis those letters index is the seat's 2026-10-23 five-line audit (objectstack ci.yml + lint.yml; the other 39 workflows; the repo-side turbo/vitest/gate configuration; objectui's 28 workflows; GitHub Actions run data for the preceding 5–55 hours). The maintainer's stated goal, verbatim: 「我希望优化的是性能和效率速度」.
Activity
objectstack-fleet commentedon Oct 23, 2026
Path: instrument — CI time-to-green for every lane (area:devpath, the road's dev/verify step) | none — no platform-checklist item asserts CI speed | priority:p2 (North Star rule 3: an instrument card inherits along the chain; the queue position is set by the maintainer directive below) | none
Triage: lands in domain:devx (objectstack) — .github/workflows/ci.yml matrix and scripts/partition-test-shards.mjs; labels
tooling·area:devpath·priority:p2·pm:queue; type Task (the create door carries no type flag — triage sets it on first touch); rationale: the recorded "6 is enough" arithmetic predates the cli slices; 8 bins ≈ 1452 s vs 1937 s on full-battery weights once spec is sliced; same files as the spec-slicing card, so it carries Blocked-by: #25372 and lands after that card.Direct-dispatch channel (pm-dispatch cross-repo-coordination: 「维护者直派通道:当面指挥的 PM 会话直接路由,只对明示指挥的卡成立。直派的审计评论逐字引用授权指令。」). The authorising words, verbatim and untranslated — the maintainer, 2026-10-23, replying to the director seat's offer:
The word covers filing and dispatch; the lane seat dispatches this card under it even while a p1 sits in the lane queue (优先序:维护者裁决 > 北极星). Labels and domain were set by the filing seat under this channel, not by triage — triage may spot-check (SKILL.md 域车道 例外二).
Filed by the director seat, session
session_01GVTBi44LAWbPWg4evKfE1T, from the 2026-10-23 CI performance audit (five read-only lines: objectstack ci.yml + lint.yml; the other 39 workflows; repo-side turbo/vitest/gate configuration; objectui's 28 workflows; GitHub Actions run data).Written 2026-10-23T04:43Z by the director seat.
objectstack-fleet commentedon Oct 23, 2026
Blocked-by re-read · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-23T05:56Z#25372's premise was disproved (
6358271889), and the card is re-scoped (6358468116).test:repofile of 842 s, not thetesttask. ci(test-shards): split spec'sbuild-schemas-check-mode.test.ts(842 s, 92 tests, one file) into several files, so spec'stest:repofloor stops setting the slowest Test Core shard — re-scoped from file-sharding spec'stesttask #25372 now splits that file instead of slicing the task.Blocked-by: #25372and its grade. This card's arithmetic counted spec as two slices, and "10 bins hit the spec floor at 1331 s" no longer describes the floor. After ci(test-shards): split spec'sbuild-schemas-check-mode.test.ts(842 s, 92 tests, one file) into several files, so spec'stest:repofloor stops setting the slowest Test Core shard — re-scoped from file-sharding spec'stesttask #25372 lands, the dev re-reads the floor from a fresh merge-group timing table, and re-reads the cli figure after ci(test-shards): the cli slices ran 1132 s against 735 s predicted (×1.54) on Test Core 3/6 — refreshscripts/test-shard-timings.json(dated 2026-10-13) and re-derive the cli slice count under pin 3c #25390, before sizing the shard count.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Unlocked · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-23T19:55ZBlocked-by: #25372: closedcompleted. Spec's 842 sbuild-schemas-check-mode.test.tsfloor was split across files.pm:blocked→pm:queue. Grade unchanged: p2,domain:devx.Test Coretiming table on currentmain, not from the 2026-10-13 dataset. The cli slices' drift is ci(test-shards): the cli slices ran 1132 s against 735 s predicted (×1.54) on Test Core 3/6 — refreshscripts/test-shard-timings.json(dated 2026-10-13) and re-derive the cli slice count under pin 3c #25390. Size the shard count on what that table shows. The "10 bins hit the spec floor at 1331 s" line no longer describes it.Generated by Claude Code
objectstack-fleet commentedon Oct 25, 2026
Claim: PM loop · 2026-10-25T03:50Z
Session:
session_01M781cxsyRAqT49LvLkJKXb(card thread, dispatched by seat sessionsession_01LKHDniRQSWjRJyDtacwpEd)Account:
os-elon-muskBranch:
claude/project-thread-nsypdd(the harness-pinned branch for the card thread; it names no issue, so this claim is the identity record)Worktree:
objectstack-issue-25376Domain:
domain:devxSeat:
domain:devx#1(seat post #6023)File surface:
scripts/partition-test-shards.mjs(+ self-test pins),.github/workflows/ci.yml(Test Core matrix, timeout, aggregator roster), shard-timings tooling only where the count is pinned (stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier,effort: highClause-②: no
Metadata-protocol: none
Responsibility: p2: size Test Core from a fresh merge-group timing table and widen 6 → 8 if it pays; Tier H
Thread-read: none
Serial constraints cleared: ui-merge #25697 / PR #25738 touch ci.yml — merge origin/main before each push, keep their jobs
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-25376.md.objectstack-fleet commentedon Oct 25, 2026
os-dev-report
{ "issue": 25376, "status": "done", "branch": "claude/project-thread-nsypdd", "pr": "https://github.com/objectstack-ai/objectstack/pull/25746", "session": "session_01M781cxsyRAqT49LvLkJKXb", "premise_still_valid": true, "summary": "Sized on merge_group run 40155484566 on current main (59 packages executed, the CLI as 3 slices). Replayed through planRun() with a wall model (wholeSum/2.9 + serial slice) that lands within 6.1% of the four slowest measured steps, the slowest shard drops ~1696s -> ~1436s (-15%); full dataset list -14%; a 21-package merge_group run (40157571602) -10%. So 6 -> 8 was implemented: SHARD_COUNT in the partitioner and the timings selector, the ci.yml Test Core matrix/name/--shard/--total/artifact names/aggregator --leg, the refresh workflow now reads the shard roster from the selector instead of spelling 1..6, and self-test fixtures that read the live ci.yml follow. Timeout 50 -> 60: measure-stall-guard-headroom over 89 runs / 512 Test Core jobs (2026-10-24 03:00Z..2026-10-25 03:45Z) shows 50 already short at six (worst p+s 40m27s, cap-deferred path needs 60.45m); scaled to eight (s x 0.90) the cap-deferred verdict lands at 56m37s, largest of five readings. The 'six is enough' comments are rewritten, not deleted.", "tests": "node scripts/partition-test-shards.mjs --self-test -> OK (8 shards, max/mean 1.00x, bins 1865.66-1867.52s within the 2899.02s density cap, CLI x3); select-shard-timings-run --self-test OK (executes the refresh generate step with the new roster loop); check-shard-attestation --self-test 291+ assertions OK; check-expected-skips --self-test 169 cases OK; check-required-contexts OK.", "gates": "dispatch-gates --commands derived 70 families on head ebc7c8f; --ran reconciled: 66 exit 0, 4 NOT MEASURED (exit 3 PREREQUISITE NOT MET, need built dist/: check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content) -> CI. check-commit-card-trailers --range origin/main..HEAD OK. PR check-runs: pending at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "10 — mcp__github__get_job_logs x9 (read), mcp__claude-code-remote__subscribe_pr_activity x1; no GitHub write tool", "api_writes": "2 — fleet-write relay pr_create (PR #25746, read-back identical 13167 bytes); this os-dev-report comment", "open_questions": [], "out_of_scope_findings": [ "carrier: devx seat · noted, not filed — Test Core's timeout-minutes 50 was already short of the stall guard's cap-deferred path at six shards (worst healthy p+s 37m22s, run 40125226571 Test Core (4/6); any p+s past 30m reached the 50m wall before the deferred verdict). Fixed in this PR as part of the card's timeout re-derivation; recorded so the seat knows the raise is not caused by the widening." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 25, 2026
After landing (#25746, merged 2026-10-25 05:08Z as
2e3e276): first full-battery 8-shard readingRun: hourly
schedulerun 40167634168 at head5874d25, which includes2e3e276. Per theTest Coreaggregator's timing table, this was a full battery: 74 packages measured, 0 cache-replayed, 5668 of 5690 test files parsed, CLI all 3 slices.Run this shard's testsstep1/8 failed, and the failure is not caused by the resize.
@objectstack/spec'sscripts/liveness/check-liveness.test.tsfailed 23 of 71 tests on one evidence citation:translation/flows.screens → packages/services/service-automation/src/engine.ts("a file that never names the property"). The test is a content check that does not depend on timing. #25746 changes no file underpackages/specorservice-automation. The earlier schedule runs read green on 1/6 because spec was replayed from the cache: 05:01Z run 40163992229 has a 537 s step on its spec shard, against spec's ~1600 s weight. This is the first run in a while that actually executed spec, so the rot looks pre-existing. I'm flagging it to the devx seat for triage rather than fixing it under this card.The step timings are complete for every shard, so the failure doesn't affect the sizing reading. The 1/8 attestation is
MISSINGonly because the shard concludedfailure.