feat(docs-hygiene): add container-position pattern forms to rename-references - #1335
feat(docs-hygiene): add container-position pattern forms to rename-references#1335kyle-sexton wants to merge 3 commits into
Conversation
…ferences Six stale references survived three sweep passes during the re-anchor -> discipline plugin rename. All six were two syntactic shapes the pattern library did not cover, and the gap is structural rather than incidental: Forms 1-12 all assume the renamed token is a skill or mode identifier. When a CONTAINER renames, the token also occupies positions none of them reach. Form 1 anchors on `/<old>`, so it cannot fire on `/plugin configure <old>` where the slash belongs to `plugin` and the token sits downstream in argument position. Form 3 needs a path. Form 2 matches, but cannot separate the container sense from the verb sense at any triage setting when the token is also a verb in the consuming codebase. Forms 13-15 anchor on syntax that admits only the naming sense: a management verb immediately before the token, a `$`-anchored heading whose entire content is the token, and the possessive clitic or a noun-class appositive. Each stays Certain regardless of blocklist membership. Validated on both axes against the real fixture rather than asserted. Recall came from the removed lines of the commit that fixed the references; precision from the whole pre-fix tree. Over that tree, bare-token Form 2 matched 134 lines for 8 real defects; Forms 13-15 matched 9 -- the 8 defects plus one frozen CHANGELOG-history line the existing rule already excludes. Phase 6 now requires that both-axis validation for any future form, because recall alone is not evidence: Form 2 already has perfect recall on every form in the library and is still unusable. triage.md records why extending the English-verb blocklist is the wrong remedy for this collision class. The blocklist holds tokens that are verbs in general; a token that is a verb in the consuming codebase fails both ways -- omitted, every hit is rated Certain; added, every hit lands ambiguous and per-match confirmation turns a handful of defects into hundreds of prompts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSXnCLnmzk8y4cKv2y1z9f
|
Claude finished @kyle-sexton's task in 3m 5s —— View job PR Review — feat(docs-hygiene): container-position pattern forms 13–15
SummaryWell-motivated, well-documented, and the measurement story (134 Form-2 hits vs 9 Forms-13–15 hits for 8 real defects) is stated consistently across patterns.md, triage.md, and the CHANGELOG. The blocking items from REVIEW.md (injection, secrets, authorization, atomicity) are not applicable to this documentation-only change. Four minor issues noted below. Findings🟡 Nit 1 — Form 14 misses single-quoted YAML frontmatter
🟡 Nit 2 — Form 15 possessive misses backtick-wrapped token In markdown documentation, the token frequently appears in inline code before the possessive clitic: 🟡 Nit 3 — Eval 7 prompt has a stray colon after "prompt": "... every /re-anchor: invocation is updated ..."The colon after 🟡 Nit 4 — Form 14 uses a capturing group where a non-capturing group suffices
What looks right
|
|
Claude finished @kyle-sexton's task in 1m 15s —— View job Security Review — PR #1335
No security vulnerabilities found. All six changed files are documentation and configuration — markdown context files and a JSON eval set. There is no executable code, no GitHub Actions workflow, no credential handling, and no network call introduced by this PR. Detailed findings by surface:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ceeb0b9634
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Extending the blocklist is therefore the WRONG remedy here; it swaps one unusable bucket for | ||
| another. The remedy is position: `patterns.md` Forms 13–15 anchor on syntax that only the | ||
| container sense can occupy (argument-to-a-management-command, a heading that IS the token, the | ||
| possessive clitic), so they stay Certain regardless of blocklist membership. |
There was a problem hiding this comment.
Suppress Form 2 when using container-position matches
Forms 13–15 cannot provide the claimed remedy while every sweep still runs Form 2. For the exact codebase-specific verb scenario described here, leaving the token off the blocklist makes hundreds of ordinary verb uses Form-2 Certain matches, while adding it still produces hundreds of mandatory ambiguous prompts; the new position matches neither suppress nor replace those results. The top-level skill also says blocklisted tokens are ambiguous regardless of regex position. Define container-sweep scoping or explicit match precedence/deduplication so only the position-anchored occurrences take the Certain path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
CONFIRMED — P1 was correct, and it invalidated this change's own claim. Fixed in 595fff52.
The critique is exact: Forms 13–15 were sold as the remedy for a codebase-specific verb, but nothing suppressed Form 2. Every line the new forms caught was ALSO still a Form 2 hit, so the prompt flood they exist to avoid remained fully intact. They only added a lens. You also correctly caught the internal contradiction — patterns.md Phase 0 says blocklisted tokens go ambiguous regardless of regex position, which contradicts the Certain rating I gave the new forms.
Added container-position precedence in patterns.md Phase 0:
- Forms 13–15 are strictly more specific than Form 2 — every line they match, Form 2 matches too. That containment is what licenses precedence rather than mere addition.
- Deduplicate by
(file, line)after the sweep, before triage. A line matched by 13–15 is attributed to that form and enters Certain; its Form 2 / chain-form duplicate for the same line is dropped as the same reference seen through a weaker lens, not a second finding. - Only lines the container forms did NOT match fall through to the blocklist rule — so Phase 0 is now scoped to what actually reaches Form 2, resolving the contradiction rather than papering over it.
audit.mdSurvey phase applies the dedup before Phase 3, and the report carries a "Form-2 hits superseded by container-position matches" count so the suppression is visible rather than inferred.
Measured effect on the same fixture: the sweep still RUNS Form 2 and still collects its 134 lines. Precedence turns those into 8 Certain container-position findings plus 126 ordinary verb uses that were never candidates, instead of 134 confirmation prompts.
Eval 9 was added to hold the behavior: dedup happens before triage, the bare-token duplicate is dropped, the superseded count is reported, and verb uses are not surfaced as candidates.
| ^#{1,6}\s+`?<old>`?\s*$ | ||
| ^(name|title):\s*"?<old>"?\s*$ |
There was a problem hiding this comment.
Match single-quoted declared names
When valid YAML frontmatter uses a single-quoted declaration such as name: 're-anchor', Form 14 does not match because this expression only permits optional double quotes. Form 2 will still see the token, but for the verb-collision case motivating this change it takes the unsafe or high-friction bare-token path, so the declared-name position is not actually covered. Accept paired single quotes as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
CONFIRMED — fixed in 595fff52. Verified against real input rather than taken on assertion:
name: 're-anchor' old regex: MISS new: MATCH
name: "re-anchor" old: MATCH new: MATCH
name: re-anchor old: MATCH new: MATCH
One refinement on the suggested shape. ["']?<old>["']? also matches the mismatched form name: "re-anchor', which is not valid YAML — a pattern that accepts invalid input to catch valid input is a false-positive source. Used a paired alternation instead:
^(name|title):\s*("<old>"|'<old>'|<old>)\s*$Confirmed name: "re-anchor' is correctly rejected. The quote-pairing requirement is now documented on the form.
Your reasoning also applies to Form 15, which the second reviewer caught independently and you implicitly cover — I fixed that in the same commit. In markdown the token is usually a code span, so the literal <old>'s sequence never appears; it is `<old>` followed by 's. Form 15 therefore missed its own motivating example (Report `re-anchor`'s effective configuration). Now `?\b<old>\b`?'s\b, verified to match both the backticked and bare forms while still rejecting the verb use each skill re-anchors ONE discipline.
…rm 2 flood The P1 review finding is correct and it invalidated this change's own claim. Forms 13-15 were added as the remedy for a token that is a verb in the consuming codebase, but nothing suppressed Form 2 — so every line the new forms caught was ALSO still a Form 2 hit, and the prompt flood the forms exist to avoid remained fully intact. The forms only added a lens. Precedence is what makes the remedy real. Forms 13-15 are strictly more specific than Form 2: every line they match, Form 2 matches too. The sweep now deduplicates by (file, line) after collecting and before triage — a container-position match takes the Certain path and its bare-token duplicate for that line is dropped as the same reference seen through a weaker lens, not a second finding. Only lines the container forms did not match fall through to the blocklist rule. On the measured fixture the sweep still runs Form 2 and still collects its 134 lines; precedence turns those into 8 Certain container-position findings plus 126 ordinary verb uses that were never candidates, rather than 134 confirmation prompts. The audit report carries the superseded count so the suppression is visible rather than inferred. Two regex gaps from the same review, both verified against real input before and after: - Form 14 missed single-quoted YAML (`name: '<old>'`). The fix uses a paired alternation rather than `["']?`, which would have matched the invalid mismatched form `"<old>'`. - Form 15 missed the token as inline code before the clitic. In markdown that is the common case, not the exception — when the token is a code span the literal `<old>'s` sequence never appears, so the form missed its own motivating example. Eval 7's prompt said "every /re-anchor: invocation", where the bare trailing colon reads as a malformed invocation; it now names the qualified `/re-anchor:<skill>` form. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSXnCLnmzk8y4cKv2y1z9f
|
Claude finished @kyle-sexton's task in 2m 18s —— View job PR Review — feat(docs-hygiene): container-position pattern forms 13–15
The fix commit ( What the fix commit correctly addressesCodex P1 — Form 2 suppression ✅ The Phase 0 rule added to Codex P2 / Nit 1 — Form 14 single-quoted YAML ✅
The paired-quote alternation is the correct approach. The added prose note ("A naive Nit 2 — Form 15 backtick before possessive ✅ Tracing Nit 3 — Eval 7 prompt stale colon ✅
One remaining item🟡 Nit 4 — Form 14 still uses a capturing group (unaddressed from first review) Both groups are capturing ( This is the only open item. It is low-severity (ripgrep itself ignores unused capture groups and the patterns work correctly as written), but fixing it now keeps the library internally consistent with the non-capturing convention. What looks right (fix commit)
|
|
Claude finished @kyle-sexton's task in 1m 33s —— View job Security Review — PR #1335
No security vulnerabilities found. All six changed files are documentation and configuration — markdown context files, a JSON eval set, and a manifest version bump. Detailed findings by surface:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 595fff52de
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| 1. A `(file, line)` matched by any of Forms 13–15 is attributed to that form and enters the | ||
| **Certain** bucket. Drop the Form 2 (and any chain-form) match for that same line — it is | ||
| the same reference seen through a weaker lens, not a second finding. | ||
| 2. Only lines Forms 13–15 did NOT match fall through to Form 2's blocklist rule above. |
There was a problem hiding this comment.
Scope Form 2 out of container-only sweeps
When <old> is a codebase-specific verb absent from the static blocklist, this still sends every line not matched by Forms 13–15 through Form 2, whose default is Certain. Fresh evidence in the newly added precedence rule is that it suppresses Form 2 only on the same (file, line) as a container match; in the documented re-anchor fixture, the other 126 ordinary verb lines therefore remain Certain auto-apply candidates rather than becoming “never candidates” as claimed. Explicitly filter unmatched Form-2 hits for container-only sweeps instead of merely deduplicating container-hit lines.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
CONFIRMED — you are right, and my previous reply overclaimed. Fixed in a5686a1b.
I wrote that precedence turned the 126 lines into "ordinary verb uses that were never candidates." Nothing in the precedence rule made that true. Deduplicating by (file, line) only helps lines a container form ALSO matched — 8 of 134 on the fixture. The remaining 126 fell straight through to Form 2 at its Certain default, exactly as you describe.
Added container-rename mode (patterns.md Phase 0b) rather than a wider dedup, because the residue is not an overlap problem:
- The sweep declares a MODE at Phase 0, decided by WHAT is being renamed.
- Container rename (plugin, marketplace entry, package): the renamed thing is a proper name, so a bare-token occurrence is evidence of nothing — as likely the ordinary word as the container. The residue is excluded from Certain regardless of blocklist membership, reported as one aggregate count ("126 bare-token occurrences not in container position, not proposed"), and surfaced only behind an explicit
--include-bare-token, then as Ambiguous. - Identifier rename (skill, mode, dotted ID): unchanged, every form applies as before.
Mode works where the static blocklist cannot because it is a property of the rename, not of whether anyone remembered to list the token in advance — which was the original complaint in triage.md that this PR set out to answer, and which my first attempt only half-answered.
Fixture with mode + precedence: 8 Certain findings, 126 reported-not-proposed, 0 confirmation prompts, against Form 2 unaided at 134. audit.md runs both rules before Phase 3 and carries both counts. Eval 10 holds the behavior, including that dedup alone is not sufficient.
| ## Form 14: Document title / declared name | ||
|
|
||
| ```regex | ||
| ^#{1,6}\s+`?<old>`?\s*$ |
There was a problem hiding this comment.
Restrict title matches to container-owned documents
When the renamed container has a generic name, this pattern promotes every exact heading with that word to Certain even when the heading names a concept or catalog category rather than the container. For example, renaming the testing plugin in this repository also matches README.md:86 (### Testing), the marketplace category heading, while renaming architecture matches the unrelated Architecture section in plugins/miro/README.md; precedence then discards the safer Form-2 classification and these become auto-apply candidates. Constrain this form to known container-owned title files or demote headings without container context.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
CONFIRMED — verified both examples against this repository before fixing. Fixed in a5686a1b.
README.md:86 ### Testing <- marketplace category heading
plugins/miro/README.md:39 ## Architecture <- unrelated design section
And both testing and architecture are real plugin names in marketplace.json, so the collision is live, not hypothetical.
Form 14's stated premise — "a heading that IS the token can only be naming it" — holds for a coined or hyphenated name like re-anchor and fails for an ordinary-word one. I generalized from the fixture, which had only the former.
Your point about precedence making it worse is the sharp end of it, and I want to name it explicitly: without precedence a bad title match is one Certain hit competing with a Form 2 hit on the same line. With precedence it DISCARDS the safer Form 2 classification, so the false positive is laundered into an auto-apply candidate. The mechanism I added in the prior commit is what raised the stakes on this form's over-reach.
Scope rule added to Form 14:
- Certain only when the file is plausibly container-owned — the container's own README/SKILL/manifest, or a path under its directory.
- A heading match in a file the container does not own is Ambiguous, whatever the token looks like.
- When the token is a common English word, every title match is demoted to Ambiguous regardless of path.
The false-positives field now carries both verified examples with their line numbers rather than the "effectively none" I originally wrote, which was wrong. Eval 11 uses your testing case directly.
The second P1 is correct: precedence resolved the overlap but left the residue. Deduplicating by (file, line) only helps lines a container form ALSO matched — 8 of Form 2's 134 on the measured fixture. The other 126 are ordinary verb uses no container form touches, so they still fell through to Form 2's Certain default. My claim that they "were never candidates" was wrong; nothing in the precedence rule made that true. The sweep now declares a MODE at Phase 0, decided by what is being renamed. For a container — a plugin, a marketplace entry, a package — the renamed thing is a proper name, so a bare-token occurrence is evidence of nothing: as likely the ordinary word as the container. In that mode the residue is excluded from Certain regardless of blocklist membership, reported as one aggregate count rather than per-match prompts, and surfaced only behind an explicit widen and then as Ambiguous. Mode succeeds where the blocklist cannot because it is a property of the rename, not of whether someone remembered to list the token in advance. The second finding is also real, and worse under precedence. Form 14's premise — "a heading that IS the token can only be naming it" — holds for a coined or hyphenated name and fails for an ordinary-word one. Verified against this repository: renaming a `testing` plugin matches README.md:86 (`### Testing`, a marketplace category heading), and renaming `architecture` matches plugins/miro/README.md:39 (`## Architecture`, an unrelated design section). A false Certain there is worse than a plain Form 2 hit, because precedence discards the safer classification. Title matches are now Certain only in plausibly container-owned files, and always Ambiguous when the token is a common English word. Fixture result with mode and precedence together: 8 Certain findings, 126 reported-not-proposed, 0 confirmation prompts, against Form 2's unaided 134. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSXnCLnmzk8y4cKv2y1z9f
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5686a1b2d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| 1. A `(file, line)` matched by any of Forms 13–15 is attributed to that form and enters the | ||
| **Certain** bucket. Drop the Form 2 (and any chain-form) match for that same line — it is | ||
| the same reference seen through a weaker lens, not a second finding. |
There was a problem hiding this comment.
Preserve Form 14's demoted classification during precedence
When Form 14 matches a title outside a container-owned document or matches a common-word name, its new scope rule says to demote it to Ambiguous, but this precedence step still unconditionally sends every Form 13–15 match to Certain and drops the safer Form 2/chain classification. Fresh evidence after the earlier title-scope finding is this unconditional instruction, which conflicts directly with the added remedy and can still auto-apply unrelated headings; preserve Form 14's computed bucket while deduplicating.
Useful? React with 👍 / 👎.
|
|
||
| ```regex | ||
| ^#{1,6}\s+`?<old>`?\s*$ | ||
| ^(name|title):\s*("<old>"|'<old>'|<old>)\s*$ |
There was a problem hiding this comment.
Match JSON manifest name declarations
For a plugin/package container rename where plugin.json or package.json still contains "name": "<old>", this declared-name expression does not match because it only accepts YAML-style name: or title: keys. Container mode then removes the remaining Form 2 occurrence from the candidate set, so the default audit misses the canonical manifest identity even though the scope rule explicitly treats manifests as container-owned; add the JSON declaration shape as a position-anchored match.
Useful? React with 👍 / 👎.
| ## Form 14: Document title / declared name | ||
|
|
||
| ```regex | ||
| ^#{1,6}\s+`?<old>`?\s*$ |
There was a problem hiding this comment.
Make title matching tolerate display capitalization
When a lowercase container name is capitalized in a heading, such as the documented testing → ### Testing case, this case-sensitive regex does not match, and container mode suppresses the bare-token fallback. Consequently the new Form 14 scope/demotion behavior and eval cannot run for a common Markdown title convention; perform case-insensitive matching for headings while retaining exact matching where identifier declarations require it.
Useful? React with 👍 / 👎.
| 3. Surface the residue only if the user explicitly asks to widen (`--include-bare-token`), | ||
| and then as Ambiguous, never Certain. |
There was a problem hiding this comment.
Register the bare-token widening flag
When a user follows this instruction and passes --include-bare-token, the top-level router rejects it because SKILL.md and audit-modes.md enumerate only three override flags and explicitly error on unknown flags. That leaves no usable way to inspect the residue that container mode intentionally hides; add this flag to the argument hint, override parser, and mode documentation or describe a widening mechanism the router already accepts.
Useful? React with 👍 / 👎.
|
Superseded by #1386. Closing rather than updating: #1386 carries this PR's content unchanged plus the rebase resolution — 0.9.0 stacked above main's 0.8.7 entry, both retained. All four review findings from this PR (both P1s and both P2s) are already applied in the commits it carries; the review history here is the record of how they were verified and fixed. |
…ferences (#1386) Closes #1283 ## Summary Six stale references survived three sweep passes during the `re-anchor` → `discipline` plugin rename (#1276). All six were two syntactic shapes `rename-references`' pattern library did not cover, and the gap is structural rather than incidental: **Forms 1–12 all assume the renamed token is a skill or mode identifier.** When a CONTAINER renames — a plugin, a marketplace entry — the token occupies positions none of them reach: - **Form 1** anchors on `/<old>`, so it cannot fire on `/plugin configure <old>`: the slash belongs to `plugin`, and the token sits downstream in argument position. - **Form 3** needs a path; none of these are paths. - **Form 2** (bare token) matches, but cannot separate the container sense from the verb sense at any triage setting when the token is also a verb in the consuming codebase. Forms 13–15 anchor on syntax that admits **only** the naming sense: | Form | Position | Why it is Certain | |---|---|---| | 13 | Command argument — `/plugin install <old>@mkt`, `/plugin configure <old>` | A management verb immediately precedes the token; prose does not say "/plugin configure" before an English verb | | 14 | Document title — `# <old>`, frontmatter `name:` | The `$` anchor: a heading that *contains* the token may be verb usage, but one that IS the token can only be naming it | | 15 | Possessive / appositive — `<old>'s`, `the <old> plugin` | English verbs do not take the possessive clitic; the noun-class appositive forces the naming reading | Command-argument hits are flagged as **functional breaks**, not cosmetic: a reader following `/plugin install <old>@marketplace` gets `plugin-not-found`. Four of the six missed references were this shape, including the README's own install block. ## Fix - `context/patterns.md` — Forms 13–15, each with the five documented fields the existing forms carry, under a short section explaining why container position is its own class. - `context/triage.md` — records the collision class the English-verb blocklist **cannot** serve. The blocklist holds tokens that are verbs *in general*; a token that is a verb *in the consuming codebase* fails both ways: omitted → every bare-token hit is rated Certain and the sweep proposes rewriting the verb uses; added → every hit lands ambiguous, where the per-match confirmation rule turns a handful of real defects into hundreds of prompts. Extending the blocklist swaps one unusable bucket for another. The remedy is position. - `context/patterns.md` Phase 6 — now requires validating any new form on **both** axes. Recall alone is not evidence: Form 2 already has perfect recall on every form in the library and is still unusable. - `context/audit.md` — pattern-form breakdown lists 13–15, so an audit report accounts for every form the sweep runs. - Seven eval cases (7-13): the container-rename sweep, and the blocklist-extension trap. ## Verification Validated on **both** axes against the real fixture rather than asserted. Recall came from the removed lines of `930c97a4` (the commit that fixed the references — its deletions *are* the defect set); precision from the whole pre-fix tree at `930c97a4^`. | Pattern | Hits on `930c97a4^` under `plugins/discipline` | Real defects among them | |---|--:|--:| | Form 2 (bare token) | **134** | 8 | | Forms 13–15 combined | **9** | 8 | The 9th hit is a frozen CHANGELOG-history line, which the existing "Frozen historical records" auto-exclusion already handles. The one defect line Forms 13–15 do *not* match is the frontmatter `description` trigger-phrase block — deliberately kept in that rename, so matching it would have been a false positive. Gates run locally: - `claude plugin validate .` — passes - `markdownlint-cli2` on all four changed markdown files — 0 errors - `scripts/check-changelog-parity.sh --check-bump origin/main` — passes (`docs-hygiene` 0.8.6 → 0.9.0 with a matching entry) - `scripts/check-changelog-parity.sh --check` — passes - `evals.json` parses; diff is additive only (25 insertions, 0 deletions to existing cases) ## Review rounds (this PR supersedes #1335 for branch reasons only — same work, rebased) Four findings across two reviewers, all verified against real input before fixing; two were correct about defects in **this PR's own claims**: - **P1 — Form 2 was never suppressed.** The first version added Forms 13–15 as the remedy for a codebase-specific verb, but nothing suppressed Form 2, so every prompt they were meant to avoid still fired. Fixed by container-position precedence: dedup by `(file, line)` after the sweep, before triage. - **P1 (second round) — precedence left the residue.** Dedup only resolves lines a container form ALSO matched (8 of 134 on the fixture). The other 126 still fell through to Form 2's Certain default, so my claim that they "were never candidates" was false. Fixed by container-rename mode: mode is decided by WHAT is renamed, so it works where the static blocklist cannot. - **P2 — Form 14 over-reached on ordinary-word names.** Verified in this repo: renaming a `testing` plugin matches `README.md:86` (`### Testing`), renaming `architecture` matches `plugins/miro/README.md:39`. Under precedence a false Certain there is worse than a Form 2 hit — it discards the safer classification. Form 14 is now scoped to container-owned files and always Ambiguous for common-word tokens. - **P2 — regex gaps.** Form 14 missed single-quoted YAML; Form 15 missed the token as inline code before the clitic (its own motivating example). Both fixed with paired-quote alternation and optional backticks, verified against real input including the mismatched-quote rejection case. Final fixture result: **8 Certain findings, 126 reported-not-proposed, 0 confirmation prompts**, against Form 2 unaided at 134. ## Related - Refs #1394 — filed from this PR's review: Form 14 is case-sensitive, so a title-cased heading falls through to Form 2 and gets a LESS safe classification. Deliberately not fixed here — the safe version needs the scope rule load-bearing first. - Refs #1335 — the original PR for this work; closed unmerged because a force-push was needed after main moved and force-push is blocked in this environment. Identical content, rebased. - Refs #1276 — the rename whose six missed references are this PR's fixture; `930c97a4` is the reference commit 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GSXnCLnmzk8y4cKv2y1z9f --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #1283
Summary
Six stale references survived three sweep passes during the
re-anchor→disciplineplugin rename (#1276). All six were two syntactic shapesrename-references' pattern library did not cover, and the gap is structural rather than incidental: Forms 1–12 all assume the renamed token is a skill or mode identifier.When a CONTAINER renames — a plugin, a marketplace entry — the token occupies positions none of them reach:
/<old>, so it cannot fire on/plugin configure <old>: the slash belongs toplugin, and the token sits downstream in argument position.Forms 13–15 anchor on syntax that admits only the naming sense:
/plugin install <old>@mkt,/plugin configure <old># <old>, frontmattername:$anchor: a heading that contains the token may be verb usage, but one that IS the token can only be naming it<old>'s,the <old> pluginCommand-argument hits are flagged as functional breaks, not cosmetic: a reader following
/plugin install <old>@marketplacegetsplugin-not-found. Four of the six missed references were this shape, including the README's own install block.Fix
context/patterns.md— Forms 13–15, each with the five documented fields the existing forms carry, under a short section explaining why container position is its own class.context/triage.md— records the collision class the English-verb blocklist cannot serve. The blocklist holds tokens that are verbs in general; a token that is a verb in the consuming codebase fails both ways: omitted → every bare-token hit is rated Certain and the sweep proposes rewriting the verb uses; added → every hit lands ambiguous, where the per-match confirmation rule turns a handful of real defects into hundreds of prompts. Extending the blocklist swaps one unusable bucket for another. The remedy is position.context/patterns.mdPhase 6 — now requires validating any new form on both axes. Recall alone is not evidence: Form 2 already has perfect recall on every form in the library and is still unusable.context/audit.md— pattern-form breakdown lists 13–15, so an audit report accounts for every form the sweep runs.Verification
Validated on both axes against the real fixture rather than asserted. Recall came from the removed lines of
930c97a4(the commit that fixed the references — its deletions are the defect set); precision from the whole pre-fix tree at930c97a4^.930c97a4^underplugins/disciplineThe 9th hit is a frozen CHANGELOG-history line, which the existing "Frozen historical records" auto-exclusion already handles. The one defect line Forms 13–15 do not match is the frontmatter
descriptiontrigger-phrase block — deliberately kept in that rename, so matching it would have been a false positive.Gates run locally:
claude plugin validate .— passesmarkdownlint-cli2on all four changed markdown files — 0 errorsscripts/check-changelog-parity.sh --check-bump origin/main— passes (docs-hygiene0.8.6 → 0.9.0 with a matching entry)scripts/check-changelog-parity.sh --check— passesevals.jsonparses; diff is additive only (25 insertions, 0 deletions to existing cases)Related
930c97a4is the reference commit🤖 Generated with Claude Code
https://claude.ai/code/session_01GSXnCLnmzk8y4cKv2y1z9f