Skip to content

docs: close out the docs-hygiene sweep's unapplied remediations, and give the findings-file contract a legal home - #3380

Merged
kyle-sexton merged 7 commits into
mainfrom
claude/orchestrate-docs-hygiene-audits-wdc55p
Aug 26, 2026
Merged

docs: close out the docs-hygiene sweep's unapplied remediations, and give the findings-file contract a legal home#3380
kyle-sexton merged 7 commits into
mainfrom
claude/orchestrate-docs-hygiene-audits-wdc55p

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

No linked issue

Summary

Closes out every remediation the repo-wide docs-hygiene sweep left unapplied in #3362, working from the resumable record that PR graduated into docs/specs/docs-hygiene-sweep-unapplied-remediations.md. Four lanes, 196 files, 28 plugin bumps.

The spec's own decay rule says the status column is its weakest part, and re-measuring proved that twice over. The L2 split lane had nothing left to do — the spec listed 13 outstanding, and every one had already landed in #3362; no SKILL.md or agent file in the repository now exceeds the 500-line body cap. And the largest open row, L7's I-1, turned out to be 104 sites across 26 files rather than the recorded 31 across 16 — a batch that was then declined on its merits.

Fix

L4 encapsulation, 32 of 34. Twenty-two cross-plugin citations reaching into another plugin's skill-private tree now name the owning skill's public invocation (/review:fanout fix, /skill-quality:check, /ai-slop:audit, /autonomy:setup, /claude-ops:lanes, /code-tidying:tidy, /source-control:setup, /session-flow:workflow, /docs-hygiene:write-for-humans). Plugins install independently, so a path into another plugin's private surface can be genuinely absent at read time; a slash command cannot be.

Two of the 34 could not be fixed that way, and the reason drove the one structural change here. Both cite the findings-file shape, which is not behavior a reader can be routed to but a spec a third-party detector must read to produce a file the fix action will consume. Naming a command hands a producer a command instead of the contract. So the contract moved rather than the citation: plugins/review/reference/findings-file-shape.md, at plugin level and outside every skill directory, where the repo-level convention can cite it legally. It stays inside the plugin rather than moving under docs/ because plugins ship without this repository. The section moved byte-for-byte, verified by round-trip diff.

Also eight citations written with an implied base of the plugin root while the real base was reference/none of them resolved for any reader — and two heading anchors dropped to file-level links, since renaming a heading is exactly the refactor the encapsulation contract exists to survive.

L2 structure. Four spoke chains flattened to one hop from their hub (audit-pass, architecture:improve, retro, course-digest), each intermediate keeping its own pointer so a reader arriving mid-chain loses nothing. Two orphaned spokes reconnected. Eighteen of 22 blind pointers now carry a when-to-read clause, ten as the Reference index. Load on demand table this repo already used in three places. And 92 long reference files gained a ## Contents index.

L5 / L6 / L7. Three babysit-prs rules restated in the positive; the write-for-agents glossary prohibition narrowed to the consuming project's domain, so the six skills defining their own working vocabulary are no longer caught by a rule whose routing target would refuse them.

Two detector-level defects found while applying, not by the audit. audit-noise exempted ## Cross-references from its enum-list rule but not the headings its own sibling lane rewrites blind pointers into, so applying one lane's fix converted it into another lane's finding — and the exemplar the doctrine points at was already self-flagging. And coupling-model.md carried a ## Contents section of six plain bullets with no links at all.

Verification

Fresh-context verifiers changed the outcome four times rather than rubber-stamping:

  • A rule was about to be demoted out of the only path that reads it. Moving eight gotcha bullets to an on-demand spoke was safe for seven, which each restated a rule an owning step already carried. "Config/docs changes still need verification" restated nothing, and Config is the one mode whose dispatch row loads no context file. It folded up into the Step 0 Config row instead, staying invocation-loaded.
  • A pointer row that looked exemplary silently reverted a shipped fix. stuck-checks.md's new row gated on a non-empty checks.stuck array alone. The second limb, added in 0.54.13, exists for the case where checks were never scheduled and that array is empty by construction. Both limbs are now stated.
  • A census was wrong by ~30%. The I-1 count was rebuilt paragraph-first after a verifier refuted the first pass, which had required the link on the same physical line while about a quarter of those pointers wrap.
  • A safety pin was about to be spent on cosmetic prose. See the declined site below.

Independent re-measurement of every agent's claims: orphan count 1 → 0 in both skills with the pre-existing unresolved-pointer count unchanged at 3; the missing-toc finding 99 → 7, the 7 being exactly the held-back set; the TOC pass +1,571 lines and 0 deleted, so content loss is not possible; audit-noise still passing all 199 of its own checks with no enum-list finding falling inside any new index section.

npx markdownlint-cli2 "**/*.md"                       0 issues in 1359 files
check-changelog-parity.sh --check/--check-order/--check-bump   pass
node scripts/validate-plugin-contracts.mjs            51 setup skills, 3023 files
scripts/check-changed-skills.sh origin/main           28 skills, 0 failed
scripts/check-detector-findings-crosswalk.sh --check  28 rule rows, clean
audit-noise detect.test.sh                            199 checks, 0 failed
scripts/run-plugin-tests.sh                           7365 passing

Three suite failures, all environmental and none attributable to this branch, each root-caused rather than waved off as flake:

  • discovery/check-coverage-complete.test.sh and source-control/worktree-claim.test.sh both assert a permission denial, and this sandbox runs as uid 0, which bypasses it. Neither suite nor its target differs from origin/main in this diff, so running them here is running them at main.
  • repo-fleet-hygiene/apply-plan.test.sh failed on fatal: failed to write commit object after the commit-signing server returned 503 mid-run. It passes in isolation, and this branch touches no file in that plugin.

Related

One finding is deliberately left standing, recorded in the spec with its reasoning: the blind pointer in plugins/planning/skills/interview/SKILL.md. It sits inside the section interview-defenses.test.sh pins by content digest to make an unreviewed edit to a safety prohibition fail loudly. Every fix re-baselines that digest — including the structurally better one of moving the misfiled reference row out of a prohibitions section, since removing the line changes the digest too. Spending a standing defense on a Tier 3 prose improvement is the wrong trade, so whether to pay it is left as a human's call.

Two more declines are recorded rather than silently dropped. L6's single compression finding fails its own skill's ship rule (compress reverts at <3% AND 0 semantic-loss, and dropping one word is ~0.1%), and ai-slop's stacked-hedging detector returns zero on that file, so it has no justification outside the skill that would revert it. L7's I-1 batch is declined because roughly half its 104 sites are bare pointers whose link text is already the domain term, where the prescribed rewrite yields a tautology (Hook: see [hook](hook.md).); "apply all in one edit" is therefore unavailable, and a partial pass leaves two competing styles in one densely cross-referenced reading path.

The spec's cross-lane note about audit-install-state is corrected: it pointed at a file the blind-pointer table never listed, its two halves disagreed on the count, and all four P3 replacements it deferred to are already present.

Refs #3362, docs/specs/docs-hygiene-sweep-unapplied-remediations.md, docs/specs/docs-hygiene-sweep-yield-measurement.md, docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md, .claude/rules/vendor-docs-are-not-style.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q


Generated by Claude Code

claude added 5 commits August 26, 2026 06:07
…the findings-file contract a legal home

The docs-hygiene sweep's L4 encapsulation lane, plus the three open L5 noise
findings and the one L7 doctrine edit that were still outstanding after #3362.

Twenty-two of the 24 cross-plugin violations were citations reaching into
another plugin's skill-private tree. Each now names the owning skill's public
invocation instead: /review:fanout fix, /skill-quality:check, /ai-slop:audit,
/autonomy:setup, /claude-ops:lanes, /code-tidying:tidy, /source-control:setup,
/session-flow:workflow, /docs-hygiene:write-for-humans. Plugins install
independently, so a path into another plugin's private surface can be genuinely
absent at read time; a slash command cannot be.

The remaining two could not be fixed that way, and the reason is worth
recording. Both cite the findings-file shape, which is not behavior a reader can
route to but a spec a third-party detector must read to produce a file the fix
action will consume. Naming a command there hands a producer a command instead
of the contract it needs. So the contract moved rather than the citation: it now
lives at plugins/review/reference/findings-file-shape.md, at plugin level and
outside every skill directory, where the repo-level convention can cite it
legally. It stays inside the plugin rather than moving under docs/ because
plugins ship without this repository. The section moved byte-for-byte, verified
by round-trip diff; only its relative links to fix-pass-mode.md were re-based,
and default-mode.md keeps a pointer.

The confidence rank order (high > medium > unscored > low) had been stated in
two uncoupled places. It now has one owner in review's plugin-level severity.md,
and both the normalization stage and the convention read it from there.

Eight unresolvable citations are also fixed. They were written in a form whose
implied base is the plugin root while the real base is reference/, so none of
them resolved for any reader; they now use the anchored ${CLAUDE_PLUGIN_ROOT}
form that parent-contract.md already used correctly for the same targets. Two
heading anchors are dropped in favour of file-level links, because renaming a
heading is exactly the refactor the encapsulation contract exists to survive.

Three babysit-prs rules are restated in the positive, saying what to do rather
than only what not to, and one stops narrating the policy it replaced.
write-for-agents' glossary prohibition is narrowed to the consuming project's
domain, so the six skills that define their own working vocabulary are no longer
caught by a rule whose routing target would refuse them.

One defect the sweep itself missed: coupling-model.md carried a Contents section
of six plain bullets with no links at all. Fixed, keeping the descriptive
glosses as when-to-read cues.

The discovery no-split record is corrected to name the test that actually goes
red. It cited agents/tool-honesty.test.sh, which reads each agent body for that
agent's own claims and therefore goes quiet when the prose moves. The hard pin
is scripts/contract.test.sh, which asserts the file contains "single write
boundary". A record that names only the quiet suite invites the re-proposal it
exists to prevent.

Verified: markdownlint clean over 1359 files, changelog parity and bump and
order gates clean, plugin contracts validated, detector-findings crosswalk
clean, and every relative link in the changed set resolves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
…okes, and settle the pointer batch

The docs-hygiene sweep's L2 deep-nesting and orphan-spoke findings, plus the
adjudication of its largest open L7 row.

Anthropic's guidance caps reference nesting at one level from the hub, and four
chains exceeded it: audit-pass reached terms.md and finding-identity.md only
through run-contract.md, architecture:improve reached its five research/deepening
files only through actions/deepening.md, retro reached its catalog only through
context/session.md, and course-digest reached screenshot-strategy.md only through
context/workflow.md. Each hub now links the leaf directly, with a read condition
per row, in the Reference index shape plugin-quality:audit and source-control:commit
already use. Every intermediate keeps its own pointer, so a reader arriving
mid-chain loses nothing. The audit-pass case was the worst of the four: the file
every other leaf opens by assuming was the one furthest from the hub.

