Skip to content

docs(skills): make the retirement pin's walk radius a declared radius - #15566

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-15528-retirement-pin-declared-radius
Sep 5, 2026
Merged

docs(skills): make the retirement pin's walk radius a declared radius#15566
os-zhuang merged 1 commit into
mainfrom
claude/issue-15528-retirement-pin-declared-radius

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

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 --affected or moves the test task'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

Section Before After
§4 Pin tests the ⭐ rule ends at "absence assertions are not stale mentions" + 4 lines: the radius is declared once per package, with its heldBy witness and matching turbo.json inputs; an undeclared radius is not a finished retirement
§4 Docs 7 lines, 3 of them the release-notes conflict-magnet anecdote 5 lines; the prohibition on content/docs/releases/ and the grep rule kept verbatim
§4 check:generated 5 lines, ending in a two-card citation 4 lines; the measurement kept, the citation dropped
§4 corrections 4 lines 3 lines; the rule kept, one anecdote sentence dropped

The 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:

      ⭐ **半径按包申报一次**:写进 `scripts/cross-package-test-inputs.mjs` 的
      `CROSS_PACKAGE_TEST_INPUTS` 并配齐 `turbo.json` 的 `PKG#test` inputs,turbo 才
      hash 得到它、CI 分片并集才看得见;walk 降在循环变量上、门禁点不出名字,那条 glob
      还要一条 `heldBy` 证人。⛔ 半径未申报的 tree-scoped pin 不是完成的退役。

(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_INPUTS for @objectstack/spec's retirement pins, spelling the radius those pins actually walk. There is no such radius to declare on main today.

All 18 *-retirement.test.ts files in packages/spec were read. Every one of them is package-scoped or narrower — the walkers seed path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), which is packages/spec/src, and the rest are file- or directory-scoped:

packages/spec/src/data/external-lookup-retirement.test.ts:106     seed '..'
packages/spec/src/system/message-queue-retirement.test.ts:105     seed '..'
packages/spec/src/ui/interaction-config-retirement.test.ts:162    seed '..'
packages/spec/src/ui/widget-i18n-retirement.test.ts:155           dirname only
packages/spec/src/identity/api-key-retirement.test.ts:110         one named file

Confirmed independently against the gate's own roster: check-cross-package-test-inputs.mjs --list-escapes lists 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/** and apps/** to spec's entry — one bare, one with a heldBy witness naming message-queue-retirement.test.ts — turns the gate RED twice, and the second failure names the witness explicitly:

  - @objectstack/spec declares glob(s) nothing holds any more — no path its escaping tests
    name lands inside them, and no `heldBy` witness reads outside the package
    any more:
      examples/**
      apps/**   (witness no longer escaping: packages/spec/src/system/message-queue-retirement.test.ts)

  - turbo.json "@objectstack/spec#test" inputs are missing the declared glob(s):
      $TURBO_ROOT$/examples/**
      $TURBO_ROOT$/apps/**

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 HEAD empty, blob back to dff68eb11).

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:

Tree task hash hashed files resolved globs examples/** hashed
clean main + this PR acc4d78a7454c5af 2875 16 no
+ declaration entry only 7955bd936f5d6405 2875 16 no
+ matching turbo.json input c290a0ea05ac4c47 3150 17 yes

The 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, and scripts/** 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.mjs reads turbo.json and requires each declared glob to appear as $TURBO_ROOT$/GLOB in the PKG#test task's inputs, printing the exact array to paste when it does not. That is why the new playbook line names turbo.json alongside 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#test inputs, one per declared glob, in the existing $TURBO_ROOT$/ spelling:

        "$TURBO_ROOT$/GLOB",

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 and turbo.json limbs 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 finding card 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:

OK: 26 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
All 117 self-test cases passed.
✓ check-skill-line-ratchet: .claude/skills/spec-property-retirement/SKILL.md is 337 lines (ceiling 337; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/spec-property-retirement/SKILL.md: widest table row is 326 bytes (pin 328; headroom 2).
governed-surface predicate: 1 of 1 path(s) hit the register — GOVERNED (exit 3)
Test Files  19 passed (19) / Tests  89 passed (89)

The 19 test files are all 18 packages/spec retirement pins plus retired-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_PROXY without --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/formula and @objectstack/lint were 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

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
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
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; turbo.json is untouched by design (a declaration is hand-kept there, never derived — measured in the PR body).


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 5, 2026 01:27
@os-zhuang
os-zhuang enabled auto-merge September 5, 2026 01:28
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit 88bc10e Sep 5, 2026
36 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-15528-retirement-pin-declared-radius branch September 5, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants