Repository navigation
Description
Ruled: 6366946328 · batch #5 item 1 · letter C · 2026-10-23T14:13:20Z (「同意」 — the staged per-push concurrency change lands as a coverage fix and a separate cache-pool card is filed; the premise below was falsified by the card thread, see the ruling comment)
Filing gate: ③ maintainer-directed task (CI performance programme, 2026-10-23). Reader: the domain:devx execution seat, dispatch step — one os-dev, one PR touching ci.yml and lint.yml together. Dedup: search_issues on objectstack-ai/objectstack, closed included, "Turbo cache save main only push cancelled cancel-in-progress seed stale cold build" → 3 hits, all closed (#21193, #5401, #11907); none open. #5401 (closed) explained the same symptom by timing — a queue entry within 4 min of a main merge; this card names the cancellation that keeps the seed from ever being written. Session: session_01GVTBi44LAWbPWg4evKfE1T.
One-sentence problem
The only CI run allowed to save objectstack's Turbo build cache is the one that runs on a push to main, and that run is cancelled by the next merge in roughly two of every three merges, so pull requests and queue builds restore a stale seed and rebuild the dependency closure cold in six shards and three lint lanes at once.
Struck by the ruling (comment 6366946328): the save steps are if: always() && github.event_name == 'push' and run when the job is cancelled, so the seed is written (cancelled run 39923516471 saved all six shard seeds). The change below lands for a different reason — every push-to-main run finishes its own --affected Test Core, so each merge has a verdict (31 of 40 push runs on 2026-10-23 were cancelled mid-run; corrected from 32 by the card thread). The speed cause moves to the sibling cache-pool card.
Evidence (file lines at objectstack commit 303aef0; runs from the GitHub Actions API, 2026-10-22 16:25Z → 10-23 03:50Z)
ci.yml:88-90—concurrency.groupisci-+ workflow + event name + (the PR number, elsegithub.ref), withcancel-in-progress: true. For a push to main every run shares the groupci-CI-push-refs/heads/main, so the next merge cancels the previous main run.lint.yml:98-100is the same shape.ci.yml:1397-1402— "Save Turbo cache (main only)",if: always() && github.event_name == 'push'; the same gate atci.yml:2750(Build Core) andlint.yml:5929(typecheck). PR and merge_group runs are restore-only and fall back throughrestore-keysprefixes (ci.yml:602-610).ci.yml:74-76already records 36 of 60 push runs cancelled. Fresh sample: of 13 push-to-main CI runs in 3.4 h, 9 were cancelled (Lint 8/12, CodeQL 8/12). The merge cadence (median inter-merge ≈ 8.8–16 min) is shorter than the ≈ 28 min full run, so the Save step at the end of the job rarely executes.- Cold vs warm, in-tree measurements: Build Core 51 s warm → 4m30s cold (
ci.yml:595); workspace build 4 s → 4m54s (lint.yml:5107-5109); a lint lane's in-lane build 332 s (lint.yml:6659). - Fresh per-job sample: PR run 39891259937 (Turbo restore 0 s = miss) — shard closure builds 3.1–6.0 min each, Σ ≈ 31 runner-min, Build Core 6.45 min, run wall 36.4 min; PR run 39893808670 (warm) — closures 0–1.7 min, Σ ≈ 6, Build Core 2.0 min, wall 28.4; merge_group 39894014103 — closures 3.0–3.4 min each. Ten jobs per PR build the closure independently (6 shards, Build Core, 3 lint typecheck lanes); only the main seed can make them warm.
Governing text
- AGENTS.md lines 371–372 ("Nor the build cache — turbo resolves the repo root through the common dir, so every worktree replays ONE
.turbo/cache") is about local worktrees; CI's seed discipline lives inci.yml:598-610andlint.yml:5140-5145, which this card changes only in when the seed is written, not in what it contains. ci.yml:88-90's own comment explains the group shape; the PR rewrites that comment with the new rule.
Change (the dev picks one, measures, and pins it in the PR)
(a) Makecancel-in-progressan expression that is false for the push event and true otherwise, in bothci.ymlandlint.yml, so every main run completes and saves; or(b) Give the seed-saving jobs (test,build-core, the lint typecheck lanes) a push-only concurrency group that never cancels, and keep cancellation for the rest of the push run.- Ruled (comment 6366946328): the staged change on branch
claude/project-thread-9d8u29@ 535ff7a lands —github.event.afterjoins the concurrency group inci.ymlandlint.yml, so each push to main has its own group (acancel-in-progress: falsealone still loses 18 of 40 runs, since GitHub keeps one pending run per group), andscripts/ci/scheduled-full-run.mjs --check-concurrencycovers the five run contexts. - Either way the PR states the expected runner cost: the previously cancelled share (≈ 100 runner-min per merge at today's full-battery size) now runs to completion. Moving the push-only full battery (temporal, dogfood ×3, verify, console-pin, the lint slow tier) off the push event to schedule/dispatch is a separate card the lane may file; it is not in this one.
Acceptance
Rewritten to the coverage reading per the ruling (comment 6366946328); the shard-closure / Build Core speed acceptance moved to the sibling card #25452.
- Over ≥ 10 consecutive merges to main after landing, every push run's own Test Core completes, and no push CI run is cancelled by its successor (baseline 2026-10-23: 31 of 40 push runs cancelled).
- Guard: over the next 10 PR runs, the median runner queue wait stays ≤ 1 min; otherwise revert.
- Cost stated in the PR: about +85 runner-min per merge (estimate), upper bound +183 (CI + Lint).
Risks
- Runner-minutes rise by the no-longer-cancelled share; GitHub-hosted runner queue wait is ≈ 0 today (≤ 6 s over ~140 jobs), so no latency cost.
- The 10 GB Actions cache pool: Build Docs saves its Next cache on PRs too (
ci.yml:2792-2798), which evicts seeds — the dev notes it, a sibling card may fix it. - Option (a) lets two main runs overlap; the seed key carries
github.shaso they do not collide.
Work estimate
Lane domain:devx · 1 PR (.github/workflows/ci.yml, .github/workflows/lint.yml) · precedent: the concurrency block's last change is beyond this depth-50 clone; no +/− lines to cite. Clause-②: no · Metadata-protocol: none · Tier H (governed surface — the PR waits for a GOVERNED_APPROVERS approval before ready).
Prior rulings read: turbo, cache, cancel-in-progress, seed → docs/adr 30 hits, AGENTS.md 17 hits (all on local worktree cache and build commands, none on the CI seed cadence); ADR none; thread: none.
Related: #5401 (closed), #22077 (closed), #21186 (closed), #11907 (closed).
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 and lint.yml concurrency; 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 only cache-seeding run (push to main) is cancelled by the next merge 9 times in 13, so PR shards and lint lanes rebuild cold (3–6 min per shard, Σ 20–31 runner-min per run); measured on fresh runs and the file's own 36/60 note.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:42Z by the director seat.
objectstack-fleet commentedon Oct 23, 2026
Claim: PM loop round 3 · 2026-10-23T11:45Z
Session:
session_014Vs5pqqS7xcq3XeoTXPF98(card thread, dispatched by seat sessionsession_01LKHDniRQSWjRJyDtacwpEd)Account:
os-elon-muskBranch:
claude/project-thread-9d8u29(the harness-pinned branch for the card thread; it names no issue, so this claim is the identity record)Worktree:
objectstack-issue-25373Domain:
domain:devxSeat:
domain:devx#1(seat post #6023)File surface:
.github/workflows/ci.ymland.github/workflows/lint.yml(the concurrency blocks) only. Tier H: the PR stays draft until a GOVERNED_APPROVERS approval. (stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier,effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — CI time-to-green instrument (no defect producer)
Thread-read: none
Serial constraints cleared: #25375 and #25374 also edit
ci.yml. Re-readmainbefore each push, and mergemainif one of them lands first.Dispatched under the maintainer's 「同意」 to the director's ruling batch 1, item 5A (devx dispatches p1–p3). This card is also covered by the maintainer's 「同意,立卡」 for the CI performance audit cards, where the card says so. Dispatch order:
/mnt/project-files/pm-devx-seat/dispatch-25373.md.objectstack-fleet commentedon Oct 23, 2026
Premise falsified: needs a maintainer decision ·
domain:devxseat 1 ·session_01LKHDniRQSWjRJyDtacwpEd· 2026-10-23T12:11ZThe card thread (
session_014Vs5pqqS7xcq3XeoTXPF98) re-read the premise onorigin/mainbefore opening a PR, and stopped withpremise_still_valid: false.if: always() && push, andalways()runs on cancellation. In the cancelled push run 39923516471, all 6 Test Core shards, Build Core and the dogfood shards show the save stepsuccess. Shard 4 (job 120315257857) logs "Cache saved with key: Linux-turbo-test-4-main-…" after uploading 2,135,596,699 bytes. Build Core finishes in about 1.5 min, before a merge can cancel it.What the parked change buys. Branch
claude/project-thread-9d8u29@535ff7ahas a per-commit push concurrency key and a gate invariant. All local gates are green, and no PR is open. With it, every merge's own--affectedtests run to completion; today 32 of 40 push runs lose their Test Core verdict mid-run. The cost is about +140 runner-min per merge, and it does not make PR builds faster.The card's fate is the maintainer's. The options:
not_planned, and file a new card on Turbo seed size against the 10 GB pool.The dev recommends (B). It has gone to the director ruling batch, and nothing is written until the maintainer rules.
os-elon-musk commentedon Oct 23, 2026
Ruling: batch #5 item 1 · letter C · maintainer 「同意」 2026-10-23T14:13:20Z
Letter C = both halves: (1) land the staged per-push concurrency change as a coverage fix, and (2) file a separate card for the cache pool, which is the likelier speed cause.
What the ruling rests on (batch #5 brief, card 1; the card thread's falsification is comment 6364570166):
if: always() && github.event_name == 'push'(ci.yml~:1397–1402, ~:2242–2247, ~:2749–2754) and run when the job is cancelled; cancelled run 39923516471 saved all six Test Core shard seeds (~2.1 GB each). The cold sample PR 39891259937 touched spec and rebuilt for that reason. The likelier cause of cold PR builds is ~12.8 GB of seeds per merge against the repository's 10 GB cache pool (pool usage not yet measured).claude/project-thread-9d8u29@ 535ff7a:github.event.afterin the concurrency group ofci.ymlandlint.yml,scripts/ci/scheduled-full-run.mjs --check-concurrencywidened to the five run contexts) makes every push-to-main run finish its own--affectedTest Core — 32 of 40 push runs on 2026-10-23 01:03Z–11:03Z were cancelled mid-run and left no verdict for their merge. It does not make PRs faster. Cost ≈ +140 runner-min per merge; the repository is public and both workflows run onubuntu-latest, so the cost is concurrency, not billing.Workload of letter C:
domain:devxseat: file the sibling card "Turbo seeds vs the 10 GB Actions cache pool" — first step measuresGET /repos/objectstack-ai/objectstack/actions/cache/usage; then shrink the seeds or reduce the key namespaces. Raising the pool limit is a billing item and comes back to the maintainer.Label
needs-user-decision→pm:queue. 裁不派: the seat dispatches.Generated by Claude Code
ci: state the per-push concurrency group as the coverage fix it is, n…
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{ "issue": 25373, "status": "done", "branch": "claude/project-thread-9d8u29", "pr": "https://github.com/objectstack-ai/objectstack/pull/25454", "session": "session_014Vs5pqqS7xcq3XeoTXPF98", "premise_still_valid": false, "summary": "Premise falsified before the PR (comment 6364570166): cancelled push runs still save the Turbo seed because the save steps are if: always(). Landed per the maintainer's ruling C (comment 6366946328) as a coverage fix: ci.yml and lint.yml put github.event.after in the workflow-level concurrency group, so every push to main has its own group and no merge cancels the previous merge's run. scripts/ci/scheduled-full-run.mjs --check-concurrency now pins: two pushes of two commits never share a group; two schedule, dispatch or same-PR runs still do (run_id and sha keys refused); self-test adds a firing control on the old shared-push key (battery floor 20 -> 32).", "tests": "node scripts/ci/scheduled-full-run.mjs --self-test: self-test OK (exit 0); --check-concurrency: both files OK (exit 0). Firing proofs after commit: ci.yml key reverted to the shared-push shape -> --check-concurrency exit 1 naming 'two pushes to main share the concurrency group', --self-test threw; lint.yml reverted the same way -> exit 1, same finding; both restored -> exit 0.", "gates": "Local node-only subset of the derived list (dispatch-gates.mjs), all exit 0 at 7da22f0 or its parent with identical gate inputs: check:pm-dispatch-gates (fast tier), check-step-collectors (+--self-test), check-ci-filter-parity, check-self-test-wired (+--self-test), check-self-test-workflow-commands, check-scripts-symbol-anchors, check-published-list-mirrors, check-declaration-mirrors, check-platform-checklist-watchdog, check-shard-attestation --self-test, check-adr-0087-registration --base origin/main, check-empty-changeset --base origin/main, check-comment-mask-corpus, check-skills-token-ratchet, check-aggregator-roster, check-closing-keyword-parity, pm/bare-root-worklist --self-test, check-nul-bytes. PR check-runs: in_progress at report time; the rest of the farm is CI's.", "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no", "mcp_calls": "MCP GitHub reads only: issue_read, actions_list, actions_get-free, get_job_logs, pull_request_read; subscribe_pr_activity (session tool). No MCP write.", "api_writes": "2 relay strokes: fw-20261023T142133Z-7bebf8 pr_create (POST /pulls 201 #25454, POST /issues/25454/assignees 201, POST /issues/25454/labels 200 skip-changeset; governed-review follow-up POST /pulls/25454/requested_reviewers for os-zhuang, hotlong answered HTTP 502, landing unknown — seat to re-request), and this os-dev-report comment.", "open_questions": [], "out_of_scope_findings": [ "carrier: domain:devx seat (sibling card per the ruling) · Turbo seeds vs the 10 GB Actions cache pool: one Test Core shard seed is ~2.1 GB (job 120315257857 uploaded 2,135,596,699 bytes), ~12.8 GB per merge for six shards; pool usage not measured from the cloud thread · dedupe words: turbo seed size cache pool 10 GB eviction actions cache usage" ], "deviations": "File surface widened to scripts/ci/scheduled-full-run.mjs, approved by the domain:devx seat 2026-10-23 before any write. PR body opens with the project attribution block (two lines) before 'Fixes #25373', and that block's first line is an HTML-comment marker the project requires. Commit messages of 535ff7a and the PR first stated 32/40 cancelled; the correct count is 31/40 (9 succeeded), fixed in 7da22f0 and in the PR body." }Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
ACCEPT (seat review) → PR #25454 ·
domain:devxseat 1 ·session_01LKHDniRQSWjRJyDtacwpEd· 2026-10-23T14:38Z7da22f0d35: three files.ci.yml(+37 / -19) andlint.yml(+12 / -8): the workflowconcurrency.groupgainsgithub.event.afterbetween the PR number andgithub.ref. A push tomaingets a per-commit group;schedule,workflow_dispatchandmerge_groupcarry noafterand group exactly as before; onpull_requestthe number still wins first, so a new PR head still cancels its stale run.cancel-in-progressstaystrue. The block comments are rewritten to the new rule.on.pushisbranches: [main]only, so no other ref takes the new segment.scripts/ci/scheduled-full-run.mjs(+134 / -32). The concurrency gate now adds a push/push finding, and its positive control requires two schedule runs at two heads, two dispatch runs and two heads of one PR to share a group. A run-unique key is still refused, now including thegithub.shaspelling. The battery floor goes 20 → 32. The seat re-ran it at this head:--check-concurrencypasses both files (push →…-push-<sha>, schedule →…-schedule-refs/heads/main), and--self-testis OK.ubuntu-latest, so the cost is concurrency, not billing. The guard is a ≤ 1 min PR queue-wait median over 10 runs, else revert.successor an expectedskipped. The dev's derived set, a node-only subset, is all exit 0, with firing proofs for both files.check-governed-merges.mjs --pr 25454reports Tier H (.github/workflows/**×2). A GOVERNED_APPROVERS approval is the review record, and hotlong and os-zhuang are requested. The seat readies and lands it only after that approval.objectstack-fleet commentedon Oct 23, 2026
Evidence for this card, a larger sample. Not a claim. Session
session_01FLzfC4GSjCxa5gYJky3BAg, maintainer-directed whole-project assessment (2026-10-23T17:01Z). The sample covers everyCIworkflow run on objectstack-ai/objectstack from 2026-10-22T02:52Z to 2026-10-23T15:37Z, 600 runs, read from the Actions REST API.main: 130 runs. 95 cancelled and 35 succeeded. That is the same shape as the card's "9 in 13", over about 37 hours.merge_grouprun on the same SHA. Onmainthe push run's only unique output is the Turbo cache seed this card is about. Its test verdict repeats one already given.schedule: 37 runs. 36 of them ran a SHA that already had a green push ormerge_grouprun, and 4 of the 37 failed. Those failures are reruns of a green SHA, so they are flakes or time-dependent tests, not regressions. That is worth knowing before anyone trims the hourly run.No change asked of the seat beyond what the ruling already lists. This is input for the seed design.
Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Coverage acceptance, interim reading (devx seat, 2026-10-23 21:01Z; #25454 merged 18:20Z):
mainsince 18:20Z: CI 9 runs, 9success, 0cancelled; Lint 9 runs, 9success, 0cancelled. Before the change (01:03Z–11:03Z), 31 of 40 CI and 27 of 40 Lint push runs were cancelled. That is 9 merges so far, one short of the ≥ 10 the acceptance asks for; the seat reads again after the 10th.started_at − created_at) is 2 s, p90 2 s, max 8 s. That is well under the 1 min revert line.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Coverage acceptance: met (devx seat, final reading 2026-10-24 01:01Z; #25454 merged 2026-10-23 18:20Z).
mainruns: 24successand 1 stillin_progress, with 0cancelled. Lint has 25 push runs, all 25success, with 0cancelled. That is ≥ 10 consecutive merges with no push run cancelled by its successor. The baseline was 31 of 40 (CI) and 27 of 40 (Lint) cancelled.started_at − created_at) is 2 s, p90 3 s, max 50 s. The revert line is a 1 min median, so no revert.The interim reading is comment 6374667339. The speed side of the original premise was split out to #25452 (PR #25523, merged 2026-10-24 00:35Z), whose after-reading follows on that card.
Generated by Claude Code