Two spokes had no inbound pointer at all. implement's context/gotchas.md was dead
within its own skill while SKILL.md carried a Gotchas heading inline instead; the
eight bullets moved byte-identical and the hub now points at them. One of the
eight did not move down. "Config/docs changes still need verification" restated
no owning step, and Config is the one mode whose dispatch row loads no context
file, so demoting it to on-demand would have weakened exactly the path that needs
it. It folded up into the Step 0 Config row instead, where the Config path
necessarily reads it. That correction came from a fresh-context verifier, not
from the applying agent.

suno's drift audit ledger is reachable under a new maintenance section. It stays
inside the skill rather than moving to plugin scope because every row in it cites
a file inside that skill, and nothing else in the plugin consumes it.

The L7 I-1 pointer batch is adjudicated and declined, recorded in the spec so it
is not re-derived. The recorded count was wrong: roughly 104 sites across 26
files, not 31 across 16, and the first census was itself wrong until a verifier
refuted it, because the detector required the link on the same physical line and
about a quarter of these pointers wrap. Half the population is bare pointers
whose link text is already the domain term, where the prescribed rewrite yields a
tautology, so "apply all in one edit" is not an available option and a partial
pass would leave two competing styles in one densely cross-referenced reading
path. Two sites are exempt from that decline and are fixed here: both named their
target contentlessly, which is the shape write-for-agents gives as its own
counter-example.

One defect the audit missed, found while validating the table-of-contents pass:
coupling-model.md listed all six of its headings as plain bullets with no links,
so a reader could see the sections but not jump to one.

Verified: orphan count 1 to 0 in both skills by the repo's own detector, with the
pre-existing unresolved-pointer count unchanged at 3; content preservation checked
bullet-for-bullet on the gotchas move; markdownlint clean; no em dashes added; and
a whole-plugin grep for prose-pinning tests before every edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
…ise flagging the shape it prescribes

The docs-hygiene sweep's L2 blind-pointer findings: 18 of 22 applied, three
declined as no longer holding, one left standing on purpose.

A blind pointer names a spoke and says what it holds, never when to open it, so
a reading agent cannot decide whether to spend the context without following the
link. Ten trailing index sections become the shape the repository already used in
three places: a Reference index. Load on demand heading over a two-column table
whose second column is the load condition. Eight more sites keep their heading and
gain an inline when-clause, because they are not spoke indexes at all: one spoke
among sibling-skill boundary notes, or a single pointer, where renaming the
heading would have misrepresented the section.

Two of those clauses are worth naming because getting them wrong would have been
invisible. babysit-prs' stuck-checks row states both entry conditions, a non-empty
checks.stuck array or a conflicting branch with a short check list. The second
limb is the one 0.54.13 added, for the case where checks were never scheduled at
all and the array is empty by construction. A row gating on the array alone reads
as exemplary and silently reverts that fix. And the six audit skills' shared
clean-tree pointer splits by whether each skill states its own unattended branch
locally, so a headless run is not steered away from its only guidance.

Applying this shape had a cost nobody had noticed: audit-noise exempts
## Cross-references from its enum-list rule but not the headings its own sibling
lane rewrites blind pointers INTO. So one lane's fix became another lane's
finding, and the exemplar the doctrine points at, plugin-quality:audit's SKILL.md,
was already reporting enum-list against its own reference index. The three
prescribed headings are now exempt: a two-column path-and-condition table is a
routing table, not the consumer roster enum-list looks for.

Three sites are declined because the finding no longer holds. claude-ops
morning-brief ships no context/ or reference/ directory, so there is no spoke to
attach a condition to; observability's real spoke index is the Context ladder
section this remediation copies as a model. The spec's cross-lane note about
audit-install-state is corrected: it points at a file the blind-pointer table
never listed, its two halves disagree on the count, and all four of the P3
replacements it defers to are already present.

planning:interview is left standing, and the spec now records why. The blind
pointer is real, but it sits inside the section interview-defenses.test.sh pins
by content digest to make an unreviewed edit to a safety prohibition fail loudly.
Every fix re-baselines that digest, the structurally better one included, since
removing the misfiled line changes the digest too. Spending a standing defense on
a Tier 3 prose improvement is the wrong trade; whether to pay it is a human's
call.

Verified: the repo's own detector confirms no enum-list finding falls inside any
new index section and audit-noise still passes all 199 of its own checks; 108
links across 16 files resolve with anchors slug-matched against real headings; no
inbound anchor pointed at a renamed heading; markdownlint clean over 1359 files;
changelog parity, order and bump gates clean; 28 changed skills checked, 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
The docs-hygiene sweep's missing-toc finding, applied as one pass rather than 92
edits, because the predicate is mechanical and the treatment is generated.

Scope came from the doctrine, and the first attempt at it was wrong in a way
worth recording. The rule reads "Reference file >300 lines with no TOC", and an
obvious reading of that is "any markdown file over 300 lines without a Contents
section". That predicate returns 111 files and adds a table of contents to
fifteen skill hubs, which is why no SKILL.md in this repository has ever carried
one: the doctrine never asked it to. The detector fixes every SKILL.md at
invocation tier, and on-demand IS the reference tier the rule names, so scope
here is the detector's own tier classification. That excludes skill hubs by
construction instead of by a list someone has to maintain.

