Skip to content

feat(pr-pipeline): add a markdown-only docs patch row - #10174

Merged
kyle-sexton merged 9 commits into
mainfrom
work-resolve-issue/issue-8956-40262011606-1
Oct 27, 2026
Merged

kyle-sexton merged 9 commits into
mainfrom
work-resolve-issue/issue-8956-40262011606-1

Conversation

@melodic-automation-lanes

Copy link
Copy Markdown
Contributor

Refs: #8956

Summary

Opened by the work-resolve-issue lane. The run's own summary:

Adds a docs row to patch-rules.json for fix-docs. It allows only paths ending in .md (new markdown allow predicate) and refuses any path under a skills/ directory at any depth and any SKILL.md, through two new optional refusals that apply only to a row naming them, so no other row changes. Not wired yet: pointing pr-refine.yml's apply-docs-patch job at the row is a .github/workflows/ edit, and this lane's issue patch row refuses every such path, so that step is left for a person.

Remaining work

  • Wire fix-docs to the row: in .github/workflows/pr-refine.yml, pass patch-prepare: docs from the apply-docs-patch job and rewrite the comment above that job, which says it uses the default row (a workflow edit this lane cannot push).
  • Update callers.test.mjs for that wiring. Its test asserts that a push job's patch-prepare equals its producer's prepare in pr-pipeline.yaml (callers.test.mjs:1993), which fix-docs does not set, so it needs a fix-docs exception that asserts docs. Also list docs in pr-run-activity-write.yml's pa
  • Once wired, update the fix-docs text that still says the default row: docs/conventions/pr-pipeline/pr-run-activity.md (the apply-docs-patch paragraph near line 1358) and the comment on pr-pipeline.yaml's fix-docs activity, and change the apply-patch.test.mjs fix-docs tests that push under default

Not verified

  • I didn't run the node test suites (apply-patch.test.mjs, resolve.test.mjs, callers.test.mjs, live-config.test.mjs): this lane allows no interpreter, and run-test-file.sh is not one of its verify scripts. The PR's CI runs them; the reviewer traced each new test by reading the code.
  • I didn't make the .github/workflows/ edits the issue asks for (pr-refine.yml passing patch-prepare: docs, plus the input description in pr-run-activity-write.yml). apply-issue-patch's issue row refuses every .github/workflows/ path, so including them would have got the whole patch refused. They
  • I didn't run CI-only checks such as actionlint, editorconfig, gitleaks and lychee-offline here; the PR's CI runs them.

Fix

  • .github/scripts/apply-patch/predicates.mjs: new markdown allow predicate (a path ending in .md, case-sensitive)
  • .github/scripts/apply-patch/apply-patch.mjs: new skills and skill-md refusals (protected-path, any case, through ..), marked optional so checkRow does not require them on every row; rename-into-refused still reads only the universal path rules
  • .github/actions/resolve-config/patch-rules.json: new docs row: universal refusals plus skills and skill-md, allow [markdown], otherwise the same as default (300-file cap, commit message, skip-moved-head false, patch-* reasons)
  • .github/actions/resolve-config/patch-rules.schema.json: docs property, the new refuse and allow enum values with descriptions, and a corrected rename-into-refused description
  • .github/scripts/apply-patch/apply-patch.test.mjs: refusal-table, checkRow and row-shape tests for the docs row; push tests showing markdown outside skills/ pushes, non-markdown paths (.sh, .json, .mjs, .MD) are refused patch-protected-path, a SKILL.md, a skills/ markdown file or a deleted SKILL.md i
  • .github/actions/resolve-config/resolve.test.mjs: the shipped-registry row list includes docs
  • docs/conventions/pr-pipeline/README.md: Patch rules section describes the docs row, the markdown allow rule and the two refusals
  • .changes/pr-pipeline/feat-8956-docs-patch-row-3e7a91c4.md: minor changelog fragment (pr-pipeline is in fragment mode)

Verification

The runner ran each check from the base copy against b109647:

  • scripts/check-changelog-fragments.sh --check: passed

