ci(dogfood): the sharded gate builds its closure in a passthrough-free run, so the shards stop scattering it - #17867
Conversation
…e run, so the shards stop scattering it The Dogfood Regression Gate carried the same run-level Turbo passthrough defect fixed earlier in the `test` job: `-- --shard=k/3` folded into the hash of every task in the run, so the three shards hashed one 66-package `^build` closure three ways and none could reach the shared, passthrough-free `build` cache. Applies that landed shape verbatim rather than a second working spelling: a dedicated, guard-wrapped, passthrough-free `turbo run build --filter=@objectstack/dogfood` step ahead of the run, and `--only` on the sharded `turbo run test` so the passthrough is hashed into the one task it is for. `name:` and `timeout-minutes: 30` are untouched -- the budget is the instrument that shows the fix working. Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU Co-authored-by: Claude <noreply@anthropic.com>
|
PM 复核:收下,已 undraft + 武装。 逐项对着 GitHub 复核,⛔ 不是核对你的报告。 本席自己验过的
⭐⭐ 三处比「修好了」更值钱的判断1. 为什么是自己的一个步骤,而不是在原步骤里再包一次。
⇒ 把两个 guarded run 塞进一个步骤,会让那个仪器拒绝给出判定 —— 而一个拒绝判定的仪器,在干净树上和一个通过的仪器长得一样。你为了保住它的可读性多开了一个步骤,⛔ 而不是为了省行数把它弄哑。 2. ⭐ 那句拒绝抬
⇒ 抬预算会遮掉它正要修的那个效果。⛔ 一个「为了让自己过去而把量表调宽」的改动,是把测量换成了沉默 —— 你把这条写在了行上,下一个想抬它的人会撞到。 3. 那张测量表带着工具版本与探针写进了注释(turbo 2.10.10、 缓存读数 —— 对照会开火,这才让读数成立
⭐ 而 ⭐⭐ 普查:你报的不只是「没有第三例」
⭐⭐⭐ 而最该被记下来的是你保留了自己第一次探针的错
⇒ 你没有把那个 5 当成答案,也没有把它悄悄换掉 —— 你换成从 而你声明了剩下的盲点( 一处偏离模板,你报成了「观测」而不是掰成一致#16868 的闭包腿测到 0 extra,你测到 1 extra —— 反向读
带 rev / 日期的历史(#2018 / #4250 / #4859 / #4928 / #16868 的测量块)⛔ 一个未动,具名方向的零断言不受影响 —— 包括 Generated by Claude Code |
Clause-②: no
Closes #16886
The
dogfood:job carried the same run-level Turbo passthrough defect that PR #16868 fixed in thetestjob for #16395. It was outside that card's declared surface, so it was still there. This applies #16868's landed diff as the template rather than a second working spelling — the two jobs are now spelled the same way.The site, measured on this branch (⛔ not the card's line number)
The card said
.github/workflows/ci.yml:1283; found by content, the run sits at:1520on the merge basec88fa2ccdand at:1579after this diff. The job header is:1423andname:is:1431— the card's:1186/:1209are 2026-09-08 readings and this file moves constantly.The change
pnpm turbo run build --filter=@objectstack/dogfood --concurrency=4 --log-order=streamstep ahead of the sharded run, so the closure is built once and reaches the shared, content-addressedbuildcache.--onlyon the shardedturbo run test, so the passthrough hash covers only thetesttask it is meant for.It is its own step, not a second guarded run inside the existing one, for the reason #16868 states: a guarded SITE is the triple (file, job, step), and
measure-stall-guard-headroomrefuses a verdict when two guarded runs share one.⛔
name:is untouched (required-status-check context) andtimeout-minutes: 30is untouched — the card names that budget as the instrument that shows the fix working, so it may not be raised to buy room.Cache reading — before / after,
--dry=jsontask hashesturbo 2.10.10,
--filter=@objectstack/dogfood, on this branch. The plain test plan is 67 tasks: 66build+ 1test.Before — every task in the run re-hashed per shard:
So the three shards hashed one 66-package build closure three ways, and none could reach the
buildcache every other job in this workflow populates — that cache is written with no passthrough in the hash.After — the two runs the new spelling issues:
The 66 closure builds now replay instead of re-executing per shard: their hashes are identical to the passthrough-free test plan's, which is what the shared cache holds. The one remaining per-shard hash difference is the
testtask itself, which is correct and intended — that is the task the passthrough is for.⭐ The sweep:
--filterplus a run-level passthrough, whole treeTriage asked for the count before closing, so here is the probe and the count rather than a claim.
Probe shape. A tokenizing scan (
shlex, quote-stripped, backslash continuations joined first) over all 37 files in.github/workflows/. For eachturbo runoccurrence it tokenizes from theturbotoken onward and asks three questions: does it carry--filter/-F; is there a bare--token afterturbo runwith at least one argument behind it; does it carry--only. Starting at theturbotoken is the load-bearing part — a naive--grep reportsset -- pnpm turbo run …(the shell builtin) andnode run-with-stall-guard.mjs … -- pnpm turbo …(the wrapper's own separator) as passthroughs. That first, naive grep over this same tree produced five hits, of which three were the wrong--entirely; the classification below is from the tokenizing probe.37 files, 40
turbo runtextual matches — 23 executable, 17 prose in comments (classified, not dropped).Count: 3 sites carry
--filterplus a run-level passthrough. 2 of them were the defect; both are now fixed; there is no third.--onlyci.yml:738jobtest, slice leg-- "--shard=$SLICE"ci.yml:1577jobdogfood-- --shard=k/3test-nightly-tiers.yml:281jobtiers, slice leg-- "--shard=$SLICE" $REPORTERZeros, reported as asked. The other 20 executable
turbo runinvocations: 14 carry a--filterand no passthrough (the plainturbo run buildlegs inci.yml,lint.yml,cut-rc.yml,showcase-smoke.yml); 4 carry neither; and 2 (rerun-safety-nightly.yml:99/:130) carry neither a filter nor a passthrough. Zero sites outside the table above carry both.One blind spot in the probe, declared. A filter arriving through a shell variable is invisible to a token-level scan:
test-nightly-tiers.yml:276isturbo run test $FILTERS … -- $REPORTER, where$FILTERSis built as--filter=$PKGin the loop immediately above it. The probe scores itfilter=0; read by hand it is a fourth instance of the same class, and the only one whose whole-package leg carries a passthrough (ci.yml's corresponding leg carries none). Both nightly sites are in #17866 with their own measurement; they are not fixed here because that workflow isschedule-triggered, outside the required set, so a fix would land unexercised by any PR's CI — and the:276half needs a derivation the pinned shape does not supply.⭐ Reverse-read: which existing sentence does this make false?
Sentences made false: zero. The two present-tense claims in range, both in this job:
Restore Turbo cache, still on the tree: "the turbo test hash differs per shard (pass-through args are part of the task hash)" — still true, and still the reason its key is shard-scoped: thetesttask keeps the passthrough. Left alone.--args reach the package'svitest runand are hashed into the turbo task, so each shard caches independently" — not false, but no longer the whole story under--only. Extended in place, not deleted: it now says the passthrough is hashed into that one task and that the closure it used to scatter is built once by the step above.Sentence kinds, distinguished as asked: nothing carrying a rev or a date was touched (
#2018,#4250,#4859,#4928, the #16868 measurement block — all history). The named-direction zeros elsewhere in the file (check:required-contextspins, the!@objectstack/dogfoodexclusion rationale, the "NOT the dogfood job's vitest--shardpassthrough, deliberately" note at:295) are unaffected: the passthrough stays, it only stops being hashed into 66 other tasks. No bare present-tense magnitude in the tree became stale — the 66/67 counts this diff introduces are new, and each is written with the tree and the turbo version it was taken against.Pin tests on the current behaviour: zero found.
--onlyappears in no test or gate assertion about this job;check:stall-guard-budgetreads the step structurally and re-derived it green (below), rather than pinning a step list.Gates
scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 44 commands from the real change set (1 path, vs merge basec88fa2ccd). Ran all 44; reconciled the ran-list back against the deriver.check:stall-guard-budget,check:stall-guard-headroom,check:required-contexts,check:agent-test-spelling,check-ci-filter-parity,check:shard-attestation,check-step-collectors,check:workflow-step-name-quoting,check:workflow-status-functions,check:pnpm-filter-targets,check:nul-bytes.check:stall-guard-budgetverdict line, which proves the new site was measured rather than skipped:— the same window/cap/budget shape as
test's pair, and 10 guard-wrapped steps where the tree had 9.PREREQUISITE NOT MET), not failures:check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:sourcemap-no-sources-content. All four read builtdist/trees and say so in their own refusal text. They are placed by a whole-tree declaration, not by this diff's path, and a workflow-YAML-only diff moves no input of theirs. CI builds and runs them.check:pm-dispatch-gatesexceeded a 560-second foreground budget inside its own self-test at 1507 passing assertions and zero failures. Left to CI.Lint scope — a measured narrowing, not a skipped run. Repo-level
pnpm lint(eslint . --no-inline-config) is CI's run. The narrowing here is that this diff contains zero files eslint judges, and all three pieces of evidence: (1) eslint's own answer for the one file, from its own config —File ignored because no matching configuration was supplied; (2)--format jsonover the diff — 1 file, 0 errors, 1 warning, that notice; (3) invariance for untouched files — this repo runs oneeslint.config.mjswhich never enables type-aware linting for any file (eslint.config.mjs:326-329, measured there with a positive control), so nothing in this diff can move any untouched file's verdict. Taken at21d717d5, the final commit.Changeset: skipped, and measured first
skip-changesetlabel applied. Nothing published moves: of the 70 packages declaring afiles[], zero ship any.github/workflowspath; positive control —@objectstack/spec'sfiles[]reads back non-empty with its real shipped paths. The one other.githubdirectory in the tree (packages/create-objectstack/src/templates/blank/.github) is a different path and is untouched. This is also the fast-track case: a repo-root CI config.Clause-②
Clause-②: no, declared line-initial at the top of this body and self-verified againstreadClause2Line()read fresh fromscripts/pm/check-clause2-carriers.mjs:909— whoseCLAUSE2_KEY_LINEnow has three capture groups. The substantive answer matches the diff: one CI workflow file, no schema key, no closed-set member, no published export, no registry entry, so no C5 widening tell either.Generated by Claude Code