Seven files are held back rather than treated. The doctrine's treatment reads
"Add a TOC at top (or a grep recipe for lookup-shaped content)", and that
alternative is load-bearing: a 1,742-line file with three H2s gets nothing from a
three-row index. Those seven are listed in the run output and left for a
judgment pass. The 305 files in the 100-to-300-line band are not findings, per
the two-band treatment that resolves the officially conflicting 100-vs-300
guidance.

Anchors follow GitHub's slugger rather than an approximation of it, including the
case where an em dash between spaces collapses to two hyphens. The verifier
re-derives each file's heading slugs independently and compares, so a slugger bug
surfaces as a dangling anchor instead of shipping; it was validated first against
all 31 pre-existing hand-written tables of contents in the repository, which it
passes clean.

That verifier reported one dangling anchor, and it was the verifier that was
wrong. sources.md documents `[depth limit](#anchor)` as an example of a quoting
normalization, in prose that sits above the first H2 and therefore inside the
heading-to-heading window the check was scanning. The fix is in the checker,
which now reads only list rows: the generated table was correct.

The pass is purely additive: 1,571 lines added and zero deleted across 92 files,
so no content can have been lost. The detector confirms the finding count fell
from 99 to exactly the 7 held files. Every affected file's plugin is bumped, with
the entry naming that plugin's own file count.

Before applying, every target was checked against the repository's scripts for a
prose pin. Note for anyone repeating that check: this sandbox's grep silently
ignores --include, so the obvious command returns the markdown files themselves
and reads as a false negative. Use rg with -g.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
main landed three commits after this branch was cut, and one of them collided:
ai-slop released 0.4.1 for the Windows jq carriage-return fix while this branch
had already used 0.4.1 for its table-of-contents entry.

This conflict is why CI had gone quiet rather than red. GitHub schedules
pull_request workflows against the computed merge commit, and with a conflict it
cannot compute one, so ci and pr-title were never created for this head while the
pull_request_target workflows (do-not-merge, pr-issue-linkage) kept reporting
green against the base. Three green checks on a PR that should run a dozen is the
tell; a missing run reads exactly like a slow one.

Same resolution rule as the earlier collision on this branch: main's entry is
released and keeps its number, this branch's entry is unreleased and renumbers
above it, and the manifest ends at the highest. So the table-of-contents entry
becomes 0.4.2, main's 0.4.1 stays where it is with its body verbatim, and the
manifest reads 0.4.2.

One thing in main's other commit needed checking rather than assuming. #3344
added scripts/check-purged-em-dashes.sh, a ratchet enforcing zero em dashes on
an allowlist of already-purged surfaces, and that allowlist covers
plugins/implementation/skills/*/SKILL.md and plugins/overengineering/skills/*/SKILL.md,
both of which this branch edits. The table-of-contents pass copies heading text
verbatim into its rows, em dashes included, so the two changes could have
collided by construction. They do not: the gate passes, 21 declared paths and 30
files scanned.

Verified on the merged tree: no conflict markers anywhere, changelog parity,
order and bump gates clean, the new em-dash gate clean, plugin contracts across
3023 files, and markdownlint clean at 1359 files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 5m 54s —— View job


CI Code Review — in progress

  • Load /review:code-review skill instructions
  • Check skip-gate conditions — PR is open, not draft, non-trivial (194 files, +2693/-278)
  • Fetch PR diff (origin/main...HEAD)
  • Manually spot-check relocated spec (findings-file-shape.md), relative-link math, ## Contents anchors, plugin.json/CHANGELOG version pairs, and shell-script diffs — all consistent
  • Found and posted one confirmed inline finding: the spec's own "residual" note contradicts a fix shipped in the same commit
  • Background sweep of remaining ~180 files for broken links / anchor mismatches / version drift still running
  • Post final summary

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 52s —— View job


Security review complete ✅

Skip gate triggered — no security-relevant surface.

Reviewed the full diff (git diff origin/main...HEAD, 194 files, +2693/-278). The change set is entirely:

No injection surfaces, authorization/access-control code, token/secret/credential handling, or GitHub Actions workflow files are touched. No new command execution, no untrusted-input handling, no permission changes.

Per /review:security-review's skip gate ("Change has no security-relevant surface after reading the diff"), no findings to report — stopping here as instructed.

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Last security-reviewed head: aef640e82a1e70e050876f6098544e06195959bf. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d909d48722

ℹ️ 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".

Comment thread plugins/review/skills/fanout/context/default-mode.md
Comment thread docs/specs/docs-hygiene-sweep-unapplied-remediations.md Outdated
…postrophe

CI's hygiene job went red on typos, and the finding is real rather than a
false positive worth arguing with: the table-of-contents row this branch
generated for design-level.md carries the anchor
#domain-events-in-depth-why-theyre-special, and "theyre" is a word the checker
corrects to "their" or "there".

The anchor cannot be spelled any other way. GitHub's slugger strips apostrophes,
so a heading containing a contraction produces exactly that token, and changing
it breaks the link. The heading itself, "Domain Events in Depth (Why They're
Special)", is pre-existing and out of this branch's scope to reword.

So the generated block carries the repo's markdown spellchecker directive, and
the suppression costs no coverage: every row in a table of contents echoes a
heading that is still spell-checked where it is actually written, further down
the file. A genuine typo in that heading would still be caught there.

Scoped to the one block rather than added to _typos.toml, which is the
constellation-wide synced policy and says plainly that a repo-specific exception
does not belong in it.

