You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ci(ui-merge): twenty ui jobs each rebuild the same seven @objectstack packages (1.6–2.5 min apiece, mostly turbo cache misses on PRs) — build them once per run and hand the dists to the ui lanes (parent #25677) #25869
Filing gate ③ (maintainer-directed) + ④: aftercare of the ui/ merge (#25752), part of #25677. Touches .github/workflows/ci.yml = Tier H: GOVERNED_APPROVERS review, the PR stops at draft.
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 3).
谁付代价(业务筛): the fleet's runner budget, and the wall clock of ui PRs. Every run that schedules the ui lanes repeats one build 20 times (Test UI ×16, Type Check UI, Lint UI, Build & E2E UI): turbo run build --filter=@objectstack/spec... --filter=@objectstack/client... … for the seven packages objectui consumes. When cardholders are running in parallel, this is ~40 runner-min per run, plus 1.6–2.5 min on the critical path of a ui-only PR.
Measured (run 40248884869, 2026-10-26)
The step "Build the @objectstack packages objectui consumes" took 1.6–2.5 min in each of the 20 ui jobs.
Turbo cache: Build & E2E UI had 13 hits and 20+ misses. Type Check UI's turbo run had 45 cached out of 104 tasks. The same task hashes (e.g. 98223300f02b7bf4, 7454d81e14530f86) are a miss in one job and a hit in another: each job restores its own actions/cache key (turbo-<job>-<ref>-), falling back to turbo-build-core-.
Caveat: main's per-job caches were cold right after the cutover. Re-read the hit rate on a run from the same day before choosing.
Wanted
The seat measures two options and picks the cheaper one per run:
(a) one ui-deps job builds the seven packages once and uploads their dist/ as an artifact, and the ui lanes download it;
(b) pull_request runs read the signed turbo remote cache, still with no write.
⛔ Do not change what the ui lanes test, or their if:.
Acceptance
On the card: total ui-lane runner-min and Test UI shard wall time, before and after, on comparable PRs.
The gate rosters follow; each --self-test exits 0.
Expected saving: ~40 runner-min per ui-scheduling run, 1–2 min per ui lane. Size: S–M. Clause-②: no. Metadata-protocol: none.
Dedupe
search_issues 2026-10-26 01:50Z 「ui jobs build objectstack packages once artifact turbo remote cache pull_request」: 20 hits. The relevant ones are closed: #21186 (wire the remote cache) and #22077 (extend it to Lint / Test Core). Neither covers the ui lanes added at cutover. New.
Epic PM: two rows added from the 2d-1 census 2026-10-26T02:24Z · session_01RSDL3SFtJaKzcymvCD8RsU
Not a claim; this card stays held until #25867 and #25868 land. Two follow-up rows from #25879 (4b 2d-1, the ui/scripts/__tests__ readers of the nested ui/.github/workflows/ci.yml) belong to this card because they are the same surface — the root * UI jobs' Turbo cache steps — and the seat that measures options (a) and (b) touches exactly those steps:
Acceptance addition: the seat's before/after table also shows the save step's duration and that a save that exceeds its bound cannot red the job. Part of #25677.
Claim: epic #25677 round 8 (post-cutover CI speed card 3; Tesla 2026-10-26 01:45Z 「创建issue」; held until #25881 and #25882 landed, both merged 03:27Z) 2026-10-26T05:20Z
Session: session_01RSDL3SFtJaKzcymvCD8RsU
Account: os-tesla
Branch: claude/project-thread-kz44z5 (the card thread's designated branch in objectstack-ai/objectstack — the thread can push only this branch, a measured platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-25869
Domain: domain:devx
Seat: epic:#25677
Scope: the whole card — build the seven @objectstack/* packages the ui lanes consume once per run and hand their dists to the ui jobs instead of each job rebuilding them; plus row F1 of comment 6406837199 (bound the root ui jobs' cache saves the objectui way, F11's combined pnpm-store cache included), row F2 of the same comment, and F13 from #25940's body (derive and pin the root lint-ui 30 / build-e2e-ui 45 timeout-minutes); push/schedule keep the full battery (Q6-b); the gate rosters follow with --self-test 0; Tier H (draft, os-zhuang + hotlong), skip-changeset
Why now: twenty ui jobs each rebuild the same seven packages (1.6–2.5 min apiece, mostly turbo cache misses on PRs); #25881 and #25882 cut the queue and PR shard counts, so this rebuild is now the largest fixed cost left per ui run
Container & model: M, mode:thread (thread session session_01XpG2CKzNjLujzcMmSxKCHy; order: this card's body, FRAME.md applies), model: opus, effort: xhigh
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — epic step
Thread-read: none
Serial constraints cleared: #25902 (#25880, open, Tier H) adds gate steps inside lint-ui of the same ci.yml — ⛔ do not touch those steps; rebase over it when it lands. 4b 2d-3c (#25712, not yet opened) deletes ui/.github/workflows/** and adds one lint-ui step; whichever lands second rebases. ⛔ Do not change the four ui jobs' if: lines, the filter outputs or the Test UI shard selection; a failed dist hand-off must fall back to building in the job, never to skipping it. Report the push-environment battery (GITHUB_ACTIONS=true GITHUB_EVENT_NAME=push node scripts/pm/check-dispatch-gates.mjs, 2182/0) before the PM flips ready
#25869 after-readings: the seven packages built once per run (#25963) · 2026-10-26T08:33Z · session_01XpG2CKzNjLujzcMmSxKCHy
#25963 landed through the queue on os-zhuang's approval. The readings below come from the Actions jobs endpoint (completed_at minus started_at, per job and per step). Before = the 51 CI runs that scheduled ui jobs between the ui/ cutover (#25825) and the landing window opening. After = the 19 completed CI runs since #25963 landed that ran Build UI Deps. That includes push runs 40283575048, 40284424233, 40289373917 and 40289957670 (the #25902 merge), plus queue entries 40286327711, 40287733434 and 40290196603. Two cancelled PR runs are left out.
The seven-package build (the card's question)
before
after
warm run: the build step per ui job
0–2 s from each job's own seed (24 runs)
Build UI Deps builds in 1–4 s; every ui job replays in 0–2 s (13 runs)
cold run: who builds
every ui job, 86–288 s each (median 201 s; 27 runs)
Build UI Deps once, 131–252 s; every ui job replays in 0–2 s (6 runs: 2 queue entries with 19 ui jobs, 4 PRs with 2)
runner-min on that step, cold full-lane run
33–77 per run (e.g. queue entry 40271867662: 70.2)
The ui jobs now start when Build UI Deps finishes:
Warm runs: the ui jobs start 42–73 s after Build UI Deps starts, because that job's own total is 39–71 s (13 runs). This is pure wall-clock cost, about +1 min per ui lane.
Cold runs: the ui jobs start 224–290 s after Build UI Deps starts (6 runs). Before, each job spent 86–288 s (median 201 s) building inside its own wall. The net change is roughly one job setup, about +0.5–1 min.
The card's expected "1–2 min per ui lane" wall saving does not hold. The change saves runner-minutes and adds about a minute of wall clock per lane.
Per-job wall clock, whole job (n, median, max)
These populations are different PR mixes, so job medians compare loosely. The step readings above are the like-for-like comparison.
job
before
after
Build UI Deps
(did not exist)
n=19, median 65 s, max 288 s
Type Check UI
n=49, median 224 s, max 1194 s
n=18, median 607 s, max 889 s
Lint UI
n=42, median 112 s, max 558 s
n=14, median 337 s, max 685 s
Build & E2E UI
n=51, median 170 s, max 457 s
n=19, median 137 s, max 166 s
Test UI shard
n=591, median 650 s, max 1060 s
n=223, median 485 s, max 784 s
Lint UI with #25902's gates in the job (runs since its merge): n=4, at 259 s, 429 s, 433 s and 685 s (push 40289957670). The 685 s run exceeds the population the 30-minute ceiling was derived from (max 558 s). By objectui's rule (≥ 3× max and ≥ max + 15 min), 685 s gives 35. The 30 still leaves 2.6× headroom over the slowest run seen, but n=4 is too few to re-derive from. That re-derivation belongs to the #25880 seat (ui/scripts/__tests__/turbo-cache-save-bound.test.ts pins Lint UI at 30).
Saves (rows F1/F11)
Every ui cache save is now a bounded, non-fatal actions/cache/save (5 min). The turbo seed saves after the landing took 0–2 s (n=12). Build UI Deps did not save the pnpm store in this window, because every run hit its exact key. No save step ran into its bound.
Premise vs measured, point 2
Option (b), a pull_request run reading the remote cache, was not taken. Turbo reads with the same TURBO_TOKEN that writes, and Build Core's credential ruling (#21186) withholds it and the signing key from PR code. The PM ruled that the ruling stands. Queue and main runs of Build UI Deps carry the remote-cache lines.
Local evidence at the PR head (cd0ae004)
Push battery, both tiers: "✓ dispatch-gates self-test: 2182 cases pass." (fast 1917 in 341.8 s, slow 265 in 872.1 s).
Derived gates: 63 of 63 exit 0. check:dual-build-cjs-loads was first a PREREQUISITE NOT MET and passed after a full pnpm build. --ran reports 0 unrun.
The PR's only CI red was Test UI 14/16, on main's known pre-install-import-graph row.
Relay writes for this card: 2 (pr_create, this comment). MCP calls: 0.
Activity
objectstack-fleet commentedon Oct 26, 2026
Epic PM: two rows added from the 2d-1 census 2026-10-26T02:24Z ·
session_01RSDL3SFtJaKzcymvCD8RsUNot a claim; this card stays held until #25867 and #25868 land. Two follow-up rows from #25879 (4b 2d-1, the
ui/scripts/__tests__readers of the nestedui/.github/workflows/ci.yml) belong to this card because they are the same surface — the root* UIjobs' Turbo cache steps — and the seat that measures options (a) and (b) touches exactly those steps:type-check-uijob's Turbo cache save has none of the objectui#6577 / fix(ci): diff-scope the no-major changeset guard against the merge base (#7005) #7048 bounds: no split restore/save, notimeout-minuteson the save, nocontinue-on-error, nocache-hitguard, and a 40-minute job ceiling that leaves the verdict no room.ui/scripts/__tests__/turbo-cache-save-bound.test.ts(deleted by test(ui-merge): the ui gate-wiring pins read the root ci.yml that runs them; pins on jobs it did not port retire #25879 as a nested-workflow reader) pointed at the root job fails 5 of its 6 pins; only "save after the last command" holds. Wanted here: bound the four root ui jobs' saves the objectui way, then restore those six pins againsttype-check-uiby path (the helperui/scripts/__tests__/helpers/root-ci.tsfrom test(ui-merge): the ui gate-wiring pins read the root ci.yml that runs them; pins on jobs it did not port retire #25879)..github/workflows/ci.yml= Tier H, as this card already is.ui/scripts/report-turbo-cache.mjs(prune before save, restored-key notice) or the script retires;report-turbo-cache.test.tslost 7 nested-workflow cases in test(ui-merge): the ui gate-wiring pins read the root ci.yml that runs them; pins on jobs it did not port retire #25879 with a pointer here.Acceptance addition: the seat's before/after table also shows the save step's duration and that a save that exceeds its bound cannot red the job. Part of #25677.
objectstack-fleet commentedon Oct 26, 2026
Claim: epic #25677 round 8 (post-cutover CI speed card 3; Tesla 2026-10-26 01:45Z 「创建issue」; held until #25881 and #25882 landed, both merged 03:27Z) 2026-10-26T05:20Z
Session:
session_01RSDL3SFtJaKzcymvCD8RsUAccount:
os-teslaBranch:
claude/project-thread-kz44z5(the card thread's designated branch in objectstack-ai/objectstack — the thread can push only this branch, a measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-25869Domain:
domain:devxSeat:
epic:#25677Scope: the whole card — build the seven
@objectstack/*packages the ui lanes consume once per run and hand their dists to the ui jobs instead of each job rebuilding them; plus row F1 of comment 6406837199 (bound the root ui jobs' cache saves the objectui way, F11's combined pnpm-store cache included), row F2 of the same comment, and F13 from #25940's body (derive and pin the rootlint-ui30 /build-e2e-ui45timeout-minutes); push/schedule keep the full battery (Q6-b); the gate rosters follow with--self-test0; Tier H (draft, os-zhuang + hotlong),skip-changesetWhy now: twenty ui jobs each rebuild the same seven packages (1.6–2.5 min apiece, mostly turbo cache misses on PRs); #25881 and #25882 cut the queue and PR shard counts, so this rebuild is now the largest fixed cost left per ui run
Container & model: M,
mode:thread(thread sessionsession_01XpG2CKzNjLujzcMmSxKCHy; order: this card's body, FRAME.md applies),model: opus,effort: xhighClause-②: no
Metadata-protocol: none
Responsibility: n/a — epic step
Thread-read: none
Serial constraints cleared: #25902 (#25880, open, Tier H) adds gate steps inside
lint-uiof the sameci.yml— ⛔ do not touch those steps; rebase over it when it lands. 4b 2d-3c (#25712, not yet opened) deletesui/.github/workflows/**and adds onelint-uistep; whichever lands second rebases. ⛔ Do not change the four ui jobs'if:lines, thefilteroutputs or the Test UI shard selection; a failed dist hand-off must fall back to building in the job, never to skipping it. Report the push-environment battery (GITHUB_ACTIONS=true GITHUB_EVENT_NAME=push node scripts/pm/check-dispatch-gates.mjs, 2182/0) before the PM flips readyobjectstack-fleet commentedon Oct 26, 2026
#25869 after-readings: the seven packages built once per run (#25963) · 2026-10-26T08:33Z ·
session_01XpG2CKzNjLujzcMmSxKCHy#25963 landed through the queue on os-zhuang's approval. The readings below come from the Actions jobs endpoint (
completed_atminusstarted_at, per job and per step). Before = the 51 CI runs that scheduled ui jobs between the ui/ cutover (#25825) and the landing window opening. After = the 19 completed CI runs since #25963 landed that ran Build UI Deps. That includes push runs 40283575048, 40284424233, 40289373917 and 40289957670 (the #25902 merge), plus queue entries 40286327711, 40287733434 and 40290196603. Two cancelled PR runs are left out.The seven-package build (the card's question)
Wall clock (Premise vs measured, point 1)
The ui jobs now start when Build UI Deps finishes:
The card's expected "1–2 min per ui lane" wall saving does not hold. The change saves runner-minutes and adds about a minute of wall clock per lane.
Per-job wall clock, whole job (n, median, max)
These populations are different PR mixes, so job medians compare loosely. The step readings above are the like-for-like comparison.
Lint UI with #25902's gates in the job (runs since its merge): n=4, at 259 s, 429 s, 433 s and 685 s (push 40289957670). The 685 s run exceeds the population the 30-minute ceiling was derived from (max 558 s). By objectui's rule (≥ 3× max and ≥ max + 15 min), 685 s gives 35. The 30 still leaves 2.6× headroom over the slowest run seen, but n=4 is too few to re-derive from. That re-derivation belongs to the #25880 seat (
ui/scripts/__tests__/turbo-cache-save-bound.test.tspins Lint UI at 30).Saves (rows F1/F11)
Every ui cache save is now a bounded, non-fatal
actions/cache/save(5 min). The turbo seed saves after the landing took 0–2 s (n=12). Build UI Deps did not save the pnpm store in this window, because every run hit its exact key. No save step ran into its bound.Premise vs measured, point 2
Option (b), a
pull_requestrun reading the remote cache, was not taken. Turbo reads with the same TURBO_TOKEN that writes, and Build Core's credential ruling (#21186) withholds it and the signing key from PR code. The PM ruled that the ruling stands. Queue andmainruns of Build UI Deps carry the remote-cache lines.Local evidence at the PR head (
cd0ae004)check:dual-build-cjs-loadswas first a PREREQUISITE NOT MET and passed after a fullpnpm build.--ranreports 0 unrun.main's known pre-install-import-graph row.Relay writes for this card: 2 (
pr_create, this comment). MCP calls: 0.