The retirement playbook's walk-radius mandate names turbo.json's <pkg>#test inputs. Since #16466 split the test task, that is the wrong task for 6 of this repo's packages, and the gate enforces the opposite in both directions — so an executor following the sentence literally reddens the build twice and has to work out why from the gate's message rather than the instruction that sent them there.
Surfaced while dispatching #15567 (closed as discharged). ⛔ Every reading below was taken by the filing seat on origin/main 2bdabe60e, not transcribed from a report. Filed bare and unassigned — ⛔ no domain:*, no grade, no type; all three are triage's.
⚠️ Routing input only. The subject is .claude/skills/spec-property-retirement/SKILL.md, a governed surface — ⛔ not this seat's to edit, and ⛔ this seat did not touch it.
The sentence, verbatim
.claude/skills/spec-property-retirement/SKILL.md, the tree-scoped-pin checklist item:
⭐ 半径按包申报一次:写进 scripts/cross-package-test-inputs.mjs 的 CROSS_PACKAGE_TEST_INPUTS 并配齐 turbo.json 的 <pkg>#test inputs,turbo 才 hash 得到它、CI 分片并集才看得见;… ⛔ 半径未申报的 tree-scoped pin 不是完成的退役。
What the tree actually requires
Measured on origin/main 2bdabe60e, from turbo.json:
| task |
inputs |
$TURBO_ROOT$ entries |
@objectstack/spec#test |
4 |
0 |
@objectstack/spec#test:repo |
34 |
30 |
⇒ On a split package the radius hashes on #test:repo, and #test must carry none. scripts/check-cross-package-test-inputs.mjs enforces both directions, and its own self-test pins the failing case: "a wide input LEFT on PKG#test reds even when test:repo is complete."
⇒ Following the sentence literally puts the inputs on the task the gate requires to be empty. Two reds: the missing declaration on test:repo, and the forbidden one on test.
The population is 6, measured — ⛔ not "spec only"
Packages declaring a test:repo script (git grep -l '"test:repo"' -- 'packages/**/package.json'):
packages/core packages/objectql packages/rest
packages/runtime packages/spec packages/types
The playbook never mentions the split
git grep -c "test:repo" -- .claude/skills/spec-property-retirement/SKILL.md → 0
control, same file: CROSS_PACKAGE_TEST_INPUTS → 1
⇒ The zero is a reading, not a broken pattern: the file is readable and the neighbouring symbol is found. The playbook has no notion that #test may be the wrong task.
⭐ Why this is worth a card rather than a footnote
The mandate's own closing clause is ⛔ 半径未申报的 tree-scoped pin 不是完成的退役 — it makes the declaration a completion condition for a retirement. An instruction that is a completion condition, and that misdirects on a third of the repo's split packages, fails in the place where its reader has least room to notice: they are following a checklist precisely because they do not already know the answer.
⭐ And the failure mode is not silent-but-harmless — it is two reds whose message points at turbo.json, not at the instruction. The reader's most likely repair is to fight the gate.
⚠️ This card is filed because the dispatch this seat wrote made exactly that mistake: it repeated @objectstack/spec#test from the card and the triage comment. The dev did not follow it — it read the tree and reported the divergence — but three independent texts (card, triage comment, dispatch) all inherited the same wrong task name from the playbook. That is the propagation this card exists to stop.
Executable criterion
The mandate names the task by the rule that picks it — on a package declaring a test:repo script the radius is declared on <pkg>#test:repo and <pkg>#test carries no root input; otherwise <pkg>#test — or points at scripts/check-cross-package-test-inputs.mjs as the authority instead of naming a task at all. ⛔ Either way it must stop naming one task unconditionally.
⛔ Out of scope: whether the split itself is right (#16466 ruled it), and any change to the gate. This is a documentation defect in a checklist, not a tooling one.
Refs: #15567 (the card that hit it, closed as discharged) · #16466 (the split) · .claude/skills/spec-property-retirement/SKILL.md · scripts/check-cross-package-test-inputs.mjs
Generated by Claude Code
The retirement playbook's walk-radius mandate names
turbo.json's<pkg>#testinputs. Since #16466 split the test task, that is the wrong task for 6 of this repo's packages, and the gate enforces the opposite in both directions — so an executor following the sentence literally reddens the build twice and has to work out why from the gate's message rather than the instruction that sent them there.Surfaced while dispatching #15567 (closed as discharged). ⛔ Every reading below was taken by the filing seat on
origin/main2bdabe60e, not transcribed from a report. Filed bare and unassigned — ⛔ nodomain:*, no grade, no type; all three are triage's..claude/skills/spec-property-retirement/SKILL.md, a governed surface — ⛔ not this seat's to edit, and ⛔ this seat did not touch it.The sentence, verbatim
.claude/skills/spec-property-retirement/SKILL.md, the tree-scoped-pin checklist item:What the tree actually requires
Measured on
origin/main2bdabe60e, fromturbo.json:$TURBO_ROOT$entries@objectstack/spec#test@objectstack/spec#test:repo⇒ On a split package the radius hashes on
#test:repo, and#testmust carry none.scripts/check-cross-package-test-inputs.mjsenforces both directions, and its own self-test pins the failing case: "a wide input LEFT on PKG#test reds even when test:repo is complete."⇒ Following the sentence literally puts the inputs on the task the gate requires to be empty. Two reds: the missing declaration on
test:repo, and the forbidden one ontest.The population is 6, measured — ⛔ not "spec only"
Packages declaring a
test:reposcript (git grep -l '"test:repo"' -- 'packages/**/package.json'):The playbook never mentions the split
⇒ The zero is a reading, not a broken pattern: the file is readable and the neighbouring symbol is found. The playbook has no notion that
#testmay be the wrong task.⭐ Why this is worth a card rather than a footnote
The mandate's own closing clause is ⛔ 半径未申报的 tree-scoped pin 不是完成的退役 — it makes the declaration a completion condition for a retirement. An instruction that is a completion condition, and that misdirects on a third of the repo's split packages, fails in the place where its reader has least room to notice: they are following a checklist precisely because they do not already know the answer.
⭐ And the failure mode is not silent-but-harmless — it is two reds whose message points at
turbo.json, not at the instruction. The reader's most likely repair is to fight the gate.@objectstack/spec#testfrom the card and the triage comment. The dev did not follow it — it read the tree and reported the divergence — but three independent texts (card, triage comment, dispatch) all inherited the same wrong task name from the playbook. That is the propagation this card exists to stop.Executable criterion
The mandate names the task by the rule that picks it — on a package declaring a
test:reposcript the radius is declared on<pkg>#test:repoand<pkg>#testcarries no root input; otherwise<pkg>#test— or points atscripts/check-cross-package-test-inputs.mjsas the authority instead of naming a task at all. ⛔ Either way it must stop naming one task unconditionally.⛔ Out of scope: whether the split itself is right (#16466 ruled it), and any change to the gate. This is a documentation defect in a checklist, not a tooling one.
Refs: #15567 (the card that hit it, closed as discharged) · #16466 (the split) ·
.claude/skills/spec-property-retirement/SKILL.md·scripts/check-cross-package-test-inputs.mjsGenerated by Claude Code