Skip to content

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

Closed

Description

@objectstack-fleet

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-62 and ci.yml:468-473 carry 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 test script: 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:557 Test Core timeout-minutes: 50; :563 the matrix shard: [1, 2, 3, 4, 5, 6]; :577-585 and :602-610 shard-scoped Turbo cache keys; the Test Core aggregator (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

  1. SHARD_COUNT 6 → 8 and the partition self-test pins (the 1.3× balance ratio pin must be re-derived from the new weights, not loosened).
  2. ci.yml: matrix 1..8; the aggregator roster and check-aggregator-roster expectations; the shard-scoped cache key namespace is already per-shard. Re-estimate timeout-minutes from 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.
  3. shard-timings-refresh.yml and measure-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

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

  1. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    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:

    seat: (a) 我按 PM 流程把 A1–A5、B1–B3 立成卡进队列(英文卡面、带 Governing text: 与工作量列),由 os-dev 派发;(b) 先只要这份报告,总监席决裁批照原计划开。
    maintainer: 同意,立卡

    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.

  2. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    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).


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlocked · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-23T19:55Z


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop · 2026-10-25T03:50Z
    Session: session_01M781cxsyRAqT49LvLkJKXb (card thread, dispatched by seat session session_01LKHDniRQSWjRJyDtacwpEd)
    Account: os-elon-musk
    Branch: 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-25376
    Domain: domain:devx
    Seat: 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: high
    Clause-②: 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.

  5. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  6. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    After landing (#25746, merged 2026-10-25 05:08Z as 2e3e276): first full-battery 8-shard reading

    Run: hourly schedule run 40167634168 at head 5874d25, which includes 2e3e276. Per the Test Core aggregator's timing table, this was a full battery: 74 packages measured, 0 cache-replayed, 5668 of 5690 test files parsed, CLI all 3 slices.

    shard Run this shard's tests step job wall
    1/8 728 s 821 s (failed, see below)
    2/8 650 s 744 s
    3/8 1207 s 1294 s
    4/8 890 s 973 s
    5/8 1419 s (23m39s) 1540 s (25m40s)
    6/8 745 s 849 s
    7/8 702 s 781 s
    8/8 500 s 592 s

    1/8 failed, and the failure is not caused by the resize. @objectstack/spec's scripts/liveness/check-liveness.test.ts failed 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 under packages/spec or service-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 MISSING only because the shard concluded failure.

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxpriority:p2Medium: important, M3tooling

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions