Skip to content

feat(pr-pipeline): let address-feedback edit any file the PR already changes - #9444

Merged
kyle-sexton merged 10 commits into
mainfrom
feat/address-feedback-scope-pr-files
Oct 23, 2026
Merged

kyle-sexton merged 10 commits into
mainfrom
feat/address-feedback-scope-pr-files

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

No related issue: lane stop F22 on PR #9418 (Issue Triage)

Summary

On #9418, claude-review raised a valid finding anchored on converge.md:243. address-feedback confirmed it but stopped with feedback-uncertain: the fix belonged in converge-plan.sh plus a test, outside the thread's editable scope, although both files were already in the PR's diff. Any finding on a doc whose fix lives in a script stalled the PR this way.

address-feedback may now edit any file the pull request already changes, rename sources included. Every existing refusal still applies:

  • .github/workflows/**, settings*.json, symlinks, gitlinks and backslash or off-normal-form paths;
  • CODEOWNERS, .gitmodules and the other instruction paths thread-scope.mjs names;
  • the pr-merge HIGH floor's trusted-actor list, trusted-trigger check and resolve-config;
  • every apply-patch refusal (patch-rules.json is unchanged).

The ready-phase and claude-security-review reviews also kept control-plane and agent-instruction surfaces out of the widened set:

  • anything under .github/;
  • CLAUDE.md, AGENTS.md, .mcp.json and .lsp.json;
  • .claude and .claude-plugin directories;
  • a plugin's hooks/, monitors/ and bin/.

A thread on one of those files still reaches it through its own scope. The tool admits a pr_paths file only as a regular file at the gated head, never a symbolic link.

A file the fix creates gets no scope from the PR's files; new files keep the old per-thread rules. A VALID reply lands from a fix in another PR file only when its evidence cites a line inside one of the fix commit's hunks in that file, so each thread keeps its own anchor.

Fix

  • thread-scope.mjs computes the set in one place. prPathsOf turns the PR's file listing into pr_paths, and inThreadScope admits a pr_paths file the fix does not add.
  • address-feedback.mjs select writes pr_paths into threads.json and run.json. Both are SHA-pinned from the select job, so every enforcer reads the same set.
  • Enforcement:
    • the model's tool, feedback-thread.sh allowed(), admits a pr_paths file that exists at the gated head;
    • the write runner, apply-patch.mjs keptThreadsFrom with the kept-threads predicate, admits a pr_paths entry unless the patch adds it;
    • the reply job, publish-feedback.mjs fixesLanded, does the same for the range, refusing a file that is added, renamed or copied, and accepts a cited pr_paths file as the thread's touched path.
  • comments-ci.md tells the model to run check-paths before calling a file out of scope, and to cite the line it changed.
  • Docs: pr-run-activity.md and the README allow row. Changelog fragments for pr-pipeline and source-control.

The write runner copies thread-scope.mjs from the base, so the widened scope takes effect only after this merges.

Verification

  • node --test on thread-scope, address-feedback, publish-feedback and apply-patch: 330 pass. New cases:
    • a thread on file A with the fix in file B, both in the PR diff, is in scope and pushes;
    • B not in the diff is refused;
    • a protected path in the diff is still refused (workflows, CODEOWNERS, resolve-config, settings, the HIGH floor);
    • a new file is refused even when pr_paths lists it;
    • an uncited PR-file fix does not land.
  • feedback-thread.test.sh passes, with new pr_paths cases for check-paths and record.
  • scripts/check-affected.sh --tests: every lint check passes.
    • The babysit-prs Python suites were selected only because the source-control plugin changed, and failed under the local runner.
    • test_guards, test_skill_contract, test_verify_rules_sync and test_check_contract_clause_coverage pass when run directly with unittest. CI runs the rest.

Related

🤖 Generated with Claude Code

kyle-sexton and others added 7 commits October 23, 2026 11:25
…changes

A finding anchored on one of a pull request's files whose fix lives in
another of its files stalled the round as feedback-uncertain. The select
job now records the PR's files (rename sources included) as pr_paths in
the thread file and run.json, and thread-scope.mjs admits them in every
kept thread's scope for an existing file. The model's tool, apply-patch's
kept-threads rule and the reply job enforce the same set. Workflows,
instruction paths, the HIGH floor and every apply-patch refusal still
apply; a file the fix creates gets no scope from pr_paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A VALID reply now lands from a fix in another of the pull request's files
only when its evidence cites that file, so each thread keeps its anchor.
comments-ci.md tells the model to run check-paths before calling a file
out of scope and to cite the changed line. The tool's pr_paths check
relies on the select job's filtering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-scope-pr-files

# Conflicts:
#	docs/conventions/pr-pipeline/README.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the ready-phase reviews of this change:
- the reply job counts a cited pr_paths file only when the cited line
  falls in a hunk of the fix commit, so one thread's fix cannot land
  another thread's reply;
- the review-thread tool admits a pr_paths file only as a regular file
  at the gated head, never a symbolic link;
- the docs name the instruction paths the code enforces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 23, 2026 15:56
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T16:00:51.603280Z ebef49e Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

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

Code review: PR #9444 (head c33c7ea)

Result: no findings. I found nothing a careful reviewer would block on.

I read the full diff (.claude-lane/pr.diff) and the PR context. I also read thread-scope.mjs and address-feedback.mjs (the files usage). I did not run any tests or scripts, because this lane has no shell. The test results in the PR description are author-claimed and unverified by me.

What I checked

  • One scope rule in four places. thread-scope.mjs (prPathsOf, prPathAllowed, inThreadScope) feeds kept-threads in apply-patch, fixesLanded in publish-feedback, and the feedback-thread.sh allowed() mirror. All four agree that a path the fix adds gets no pr_paths scope.
    • The shell tool checks the mode at the gated head (100644 or 100755). That excludes new files, symlinks and gitlinks.
    • apply-patch treats status A as added. Its diffs use --no-renames, so a rename shows as a delete plus an add.
    • The reply job treats added, renamed and copied as added.
  • Refusals still apply. inThreadScope runs the isProtectedPath, BAD_SEGMENT and PLAIN_PATH checks before any pr_paths admit. prPathAllowed re-checks the instruction and control-plane patterns on the write runner side. So the .github/ surfaces and the other excluded paths stay out even if a thread file listed them.
  • Compatibility. keptThreadsFrom and parseRun accept a missing pr_paths. Older thread files and run.json files therefore still parse. The pr_paths value is validated as an array of strings.
  • Predicate call change. Passing (path, entry) to every predicate is harmless for the others, which ignore the second argument. kept-threads treats an absent entry as added, so it fails closed.
  • Closing issues. None. The PR states "No related issue", so there are no acceptance criteria to check.
  • Plugin manifests. Neither plugin.json nor marketplace.json is touched, so there are no manifest <field> lines. The changelog fragments use bump: minor, which fits a new capability.
  • Hold classes. The change adds no model call or spend. It touches no trusted-actors, check-trusted-trigger, CODEOWNERS or .gitmodules file. It makes no hold-class change, so there is no hold.

Minor observation (not a finding)

  • lineChanged accepts any line inside a hunk's new-side range, and unified-diff hunks carry up to 3 context lines on each side. So "cites a line it changed" is in practice "cites a line within a changed hunk". The PR description and pr-run-activity.md already say "inside one of the hunks"; only the comments-ci.md wording ("a line it changed") is slightly tighter than the check.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

claude-security-review: 1 inline finding(s) on ebef49e250d7e5f0be5c6c1ce79399103f215dd3; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

Comment thread .github/scripts/pr-unblock/thread-scope.mjs Outdated
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

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

Security review: PR #9444 (head c33c7ea)

No security findings.

critical-findings: 0

I read the full diff and the PR context, and checked INSTRUCTION_PATH in thread-scope.mjs and allowed() in feedback-thread.sh against the new pr_paths scope. The PR touches no .claude-plugin/plugin.json or marketplace.json, so there is no manifest <field> line to report. It touches none of the trust-gate paths either (trusted-actors, check-trusted-trigger, CODEOWNERS, .gitmodules), so there is no hold.

What I checked:

  • Scope widening. prPathAllowed and CONTROL_PATH drop these paths from pr_paths, so none of them gets the widened scope:
    • .github/** (the HIGH floor, resolve-config and the pipeline's own scripts)
    • CLAUDE.md, AGENTS.md, .mcp.json, .lsp.json
    • .claude/ and .claude-plugin/
    • a plugin's hooks/, monitors/ and bin/
    • package manifests and settings*.json
    • .github/workflows/, symlinks, backslash or off-normal-form paths
  • Defence in depth. inThreadScope re-applies prPathAllowed on every check, so a forged pr_paths entry in threads.json or run.json does not widen scope.
  • Added files.
    • apply-patch.mjs diffs with --no-renames, so a rename shows as a delete plus an add, and the add is refused.
    • publish-feedback.mjs refuses added, renamed and copied files for the same reason.
    • feedback-thread.sh requires a regular-file mode (100644 or 100755) at the gated head, so new files, symlinks and gitlinks are refused.
  • Integrity of pr_paths. Both threads.json and run.json are SHA-pinned from the select job. parseRun and keptThreadsFrom type-check the field.
  • Evidence citation. lineChanged only makes a VALID reply land more narrowly, since the reply must cite a line the fix changed. It does not widen what can be pushed.
  • Instruction-surface text. The docs and comments-ci.md now list a shorter set of "instruction paths". The code (INSTRUCTION_PATH, the jq regex in feedback-thread.sh) is unchanged in this diff and already matched the shorter list, so this PR removes no enforcement. I could not read docs/conventions/instruction-exception-register/README.md, so I judged by consequence instead of the protected-class list.

Residual risk, not a finding: the scope now includes scripts and code files that the PR already changes, such as repo-level scripts/*.sh. A review-thread comment that tries to steer the model could therefore lead to a model-authored edit in those files. The edit is limited to files the PR author already controls. It still passes the patch scan and the patch-rules.json refusals before it is pushed.

kyle-sexton and others added 3 commits October 23, 2026 12:02
…pr_paths

claude-security-review found that pr_paths put this pipeline's own
scripts and actions, and agent-instruction files, in every thread's
edit scope. pr_paths now leaves out anything under .github/, CLAUDE.md,
AGENTS.md, .mcp.json, .lsp.json, a .claude or .claude-plugin directory,
and a plugin's hooks/, monitors/ and bin/. A thread on such a file
still reaches it through its own scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 5ac7f1d Oct 23, 2026
84 of 87 checks passed
@kyle-sexton
kyle-sexton deleted the feat/address-feedback-scope-pr-files branch October 23, 2026 16:19
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