docs(skills): make the retirement pin's walk radius a declared radius - #15566
Merged
Merged
Conversation
The retirement playbook mandates a tree-scoped absence pin but said nothing about declaring the radius that pin walks, so the mandated shape produces a test whose inputs turbo does not hash: a resurrection outside the package's declared globs neither puts the suite into `turbo ls --affected` nor moves the `test` task's cache key, and a cached green can replay over the scan. The rule gains its declaration half: the radius is declared once per package in `CROSS_PACKAGE_TEST_INPUTS`, with the `heldBy` witness the loop-variable walk needs and the matching `turbo.json` inputs, and a pin whose radius is undeclared is not a finished retirement. Paid for under the file's line ceiling by tightening three adjacent bullets in the same section; no prohibition dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Contributor
Author
|
For the approvers: the mechanical half this rule points at — the gate cannot yet red an undeclared tree-scoped walk inside an already-declared package — is filed as #15565 (routed to the devx lane), with the measurement and the grammar gap attached. This PR is the playbook rule only; Generated by Claude Code |
os-zhuang
approved these changes
Sep 5, 2026
os-zhuang
marked this pull request as ready for review
September 5, 2026 01:27
os-zhuang
enabled auto-merge
September 5, 2026 01:28
os-zhuang
deleted the
claude/issue-15528-retirement-pin-declared-radius
branch
September 5, 2026 01:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #15528
The retirement playbook mandates a ⭐ tree-scoped absence pin but says nothing about declaring the radius that pin walks. The mandated shape therefore produces a test whose real inputs are wider than its package and which neither CI scoping layer can see: the walk descends on a loop variable, so the cross-package gate resolves the ESCAPE and not the NAME, and nothing puts the suite into
turbo ls --affectedor moves thetesttask's cache key. This adds the declaration half to the rule.One file changes.
.claude/skills/spec-property-retirement/SKILL.md, net 0 lines (337 of 337, ceiling unchanged, table-row pin unchanged at 328/326).Before → After, per hunk
heldBywitness and matchingturbo.jsoninputs; an undeclared radius is not a finished retirementcontent/docs/releases/and the grep rule kept verbatimcheck:generatedThe four new lines pay for themselves out of three adjacent bullets in the same section. No prohibition was dropped — every ⛔ in §4 before this change is present after it.
The rule added, verbatim:
(The real line spells the placeholder with angle brackets; it is written here without them because GitHub's body sanitizer eats short bracketed fragments.)
The declaration entry does NOT land, and this is a measurement rather than a decision
The plan for this PR carried a second half: one entry in
CROSS_PACKAGE_TEST_INPUTSfor@objectstack/spec's retirement pins, spelling the radius those pins actually walk. There is no such radius to declare onmaintoday.All 18
*-retirement.test.tsfiles inpackages/specwere read. Every one of them is package-scoped or narrower — the walkers seedpath.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), which ispackages/spec/src, and the rest are file- or directory-scoped:Confirmed independently against the gate's own roster:
check-cross-package-test-inputs.mjs --list-escapeslists 24 escaping tests for@objectstack/spec, and not one of them is a retirement pin.Declaring a radius anyway was tried and measured, not assumed. Adding
examples/**andapps/**to spec's entry — one bare, one with aheldBywitness namingmessage-queue-retirement.test.ts— turns the gate RED twice, and the second failure names the witness explicitly:The tree-scoped pin the review was written against is not on
main— it is in the draft PR that surfaced this, and the new playbook rule is what obliges that PR (and every retirement after it) to declare its radius when it lands. The file was restored byte-identically after the experiment (git diff HEADempty, blob back todff68eb11).How a declaration reaches turbo: HAND-KEPT, not derived
Asked as a question and answered by measurement, because the answer decides who owns the second half.
turbo run test --filter=@objectstack/spec --dry-run=json, three trees:examples/**hashedmain+ this PRacc4d78a7454c5af7955bd936f5d6405turbo.jsoninputc290a0ea05ac4c47The declaration alone moves nothing in turbo's input set. The task hash does change on that middle row, and the reason is worth stating so nobody reads it as derivation: the declaration file lives at
scripts/cross-package-test-inputs.mjs, andscripts/**is already one of spec's declared globs, so editing it perturbs the hash the same way editing any other declared input would. The input SET is identical — same 2875 files, same 16 globs.The linkage is hand-kept:
check-cross-package-test-inputs.mjsreadsturbo.jsonand requires each declared glob to appear as$TURBO_ROOT$/GLOBin thePKG#testtask'sinputs, printing the exact array to paste when it does not. That is why the new playbook line namesturbo.jsonalongside the table — a declaration written without it is a red gate, not a hashed radius.⇒ The devx-lane half, when the first tree-scoped pin lands. Its declaration will need these exact lines added to
turbo.json's@objectstack/spec#testinputs, one per declared glob, in the existing$TURBO_ROOT$/spelling:Does the gate now red on an undeclared tree-scoped pin? No — the playbook rule is the only hold
Stated plainly because the honest answer is the less satisfying one. This PR changes no judging logic (deliberately, and it was out of scope), so the gate behaves exactly as before: for a package that already carries a declaration, an added tree-scoped walk is invisible to all five of
verify()'s limbs. A loop-variable descent names no literal, so the "uncovered literals" limb sees nothing; it adds no glob, so the holder andturbo.jsonlimbs see nothing; and the package-level limbs are already satisfied by spec's other 24 escaping tests.The prose rule is therefore the whole enforcement. The gate change that would make it mechanical — assert on the SEED's escape depth, which the resolver already computes and keeps even when it cannot recover the name — has been filed as a standalone
findingcard for triage, and deliberately not made here.Verification
Gate verdict lines, read from each gate's own output (exit codes captured before any pipe), at
8e18931dd:The 19 test files are all 18
packages/specretirement pins plusretired-key-migrate-sentence.test.ts, which reads this playbook as one of its two judged corpora and is the test that would fail if the edit disturbed the prescription-sentence rules in §2.The full derived gate family for this change set (17 commands,
dispatch-gates.mjs --repo objectstack-ai/objectstack) was run and reconciled. Two returned non-zero and neither is a finding: the required-set sweep classified the ENVIRONMENT (exit 2,HTTPS_PROXYwithout--use-env-proxy; re-run through the proxy, exit 0, report-only by design), and the formula doc gate exited 3 PREREQUISITE NOT MET twice until@objectstack/formulaand@objectstack/lintwere built, after which it exits 0.This is a GOVERNED surface (
.claude/**), so it stays a draft and a human merge is the review record. No changeset: nothing here is published from a package.🤖 Generated with Claude Code
https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Generated by Claude Code