Repository navigation
scripts: a local Spec Main Shape Gate reproduction writes main-spec type-check verdicts into turbo's worktree-shared cache, so a later unforced installed-spec type-check in any worktree replays them (a false green) #12114
Description
Activity
objectstack-fleet commented
on Oct 11, 2026 ContributorAuthorMore actionsTriage: first grade,
enhancement·priority:p3·domain:devx·area:devpath·pm:queue. Maintainer-directed, so the tooling queue rule's entry lines do not applyTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-11T03:55Z. ⛔ Not a claim, ⛔ not a dispatch.- Why it enters the queue: the maintainer asked for this mechanism verbatim (「要开卡:发现一个可以做成机制的问题 …」), which exempts it from the
Unblocks:/ published-surface entry lines. - Why p3: it is local only, and CI is unaffected because it forces and shares no cache. The harm is a false verdict in a developer's own pre-push type-check after a local gate reproduction.
- Lane:
scripts/and the gate's local recipe aredomain:devxin this repository. - Direction:
- The cheapest durable option is an injected worktree that never shares turbo cache entries with an installed one: its own cache directory, or an injection marker inside turbo's hash.
- Prefer the option that needs no remembered flag.
- ⛔ No change to the CI workflow's
TURBO_FORCE=true, which stays as pinned.
- Pin, as filed: a local reproduction followed by an installed
type-checkin a sibling worktree reports notype-checkcache hit.
- Why it enters the queue: the maintainer asked for this mechanism verbatim (「要开卡:发现一个可以做成机制的问题 …」), which exempts it from the
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoenhancementNew feature or requestNew feature or requestand removed
on Oct 11, 2026 objectstack-fleet commented
on Oct 11, 2026 ContributorAuthorMore actionsClaim: PM loop round 83
Session:session_01DwLS3LzXyNmyTunMGbpc8W
Account:zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee, label-write read-back MATCHES)
Branch:claude/issue-12114-injected-tree-cache
Worktree:objectui-issue-12114
Domain:domain:devx
Seat:domain:devx#1(seat post objectui#5748, round-open marker6106236990)
File surface:scripts/spec-main-shape-gate.mjs(theinjectpath and its local recipe),scripts/__tests__/spec-main-shape-gate.test.ts, andturbo.jsononly if the chosen option puts an injection marker inside turbo's hash; ⛔ not.github/workflows/spec-main-shape-gate.yml(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: default
Clause-②: no
Responsibility:n/a — not a defect card
Thread-read: 6105209514
Serial constraints cleared: objectui's 5 open PRs (#12122, #12089, #11845, #11844, #11600) touch none of the three paths; the newestorigin/maintouch to them isf88a900e(2026-10-02T01:47Z). The 6 openpm:dispatchedobjectui cards (#12121, #12109, #12098, #12082, #12081 indomain:ui; #7611pm:epic) declarepackages/**surfaces or none. The sibling dispatched this round, objectui#5250, works inscripts/check-doc-snippet-types.mjs,content/docs/**andexamples/**, which is disjoint. Reading time 2026-10-11T06:28Z.objectstack-fleet commented
on Oct 11, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 12114,
"status": "done",
"branch": "claude/issue-12114-injected-tree-cache",
"pr": "#12125",
"session": "session_01DwLS3LzXyNmyTunMGbpc8W (subagent run; the id is the parent PM seat session)",
"premise_still_valid": true,
"summary": "The premise holds and is now measured. A linked worktree's turbo 2.10.9 writes to the main checkout's .turbo/cache ('using shared worktree cache'). --force skips cache reads but still writes (turbo help: '--cache=local:w,remote:w'), so even the CI recipe run locally poisons the cache. inject left every hash unchanged: the whole type-check graph had 83/83 task hashes equal before and after. Fix (option a): turbo.json globalDependencies names node_modules/@objectstack/spec/.spec-main-shape-gate.json. That is the marker inject already writes into every replaced copy, reached by a LITERAL path through the root link to the spec; a wildcard inside node_modules hashes nothing, silently (measured). Installed trees hash exactly as before. An injected tree hashes apart in both directions with no flag to remember (whole graph 0/83 equal), and 'pnpm install --force' removes the marker together with the injection. CI's TURBO_FORCE=true and the workflow are untouched.",
"tests": "Live two-worktree reproduction, turbo run type-check --filter=@object-ui/types, with an identical untracked probe importing SpecGateProbe12114 from the injected spec. BEFORE (29b9949): A inject + TURBO_FORCE=true wrote e02dab71f230fcc0. B (installed) unforced: 'cache hit, replaying logs e02dab71f230fcc0', Cached 1/2, exit 0, a FALSE GREEN. B forced: TS2305 (true verdict). AFTER (81dea3f): installed A and B both hash 95eb3fecb9111eb5. A inject logs 'turbo hashes node_modules/@objectstack/spec/.spec-main-shape-gate.json' and the hash becomes 67c390de3fefe78f. A forced: green. B unforced: 'cache miss, executing 95eb3fecb9111eb5' then TS2305, Cached 0/2 (true verdict). A unforced: hits only its own 67c390de3fefe78f. 'pnpm install --frozen-lockfile --force' in A restores 95eb3fecb9111eb5. New pins: 3 (wiring; a real turbo --dry=json over a fixture git repo copying this turbo.json and driving the real inject CLI; a firing control without the root link). Red on main's script and turbo.json: 'Tests 3 failed | 28 passed (31)'. Ablation of the turbo.json entry only: 'Tests 2 failed | 29 passed (31)', with "expected [ 'package.json' ] to include 'node_modules/@objectstack/spec/.spec-...'" and the firing control green. Restore was proven by an empty git diff HEAD plus blob hashes equal to HEAD. No dist is involved (scripts run from source). Final head a1b9bd6: 13 derived test files 'Tests 625 passed (625)'; lint:root 0 errors; --self-test 26/26.",
"mcp_calls": "0",
"api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, landed as objectstack-fleet[bot]). (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12125/assignees (zhuangjianguo); read-back: 9381 bytes sent, 9381 stored, identical. (2) this os-dev-report = POST /repos//issues/12114/comments. Plus 4 git pushes (not REST). 0 label writes (per the PM correction).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed. content/docs/guide/ci-cd-pipeline.md (Spec Main Shape Gate section) does not describe a local reproduction; the recipe (inject, then pnpm type-check --continue, then pnpm install --frozen-lockfile --force) lives only in the script header. Its existing claim that turbo does not hash the content of node_modules stays true. Not class a/b/c: a doc gap, no wrong answer at a public door."
],
"gates": {
"pnpm exec vitest run (13 files: git grep -l -e turbo.json -e spec-main-shape-gate under scripts/tests, helpers excluded) @a1b9bd68": 0,
"pnpm exec vitest run scripts/tests/spec-main-shape-gate.test.ts @81dea3ff (31 passed; also in the 13-file run above)": 0,
"pnpm lint:root @a1b9bd68 (0 errors, 34 warnings, none in touched files)": 0,
"pnpm check:new-line-citations @a1b9bd68 (0 new citation(s))": 0,
"pnpm check:control-bytes @a1b9bd68": 0,
"node scripts/check-changeset-presence.mjs @a1b9bd68 ('7 file(s) changed, 0 of them published source ... no changeset is owed')": 0,
"node scripts/spec-main-shape-gate.mjs --self-test (26/26)": 0,
"node scripts/check-governed-queue-guard.mjs --test (7 paths: NOT GOVERNED)": 0,
"CI on PR 12125 at report time": "in_progress (13 completed, 17 in progress; not waited on)"
},
"line_budget": {
"scripts/spec-main-shape-gate.mjs": "+60 -7",
"scripts/tests/spec-main-shape-gate.test.ts": "+161 -0",
"turbo.json": "+1 -0",
"scripts/tests/turbo-build-inputs.test.ts": "+1 -1",
"scripts/tests/turbo-lint-inputs.test.ts": "+1 -1",
"scripts/tests/turbo-test-inputs.test.ts": "+1 -1",
"scripts/tests/turbo-type-check-inputs.test.ts": "+1 -1"
},
"deviations": [
"FILE SURFACE: four comment lines in scripts/tests/turbo-{build,lint,test,type-check}-inputs.test.ts said 'globalDependenciesis unset'. That became false with this change, so each now reads 'holds no source file'. Comment-only, under the charter rule that prose a change makes false must be fixed. No open PR touches these files. The seat should append them to the claim's file surface.",
"The injected tarball was the installed published spec plus one probe export, not a spec built from objectstack main. The mechanism under test is turbo cache keying, which never reads the spec bytes, and the probe makes the false verdict visible. --upstream-checkout was the read-only shared /home/user/objectstack, which needed no dependency substitution.",
"The live reproduction executed a filtered graph (@object-ui/types), not the full 'pnpm type-check'. The whole 83-task graph was covered by dry-run hash comparisons. The card's 80/81 figure was not re-run.",
"Deleting the two inert cache entries this run wrote in /home/user/objectui/.turbo/cache (e02dab71f230fcc0, 67c390de3fefe78f; 3 files each) was refused by the auto-mode classifier as a shared-resource write. They remain. The first dry run had also created that gitignored directory (turbo's own behaviour).",
"A git fetch into my own ref (deleted afterwards) auto-followed one remote tag into the shared .git: refs/tags/@object-ui/types@17.7.0.",
"Commit trailers use the AGENTS.md model-free pair (Co-authored-by: Claude) rather than the harness's model-named Co-Authored-By line, per AGENTS.md precedence.",
"No skip-changeset label, per the PM correction: the presence check passed with no changeset. The PR carries a 'tests' label that the labeler applied, not this run."
],
"files_changed": [
"scripts/spec-main-shape-gate.mjs",
"scripts/tests/spec-main-shape-gate.test.ts",
"turbo.json",
"scripts/tests/turbo-build-inputs.test.ts",
"scripts/tests/turbo-lint-inputs.test.ts",
"scripts/tests/turbo-test-inputs.test.ts",
"scripts/tests/turbo-type-check-inputs.test.ts"
]
}objectstack-fleet commented
on Oct 11, 2026 ContributorAuthorMore actionsReview: ACCEPT, PR objectui#12125 (2026-10-11T07:02Z)
domain:devx@ objectui seat 1 (seat post objectui#5748),session_01DwLS3LzXyNmyTunMGbpc8W. Checked against GitHub at heada1b9bd688c, not against the report6106471070.
Implemented-by:claude/issue-12114-injected-tree-cache· Reviewed-by: this seat (no contract face is touched, so CI plus the seat's read is the review of record).Checklist
- Shape: draft ✓ · base
main✓ · first lineFixes #12114, and it is the only closing keyword in the body ✓ · PR assigneezhuangjianguo✓.Fixesis right: the PR delivers the card's pin as filed, both as a live two-worktree reproduction (before:cache hit, replaying logs, a false green; after:cache missand the true TS2305) and as a pinned realturbo --dry=jsonrun over a fixture. - Surface: 7 files. 3 are in the claim (
scripts/spec-main-shape-gate.mjs, its test,turbo.json). The other 4 are one comment line each inscripts/__tests__/turbo-{build,lint,test,type-check}-inputs.test.ts(「globalDependenciesis unset」, false once this lands). This is a bounded in-place fix (same change, comment only, no open PR holds those files), and this comment adds them to the claim's file surface. ⛔.github/workflows/spec-main-shape-gate.ymlis untouched, so CI'sTURBO_FORCE=truepin stands. - Governed:
check-governed-merges --pr objectstack-ai/objectui#12125reads NOT governed, 0 of 7 paths, 237 changed lines (≤ 3000). - Changeset: none owed.
check-changeset-presencereads 「7 file(s) changed, 0 of them published source … no changeset is owed」. Rootscripts/,turbo.jsonand tests publish nothing. No label is needed. - Diff read by the seat: one literal
globalDependenciesentry (node_modules/@objectstack/spec/.spec-main-shape-gate.json). The markerinjectalready writes into each replaced copy is now in turbo's hash.injectlogs whether the root link exists. The header's old sentence was rewritten so it stays true. The path relies on the root manifest declaring the spec: on objectuiorigin/main29b99490, rootpackage.json:145reads"@objectstack/spec": "^17.0.0", and the new wiring pin fails if it ever stops. - Tests (report, not re-run by the seat): 3 new pins, red on
main's script andturbo.json(3 failed | 28 passed). Ablating theturbo.jsonentry alone gives2 failed, with the firing control green. 13 derived test files:625 passed.--self-test26/26. - CI at review: 39 runs on
a1b9bd688c, 23 success, 3 skipped, 13 in progress (8 test shards, Type Check, Lint, Spec Main Shape Gate and 2 others). Landing waits for every check to be green.
Findings
content/docs/guide/ci-cd-pipeline.mddoes not describe the local reproduction recipe: Acceptance notes. No wrong answer at a public door, carrier none.- Two inert entries left in the shared checkout's
.turbo/cache(e02dab71f230fcc0, keyed on a deleted probe file;67c390de3fefe78f, keyed on a unique injection marker): Acceptance notes. Neither can be hit. - A tag fetch that followed into the shared
.git(refs/tags/@object-ui/types@17.7.0): dropped, since it mirrors the remote tag.
Next: on all-green,
pr_ready+automerge_enablethrough the relay. The seat follows the PR to MERGED.- Shape: draft ✓ · base
objectstack-fleet commented
on Oct 11, 2026 ContributorAuthorMore actionsLanded (2026-10-11T07:39Z): PR objectui#12125 merged through the merge queue at 2026-10-11T07:38:30Z, merge commit
a194b4e37.Fixes #12114closed this cardcompleted.domain:devx@ objectui seat 1,session_01DwLS3LzXyNmyTunMGbpc8W.- Landing probe on objectui
origin/maina194b4e3:turbo.json:4carries"globalDependencies": ["node_modules/@objectstack/spec/.spec-main-shape-gate.json"].TURBO_HASH_MARKERappears inscripts/spec-main-shape-gate.mjs(4 hits) and in its test (9). All 4turbo-*-inputs.test.tscomments read 「holds no source file」. Control in the same file:"globalEnv"hits 1. - Close-out:
pm:dispatchedand the assignee were removed in this act and read backMATCHES.enhancement,priority:p3,domain:devxandarea:devpathstay. - No follow-up card. The two findings stay in the PR's Acceptance notes, per the ACCEPT
6106491265.
- Landing probe on objectui
Filing class: a mechanizable guard, measured by a dispatched dev and asked for by the maintainer. The maintainer asked for it in the
domain:uiseat 3 session (session_01B1gHb9baeX7oioD5sHVm7z), verbatim, 2026-10-11: 「要开卡:发现一个可以做成机制的问题:在本地复现这个闸门时,turbo 的跨 worktree 共享缓存会把基于 main 版 spec 的结果,回放给基于已安装版 spec 的类型检查,得到假绿。复现时需要加 TURBO_FORCE=true。」 ⛔ Not graded or routed here: triage grades.The measurement
From the
os-dev-report6100892115on objectui#12085 (the dispatch that folded objectui#12093's gate fix, PR objectui#12100):Spec Main Shape Gatelocally. They built@objectstack/specfrom objectstackmain, packed it, and injected it withnode scripts/spec-main-shape-gate.mjs injectinto a sibling git worktree, then ran the type-check there.pnpm type-checkagainst the INSTALLED spec, in another worktree with equal task hashes, reported 81/81. 80 of those were cache hits replayed from the main-spec run. The dev discarded the run as NOT MEASURED, and aTURBO_FORCE=truere-run (81/81 forced, 0 cache hits) gave the real verdict.Why the script's existing guard does not cover it
scripts/spec-main-shape-gate.mjs's header section "The turbo cache is a FALSE GREEN here, and the workflow must bypass it" covers the gate's own run: turbo'stype-checkhash covers sources, the lockfile and a declared env list, but not the content ofnode_modules. So a run after an injection can replay the pre-injection verdict. The workflow runsTURBO_FORCE=true pnpm type-check(.github/workflows/spec-main-shape-gate.yml), andscripts/__tests__/spec-main-shape-gate.test.tspins that.This finding is the reverse direction, and local only:
That is a green (or red) answer to a question about a spec the worktree does not have. CI is unaffected: it forces, and it shares no cache with a local worktree.
Direction (for triage to grade, not a ruling)
Make the local reproduction unable to poison the shared cache. Some candidate options:
injectrefuses to finish without stating the guard, or the script's local recipe runs the type-check itself withTURBO_FORCE=true(or--force) and never writes cache entries for an injected tree;--cache-dir/TURBO_CACHE_DIR), so it never shares entries;globalDependenciesfile thatinjectwrites), so injected and installed trees can never share an entry.Each option needs a pin: a local reproduction followed by an installed type-check in a sibling worktree must not report a cache hit for
type-check.Dedupe: an objectui issue search for turbo shared worktree cache, replay, Spec Main Shape Gate local reproduction and
TURBO_FORCEfinds six turbo-input and gate cards: objectui#4178, #4184, #4185, #6577, #7855 and #9944, all closed. None is this direction.