tooling(devx): the role-word NEW-use message names the pure-relocation case - #15933
Merged
os-project-manager merged 1 commit intoSep 5, 2026
Merged
Conversation
…n case The baseline is path-keyed, so splitting or moving a baselined file re-addresses its occurrences without adding one: the run reports them as NEW use at the new paths and a ratchet-DOWN at the old one, and the only remedy offered for the first half is the MAINTAINER-ONLY path whose warning is written for a genuine new boundary. Nothing in the message told those two cases apart, so the argument that a relocation is safe was re-derived by hand, by the author and again by the reviewer, every time. The message now names the case, states its recognition signal (a ratchet-DOWN row in the same run whose counts account for the NEW-use rows) and the evidence a reviewer checks (a baseline diff touching only those paths, the old row removed and the new rows summing back to it). Wording only. The verdicts, the accept set and the ratchet's strength are unchanged, and the clause says in writing that the gate will not net the two halves against each other and why: the ratchet is keyed to WHERE the word is, so a file that gains an occurrence while a sibling loses an unrelated one has to stay distinguishable from a move. The clause is generic for the same reason - naming the actual old path and its counts would mean pairing NEW-use rows with vanished baseline rows and summing across files, which is that refused verdict arriving as advice. The two ratchet-DOWN messages become named pure functions, the way grewMessage already is, so the coupling the clause creates is reachable from the self-test; their emitted text is byte-identical. A new self-test battery of seven pins the wording, including the refusal itself and the example diff's arithmetic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vtdMao3dQS9EfQfpyWixd
os-project-manager
marked this pull request as ready for review
September 5, 2026 15:22
os-project-manager
enabled auto-merge
September 5, 2026 15:22
os-project-manager
deleted the
claude/issue-14659-role-word-update-message-split-case
branch
September 5, 2026 15:47
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 #14659
Direction is the re-triage ruling on the card (comment
5542584859): option 2 only —amend the message, do not teach the gate a relocation verdict. This is a text change.
The gate's accept set, its verdicts and its ratchet strength are unchanged, and
scripts/role-word-baseline.jsonis neither in scope nor written.The friction
scripts/role-word-baseline.jsonis keyed by file PATH, so a split or move re-addressesoccurrences without adding one. The run then reports the moved occurrences as NEW use at
their new paths and a ratchet-DOWN at the old path — and the only remedy offered for
the first half is the one the message marks MAINTAINER-ONLY, whose warning is written for
a genuine new boundary. Nothing told those two cases apart, so the argument that a
relocation is safe was re-derived by hand, by the author and again by the reviewer.
What changed
The NEW-use message gains a closing clause that names the case, its recognition signal and
its evidence. Verbatim, as the author now reads it:
Two supporting edits, both in service of pinning that text:
grewMessagealreadyis. The clause quotes one of them as the author's recognition signal, so the coupling has
to be reachable from the self-test — a re-typed fixture would prove nothing. Their
emitted text is byte-identical (evidence below).
newUseOfferNamesRelocation()joinsratchetRemedyCarriesAuthority()as a predicate onthe same offer detector, so the convention is "a message that offers the
baseline-expanding path must also name the one case that path is wrong for", and the
self-test can prove the predicate discriminates instead of approving every long message.
The one thing the ruling asked to establish first
The ruling said to check whether the gate can already tell — whether it could print the
SPECIFIC form naming the old path and its counts — and warned that adding cross-file
bookkeeping to make that possible is option 1 arriving through the back door.
Measured: it cannot, and must not be made to.
newUseMessage(file, count)is pure over onefile. To name the old path and assert the total held, the gate would have to pair NEW-use
rows with vanished baseline rows and sum across files — the refused verdict arriving as
advice, computed in the same place and believed the same way. So the clause is generic:
it states the test, and the author states the answer in the diff where a reviewer can check
it. The clause says the refusal out loud, and the self-test pins that sentence, because the
risk this wording carries is not that it disappears but that a later edit softens it into
an apology for the gate.
Evidence
Premise re-verified before writing. A sandbox tree reproducing the card's split (a
baselined file at 2, both lines moved byte-identically into two new paths under a new
rules/dir) reports exactly the three rows the card records, with the wording intact:Verdict-identical. Same sandbox, before and after:
3 problem(s)and exit 1 both times;the ratchet-DOWN row diffs clean; the NEW-use text is byte-identical up to the splice point.
On the real tree
node scripts/check-role-word.mjsexits 0 (236 files, 44 baselined).Self-test. A new battery of seven, declared in
SELF_TEST_BATTERIESwith the rosterfloor raised 12 to 13. Ablation, each leg committed-then-mutated with the mutation proven on
disk (deleted-text count 0, injected-text count 1) and each restore proven by an empty
git diff HEADplus a blob hash equal to HEAD's:An earlier attempt at leg A was a no-op — its anchor spanned a source line break, so the
replacement matched nothing and the self-test stayed green. That reading is discarded as NOT
MEASURED, not as a pass; the leg above is the redo against the real source spelling.
Gates.
node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstackderived 31 commands on the final one-file list; results and the--ranreconciliation are in the report comment on the card. Governed-surface predicatere-evaluated on the final list against
GOVERNED_SURFACES: 0 of 5 rows hit, so this is anordinary draft PR.
Changeset: none,
skip-changeset. Rule applied: a changeset is required for anythingthat publishes, and the label is for a diff that publishes nothing from any released
package.
scripts/is not a workspace package, andlint.ymlnames this very shape — "thisPR edits a CI-internal script" — as the textbook case for the label.
On the reserved word in this PR. The gate's ROOTS are
content/docsandskills, soscripts/**is outside its population and the words added to the message are not scanned —proven by the green run above rather than assumed. Nothing was silenced.
Out of scope and not addressed here: #14296 and #14300 are referenced only as background.
🤖 Generated with Claude Code
https://claude.ai/code/session_016vtdMao3dQS9EfQfpyWixd
Generated by Claude Code