The run reports:

  • .lane/checks/bin/check-changelog-fragments: passed, all 3 fragments valid (an earlier direct CHANGELOG.md edit failed check-affected's changelog-parity in fragment mode; I reverted it and wrote a fragment instead)
  • .lane/checks/bin/check-affected: passed, 8 checks passed and 5 skipped over 8 changed files
  • fresh-context review subagent over the whole diff: no correctness bugs; it raised a missing space and an inaccurate rename-into-refused description in the schema, and a test filename that collides on case-insensitive filesystems. All three are fixed
  • The lane run: https://github.com/melodic-software/claude-code-plugins/actions/runs/40262011606

Left out: the items under Not verified.

Related

#8956

Lane-Activity: work-resolve-issue/resolve-issue
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed ba94febac62b9b6902df13abb2fa64e9fa43b82c: 0 finding(s), 0 as inline comments.

No security issues found in this pull request.

critical-findings: 0

What I checked. I read all 8 changed files in the diff and the PR context. I read the PR description as data only. It contains no embedded instructions.

Trusted path hit. .github/actions/resolve-config/patch-rules.json matches a trusted-path glob, and so does the schema next to it. The change only adds a docs row. No workflow selects that row yet, because the PR says the pr-refine.yml wiring is left for a person. Even once it is wired, the row can only be stricter than default:

  • It allows only paths ending in .md, where default allows any.
  • It carries every universal refusal that default has (github-workflows, codeowners, gitmodules, settings, symlink, gitlink, rename-into-refused) and adds skills and skill-md.
  • The cap, commit template, escalations and skip-moved-head are copied from default.

The change does not widen trust, token scope, the kill switch, a merge hold, or what the broker's signer process grants.

Path-matching logic.

  • The two new refusals use segments(), the same normaliser the existing rules use. It lowercases and resolves . and .. segments, so Skills/ and a/../skills/x.md are caught.
  • Entries come from diff-tree --no-renames, so a rename shows up as a delete plus an add. The old path is checked as well as the new one: a rename out of skills/ or of a SKILL.md is refused on the delete side.
  • rename-into-refused still reads only the universal path rules. Entries it did not catch still face the full row, so nothing slips through.
  • refusalsOf defaults to non-optional refusals, and checkRow skips optional ones when checking that a row lists every refusal. Existing rows therefore behave exactly as before. Any caller that passes a row's refuse list still gets that row's own refusals.
  • The markdown predicate is endsWith(".md") and is case-sensitive. Case variants such as .MD are refused. A tricky name like x.md/.. is normalised away before the path reaches the allow rule.

Manifests. No plugin.json or marketplace.json change.

Instruction-surface deletions. None. The diff removes no standing rule.

Spend. This change adds no lane runs and no paid usage.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed ba94febac62b9b6902df13abb2fa64e9fa43b82c: 0 finding(s), 0 as inline comments.

No findings. I read all 8 changed files and traced the new code paths. I did not run any tests; I had no shell.

What I checked

  • Refusal table: skills and skill-md are marked optional in REFUSALS. refusalsOf and checkRow skip optional refusals unless a row names them, so every other row behaves as before. push uses [...row.refuse, ...ALWAYS], so the docs row picks up both refusals in .github/scripts/apply-patch/apply-patch.mjs. The merge-row path takes the same list, but docs is not a merge row.
  • Rename handling: renames are checked only against rename-into-refused, which still reads the universal path rules. A patch that renames a file into or out of skills/ is still caught. The push diff uses --no-renames, so the old and new paths each arrive as a delete or an add and face the skills and skill-md refusals.
  • Path matching: segments() lowercases and resolves .., so Skills/, a/../skills/x.md and SKILL.md in any case are refused. docs/skills.md and skillset/ are not refused, which the tests assert.
  • Markdown allow rule: markdown is a case-sensitive .md suffix check, so GUIDE.MD escalates patch-protected-path.
  • Other readers of the registry:
    • checkPatchRules checks the new row against the schema, which lists skills, skill-md and markdown.
    • It still enforces the universal refusals, which the docs row lists.
    • deny-rules.mjs reads only the issue row, so the new refusals need no deny patterns.
    • intake-triage/admit.mjs imports only PROTECTED_REFUSALS.
  • Tests:
    • Fixture: the new push tests fit the repoWithPatch fixture. scripts/x.sh, README.md and notes.md already exist there, and docs/ does not.
    • Escalation text: the expected text matches the code's order. skills is listed before skill-md, and the non-markdown case produces not allowed by markdown: <path>.
    • Existing tests: the all-rows instruction-path test was updated to filter out optional refusals. I found no other test that enumerates every row and would break.
  • Schema and docs text: the corrected rename-into-refused description matches pathRefused in .github/scripts/apply-patch/protected-paths.mjs. The README and changelog fragment describe the behaviour accurately.
  • Closing issue: the PR says Refs: #8956, and its context file has no closing-issue section with acceptance criteria. Nothing to check there.

Scope notes

  • The docs row is stricter than default, so it widens nothing. Nothing selects it yet, which the PR states. The pr-refine.yml wiring and the follow-up test and doc edits are listed under its "Remaining work" and are left for a person.
  • The embedded PR text contains no instructions aimed at the reviewer.
  • The author's verification claims (changelog check, check-affected, subagent review) are unverified by me.
  • Spend: none beyond ordinary CI runs, so no cost hold.

@melodic-automation-lanes

Copy link
Copy Markdown
Contributor Author

Unattended merge: native auto-merge leaves this pull request unarmed at head b1096471f85c5922b6e72f47c89ea5884f83919c. A person must clear this reason, so the pr-merge lane added the needs-human label: fix the reason, then remove the label, and the next scheduled run judges it again.

it changes .github/actions/resolve-config/patch-rules.json, a hold path

@melodic-automation-lanes melodic-automation-lanes Bot added the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 26, 2026
# Conflicts:
#	.github/actions/resolve-config/patch-rules.schema.json
#	docs/conventions/pr-pipeline/README.md
@kyle-sexton kyle-sexton removed the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 26, 2026
@melodic-automation-lanes melodic-automation-lanes Bot added the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 26, 2026
@melodic-automation-lanes

Copy link
Copy Markdown
Contributor Author

The pr-unblock lane stopped on this pull request and needs a person: the lane could not fix every failing check; its run log names each one and why.

  • Reason: ci-fix-escalated
  • Resume key: f113e3b36875de3e69efde1cac4e81db62359bad (the head the lane stopped on)

To resume, deal with the reason above, remove the needs-human label (and do-not-merge, if set), then dispatch the pr-unblock workflow with pr-number=10174 and activity=fix-ci:

gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=10174 -f activity=fix-ci

kyle-sexton and others added 7 commits October 26, 2026 12:53
refusalsOf with no names applied every REFUSALS key, so the new optional
skills rule refused a settings file under plugins/<p>/skills/ and broke
"admits a settings file anywhere under plugins/". Optional refusals apply
only to a row that names them, as checkRow already treats them.

Refs: #8956

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sue-8956-40262011606-1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane-Activity: pr-unblock/resolve-conflicts
Lane-Activity: pr-unblock/resolve-conflicts
…sue-8956-40262011606-1

No conflicts: the branch's apply-patch, resolve-config patch-rules and
pr-pipeline README changes touch no file main changed since 3070246.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sue-8956-40262011606-1

No conflicts: main's ADR, machine-health and release commits touch no file
this branch changes.

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

@kyle-sexton kyle-sexton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Owner decision 2026-10-26 ~22:3xZ in the hub session: merge the PRs currently held for the owner, security-flagged or otherwise. Approving head ba94feb under that decision; this lifts its hold path (resolve-config/patch-rules.json) per merge-holds.mjs. The needs-human label still needs removal by the owner.

@kyle-sexton kyle-sexton removed the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 27, 2026
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 6c502cb Oct 27, 2026
56 of 57 checks passed
@kyle-sexton
kyle-sexton deleted the work-resolve-issue/issue-8956-40262011606-1 branch October 27, 2026 02:44
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.

1 participant