Verified: typos exits 0 over the tree, markdownlint clean on the file, and all
124 tables of contents still resolve with zero dangling anchors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 45s —— View job


Security review complete ✅

Skip gate triggered — no security-relevant surface.

This lane's relevance gate compares only the commits landed since the last reviewed head (969f4bd, see the bot comment above). The only new commit is aef640e — a single-file diff:

That's the entire delta: two markdown comments wrapping existing link text, no code, no config, no workflow file, no logic change. No injection surface, no auth/access-control code, no secret/credential handling, no permission changes.

Per /review:security-review's skip gate ("Change has no security-relevant surface after reading the diff"), no findings to report for this update.

(For the full PR: the prior review on this thread already covered the base diff through 969f4bd and likewise found no security-relevant surface — markdown/prose edits, plugin.json version bumps, and two comment-only shell-script diffs.)

Branch: claude/orchestrate-docs-hygiene-audits-wdc55p

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Code review in progress

View job run

…hat contradicted its own commit

Two review findings, both correct, both fixed here.

Codex, P2. Moving the findings-file contract to plugin scope left ADR 0010
citing `default-mode.md:48` for the shape and `:77` for the coverage fields.
Neither line carries that content any more, so a reader following either one
lands on unrelated text, and the ADR names a file that is no longer the owner.

An earlier pass on this branch reasoned that ADR citations are historical and
should be left alone. That was wrong here, and the distinction is worth stating:
the repository excludes `docs/adr/**` from its em-dash purge because a decision
record is a historical account rather than prose to restyle, which is a rule
about STYLE. These two are load-bearing evidence citations inside Context and
Consequences, the kind a reader is meant to follow to check the claim being
made. A dead evidence link degrades the record; retargeting it preserves exactly
what the record was asserting. Both claims were verified present at the new
location before the cites were changed.

The Claude code reviewer, on the spec. Its "residual" note said the two
`troubleshoot.md` pointer sites stay open and "carry forward as their own
two-site finding" — while the same commit that shipped the note also fixed both
sites. The note also quoted a prescribed replacement that differs from what
actually shipped: it says `see [SKILL.md](../SKILL.md)`, the code says
`see [Confidence flags](../SKILL.md)`, and the second is the better fix, since
naming the target section rather than the file is the half the doctrine's
counter-example is actually about.

That contradiction is mine. The adjudicating pass wrote the note before the
sites were fixed, and both landed in one commit without being reconciled. It
matters more than an ordinary stale line, because this document's whole claim on
a future reader is that it is the resumable record: a row asserting open work
that is already closed would cost that reader a PR to discover, and it
undercuts the decay rule the same document leads with. The row now records the
applied state, quotes the shipped text, and keeps the reasoning for why these
two were never part of the declined batch.

Verified: no `default-mode.md:<line>` citation remains anywhere in the tree, the
spec's quoted text now matches the file byte-for-byte, typos exits 0, and
markdownlint is clean on both files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTVH5ZRVph75kvxzUAnb6q
@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 51s —— View job


