feat(docs-hygiene): audit-noise gains three residue shapes (0.20.0) - #3162
Conversation
The code-side sibling /code-tidying:audit-comment-residue detects four residue shapes; audit-noise detected five noise shapes; the two sets did not tile the space. Only history-narration had a markdown counterpart (audit-noise's citation). plan-reference, conversational-antecedent, and ticket-pr-residue had no detector on either side, so a README or rule body saying "as you asked, retry three times" was invisible to the whole fleet -- a gap behind an otherwise correct boundary, not a skipped file type. The shapes go to audit-noise rather than widening the code skill to .md, because on a markdown line history-narration and citation would fire together with opposite rulings (delete vs. relocate to a Sources footer). Two owners for one line is a precedence problem; one owner per file type is not. The boundary is now explicitly by file type, with the three shape names deliberately shared. Patterns are adapted, not copied. The code lib classifies only the extracted comment portion of a line; this one classifies whole prose. Measured against this repo's 1136-file tracked-markdown corpus, four of the sibling's cues had to go: "per the plan" prefix-matches "per the planning chapter"; "as planned" is a substring of "was planned"; "in this change" and "in this session" are ordinary domain vocabulary here. "in this PR" now requires a first-person actor behind it, and "as we discussed" stands down before an anaphoric follower. Those tightenings cut the corpus delta from 32 findings to 12. ticket-pr-residue's carve-out is restated in markdown terms: a task-list checklist item and a TODO-family marker with a parenthesised reference are never flagged, because both denote outstanding tracked work. Nothing further is carved out -- the sanctioned home for a provenance citation is a Sources or History footer, which the existing section exemptions already skip. Refs #3125 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HigdNorttH9UCTeh5QdycM
|
Claude finished @kyle-sexton's task in 1m 18s —— View job Claude's todo list
Security reviewNo security-relevant surface in this diff. The change adds three regex-based prose classifiers ( Skip-gate condition 2 applies (change has no security-relevant surface after reading the diff) — reporting nothing further per the lane's high-signal bar. |
|
Last security-reviewed head: |
…arses
The 0.19.0 summary rewrite introduced a colon ("Classify markdown noise:
citations, ...") in an unquoted YAML scalar, which makes the frontmatter
invalid: a block-mapping value cannot contain ": ". check-hook-exec-form.sh
fails closed on frontmatter it cannot read and rejected the file.
skill-quality's check-skill.sh passed the same file, so the defect reached
CI: its frontmatter reader is lenient enough to return the value that a
strict YAML parse refuses. Quoting the scalar fixes the file; the reader
divergence is a separate finding.
Value unchanged at exactly 100 codepoints, still inside the summary cap.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HigdNorttH9UCTeh5QdycM
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d45c36f27
ℹ️ 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".
|
Claude finished @kyle-sexton's task in 53s —— View job Tasks
Security reviewSkip gate (condition 3) applies. The prior review on this PR already covered the full diff at The only change since that head is the single commit --- a/plugins/docs-hygiene/skills/audit-noise/SKILL.md
+++ b/plugins/docs-hygiene/skills/audit-noise/SKILL.md
@@ -7,7 +7,7 @@
metadata:
workflow-stage: anytime
- summary: Classify markdown noise: citations, ghost refs, meta-commentary, plan/conversational/tracker residue
+ summary: "Classify markdown noise: citations, ghost refs, meta-commentary, plan/conversational/tracker residue"This wraps a YAML frontmatter No security issues found. Nothing further to report per the lane's high-signal bar. |
|
Claude finished @kyle-sexton's task in 4m 19s —— View job Code review (
|
…llowers Two review findings on the 0.19.0 shape, plus the summary line the cheatsheet gate rejected on the previous push. The `in` exemption was a blanket: any antecedent whose next word was `in` stood down, so "as we decided in the ADR" was spared (right) alongside "as we decided in favor of X" and "as we discussed in yesterday's meeting" (wrong — the referent there is the conversation, not a document). The follower test now asks what the reference points AT: `in` stands the shape down only ahead of a document locator — a section sign or `#anchor`, a section/chapter/step/table, a link or path, an inline-code reference the strip removed, or a named durable document. Tracker nouns are deliberately absent, because a decision parked in an issue is provenance that ticket-pr-residue owns. Followers are compared case-insensitively; the other stop-words are unchanged. The actor-less passive "As requested, ..." matched nothing, because the pattern required `you` or `we`. It is now matched as a clause-final adverbial only, which keeps the live attribution "as requested by the client" and the ordinary verb phrase "was requested" out without a second pattern. `metadata.summary` is now a plain unquoted scalar with no colon. Quoting it made the cheatsheet reader count 102 codepoints and fail the plugin gate; that reader also rejects ": " outright, since an invalid frontmatter value makes Claude Code drop ALL frontmatter silently. Colon-free and unquoted is the only form the three readers agree on. Cheat sheet regenerated to match. Corpus sweep over the 1136 tracked markdown files is byte-identical before and after (T1=13 T2=42 T3=0), confirmed line-by-line against the old detector: zero disagreements. detect.test.sh is 87 checks, all passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HigdNorttH9UCTeh5QdycM
|
Claude has reviewed this PR 4 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
`plan-reference` and `conversational-antecedent` both required a literal space
directly after the first-person pronoun, so a contracted actor fell through
silently — "in this PR we've already switched the default" and "as we've
discussed, the timeout is 30s" are the exact narration and antecedent shapes
those rules target, and neither was flagged.
Unlike the follower tightenings that preceded it, this is not a precision/recall
trade. The discriminator in both patterns is the PRONOUN, not the verb behind
it, so admitting a contraction of that same pronoun adds no new false-positive
surface; it only stops the shape escaping on an apostrophe.
Both apostrophe forms are handled. Prose in this corpus frequently uses the
typographic right single quote `’` (U+2019), which most editors produce, so a
fix matching only `'` would have closed half the gap while looking complete.
They are spelled as literal ALTERNATIVES — `(\'ve|\'d|’ve|’d)` — never a
bracket class: `’` is multibyte, and a bracket class over it breaks under a C
locale, where bash's regex is byte-based. That is the same spelling, for the
same reason, as the I6_ERE in claude-config's instruction-scan.sh. Verified to
behave identically under LC_ALL=C and LC_ALL=C.UTF-8.
The two contraction sets differ, deliberately:
- `conversational-antecedent` admits only `'ve` and `'d`. Its follower is a past
participle (asked/requested/discussed/agreed/decided), and those are the only
two auxiliaries that can precede one. Admitting `'re` would newly match the
present-tense passive "do it as you're asked", which addresses the reader
generically rather than pointing at a prior exchange — a real false positive
avoided, not a hypothetical one.
- `plan-reference` admits all five (`'ve 're 'll 'd 'm`), because any auxiliary
can lead its present/future narration ("in this PR we'll switch the default",
"in this commit I'm switching"). The non-words the shared alternation also
spells (`I're`, `we'm`) cost nothing and keep it one group rather than two
per-pronoun ones.
Corpus sweep over the 1136-file tracked-markdown corpus is unchanged at
T1=13 T2=42 T3=0, with a byte-identical finding list. That zero delta is genuine
absence rather than an inert pattern: the corpus contains no instance of either
contracted shape (verified by direct grep), and detect.test.sh gains 15 checks
covering both functions, both apostrophe forms, the follower stand-downs behind
a contraction, and the negatives.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HigdNorttH9UCTeh5QdycM
…egration-cuy22l # Conflicts: # plugins/docs-hygiene/CHANGELOG.md # plugins/docs-hygiene/README.md
|
Claude finished @kyle-sexton's task in 1m 17s —— View job Tasks
Security reviewSkip gate (condition 2/3) applies — no security-relevant surface, including in the commits since the last review. The prior two reviews on this PR covered the diff through
I read the full diff of No security issues found. Nothing further to report per the lane's high-signal bar. |
|
Claude finished @kyle-sexton's task in 4m 9s —— View job Tasks
Code review (
|
|
No description provided. |
…egration-cuy22l # Conflicts: # plugins/docs-hygiene/.claude-plugin/plugin.json # plugins/docs-hygiene/CHANGELOG.md
|
Claude finished @kyle-sexton's task in 1m 12s —— View job Tasks
Code review (
|
|
Claude finished @kyle-sexton's task in 1m 6s —— View job Tasks
Security reviewSkip gate (condition 3) applies — this head's PR diff is unchanged from the last successful security review. Current head is Confirmed via As established in prior passes: this diff is pure bash No security issues found. Nothing further to report per the lane's high-signal bar. |
|
🔒 Lane claim + escalation (melo-lap-001-merge-20260823T045045Z, autopilot, PR-queue coordinator). Fresh merge-gate re-check just now shows this PR has moved from BLOCKED (unresolved threads only) to Independent read of the 3 unresolved bot threads: all three are genuinely addressed — kyle-sexton (human) replied to each with the exact fix commit ( Leaving for human: resolve the (already-addressed) threads and merge the branch to pick up the current main, or route through the conflict-handling pass. |
…egration-cuy22l # Conflicts: # plugins/docs-hygiene/.claude-plugin/plugin.json # plugins/docs-hygiene/CHANGELOG.md
|
Claude finished @kyle-sexton's task in 1m 17s —— View job Tasks
Security reviewSkip gate (condition 3) applies — this head's PR diff is unchanged from the last successful security review. Current head is Confirmed two ways:
The only textual movement visible between As established in every prior pass on this PR: the reviewable diff is pure bash No security issues found. Nothing further to report per the lane's high-signal bar. |
|
Both blockers from the merge-gate pass are cleared. Conflict resolved — head is now One correction to the lane's diagnosis: Resolution: kept our Re-verified after the merge: Threads resolved. The three bot threads are now marked resolved. The lane's read was correct — all three were genuinely addressed, each with a reply naming its fix commit ( No human action needed on either count. The PR should re-evaluate as mergeable once CI completes on Generated by Claude Code |
|
Claude finished @kyle-sexton's task in 1m 43s —— View job Tasks
Code review (
|
#3162 landed audit-noise's three residue shapes as 0.20.0 while this branch was open, so the 0.19.3 bump here sat below main. Conflicts were confined to plugin.json and CHANGELOG.md; SKILL.md and detect.test.sh auto-merged. Resolved by taking 0.20.1 and stacking this entry above 0.20.0 unmodified. The SKILL.md preview fix and its extract-and-execute test survive the merge intact, and the suite passes at 109 checks against the combined tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwvuaokrR5unJQWZP9j1ZL
Composes this PR's negation-without-positive shape (audit-noise's 6th) with main's three residue shapes from #3162/#3187 (audit-noise's 7th-9th), for a combined nine-shape classifier. Renumbers this PR's version from the colliding 0.20.0 to 0.21.0 (main already shipped 0.20.0 and 0.20.1), and updates every "six/eight shapes" claim across CHANGELOGs, SKILL.md, README, the detector-findings crosswalk, emit-findings.sh's declined-shape roster, and its test suite to the composed total of nine (one crosswalk row, eight declined).
…4.3) (#3215) Closes #3191 ## Summary Three rows of `audit-comment-residue`'s shape-definition table wrote their example phrases in plain double quotes. `audit-noise` strips inline-code spans before matching, so those rows flagged against their own definitions on every sweep. The sibling skill already writes the same examples in backticks and does not self-match. ## Fix Wrapped the quoted example phrases in the `plan-reference`, `conversational-antecedent`, and `ticket-pr-residue` rows in backticks. No detector behavior change. Plugin version `0.14.2` → `0.14.3` with a changelog entry. ## Verification - `audit-noise` `detect.sh` against `origin/main`'s copy of the skill: T1=2 T2=1 (the three named rows: `plan-reference` L38, `conversational-antecedent` L39, `ticket-pr-residue` L40). - Same detector against this branch's file: `Summary total: files=1 T1=0 T2=0 T3=0`. - `scripts/check-changelog-parity.sh` `--check` / `--check-bump origin/main` / `--check-order` / `--check-preserved origin/main`: PASS. - `scripts/check-changed-skills.sh origin/main`: PASS (0 errors, 1 pre-existing Gotchas warning). - `scripts/check-skill-count-claims.sh --check`: PASS. - `scripts/check-skill-leaf-names.sh --check`: PASS. - `scripts/check-cross-plugin-source-drift.sh --check`: PASS. - `markdownlint-cli2` on both changed markdown files: 0 issues. - `claude plugin validate plugins/code-tidying`: Validation passed. ## Related - Refs #3162 — where the self-matches were found and adjudicated; that PR was fenced to `plugins/docs-hygiene/`. - `plugins/docs-hygiene/skills/audit-noise/SKILL.md` — the backticked sibling rows this matches.
…ly (0.20.0) (#3245) Closes #3189 ## Summary Three readers of `metadata.summary` used to disagree. During #3162 a malformed summary reached CI twice, failing in opposite directions, each time after `check-skill.sh` reported green. Check 22 now enforces the same contract the cheat-sheet generator's `summaryError()` already enforces: a plain, unquoted, colon-free scalar of at most 100 codepoints. The implementations stay separate. `summaryError()` is repo-internal JavaScript; `check-skill.sh` ships inside an installable plugin that has no Node. They are bound by a shared case table (`summary-contract-cases.json`) and a YAML-oracle parity gate. ## Fix - Check 22 reads the value raw (no quote strip, no trailing-comment strip) and rejects anything that cannot survive as a plain YAML scalar. - `skill_frontmatter::summary_error` restates the JS guard, including the parse-failure holes a parser sweep found (`leading ,` / `?`, lone `=`, C1 controls, U+2028/U+2029). - A new CI job (`summary-reader-parity-gate`) is on `ci-status.needs` so it can actually gate a merge. - The 3162 regressions are now local FAILs. ## Verification - `plugins/skill-quality/scripts/check-skill.test.sh` — assertions passed, including the two #3162 regressions - `scripts/check-summary-reader-parity.test.sh` — 33 shared cases plus a 161-summary tree sweep - `scripts/check-lane-coverage.sh --check` — 44 lanes reachable - `scripts/check-shell-portability.sh origin/main` — clean - `check-skill.sh check` against this plugin — PASS ## Related - Refs #3162 — where both CI failures occurred --------- Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Closes #3125
Summary
/code-tidying:audit-comment-residuedetects four residue shapes in code;/docs-hygiene:audit-noiseowns.mdand detected five noise shapes. The two sets did not tile the space — onlyhistory-narrationhad a markdown counterpart (citation).plan-reference,conversational-antecedent, andticket-pr-residuehad no detector on either side of the boundary, so a README, rule body, orCLAUDE.mdsaying "as you asked, retry three times" or "see PR #45 for the rationale" was invisible to the whole fleet. Not a skipped file type — a gap behind an otherwise correct boundary.The shapes went to
audit-noiserather than widening the code skill to.md, and the reason is a treatment conflict, not a preference: on a markdown line the code skill'shistory-narrationand this skill'scitationfire together with opposite rulings (citationsays relocate to a## Sourcesfooter,history-narrationsays delete). Two owners for one line is a precedence problem; one owner per file type is not. The boundary is now explicitly by file type, with the three shape names deliberately shared so one authoring failure keeps one name wherever it lands.Fix
audit-noiseis now an eight-shape classifier:plan-referenceandconversational-antecedentat Tier 1,ticket-pr-residueat Tier 2.The patterns are adapted, not copied, and the adaptation is the substance of the change. The code lib classifies only the extracted comment portion of a line; this one classifies whole prose, where the same words are load-bearing far more often. Measured against this repository's own 1136-file tracked-markdown corpus, four of the sibling's cues had to go:
per the plan— prefix-matches "per the planning chapter", and a doc citing a plan artifact that still exists is a live cross-reference, not residueas planned— a substring of "was planned", so "what was planned, what was done instead" self-matchedin this change/in this session— ordinary domain vocabulary in an agent-tooling corpusin this PRsurvives only with a first-person actor behind it, which separates narration ("in this PR we switch the default") from a live referent ("the files changed in this PR").ticket-pr-residue's carve-out is restated in markdown terms rather than inherited: a task-list checklist item (- [ ] … #123) and aTODO(#123)-family marker are never flagged, because both denote outstanding tracked work — the reference is the actionable part of the line — which is what the code skill's sanctioned-TODOexception is actually about. Nothing further is carved out: the sanctioned home for a provenance citation is a## Sources/## Historyfooter, and the existing section exemptions already skip those (as they skipCHANGELOG.md, fenced blocks, and frontmatter) before any shape runs. An inline parenthetical (… (tracked in #482)) stays Tier 2 on purpose, so a reviewer rules on it rather than the scanner.Both tier tables (
audit_noise_shape_tierandaudit_noise_shape_tier_into) are updated — a shape added to only one silently falls through to Tier 3.Review feedback incorporated
Three findings from the automated reviewers were addressed in
3345108band825ebb1b:as requestedwas missed. Added, but not as the bare cue suggested — bare would match inside "the change was requested", the same substring bug this skill's changelog records foras planned. It is boundary-guarded and matched only as a clause-final adverbial, which also spares the live attributionas requested by the client.inexemption was too broad.as we discussed in yesterday's meetingwas being suppressed.innow defers to a document-locator predicate — does the reference name a written locus a reader can still open (§,#anchor, section/chapter, a named durable doc, a link or path), or the conversation the sentence came from? Tracker nouns are deliberately excluded, so this shape cannot launder a lineticket-pr-residueowns. Follower comparison is now case-normalized.we've,we'll,I'metc. now match — in both the ASCII apostrophe and the U+2019 typographic form, as literal alternatives rather than a character class (a bracket class decomposes U+2019 under a C locale; there is prior art for this inclaude-config/.../instruction-scan.sh:116). The two call sites take deliberately different contraction sets:conversational-antecedenttakes only've|'d, because admitting'rewould flag "do it as you're asked".Verification
Issue probes reproduced before and after. At
dff0942, probe 1 (the three orphaned shapes) gaveT1=0 T2=0 T3=0and probe 2 (control) gaveT1=3, allcitation— exactly as reported. Post-change:T1=4 T2=2 T3=0: twoconversational-antecedent(T1), twoplan-reference(T1), twoticket-pr-residue(T2)T1=3 T2=0 T3=0, still exactly threecitation, nothing newCorpus false-positive sweep over
git ls-files '*.md'minus**/evals/fixtures/**andCHANGELOG.md(1136 files, matching the skill's own documented repo-wide defaults):dff0942)The middle row is the point of the exercise: a close prose port of the code lib added 32 findings, 20 of them false positives. The sweep is what produced the four dropped cues above. All 12 new findings were read individually: 7 true positives, 3 self-matches on the sibling skill's own shape-definition table rows (dismissible under the already-documented "shape-definition example matching its own pattern" ground), and 2 false positives, both accepted with reasons rather than patched — see "known limitations" below.
Both later commits were held to the same bar. The
in-locator change is precision-only: the corpus finding stream is byte-identical before and after, verified by a line-level differ running the old and new predicate over every line of all 1136 files (disagreements=0), not by comparing totals. The contraction change adds no findings either — a direct grep confirms the corpus currently contains zero contracted instances of either shape, so that recall gap was real but latent.Gates, at the current head:
detect.test.sh102/102 (from 56 originally; +46),shellcheck --rcfile=.shellcheckrcclean,shfmt -dno diff,check-shell-portability.shclean in CI-faithful mode,scripts/validate-plugins.shpass,scripts/check-hook-exec-form.shpass,check-changelog-parity.sh --checkand--check-orderpass,markdownlint-cli20 issues in 55 files,typos,editorconfig-checker, andcheck-skill.shPASS (0 errors, 1 pre-existing warning).Two CI failures were found and fixed during review, both in the skill's frontmatter
metadata.summary:hook-exec-form-gaterejected an unquoted scalar containing": ", andplugin-gatethen rejected the quoted form becausescripts/cheatsheet-config.mjsrequires a plain unquoted scalar. The value is now colon-free and unquoted at 97 codepoints, checked againstsummaryError()directly.Related
Refs #3117— the issue's## Related: default scopesection proposes generalizing a scope-resolution order across the code-tidying scanners. Deliberately not implemented here: it is a separate concern whose subjects are#3117andaudit-comment-residue, andaudit-noisealready has the pagination and confirm-then-run repo-wide offer that issue holds up as the model.skill-quality's regex reader accepted frontmatter that a strict YAML parse rejected; then the cheat-sheet guard rejected what both others accepted. No single local check catches both states. This is the sharpest follow-up candidate here and is not fixed in this PR.plugins/code-tidying/skills/audit-comment-residue/SKILL.md:38-40— its own shape-definition rows, whose examples use plain double quotes rather than backticks, so the inline-code strip does not remove them. The one-line fix is backticking those three cells, which is outside this PR's plugin scope. This skill's own new rows use backticks precisely so they do not self-match (verified: zero findings anywhere underplugins/docs-hygiene/).docs/conventions/finding-suppression/README.md:64flags from inside a fenced block.detect.sh's fence toggle treats the inner```of a````-wrapped nested fence as a close, so lines 47–65 are scanned as if outside a fence. This affects all eight shapes; fixing the fence tracker is its own change with its own regression surface.plugins/playbooks/skills/fable-5/context/communication.md:120— "per your request" sits inside a double-quoted template of what the agent should say to the user. The only structural fix is stripping double-quoted spans the way inline-code spans are stripped, which would change strip semantics for all eight shapes and suppress real residue in quoted prose. The consumer-side remedies (backtick it, ormarkdown-discipline-ignore-line) already exist. This is the finding most worth a reviewer's second opinion.under,at, andoncarry the identical latent weaknessinhad —as we agreed on Tuesday,as we decided at the standupare residue that still stands the shape down. Needs its own corpus measurement (onespecially is high-traffic prose) and should not ride this change.Generated by Claude Code