Skip to content

fix(code-tidying): decompose docs-prose lane to per-section merge (#701) - #726

Merged
kyle-sexton merged 4 commits into
mainfrom
fix/701-code-tidying-docs-prose-decompose
Jul 20, 2026
Merged

fix(code-tidying): decompose docs-prose lane to per-section merge (#701)#726
kyle-sexton merged 4 commits into
mainfrom
fix/701-code-tidying-docs-prose-decompose

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Summary

The code-tidying docs-prose lane declared undeclared wholesale replacementdocs-prose.md:14 said a project lane at .claude/tidy-lanes/docs-prose.md "overrides this file entirely". This is forbidden by the consumer-config layering contract ("Merge semantics"): it froze the generic watch-for patterns (P-1..P-6) out of any repo that customized Scope, so bundled pattern improvements could never reach it. Ruling #649 dispositioned this surface CORRECT (decompose, don't ratify).

Fix

Mirrors the sanctioned #647 per-key precedent (source-control):

  • docs-prose.md decomposed with a declared ## Merge semantics section. Scope is a per-section override (retargets doc globs); the generic watch-for patterns are additive — a project's entries append to the bundled P-1..P-6 rather than replacing them, so bundled improvements keep flowing. Every other section is per-section override with fall-through to the bundled value when omitted.
  • Resolution engine updated (tidy/SKILL.md Lane resolution + Phase A step 2): when a project lane declares ## Merge semantics, the engine reads both the project and bundled layers and merges per that declaration — no longer "read one and stop". A lane with no declaration resolves project-only (legacy path), so unmigrated lanes are byte-identically unchanged (opt-in migration).
  • setup/SKILL.md precedence wording aligned to the per-lane declared semantics.
  • Implementers table row for code-tidying updated out of the single-layer/undeclared framing to the honest post-merge shape.
  • Sibling deviations tracked, not folded in (per the issue): the .local.* single-layer gap → code-tidying: setup refuses .local.* overlay — single-layer gap (split from #701) #723; shell-tooling's identical wholesale language → code-tidying: shell-tooling lane carries same undeclared wholesale replacement as #701 #724.

Verification

Branch fast-forwarded onto current origin/main before commit; diff is the 6 files below only.

$ npx markdownlint-cli2 <5 changed .md files>
Summary: 0 error(s)

$ npx editorconfig-checker -config .editorconfig-checker.json <6 changed files>
(exit 0, no findings)

$ bash scripts/check-changelog-parity.sh --check
Every versioned plugin has a CHANGELOG.md (or a stale-guarded baseline entry).

$ bash scripts/check-changelog-parity.sh --check-bump origin/main
Every plugin whose version changed vs origin/main has a '## [<version>]' CHANGELOG.md entry.

$ python -c "import json; json.load(open('plugins/code-tidying/.claude-plugin/plugin.json'))"
OK: parses, version 0.7.0

Relative-link integrity: the new [Merge semantics](#merge-semantics) anchor resolves to the added ## Merge semantics heading in the same file.

Closes #701

Related

The docs-prose lane declared undeclared wholesale replacement ("a project
lane overrides this file entirely"), forbidden by the consumer-config
layering contract. It froze bundled watch-for pattern improvements (P-1..P-6)
out of any repo that customized Scope.

Decompose per the #647 precedent: a project lane now merges per-section via a
declared `## Merge semantics` block — Scope is a per-section override,
watch-for patterns are additive (concatenate onto the bundled set). The tidy
resolution engine reads both the project and bundled layers and merges per the
lane's declaration; lanes without the declaration resolve project-only
(legacy path), so unmigrated lanes are unchanged.

Sibling deviations tracked, not folded in: the .local.* single-layer gap
(#723) and shell-tooling's identical wholesale language (#724).

Co-Authored-By: Claude <noreply@anthropic.com>
@kyle-sexton kyle-sexton added the automated Opened by automation. label Jul 20, 2026
@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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


PR Review

  • Gather context and understand the request
  • Review changed files
  • Analyze correctness and alignment with project guidelines
  • Post review findings

Overall Assessment

The approach is sound: using the presence of a ## Merge semantics section in the project layer as the merge-mode signal is elegant and fully backward-compatible — existing project lanes without that section continue to resolve project-only unchanged. The CHANGELOG entry, version bump (0.6.0 → 0.7.0), and implementers table update are all accurate. Scope discipline is correct: shell-tooling (#724) and the .local.* gap (#723) are tracked but not folded in.

One documentation clarity issue and one minor gap below.


Finding 1 — Ambiguous "this section" in bundled lane (medium)

File: plugins/code-tidying/skills/tidy/lanes/docs-prose.md, line 26

The presence of this section is what tells `/code-tidying:tidy` to read **both**
the project lane and this bundled lane and merge them, rather than resolving the
project lane alone.

"This section" here refers to the ## Merge semantics section — but this text lives in the bundled lane's own ## Merge semantics block. A consumer reading the bundled file would naturally parse "the presence of this section" as "the fact that this bundled lane has ## Merge semantics." That's wrong: the engine checks for ## Merge semantics in the project layer, not here.

tidy/SKILL.md states this correctly ("governed by the project layer's own ## Merge semantics section"). The bundled lane should match that clarity:

The presence of this section is what tells `/code-tidying:tidy` to read **both** the project
lane and this bundled lane and merge them, rather than resolving the project lane alone.


When a project lane at `.claude/tidy-lanes/docs-prose.md` includes a `## Merge semantics`
section, `/code-tidying:tidy` reads **both** that project lane and this bundled lane and merges
them per that declaration. A project lane without this section resolves project-only.

Fix this →


Finding 2 — No documented escape hatch for opting out of merge mode (low)

setup/SKILL.md step 4 says bundled-lane overrides "start from the bundled lane file… and adjust its scope globs / exclusions to this repo's actual layout." Because the bundled docs-prose.md now includes ## Merge semantics, a scaffolded project lane will inherit it and silently opt into merge mode. A consumer who wants project-only resolution (the old behavior) would need to delete the section — but this is nowhere mentioned.

Given the intent is that merge mode is the better path and project-only is the legacy path, this is low priority. But a single parenthetical in the scaffolding step 4 description would close the gap:

Start from the bundled lane file and adjust its scope globs / exclusions to this repo's actual layout. The scaffolded lane will include ## Merge semantics (merge mode); delete that section to resolve project-only instead.


Other observations (no action required)


Finding 1 should be fixed before merge (misreads as "bundled section triggers merge" when the engine actually checks the project layer). Finding 2 is optional cleanup.

…ing contract

Replace two hardcoded raw.githubusercontent.com URLs with repo-relative
markdown links to docs/conventions/consumer-config-layering/README.md, which
lives natively in this repo. The raw URL fetched external content for a
same-repo file — the anti-pattern issue #432 flags. Relative links render
natively on GitHub, need no network fetch, and survive branch renames.
@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 6s —— View job


PR Review

  • Gather context and understand the request
  • Review changed files against latest commit
  • Check if prior review findings were addressed
  • Post updated review findings

Overall Assessment

The core change is sound and the second commit (fb51db4) correctly switches raw.githubusercontent.com URLs to repo-relative links — but introduces a new low-severity concern. Finding 1 from the prior review remains open and should be resolved before merge.


Finding 1 — Ambiguous "this section" in bundled lane (medium — unresolved from prior review)

File: plugins/code-tidying/skills/tidy/lanes/docs-prose.md, line 26

The presence of this section is what tells `/code-tidying:tidy` to read **both**
the project lane and this bundled lane and merge them, rather than resolving the
project lane alone.

This text lives inside the bundled lane's own ## Merge semantics block. A consumer reading it would naturally parse "the presence of this section" as "the fact that this bundled lane has ## Merge semantics." That is wrong: tidy/SKILL.md line 61 correctly states the engine checks the project layer's own ## Merge semantics section.

Suggested replacement:

When a project lane at `.claude/tidy-lanes/docs-prose.md` includes a `## Merge semantics`
section, `/code-tidying:tidy` reads **both** that project lane and this bundled lane and merges
them per that declaration. A project lane without this section resolves project-only.

Fix this →


Finding 3 — Relative links exit the plugin directory (low — new, from fb51db4)

Files: plugins/code-tidying/skills/tidy/SKILL.md, line 61 and plugins/code-tidying/skills/tidy/lanes/docs-prose.md, line 20

The fb51db4 commit replaces raw.githubusercontent.com URLs with repo-relative links:

  • tidy/SKILL.md: ../../../../docs/conventions/consumer-config-layering/README.md (4 levels up, but plugin root is only 3 levels from SKILL.md's directory — exits the plugin)
  • docs-prose.md: ../../../../../docs/conventions/consumer-config-layering/README.md (5 levels up, plugin root is only 4 levels from lanes/ — exits the plugin)

The CLAUDE.md design rule says "No ../ reach-outs" from plugin files. These paths traverse outside ${CLAUDE_PLUGIN_ROOT} when the plugin is installed. The prior review explicitly marked the raw URLs as "appropriate for skill files fetched by an LLM agent. Intentional" precisely because the docs/ tree ships in this marketplace repo, not in the plugin bundle.

Both links are informational-only (the merge behavior is described inline, so an LLM running the skill doesn't need to fetch the linked file), which keeps severity low. But if the LLM ever does attempt to resolve them from an installed plugin context, the paths won't exist. The commit message's stated rationale ("anti-pattern issue #432 flags") is valid for in-repo links that render on GitHub — but these links target a file outside the plugin bundle, which is the exact case raw URLs are correct for.

Options:

  1. Revert to raw URLs for these two cross-plugin references, treating them as the external-to-plugin citations they are.
  2. Accept as-is with acknowledgment that the links are display-only and the LLM won't need to follow them in practice.

Finding 2 — No documented escape hatch for merge-mode opt-out (low — unresolved from prior review)

Still unaddressed, still low priority. A parenthetical in setup/SKILL.md's step 4 scaffolding description would close it:

The scaffolded lane will include ## Merge semantics (merge mode); delete that section to resolve project-only instead.

Optional — does not block merge.


Other observations (no action required)

  • tidy/SKILL.md Lane resolution prose (lines 56–64) is clear and correctly attributes merge-mode trigger to the project layer. SKILL.md and docs-prose.md are inconsistent on this point — Finding 1 closes the gap.
  • setup/SKILL.md additions — the TODO(#723) notation and single-layer gap description are well-scoped and accurate.
  • consumer-config-layering/README.md cell — the updated implementers row is verbose but accurate; the issue references make the status self-documenting.
  • Version bump 0.6.0 → 0.7.0 and CHANGELOG entry are correct and complete.

Finding 1 should be fixed before merge. Finding 3 warrants a conscious decision (revert or accept). Finding 2 is optional cleanup.

…isambiguate merge-semantics prose

Revert fb51db4's relative-link change. The consumer-config layering
contract README lives at the marketplace-repo root, outside the
code-tidying plugin's own bundle, so it does not ship when the plugin is
installed elsewhere — a relative `../` link resolves to nothing in an
installed context, and this repo's CLAUDE.md forbids `../` reach-outs
from plugin files. The raw.githubusercontent URL is the correct tool for
a cross-plugin-bundle-boundary reference (not the #432 anti-pattern,
which is about content that lives natively in-bundle). A prior review
had already ratified these raw URLs as intentional.

Also disambiguate the bundled lane's "presence of this section" wording:
it referred to the PROJECT lane's own `## Merge semantics` section, but
could be misread as the bundled lane's (always-present) section.

Co-Authored-By: Claude <noreply@anthropic.com>
@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 38s —— View job


PR Review (3rd pass — commit 23716ce)

  • Gather context and understand the request
  • Read changed files at HEAD to verify prior findings addressed
  • Analyze correctness and alignment with project guidelines
  • Post review findings

Overall Assessment

All medium-severity findings from the prior two reviews are now resolved. The PR is clean and ready to merge.


Finding 1 — Ambiguous "this section" ✅ Resolved

File: plugins/code-tidying/skills/tidy/lanes/docs-prose.md, line 26

The ambiguous "The presence of this section is what tells…" wording (which could be read as "the bundled lane's own section triggers merge") has been replaced with the exact formulation recommended in the prior review:

When a project lane at `.claude/tidy-lanes/docs-prose.md` includes a `## Merge semantics`
section, `/code-tidying:tidy` reads **both** that project lane and this bundled lane and merges
them per that declaration. A project lane without this section resolves project-only.

This now correctly attributes the merge trigger to the project layer, consistent with tidy/SKILL.md line 61.


Finding 3 — Relative links exiting plugin directory ✅ Resolved

Files: tidy/SKILL.md, line 61 and docs-prose.md, line 20

Both relative ../ links (from commit fb51db4) have been reverted to raw.githubusercontent.com URLs. The commit message correctly explains the distinction: this is a cross-plugin-bundle-boundary reference (the docs/ tree ships in the marketplace repo, not in the installed plugin bundle), which is precisely the case raw URLs are correct for — not the #432 anti-pattern, which applies to content natively in-bundle.


Finding 2 — No documented escape hatch for merge-mode opt-out (low — unresolved, non-blocking)

setup/SKILL.md step 4 still does not mention deleting ## Merge semantics to resolve project-only. This was explicitly flagged as optional in both prior reviews and does not block merge. Leaving it for a follow-up or #725 / related tidy sweep.


Other observations (no action required)

  • Commit message on 23716ce is precise and self-contained: names the reverted commit, explains why raw URLs are correct for cross-bundle-boundary links (not the session-flow: topic-docs placement contract resolved via hardcoded raw.githubusercontent URL instead of bundled copy #432 anti-pattern), and credits the co-authored fix. No complaints.
  • SKILL.md lane resolution block (lines 56–64) is internally consistent: the project-layer trigger for merge mode is stated clearly, the bundled docs-prose lane is correctly cited as the reference implementation.
  • setup/SKILL.md wording on per-lane declared semantics is clean; the TODO(#723) notation for the single-layer gap is appropriately scoped.
  • Version bump 0.6.0 → 0.7.0, CHANGELOG entry, and implementers table update remain accurate and complete.

This PR is ready to merge. Findings 1 and 3 (medium and low) resolved; Finding 2 (low) is explicitly non-blocking.

@kyle-sexton
kyle-sexton marked this pull request as ready for review July 20, 2026 18:02
@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Post-green review pass complete (rule 8). Bot review classification (3 rounds total on this PR):

Finding Verdict Action
Hardcoded raw.githubusercontent URL to same-repo file (orchestrator's own high-blast-radius finding) Initially flagged VALID by me — later corrected: this repo's CLAUDE.md forbids ../ reach-outs from plugin files, and the target doc lives outside the plugin bundle (won't ship on install), so the raw URL was actually correct all along (a prior review had already ruled it "Intentional" for this exact reason). Reverted my own fix. Reverted, verified live (HTTP 200)
Ambiguous "this section" wording in merge-semantics doc VALID, non-blocking Fixed — reviewer's exact suggested wording applied
No documented escape hatch for merge-mode opt-out Low, explicitly non-blocking in all 3 review rounds Not fixed, left as-is

No inline threads, CI fully green (18/18).

Flipping to ready for review; handing off to the babysit lane for merge.

@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 40s —— View job


PR Review (final pass — ready_for_review trigger)

  • Gather context and read changed files at HEAD
  • Verify prior findings remain resolved
  • Check for any new issues
  • Post final assessment

Overall Assessment

This is a clean, well-scoped conformance fix. All medium-severity findings from the prior three review rounds are confirmed resolved at HEAD (23716ce). No new issues found.


Prior Findings — Status at HEAD

Finding 1 — Ambiguous "this section" wording ✅ Resolved

docs-prose.md line 26 now reads:

When a project lane at .claude/tidy-lanes/docs-prose.md includes a ## Merge semantics section, /code-tidying:tidy reads both that project lane and this bundled lane and merges them per that declaration. A project lane without this section resolves project-only.

This correctly attributes the merge trigger to the project layer and is consistent with tidy/SKILL.md line 61.

Finding 3 — Relative links exiting plugin directory ✅ Resolved

Both links in tidy/SKILL.md line 61 and docs-prose.md line 20 are back to raw.githubusercontent.com URLs — correct for cross-plugin-bundle-boundary references.

Finding 2 — No documented escape hatch for merge-mode opt-out (low, non-blocking)

setup/SKILL.md step 4 still does not mention deleting ## Merge semantics to resolve project-only. Unchanged from prior rounds. Explicitly non-blocking.


Additional Verification


This PR is ready to merge. Findings 1 and 3 (medium and low) resolved; Finding 2 (low) is explicitly non-blocking and left for follow-up.

@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: 23716ce355

ℹ️ 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/code-tidying/skills/tidy/SKILL.md
…docs-prose-decompose

# Conflicts:
#	plugins/code-tidying/.claude-plugin/plugin.json
#	plugins/code-tidying/CHANGELOG.md
@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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


Security Review

  • Gather context and read PR diff
  • Read changed files at HEAD
  • Analyze for security vulnerabilities
  • Post security review findings

Scope

Changed files reviewed: docs/conventions/consumer-config-layering/README.md, plugins/code-tidying/.claude-plugin/plugin.json, plugins/code-tidying/CHANGELOG.md, plugins/code-tidying/skills/setup/SKILL.md, plugins/code-tidying/skills/tidy/SKILL.md, plugins/code-tidying/skills/tidy/lanes/docs-prose.md. No GitHub Actions workflows were modified.


Finding 1 — Mutable main-branch URL in LLM skill instruction text

Severity: SUGGESTION | Confidence: MEDIUM

Locations:

Both files embed:

https://raw.githubusercontent.com/melodic-software/claude-code-plugins/main/docs/conventions/consumer-config-layering/README.md

The prior review rounds explicitly classified these as "appropriate for skill files fetched by an LLM agent" — meaning these URLs are intended for LLM agents to follow during skill execution. Because the reference pins to main (a mutable pointer), any future commit to docs/conventions/consumer-config-layering/README.md on main — including via a malicious PR or compromised contributor — would immediately change the content agents read from this URL without requiring a plugin version bump or consumer update. The fetched content enters the agent's context window and could carry adversarial instructions.

Mitigating factors: The target file is in the same repo under the same trust boundary; org branch-protection rules govern access to main; and the PR review history (23716ce commit message) explicitly explains why this URL form was chosen over a repo-relative path. The current content is benign documentation.

Recommended fix: Pin both URLs to a specific commit SHA instead of main:

https://raw.githubusercontent.com/melodic-software/claude-code-plugins/<SHA>/docs/conventions/consumer-config-layering/README.md

On subsequent updates to the layering contract doc, the SHA in these skill files would be bumped deliberately as part of the PR — turning an implicit dependency into an explicit, auditable one. This follows the same principle as pinning GitHub Actions to commit SHAs rather than branch names.


No other findings

  • plugin.json — version bump 0.6.1 → 0.7.0 only; no new permissions, dependencies, or external trust grants.
  • CHANGELOG.md — purely additive documentation; no executable content.
  • setup/SKILL.md — prose-only changes; no new tool grants, remote fetches, or config that expands the plugin's trust surface.
  • Additive watch-for merging — the new concatenation behavior for watch-for patterns in project lanes is within the project's existing trust boundary (the project team controls .claude/tidy-lanes/). Not a vulnerability.
  • ## Merge semantics as LLM instruction surface — the project layer's merge semantics section is read by the agent and followed. This is within scope of the project's trust boundary and is the intended design. Not a vulnerability in the context of this PR.
  • No GitHub Actions changes. No pull_request_target, workflow_run, script injection, or permission-widening patterns to evaluate.

One suggestion (commit SHA pinning for the raw URL); no blocking security issues found.

@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 12s —— View job


PR Review (post-sync pass — merge with origin/main)

  • Gather context and understand the request
  • Read changed files at HEAD after sync merge
  • Check whether sync merge introduced any new issues
  • Verify prior findings remain resolved
  • Post review findings

Overall Assessment

The sync merge (0baa62a) brings in only 3a3f108 (fix(work-items): paginate open-linked-PR filter) from origin/main — a completely unrelated file that is not in the 6 changed files of this PR. The merge introduced no changes to any of this PR's files, and no conflicts. All prior medium-severity findings remain resolved. The PR content is unchanged from the 3rd and 4th review passes that already gave it a clean bill.


Prior Findings — Status at HEAD (0baa62a)

Finding 1 — Ambiguous "this section" wording ✅ Resolved (unchanged from prior pass)

docs-prose.md line 26 correctly reads:

When a project lane at .claude/tidy-lanes/docs-prose.md includes a ## Merge semantics section, /code-tidying:tidy reads both that project lane and this bundled lane and merges them per that declaration. A project lane without this section resolves project-only.

Finding 3 — Relative links exiting plugin directory ✅ Resolved (unchanged from prior pass)

Both tidy/SKILL.md line 61 and docs-prose.md line 20 use raw.githubusercontent.com URLs — correct for cross-plugin-bundle-boundary references.

Finding 2 — No documented escape hatch for merge-mode opt-out (low, non-blocking)

Unchanged and explicitly non-blocking. setup/SKILL.md step 4 still does not mention deleting ## Merge semantics to resolve project-only. Left for follow-up.


Open Review Thread (Codex)

The unresolved Codex thread on tidy/SKILL.md line 64 concerns whether existing v0.6 docs-prose project lanes should be migrated or detected by setup. kyle-sexton's classification is correct: the no-declaration branch is an intentional, documented backward-compatibility pathtidy/SKILL.md explicitly calls it "the legacy first-match path; lanes still on it are migrated one at a time." This is a scope decision matching the pattern used for #723 and #724 (tracked, not folded in). The thread should be resolved as "by design / out of scope" by a maintainer to unblock the merge.

No new technical issues were introduced by the sync merge.


This PR remains ready to merge. The only merge blocker is the unresolved Codex review thread — the finding itself describes intentional documented behavior and warrants a maintainer close as "by design."

@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

- **Bundled-lane overrides** (`shell-tooling`, `docs-prose`) have no template; start from the bundled
lane file `${CLAUDE_PLUGIN_ROOT}/skills/tidy/lanes/<lane>.md` and adjust its scope globs / exclusions
to this repo's actual layout.

P2 Badge Avoid scaffolding duplicate bundled watch-for patterns

When setup apply creates a docs-prose override, this instruction copies the entire bundled lane, including ## Merge semantics and P-1..P-6, then only retargets its scope/exclusions. The new resolver sees that declaration and concatenates the project's copied watch-for list with the bundled list, so every generic pattern is duplicated for newly scaffolded docs-prose lanes (and copied non-pattern sections also mask future bundled updates). Scaffold this lane as a sparse merge-layer containing only its declaration and the sections the project changes, rather than copying the complete bundled file.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated Opened by automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

code-tidying: docs-prose lane uses undeclared wholesale replacement — decompose to per-key override (conformance, ruling #649)

1 participant