Skip to content

fix(pr-review-cli): read only a reviewed-head marker from the same caller - #972

Merged
kyle-sexton merged 2 commits into
mainfrom
fix/967-review-marker-key
Nov 3, 2026
Merged

kyle-sexton merged 2 commits into
mainfrom
fix/967-review-marker-key

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Refs: #967

Summary

Two callers on one pull request share the reviewed-head marker lane=claude-review. A docs-only skip by the legacy pr-review.yml recorded a head that pr-review-cli.yml then skipped as already reviewed, so a workflow change merged without code review on pr-pipeline-sandbox#273.

This PR delivers the reusable-side fix. A marker now counts as a prior review only for the caller that wrote it.

Fix

  • publish.cjs always writes the second marker line, now with the caller workflow path from GITHUB_WORKFLOW_REF: <!-- claude-lane-reviewed-base ref=main merge-base=<sha|none> caller=.github/workflows/review.yml -->.
  • The scope step in pr-review-cli.yml (all three legs) reads only a marker naming its own caller.
  • The scope steps in pr-review.yml and pr-review-security.yml ignore a marker naming a caller, so a CLI skip cannot narrow a legacy review.

Why the caller is on line 2:

Transition: an open pull request's existing CLI marker names no caller, so its next push gets one whole review and a new lane comment. That cost is one review per open PR.

Verification

  • New tests in claude-lane-scope.test.cjs cover the issue's fixture (CLI marker at A, newer legacy marker at the head, reviews incrementally from A), a legacy marker alone, another caller's marker, the caller's own marker still skipping, and both legacy lanes ignoring a marker naming a caller.
  • Negative control: with the three workflows restored from origin/main, all 6 new tests fail.
  • node --test passes on the scope, publish, CLI, API-call, completion and script-body suites.
  • GitHub documents that in a reusable workflow "the github context is always associated with the caller workflow" (docs). That the GITHUB_WORKFLOW_REF variable follows the same rule is checked on this PR's own review lanes only after merge, through the sandbox step below.

Left out: the live sandbox re-run, because the sandbox pins a released reusable (see Remaining).

Remaining

Related

  • Refs #8994: this PR is the vehicle for that issue's live ready probe.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VQb9Q1VgLEiwGgRVshK3b7


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

…ller

Two callers on one pull request share the marker key lane=claude-review.
A docs-only skip by the legacy pr-review.yml recorded a head that
pr-review-cli.yml then skipped as already reviewed.

The marker's second line now always carries the caller workflow, and
pr-review-cli.yml reads only a marker naming its own caller. pr-review.yml
and pr-review-security.yml ignore a marker naming a caller. The first line
stays unchanged because other repositories match it with anchored patterns.

Refs: #967

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQb9Q1VgLEiwGgRVshK3b7
@kyle-sexton
kyle-sexton marked this pull request as ready for review November 3, 2026 03:51
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 3, 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-11-03T04:04:40.066197Z e50d559 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 Nov 3, 2026 •

Copy link
Copy Markdown

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

No security findings in PR #972. The skip gate does not apply, because the change touches review-scoping and skip logic, so I read the whole diff.

What changed. The claude-lane-reviewed-base marker line now also records a caller= value, taken from GITHUB_WORKFLOW_REF with whitespace replaced. pr-review-cli.yml reads only markers that name its own caller. pr-review.yml and pr-review-security.yml ignore any marker that carries a caller=. The tests and README are updated to match.

What I checked.

  • Who can write the marker. The comment.user?.login === "github-actions[bot]" filter is unchanged in all five scope steps. A PR author cannot forge a marker that makes the lane skip or narrow a review.
  • Where caller comes from. It comes from the workflow ref of the calling workflow, which is not PR-body text. The \s replacement and the (\S+) regex keep it to a single token. A PR that renames the caller workflow only makes the lane fail safe, since it finds no matching marker and reviews the whole pull request.
  • Legacy markers. In pr-review-cli.yml, a marker with no caller, an unparseable second line, or another caller's name no longer counts as a record. The result is a whole review, not a skip. The test "a newer legacy marker at the head neither skips nor narrows the review" covers this.
  • Model-written summary text. The marker body also holds the model's summary, which comes from untrusted PR content. The /^<!-- claude-lane-reviewed-base .* caller=/mu test in the legacy workflows scans the whole body, so a summary line shaped like that header could make a legacy lane discard its own marker. That causes a whole re-review, not a skipped one. In pr-review-cli.yml only line 2 is matched, and publish.cjs writes that line from fixed values.
  • base dereference. BASE_LINE.exec(lines[1]) is called after the filter has already matched that line, so base cannot be null.
  • Trust controls. I read nothing that widens a trusted-actor list, token scope, kill switch, merge hold or isolation. publish-review/publish.cjs and the workflow permissions: and triggers are otherwise unchanged. The publish.cjs edit only writes the extra marker field.

I did not read docs/contracts/instruction-exception-register/README.md, since no standing instruction is removed or softened. The workflow scripts' marker handling is covered by the zizmor lane, and nothing here needed deeper reasoning.

manifest fields: none hit (no plugin manifests changed).

critical-findings: 0

@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

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

Code review: no findings

I read the full diff (9 files) and the PR context. I did not run the test suites. The PR body says they pass, but that is the author's claim and I haven't verified it.

What I checked

  • Caller value on both sides. publish.cjs and the three scope steps in pr-review-cli.yml derive the caller from GITHUB_WORKFLOW_REF the same way (drop @ref, drop owner/repo/, replace whitespace with _). The scope steps read process.env directly, and the publish step runs as a composite action, so the variable is present in both places.
  • Missing variable. If GITHUB_WORKFLOW_REF is unset, the marker is written as caller=. The scope regex needs caller=(\S+), so it never matches and the lane reviews the whole pull request. That is a safe failure.
  • merge-base=none. The scope step maps it back to an empty merge base, the same as the old no-base-line case. The last-summary slice moves from "skip 2 lines, then 1" to slice(3), which is the same offset.
  • marker-id. It is now set only for the caller's own marker, so a different caller's marker is never updated in place. A new comment is created instead, as the PR's transition note says.
  • Legacy lanes. pr-review.yml and pr-review-security.yml still write the old second line without a caller and still use their old BASE_LINE. Their added filter ignores any marker whose base line names a caller. Neither legacy workflow uses the publish-review action, so they never write a caller marker themselves.
  • Tests. The new scope tests cover the fixture from the issue, a legacy marker alone, another caller's marker, the caller's own marker still skipping, and both legacy lanes ignoring a caller marker. The existing fixtures that now need a caller on line 2 are updated.
  • Closing issues. The PR uses Refs: #967, so no closing issue is read and no acceptance criteria apply.
  • Path-scoped rules. The only rule file, pr-body-contract.md, covers the PR body. The body opens with Refs: and has the required sections.

Unverified: that GITHUB_WORKFLOW_REF carries the caller's path inside a reusable workflow. The PR acknowledges this and defers the live check to the sandbox re-run after merge. If the variable named the reusable instead of the caller, two callers would again share one marker value, so this check matters.

Not flagged (cosmetic): the new README sentence leaves one line well past the surrounding wrap width.

@kyle-sexton
kyle-sexton marked this pull request as draft November 3, 2026 04:02
@kyle-sexton
kyle-sexton marked this pull request as ready for review November 3, 2026 04:02
@kyle-sexton
kyle-sexton added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 0086352 Nov 3, 2026
56 checks passed
@kyle-sexton
kyle-sexton deleted the fix/967-review-marker-key branch November 3, 2026 04:10
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