Skip to content

tooling(dispatch-gates): the STALE TREE reading keeps only the moved paths the derivation actually opened - #26585

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-l7gal4
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-l7gal4

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #26334

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:scripts/pm/dispatch-gates.mjs 的 STALE TREE 读数只再数派生真正打开过的文件(derivationInputs,从 discovery 实测:全部 workflow、跟过的 composite action、根 package.json、每个门禁族的脚本/import/spawn/按路径读取/包清单,加引擎自身闭包);scripts/ 下没人读的生成记录(sdui 清单记录、ADR 锚点)移动时不再误报,安静行点名被排除的路径。
  • 为什么改:ui/重构落地每次都动 scripts/ 下的生成记录,pm-only 树因此每次都读到假 STALE TREE(卡上实测派生集 52 不变),警告被忽视就失去意义。
  • 风险与回滚:只改读数的过滤,不改派生族、不改任何门禁命令;一个不该排除的输入会漏报——自检用实测集钉住闭包(清单、全部 workflow、每个门禁文件、引擎与其数据模块);回滚即 revert 本 PR 的合并提交。
  • 先看:scripts/pm/dispatch-gates.mjs 的 derivationInputs / liveDerivationInputs(排除规则与降级方向)、baseDrift 的 narrowed hunk、driftLines 安静分支;然后 dispatch-gates.self-test.mjs 的 base drift 段。
  • 两分钟验证:在落后 origin/main 且只差一次 ui 落地的 pm 检出跑 node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,预期 stderr 的 banner 是 "none of the commit(s) this tree can SEE touched … 1 path(s) under the surface moved too, none of them an input of this answer: scripts/sdui-manifest.record.json",不再出现 STALE TREE(--tier 不做派生,仍列原始清单并注明未收窄)。
  • 需要你做的:无,席位落地。

What changes

DERIVATION_SURFACE stays the pathspec roots the staleness diff is scoped to (.github/workflows, .github/actions, package.json, scripts). What is new is that the moved paths under those roots are narrowed to the files the derivation actually opened, measured rather than listed — the "narrowed surface" option of the two the order named, chosen because its self-test can prove the negative from the discovery itself instead of from a hand list that would rot the next time a generated record lands under scripts/.

  • derivationInputs() (new, exported): the measured set — every workflow file, every composite action the follow opened, the root package.json, and for every discovered family its gate files, first-party imports, spawned programs, program-text reads and package manifests, plus the engine's own module closure (this file, its first-party imports — the data module two levels down from every family — and the battery it loads by import()). Memoised per discovery, which is memoised per tree, so a derivation that already discovered pays nothing more.
  • narrowToDerivationInputs(moved, inputs) (new, exported): the pure split into changed (inputs) and ignored (under the roots, not inputs). inputs null keeps everything — the superset reading.
  • baseDrift({ cwd, inputs }): reads the same three-dot diff, then narrows it by the inputs its CALLER names — a set, or a function asked only once something moved under the roots. The reading gains an ignored field beside changed (null = not narrowed), and only changed decides loud vs quiet. The CLI's deriving modes (--commands, --ran, the human list) hand in liveDerivationInputs, which costs nothing extra because the derivation discovers the same tree through the same memo; --tier reads no workflow by contract, so it hands in nothing and its loud reading says it was not narrowed. A first draft let baseDrift discover on its own: a battery of --tier children on a stale tree then paid a ~14 s discovery each and the full self-test ran 24 minutes — so the choice moved to the caller. A discovery that throws degrades to no narrowing (over-report, never under-report).
  • driftLines: the quiet branch names what it set aside (N path(s) under the surface moved too, none of them an input of this answer: …, first three named), so the quiet reads as a measurement and not as the silence a level tree gets. A reading that set nothing aside renders byte-identically to before.
  • Derived families and gate commands: untouched — no discovery code changed; --commands derives the same 30 families on a51cd08 and on 4b203a9.

The card's named specimen, scripts/sdui-manifest.sources/**, had already been retired on main by e931621 (2026-10-27T01:15Z, #26367) before the seat's premise check — see Acceptance notes — so the live specimens are scripts/sdui-manifest.record.json (moves on every ui landing that regenerates the manifest) and scripts/adr-anchors/*.json (moves on refactor landings); the fix closes the class rather than the one path.

Tests

node scripts/pm/dispatch-gates.mjs --self-test (both tiers) on head 4b203a9: ✓ dispatch-gates self-test: 2224 cases pass. (fast 1935 case(s) in 353.9s · slow 289 case(s) in 974.3s). ⚠️ The base-drift section is in the SLOW tier, and CI runs only the fast tier on pull_request / merge_group (scripts/pm/check-dispatch-gates.mjs, #22991) — so this PR's check-runs do not exercise the new temporary-repository and LIVE cases; this local two-tier run is their evidence, and the hourly schedule run is the first CI run that will. The full run also caught two slow-tier-only ordering bugs in the first draft of these cases (a case reading a fixture above its declaration); fixed in 9a12ebe and 4b203a9, and every identifier the new cases read was then checked declared-before-read. New cases in the base-drift section, one per direction the order asked for and the live pins the measured set needs:

  • FRESH — temporary repository: upstream regenerates scripts/sdui-manifest.sources/core.json under the roots; the raw reading reports it (the departure pin: what used to go loud); narrowed by the inputs the same tree reads changed: [], ignored: [that record], and renders the quiet two-line shape naming the set-aside record, no STALE TREE; a foreign checkout handed no inputs is not narrowed.
  • STALE — same repository: a changed scripts/check-thing.mjs still goes loud and is named alone (Stale here: scripts/check-thing.mjs) with the record still set aside; a workflow (.github/workflows/lint.yml) and the root package.json moving upstream go loud, both named.
  • LIVE pins on this tree's measured set: every input is a tracked file; it holds the root manifest and every workflow file; this engine, its data module and its battery; every gate file of every discovered family; it is a strict subset of the tracked files under scripts/ (265 of 442 on 4b203a9), so the narrowing is not vacuous; liveDerivationInputs() answers that same set; and scripts/sdui-manifest.record.json is tracked and NOT an input.
  • Mode split: a level tree never asks for the inputs (a throwing function proves it is not called); inputs handed in as a function read identically to the set; an un-narrowed loud reading says Not narrowed to what the answer is made of … A --commands or --ran run measures the inputs and lists only those., a narrowed one does not.
  • Renderings: the quiet line with set-aside paths (counted past the third), byte-identity when nothing was set aside, the pure split's order.

Acceptance notes

  • Premise, measured (os-dev rule 6): the card's trigger directory scripts/sdui-manifest.sources/ does not exist on main — retired by e931621 (2026-10-27T01:15Z, "retire the per-package SDUI manifest records", ci(sdui): retire the per-package SDUI manifest records; CI's regeneration holds freshness (#26137 PR B) #26367), after the card was filed (2026-10-26T21:5xZ) and before the seat's read-only premise check at b53322d (git ls-tree b53322d5 scripts/ lists scripts/sdui-manifest.record.json, check-sdui-manifest.mjs, gen-sdui-manifest-node.mjs and no sdui-manifest.sources). The mechanism the card names holds unchanged: the whole scripts/ root was counted, and generated records under it still move on landings in other lanes — scripts/sdui-manifest.record.json at 1bbb7bf (ui), scripts/adr-anchors/*.json at b7f8a2e, 2e7127b (refactor) — and the derivation opens none of them (measured: 265 of 442 tracked scripts/** files are inputs on 4b203a9). The card's "Wanted" is met for the class; premise_still_valid: true with that correction.
  • Inputs outside the roots (observation, not fixed here): the measured set holds 43 files outside DERIVATION_SURFACE — gate scripts resolved through package manifests (packages/spec/scripts/check-*.ts, packages/lint/scripts/*.mjs), packages/spec/package.json, and program-text reads such as .claude/skills/pm-dispatch/SKILL.md. The diff stays scoped to the roots, as the ruling's "nothing wider" asks, so an upstream change to one of those still reads as off-surface, exactly as before this PR. Widening the diff to the measured set would be the honest next step; it is a separate decision.
  • The fix: remedy in the third unmeasured door still prints the raw git diff --name-only … -- ROOTS command: it is the superset a reader can run by hand; the narrowing is applied on top of it and is not something a shell one-liner can reproduce.
  • A changed dispatch-gates.self-test.mjs upstream counts as an input (the engine closure includes the battery) — a conservative choice: it does not move the answer, but check:pm-dispatch-gates runs it, and over-reporting is this file's degraded direction.

Verification

Three real landings replayed on throwaway checkouts (a --shared clone of this worktree with refs/remotes/origin/main pinned at the landing and HEAD at its parent; "before" = that tree's own engine, --tier; "after" = this PR's engine module closure committed on top, run in a deriving mode, --commands):

1bbb7bf — a ui landing whose only movement under the roots is scripts/sdui-manifest.record.json (the card's class)

Before:

  ⚠️  STALE TREE — this answer is derived from a tree at least 1 commit(s) behind origin/main, and 1 file(s) it derives from CHANGED across that range.
    Stale here: scripts/sdui-manifest.record.json

After:

  At least 1 commit(s) behind origin/main, and none of the commit(s) this tree can SEE touched what this answer derives from — HEAD 2026-10-26T12:40:29+00:00 vs origin/main 1bbb7bf4 2026-10-26T12:45:21+00:00. 1 path(s) under the surface moved too, none of them an input of this answer: scripts/sdui-manifest.record.json.
b7f8a2e — a refactor landing whose only movement under the roots is an ADR anchor record

Before: STALE TREE … 1 file(s) it derives from CHANGED / Stale here: scripts/adr-anchors/packages__objectql__src__engine-execute-transactions.ts.json.

After: none of the commit(s) this tree can SEE touched what this answer derives from … 1 path(s) under the surface moved too, none of them an input of this answer: scripts/adr-anchors/packages__objectql__src__engine-execute-transactions.ts.json.

e931621 — the sentinel retirement itself: two workflows and three gate scripts moved beside 27 records (the control that must stay STALE)

Before: STALE TREE … 32 file(s) it derives from CHANGED / Stale here: .github/workflows/ci.yml .github/workflows/lint.yml scripts/check-changeset-no-major.mjs scripts/check-sdui-manifest.mjs scripts/gen-sdui-manifest-node.mjs scripts/sdui-manifest.record.json … +26 more.

After: STALE TREE … 5 file(s) it derives from CHANGED / Stale here: .github/workflows/ci.yml .github/workflows/lint.yml scripts/check-changeset-no-major.mjs scripts/check-sdui-manifest.mjs scripts/gen-sdui-manifest-node.mjs — the verdict for a real derivation-input change is unchanged; only the records left the list.

The --ran reconciliation on this branch, head 4b203a9 (no drift line: the tree was level with the fetched origin/main when it ran):

Derived gates — 30 families, run locally on 4b203a9, reconciled with --ran
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs --self-test :: exit 0
node scripts/check-self-test-wired.mjs :: exit 0
node scripts/check-self-test-wired.mjs --self-test :: exit 0
node scripts/check-self-test-workflow-commands.mjs :: exit 0
node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0
node scripts/check-whole-set-label-write.mjs :: exit 0
node scripts/check-whole-set-label-write.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:bash32-floor :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:cli-command-ids :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:declared-population-live :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:entry-guard :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:parse-guard :: exit 0
pnpm check:pnpm-filter-targets :: exit 0
pnpm check:pnpm-flag-spellings :: exit 0
pnpm check:ratchet-remedy-authority :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:scripts-symbol-anchors :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:pm-dispatch-gates :: exit 0

Run reconciliation — 30 derived, 30 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 30 derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED (a DERIVED zero — all 30 recorded an exit code and none of them is 3).

check:dual-build-cjs-loads is not in this card's derived list. --tier on each throwaway tree now prints the raw list plus the not-narrowed line (e.g. 32 files on e931621), by design. No package is touched (no ① closure, no ② package suite); pnpm lint as a repo-wide sweep is CI's run — eslint scripts/pm/dispatch-gates.mjs scripts/pm/dispatch-gates.self-test.mjs exits 0 locally.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (n/a — no schema touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (eslint on the two files, exit 0; the repo sweep is CI's)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (scripts/pm/** publishes nothing — skip-changeset)
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (n/a)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbZ5vD35MzQ8UqhhTJB

os-warren and others added 4 commits October 27, 2026 06:45
…paths the derivation actually opened

`DERIVATION_SURFACE` stays the pathspec roots the staleness diff is scoped to,
but `scripts/` also holds generated records nothing derives from (the SDUI
manifest record, the ADR anchor files), regenerated by landings in other lanes,
so every such landing read as a STALE TREE over a pm-only tree whose families
had not moved. `baseDrift` now splits the moved paths against
`derivationInputs` — the files the discovery really opened: every workflow,
the composite actions it followed, the root manifest, each family's gate files,
imports, spawned programs, path reads and package manifests, plus this engine's
own module closure — into `changed` (inputs, the only ones that decide loud vs
quiet) and `ignored` (under the roots, not inputs), and the quiet rendering
names what it set aside. A caller may hand in `inputs` itself; a foreign
checkout with no discovery keeps the raw superset reading.

Self-test: a record-only drift reads FRESH; a gate-script, workflow or root
manifest drift still reads STALE; live-tree pins on the measured set.

Claude-Session: https://claude.ai/code/session_01JQwxbZ5vD35MzQ8UqhhTJB
Co-authored-by: Claude <noreply@anthropic.com>
…ixture it reads

The two cases read `loudText` above its declaration, a temporal-dead-zone
ReferenceError that only the slow tier reaches (the base-drift section is
slow), so the fast-tier `check:pm-dispatch-gates` run stayed green.

Claude-Session: https://claude.ai/code/session_01JQwxbZ5vD35MzQ8UqhhTJB
Co-authored-by: Claude <noreply@anthropic.com>
… it compares against

The same slow-tier-only temporal-dead-zone shape as the previous commit:
the case read `live` two lines above its declaration. Every identifier the
new drift cases read is now checked to be declared above its first read.

Claude-Session: https://claude.ai/code/session_01JQwxbZ5vD35MzQ8UqhhTJB
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 4b203a9dfd62f74036f9a45a7bb52c1a01b649df
Local-runs: none

Director seat (summon #52, ledger objectstack#12708), by the maintainer's word 「#26566、#26568、#26570、#26585 也要追加复审」: the PR is an open draft at this head with no review on it; this record is read-only — the diff, card #26334, the head's check runs. dispatch-gates --tier on scripts/pm/dispatch-gates.mjs and its self-test: no governed or published path, Clause-②: no, Metadata-protocol: none ⇒ the declaration face, TIER_DEFAULT; served at CONTRACT_REVIEW_TIER. The seat does not ready, queue or merge.

① Derived judgments

  • Drift is now measured against what the answer is made of. derivationInputs({ tree }) (memoised per tree) enumerates the files the tier/family derivation actually opens — package.json, the engine closure, workflows, composite actions, each family's files/imports/runs/reads/manifests; narrowToDerivationInputs(moved, inputs) splits a scripts/** move into { changed, ignored }, and baseDrift reports only changed as drift. The card's complaint (a --ran reconciliation declared stale because a generated record under scripts/ moved on another lane's landing) is closed for the class, not the one path.
  • Degrades to over-report, never to silence. liveDerivationInputs() is try/catch → null; narrowToDerivationInputs with null inputs returns ignored: null and baseDrift then prints "Not narrowed to what the answer is made of…" and counts every move, i.e. yesterday's behaviour. --tier passes inputs: null explicitly, so a tier answer is still refused on any scripts/** move. The quiet line names what was set aside ("N path(s) under the surface moved too, none of them an input of this answer: …"), so a quiet result reads as a measurement; a reading that set nothing aside renders byte-identically to before, per the body — consistent with the diff.
  • Premise correction accepted. The card's named specimen scripts/sdui-manifest.sources/** was retired by ci(sdui): retire the per-package SDUI manifest records; CI's regeneration holds freshness (#26137 PR B) #26367 (2026-10-27T01:15Z) before the seat's premise check; the live specimens are scripts/sdui-manifest.record.json and scripts/adr-anchors/*.json. The mechanism the card describes is unchanged by that retirement, and the fix is by input set rather than by path, so the correction does not change what was built. premise_still_valid: true with the correction is the right reading.
  • Export surface. derivationInputs, narrowToDerivationInputs, liveDerivationInputs are new named exports of an internal tooling module (scripts/pm/**), consumed by the self-test; nothing published.

② Semver level

scripts/pm/** publishes nothing; skip-changeset; both declaration lines present and equal. No level owed. Correct.

③ Boundary flags

  • Check runs pinned to 4b203a9d: 28 success, 17 expected skips, 0 other — Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Governed Surface Queue Guard, Test Core (2 shards), TypeScript Type Check, the three claim guards. No local re-run.
  • The new base-drift self-test cases are slow-tier by the dev flags, and the PR's CI runs the fast tier only — so the eight narrowing cases are measured by the dev's check:pm-dispatch-gates run under the verify lock (body), not by any green on this head. Named so the green is not over-read; not a must-fix (the slow tier is the repo's own split).
  • Open draft, no reviewer yet; nothing here blocks pr_ready. Head-pinned: a new push owes a new record.

Implemented-by: claude/project-thread-l7gal4
Reviewed-by: session_01ADHkmQr732toX135tyo5zs

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

objectstack-fleet Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Retracted: this comment was a duplicate post of the director seat's contract-review record on this PR; the record of record is comment 6439771311 above (same head, same verdict). Nothing else changes.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么:scripts/pm/dispatch-gates.mjs 的 STALE TREE 读数只再数派生真正打开过的文件(derivationInputs:全部 workflow、跟过的 composite action、根 package.json、每个门禁族的脚本/import/spawn/按路径读取/包清单,加引擎自身闭包);scripts/ 下没人读的生成记录(sdui 清单记录、ADR 锚点)移动时不再误报,安静行点名被排除的路径。自测加 base drift 用例。
为什么改:ui/重构落地每次都动 scripts/ 下的生成记录,pm-only 树因此每次读到假 STALE TREE,警告被忽视就失去意义。
风险与回滚:只改读数过滤,不改派生族和门禁命令;求输入集失败时退回旧行为(全数),--tier 不派生,仍按原清单。回滚 = revert 本 PR。
先看:① derivationInputs / liveDerivationInputs(降级方向);② narrowToDerivationInputs 与 baseDrift 的 narrowed 段;③ dispatch-gates.self-test.mjs 的 base drift 段。
两分钟验证:在只落后一次 ui 落地的 pm 检出跑 node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,banner 说「N path(s) under the surface moved too, none of them an input of this answer」,不再出 STALE TREE。
需要你做的:无。Tier S,总监契约复核 PASS + 本核对后席位 ready 并布自动合并。
席位意见:同意落地。注意 base drift 新用例在慢档,PR 上 CI 只跑快档,证据是开发者本地两档全跑(2224 例过)。

席位核对

ACCEPT · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-27T10:40Z — seat review of record for #26334 on head 4b203a9d, against GitHub, not the report's own account. Two paths, scripts/pm/dispatch-gates.mjs and scripts/pm/dispatch-gates.self-test.mjs — no governed or published path ⇒ Tier S: the record of the review tier is the director seat's independent ## Contract review at comment 6439771311 (Served-tier: TIER_DEFAULT declared face, served at CONTRACT_REVIEW_TIER, head 4b203a9d, VERDICT: PASS, Local-runs: none; reviewer session_01ADHkmQr732toX135tyo5zs, not the implementer). This seat adds the landing read and lands it itself.

  1. Shape. Draft, base main, mergeable_state: clean, 4 commits (one merge of origin/main, 37b1183e), 31 behind main; +277/−15 across exactly the claim's surface (claim 6435073454). Body: harness attribution lines, Fixes #26334, Clause-②: no, Metadata-protocol: none line-initial, six-line ## 维护者速读. Labels size/m, skip-changeset. Branch claude/project-thread-l7gal4, as the claim names.
  2. Diff, read by the seat. narrowToDerivationInputs(moved, inputs) returns { changed: [...moved], ignored: null } when inputs is null — the old count; liveDerivationInputs() catches into null; the self-test drives baseDrift({ inputs: null }) for the raw reading and --tier passes inputs: null. So the change can under-warn only through a file the derivation opens but derivationInputs misses, and the self-test pins the closure (manifest, every workflow, every gate file, the engine and its data module). The order's 「narrowed surface」 option, chosen and named in the body; no derived family or gate command changed.
  3. Gates, pinned to head 4b203a9d. 45 check-runs: 28 success, 17 skipped, none red or pending (seat read 2026-10-27T10:38Z) — Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Governed Surface Queue Guard, Test Core, TypeScript Type Check, the claim guards. The dev's report (6437866201): 30 derived, 30 run, 0 NOT MEASURED; full two-tier check:pm-dispatch-gates 2224 pass under the verify lock.
  4. Accepted deviations. (a) Premise correction: the card's specimen scripts/sdui-manifest.sources/** was retired by ci(sdui): retire the per-package SDUI manifest records; CI's regeneration holds freshness (#26137 PR B) #26367 before the seat's premise check; the live specimens are scripts/sdui-manifest.record.json and scripts/adr-anchors/*.json, same class — the seat's claim premise was stale on the path, not on the mechanism. (b) The card finished one tier down after the maintainer's word of 2026-10-27T07:14Z (claim amended 2026-10-27T07:20Z); the review of record ran at CONTRACT_REVIEW_TIER. (c) The base-drift cases are slow-tier and the PR's CI runs the fast tier only; their evidence is the dev's local two-tier run, named so the green is not over-read (the director's ③ reads the same).
  5. Carrier. Nothing filed from this review: no should-fix named.
  6. Landing. Tier S ⇒ on this record the seat readies the PR and arms auto-merge through the relay (pr_ready, automerge_enable), follows it to MERGED, and closes tooling(dispatch-gates): STALE TREE counts the sdui-manifest hash sentinels as derivation inputs, so a pm-only tree reads stale on every ui landing #26334 with the landing record.

Generated by Claude Code

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

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(dispatch-gates): STALE TREE counts the sdui-manifest hash sentinels as derivation inputs, so a pm-only tree reads stale on every ui landing

1 participant