Code review in progress

  • Load /review:code-review skill instructions
  • Check skip-gate conditions — PR is open, not draft, non-trivial, HEAD moved since last review
  • Verified the two prior findings (Codex's ADR-0010 stale citations, and my own "residual" spec contradiction) — both fixed correctly in d4f044a, confirmed byte-for-byte
  • Verified findings-file-shape.md moved intact and all internal relative links resolve from its new location
  • Fan out background review agents across remaining lanes (encapsulation rewrites, spoke-chain/TOC, L5/L6/L7 + detector defects, version bumps/shell scripts) — running
  • Adversarially validate candidate findings
  • Post inline comments for anchorable findings
  • Post final summary

Copy link
Copy Markdown
Contributor Author

Review coverage on the current head, given the lane's infra failure

The automated code-review lane failed with an infrastructure error on d4f044af (no execution file was produced), so per its own warning that result is not a "no findings" verdict. I could not re-run it: the run is non-retryable (403), claude-review.yml has no workflow_dispatch trigger, and the caller omits synchronize, so a further push will not re-trigger the lane either. Recording what coverage does exist rather than leaving the warning box to imply none.

Completed reviews, and what they found. Both ran on earlier heads of this branch and both produced a finding, each of which is fixed:

  • Codex, P2 — moving the findings-file contract left ADR 0010 citing default-mode.md:48 and :77, lines that no longer carry that content. Fixed in d4f044af. An earlier pass on this branch had reasoned those citations were historical and should stay; that was wrong, and the distinction is worth recording: this repo excludes docs/adr/** from the em-dash purge because a decision record is a historical account rather than prose to restyle, which is a rule about style. The two cites in question are load-bearing evidence links inside Context and Consequences, the kind a reader follows to check the claim. Both claims were verified present at the new location before the cites were changed.
  • Claude code review (on d909d487) — the spec's "residual" note claimed two troubleshoot.md pointer sites were still open while the same commit had already fixed them, and quoted a prescribed replacement that differed from what shipped. Fixed in d4f044af. That one was mine: the adjudicating pass wrote the note before the sites were fixed and both landed in one commit unreconciled.
  • Security review — completed on both 969f4bdf and aef640e8, skip gate, no security-relevant surface.

The one item the failed lane left unfinished. Its last progress update showed a background sweep of the remaining ~180 files for broken links, anchor mismatches, and version drift still running when the job died. I ran that sweep independently rather than assume it would have come back clean:

changed markdown files: 165
local links checked:    2505
broken:                 1
  docs/PLUGIN-PHILOSOPHY.md:358  ../audit/context/suppression.md  (no such file)

That single hit is an illustrative example inside the doctrine's own prose, demonstrating the correct citation form; its target was never meant to exist, it is present identically on origin/main, and this branch does not touch that line. So: zero real breakage across the classes this diff actually risked, which are the 92 generated table-of-contents anchors, the twelve re-pointed citations from the contract move, the eight ${CLAUDE_PLUGIN_ROOT} rewrites, and the two retargeted ADR references.

Three details in that checker mattered, since a naive version reports noise instead of an answer: fenced blocks and inline code spans are stripped first, because the spec quotes other files' pointer text verbatim and those quotes resolve against the quoted file rather than the quoting one; ${CLAUDE_PLUGIN_ROOT} is resolved rather than skipped, since that is precisely the class this branch exists to fix; and anchors are checked against the target file's real headings using GitHub's slugger with its duplicate-suffix rule, so a link that finds the right file but a heading that no longer exists still counts as broken.

CI on d4f044af: green, including plugin-gate, hygiene, and ci-status. plugin-gate passing is also the check on a claim in the PR body: three tests failed in my local run, and I attributed all three to the sandbox running as uid 0, which bypasses the permission denials two of them assert. CI runs as a normal user and the suite passes there, so that attribution held rather than being an excuse.


Generated by Claude Code

@kyle-sexton
kyle-sexton merged commit 6c7a103 into main Aug 26, 2026
54 checks passed
@kyle-sexton
kyle-sexton deleted the claude/orchestrate-docs-hygiene-audits-wdc55p branch August 26, 2026 07:36
claude Bot pushed a commit that referenced this pull request Aug 28, 2026
…its declared recall gap (#3460)

The repo-wide docs-hygiene sweep (#3362) ran eight lanes and graduated its remainder into
docs/specs/docs-hygiene-sweep-unapplied-remediations.md. #3380 closed out L2, L4, L5, L6 and L7 and
left L3, the extract-ssot deduplication lane, untouched. An adversarial verifier re-tested that
premise cluster by cluster before anything was edited: all 13 remediated clusters were still open,
no later commit had applied them, and no open pull request covered them.

That lane also declared its own recall limit and named the fix. This carries it out: a shingled
n-gram pass over whitespace-normalized markdown with line breaks removed, plus the reading-driven
semantic pass it had no subagent tool to attempt. Against a control paragraph re-wrapped at three
widths, the old line-anchored method shares zero lines and the new pass recovers 100%.

Five of the findings are factual defects rather than prose drift:

- A fallback that could never fire, at 25 sites, and a 26th that fired and said nothing. Piping a
  probe into head before || makes the fallback unreachable, so a failed git status rendered an
  empty string under a label that reads as a clean tree. verification:confirm is the fleet's one
  uncapped site, so its fallback did run and emitted an empty string, which under that label is the
  same misreading by a different mechanism. Proven by execution.
- An inline floor whose carriers had drifted into two distinct texts. loop-lane §6 binds three lane
  bodies on the values; under that scope the values never drifted and the surrounding prose did.
  Both de-slop shards made the same substitutions, one of which left a comma splice.
- A dropped-allow-rule roster missing the Monitor class upstream added in v2.1.236, so a dropped
  Monitor grant was reported under none of the classes. Bounded to that version, since on an older
  install the verdict inverts in the less safe direction.
- A line-number citation asserting the opposite of the line it named: four surfaces cited
  check-skill.sh:414 as the hard FAIL for a dropped trigger phrase, where 414 says a trigger move
  WARNs and never blocks and the err is at 462. main fixed one of the four independently while this
  branch was in review; the other three now name the check rather than a line.
- A title taxonomy credited to a living author that the owner file records as unaudited and not his,
  including in a shipped prompt template.

docs/PLUGIN-PHILOSOPHY.md gains the runtime-grounded clause 20 setup skills were asserting with
nothing to point at, and four Convention registry rows: three owner docs that declare themselves
owners and were absent from the registry that indexes them, plus the precompute convention.

Three adversarial review rounds were run against the change set itself, and each found real defects
in its record-keeping rather than its mechanics. Six changelog entries described a change their own
diff did not make. The new detector-findings adopter row claimed a mechanical selection the producer
does not have, and its shape count was wrong at the source: audit-noise's context/persist-findings.md
and emit-findings.sh header both said six shapes and five declined, where lib/noise-shapes.sh appends
eight and detect.sh drives a ninth. Round three re-derived every remaining claim and found eight
more: "three distinct texts" was two, the spec overstated what loop-lane 6 binds, the
check-skill.sh:414 cluster was declared closed while audit-noise's own script still carried it (the
earlier sweep grepped only *.md), "every site carries one wording" was 18 of 20, the four-preambles
claim went stale when provenance landed with the merge, one entry misdescribed a file that was
internally inconsistent rather than wrong, a contradiction count read 15 where the file records 12,
and one roster row attached a quote to the wrong subject. All corrected, each re-verified against
the repository first, and each count now points at the artifact that is its source.

The full roster, the twelve contradictions the semantic pass surfaced, the four filtered-probe sites
deliberately left unnormalized and why, and the measured recall limits of the detector itself are
recorded in docs/specs/extract-ssot-sweep-2026-08-28.md so the remainder is resumable. That file
states plainly that its recall figures are unreproducible from this repository, because the
detector was a session tool and was deliberately not committed.

Refs #3362, refs #3380, refs #3178.
claude Bot added a commit that referenced this pull request Aug 28, 2026
…closed gate that failed open (#3468)

#3460 merged a whole-repo extract-ssot sweep and recorded, in its own resumable
spec, three things it deliberately left open. This closes them, and closes a
fourth the sweep did not know it had.

A post-merge security audit found the defect #3460 fixed for git-status probes
still live in the rest of its class. video-digest/SKILL.md states "STOP if the
pre-computed context above shows MISSING for yt-dlp, ffmpeg, or ImageMagick.
Cloud agents without the media toolchain fail closed." Its probes were
`yt-dlp --version 2>/dev/null | head -1 || echo "MISSING ..."`. Because || binds
to the pipeline and head exits 0 regardless, an absent yt-dlp rendered an empty
string, never MISSING. The gate could not fire: a skill documenting itself as
failing closed failed open. Fixed there and at course-digest, ai-slop:audit,
provenance:audit, firecrawl:update and claude-ops:observability, using the
guard-first shape firecrawl:firecrawl already shipped, so the fleet gains no new
idiom. Proven by execution both ways.

Also fixes a grant #3460 left behind: it rewrote the two prototype skills'
injections to begin with { while their grant stayed the prefix rule
Bash(git status:*), whose leading token no longer matches.

The five filtered probes #3460 deferred are bound to their probes, each keeping
its own filter, cap and label noun so "the filter matched nothing" and "git did
not run" stay distinguishable.

The ADR 0018 encapsulation floor is closed. The spec recorded two sites and
declared the roster a floor; re-derivation across all of docs/** with five
independent search shapes found 16 citations at 12 sites in 8 files, among them
V-review-13 and V-review-14, open on the predecessor's roster since 2026-08-26
(34 to 32). The sharpest: docs/PLUGIN-PHILOSOPHY.md's Convention registry row,
which #3460 itself added, was written in the exact bare unresolvable form ADR
0018 names as its real defect class. 23 citations are kept on a stated test and
recorded as a judgment set so a later pass can overturn them.

A fourth review round found five more false claims in the merged record, each
re-derived before fixing. Two are structural: a cross-reference pointing at a
section that names none of its four clusters, and a quote attributed to two
files that neither makes -- the identical wrong-subject defect round three
fixed, recurring one paragraph away.

Refs #3460, refs #3362, refs #3380.
claude Bot added a commit that referenced this pull request Aug 28, 2026
…five wrong keeps (#3475)

#3468 closed 16 cross-plugin path citations under ADR 0018 and kept 23 on a
test it never wrote down. Its own verifier reported '3 keeps refuted; 4 cannot
verify' and that reasoning was unreadable, because the verifier ran as a remote
session the agent could not read back. An independent verifier settled it: five
are wrong, not three, and it found why this recurred.

The dividing test #3468 applied -- fix a citation that is an ADDRESS for an
obligation, keep one that is EVIDENCE about this tree at a moment in time --
appears nowhere in ADR 0018. Clause 2 reads unconditionally. But ADR 0018 is
itself a docs/** file and path-cites plugin skill privates five times, quoting
their contents inline. Either it violates itself on its own first page, or
clause 2 is scoped to citations that function as an address. Only the second
reading is coherent, and an unwritten rule is what let one commit rule two ways
in two files. This writes it down, as an Amendment following ADR 0011's
convention: the evidence/address test, scripts/lib being outside the
entry-surface carve-out, and how plugin-level non-skill trees generalize.

The five wrong keeps. shell-test-helpers cited a private scripts/lib/ path --
and that is a self-contradiction inside c66f26c itself, which added
detector-findings 2.8.1 fixing the byte-identical shape and stating the ground,
then kept it one file over. Three line and step pins are dropped as the same
class 2.7.1 removed a :414 pin for; each citation already quotes its content
inline, so the drop is lossless. records.json:3's keep-ground was false: the
sweep kept it because generation overwrites hand-edits, but that store's own
note says 'Hand-editable and human-gated'.

Recorded as open remainder rather than swept: twelve citations c66f26c created
itself, every fix having written a changelog entry quoting the path it removed,
so the population is 16 fixed and 35 kept rather than 16 and 23; three trees
excluded by fiat with no carve-out authorizing it; 51 citations into
plugin-level non-skill trees; and a stale dometrain security record whose own
version-bump re-trigger has fired unnoticed.

A fifth review round found two more false claims, both stale statuses. '34 to
32' was wrong: re-deriving all 34 rows against the roster's own text test finds
22 already closed, twelve of them by #3380, the same commit that last wrote the
roster and left its own 'all 34 re-verified' line standing over twelve citations
it had just deleted. This change set republished that status in a file whose
line 18 reads 'the check is the text, never the status and never the line
number.' And the spec still shipped the probe shape #3469 removed, presented as
verified in three states, two of which print the failure token under pipefail.

Refs #3468, refs #3469, refs #3460. Sibling #3474.
claude Bot added a commit that referenced this pull request Aug 28, 2026
…reopened it three times (#3478)

The L4 roster's Group 2, eight intra-plugin path-form citations, was the last
block anyone believed open. All eight were already closed, by 6c7a103 (#3380)
on 2026-08-26 -- the same commit that wrote the roster. Its own message names
what it did: eight citations written with an implied base of the plugin root
while the real base was reference/, none of which resolved for any reader.

Verified one at a time against the roster's own text test. All eight now read
${CLAUDE_PLUGIN_ROOT}/skills/<skill>/<path> and all seven distinct targets
exist on disk. Zero plugins/** files edited, so no bump and no plugin changelog
entry: nothing needed changing.

The reason four separate passes each re-derived this roster from scratch is one
sentence. #3380 fixed 32 of 34 rows and left its summary asserting that all 34
path:line citations were re-verified on 2026-08-26 and every one resolves --
standing over citations it had just deleted. A fifth-round audit caught that for
Group 1, where 22 of 32 were already closed and twelve of those by #3380 itself.
This closes the same hole for Group 2. The generalizable rule is now in the
sweep spec: a record that fixes findings and updates its own summary in the same
commit must update the summary, or the summary outranks the fix for every later
reader.

The roster's inventory rows are left verbatim, per its own decay rule that the
inventory is the part that cannot be re-derived, and per the precedent that
#3474 and #3475 both closed rows without touching the file. Only an additive
closure stamp is appended.

On whether ADR 0018 reaches this class, the honest answer is that its
encapsulation half does not. Clause 1 legalises intra-plugin citations and names
this exact citing surface. Clause 2 cannot apply, because both files ship inside
one plugin so the runtime absence motivating it cannot occur, and the 2026-08-28
amendment's fix-an-address / keep-evidence test divides clause 2 applications
only. Only clause 3 reaches Group 2, and clause 3 is a resolvability rule rather
than an encapsulation one: had these been open, the remedy would have been path
form and nothing else. The clause that earned its keep is the ADR's own
observation that proximity did not prevent them.

A second derivation making no reference to the roster resolved every citation
token in every plugin-level reference/, context/ and agents/ tree plus every
plugin README against the base its own form implies: 52 tokens, 0 clause-3
failures. Group 3's two anchors were also closed by #3380. 34 closed, 0 open.

No fresh-context verifier reviewed this diff. Nested spawning is unavailable at
this depth: the Agent tool is withheld pre-launch, so there is no call to refuse
and no refusal string. A second mechanical derivation was substituted and every
line reference re-checked against the live tree, which is weaker than a fresh
context and is recorded as such.

Refs #3477, refs #3476, refs #3475, refs #3474, refs #3469, refs #3468.
kyle-sexton pushed a commit that referenced this pull request Aug 28, 2026
…he citations its derivation could not see

A fresh-context verifier reproduced the F3 derivation independently (119 tokens,
3 failures pre-fix, 0 post-fix, same three sites) and found three new false
statements in the round that produced it.

- "#3380 closed 32 of 34 rows in three plugins' files" is refuted by
  `git show --stat 6c7a103`: the rows span a `.claude/rules/` file,
  `docs/PLUGIN-PHILOSOPHY.md`, four convention READMEs and several plugins'
  trees, and the majority are not plugin files at all.
- The `config-cascade` sentences were pinned at `:13-14` and `:11-13`; the
  quoted forms are on 12, 13 and 14 and the assertion runs 14 to 16. A line pin
  written into the file whose own decay rule says the check is the text. Both
  re-anchored on text rather than corrected.
- "names no invocation at all" is contradicted by the bullet's own text, which
  names two. It names no invocation as the replacement, which is the claim the
  ruling actually rests on.

The claim that both earlier derivations shared one blind spot is downgraded to
what the evidence supports: derivation 1's expression is recorded and does have
it, derivation 2's was never written down. An unrecorded expression cannot be
audited, only believed, and that is the defect worth carrying forward.

The verifier also found three citations the third derivation could not see,
because it was `skills/`-scoped and these name no skill. They sit three lines
above V-disc-04 through V-disc-06, which this sweep closed: a pass corrected the
citations below them and left these standing. Fixed to the anchored form, which
is right here because the file is not fetched across the plugin boundary.
kyle-sexton added a commit that referenced this pull request Aug 28, 2026
…citations no reader could resolve (#3480)

Three rounds of correction, each one fixing the round before it.

The record asserted that #3380 wrote the L4 roster and fixed 32 of its 34 rows
in the same commit, and drew a generalizable rule from it. `--diff-filter=A`
returns #3362 and #3380's hunks miss the L4 range entirely, so the rule
described an event that did not happen. Replaced with its near-inverse: a
commit that closes findings inventoried in a record it did not author still
owes that record's summary an update.

Six citations resolved against nothing. Three name a SKILL.md directly and
three name agent definitions; each earlier derivation was blind to exactly the
rows the next one found, because each was built from a token shape rather than
from the defect class. The three in discovery sat three lines above rows this
sweep closed. A fourth derivation is owed and recorded as owed.

The first remedy was wrong for one of them: config-resolution.md is fetched
across the plugin boundary, so ${CLAUDE_PLUGIN_ROOT} names the fetching plugin
and the anchor was unfollowable for exactly the reader that needed it. It now
uses the public invocation. Every later fix checks who fetches the file before
choosing the remedy.

A fresh-context verifier reproduced the disputed 119-token derivation
independently, delta zero, and found three false statements in the correction
itself: a miscounted file spread, two line pins in the file whose own rule
forbids line pins, and an absolute its own source text contradicts. All fixed.
A claim that two derivations shared one blind spot is downgraded to what the
evidence supports, since the second derivation's expression was never recorded
anywhere and cannot be audited, only believed.

discovery 0.16.17, source-control 0.55.30, work-items 0.39.39,
songwriting 1.4.18.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants