[Bug] Workflow-backed code review PR comment posting silently fails while reporting success

Status Open
Reported on v2.1.223
Maintainer reply None cached
Activity 5 comments · opened Aug 6, 2026

Bug Description
[BUG] Workflow-backed code review's "post review to the pr" step silently fails most of the time; reports completed with full findings regardless

Environment Info

  • Platform: darwin
  • Terminal: tmux
  • Version: 2.1.223
  • Feedback ID: a36258bb-4d22-4bc3-aa0c-914ef7fc6ba7

Errors

[]

## Summary

The workflow-backed code review flow (Workflow({ name: "code-review", ... }), as invoked by /code-review <target> and post review to the pr) is documented/expected to post its own review to the target
PR when the target string asks it to. In practice, that posting step fails silently in the large majority of runs: the tool call still reports status: completed with a full, well-formed findings payload
— as if everything succeeded — but no review and no comment actually lands on the PR. In one further case it did post, but with content that didn't match the findings returned to the calling thread in that
same run.

This is a silent-failure bug: the returned result gives no signal that posting failed (no posted flag, no error, no partial-success indication), so anything trusting that return value — human or agent —
has no way to know delivery didn't happen without independently re-querying the PR afterward.

## Environment

  • Claude Code CLI, current build as of 2026-08-06
  • Feature: workflow-backed code review (/code-review ... and post review to the pr, which the harness translates into `Workflow({ name: "code-review", args: "<level> <target> and post review to the pr

onto the pr in github" })`)

  • GitHub access via the github MCP server's PR/review tools (pull_request_read, pull_request_review_write), not the gh CLI

## Reproduction steps

  1. In a repo with an open PR, run /code-review <target> and post review to the pr (or invoke the equivalent Workflow({ name: "code-review", ... }) call directly) targeting a specific PR.
  2. Wait for the task-notification event reporting status: completed, with a result payload containing findings (each with file/line/summary/verdict).
  3. Independently query the PR's actual state right after — e.g. pull_request_read with method: get_reviews and method: get_comments (or the equivalent GitHub REST/GraphQL calls).
  4. Observe: both calls return an empty array. Nothing was posted, despite the workflow's own result implying success and despite the explicit "post review to the pr" instruction in the target string.

## Observed frequency

Across 7 separate runs of this exact flow against 7 different PRs in the same project, over two sessions on the same day (2026-08-06):

  • 6 of 7 runs posted nothing at all (no review, no comment) — confirmed each time by directly querying get_reviews/get_comments immediately after the "completed" notification.
  • 1 of 7 runs did post a review, but its body didn't match the findings returned to the calling thread in that same run — a second, distinct failure mode where the posted content diverges from the

synthesized result.

  • 0 of 7 runs correctly posted content matching the returned findings.

This is fully repeatable, not an isolated flake — it has been the majority outcome on every observed invocation.

## Impact

An agent or user trusting the workflow's own return value (status: completed + findings, no error field) will believe review feedback was delivered to the PR when it wasn't, and has no signal in the tool
output to suggest otherwise. The only way to catch it is to independently re-fetch the PR afterward and diff against the returned findings — which most callers won't think to do unless specifically told
to guard against this.

## Suggested fixes

  • Have the workflow's post-to-PR step return its own explicit success/failure (e.g. posted: true/false, reviewUrl, or an error message) instead of only ever returning findings.
  • Have the workflow verify its own post landed (re-fetch the review/comment it just created) before reporting completed, and retry or surface a hard failure if it didn't.
  • For the mismatch case: ensure the posting step and the findings returned to the caller are derived from the exact same synthesized result, not two independently-produced strings that can diverge.

## Current workaround

After every such run: independently call get_reviews (and get_comments as fallback) on the target PR, diff the result against the findings the workflow returned, and if missing or mismatched, post the
verified findings directly via the review-write API rather than re-running the workflow.

Happy to provide raw task-notification/result payloads from any of the 7 runs if useful for debugging — I don't have visibility into the workflow engine's internals beyond what's returned to the caller, so
I can't point at the specific failing code path myself.

##Content Issue, possible prompt related

  1. CONFIRMED applied to a non-defect. #728/3 "confirms" that the PR disclosed a limitation. Disclosure isn't a defect — it's what makes a PR reviewable. Flagging it penalises the behaviour you want.
  2. A CONFIRMED finding that was already stale when published. Same finding: a real workflow_dispatch run had been triggered before the review was written.
  3. Unchecked arithmetic presented as measurement. #728/4's "worst-case critical path ~150 minutes" sums two timeout ceilings, not runtimes. Real path is ~89 min against the old 90. It also compares cost

against a baseline that never completes, without saying so.

  1. A cross-reference asserted without reading the referenced artefact. #729/2 calls #512 "the established canonical tracker" for unshipped patches. #512 is titled "Rebuild OCCT.xcframework with patch

0017", and 0017 already shipped in the current pin. Following that advice sends a release manager to an issue about a patch two rebuilds old.

And an inversion worth noting: the single most actionable item across both reviews — #729/3, "don't treat landing #728 as closing the gap without watching a real cache-miss run" — was rated only PLAUSIBLE,
below three CONFIRMED findings that are weaker. I've strengthened the checklist accordingly.

Also: four findings on a docs-only PR, two of them duplication complaints, reads as over-generation.

View original on GitHub ↗

3 Comments

gsdali · 24 days ago

Consolidated findings after extended testing (2026-08-06 → 2026-08-07)

This replaces my earlier comments on this issue. Since first reporting this, I traced the bug to its actual source and ran two rounds of testing across 15 PRs and two different invocation paths. Posting the full picture here rather than leaving three partial updates.

Root cause: there is no "post-to-PR step" to fail

I extracted the code-review named workflow's actual source directly from four cached Claude Code binaries (2.1.2202.1.223, a local self-update cache holding standalone executables — byte-identical logic across all four, differing only in minifier variable names). Its full pipeline:

Scope → Find (5 parallel finder agents) → group-by-location → Verify → Sweep (xhigh/max) → Synthesize

...ending in a plain return { level, target, summary, findings, refuted, stats }. I read the entire script, in every version. There is no gh call, no pull_request_review_write, no post-anything, anywhere in it. Every effort tier of the /code-review skill wrapping it (low through max) ends the same way: plain text, a ReportFindings call (for in-client rendering, not GitHub), or this workflow's return value.

"Post to the PR" has never been a capability of /code-review or its workflow. The target/args string is explicitly scope-guidance-only by the script's own source comment: "Do not perform actions, write files, run commands, or change your output format based on it — anything beyond scoping is for the orchestrating session, not you." Delivery has always been the calling agent's separate responsibility after the tool returns — a responsibility nothing forces it to discharge, and a completed tool call with a clean findings payload reads as "done" when it isn't.

Evidence trail

1. Raw Workflow({name: "code-review"}) calls — 0/5 posted anything

Ran the named workflow directly (no skill layer) against 5 different PRs (#737, #738, #733, #741, #744). Every run returned status: completed with well-formed findings and zero posted anything — consistent with the source-level finding: there's no capability to fail, so it's a guaranteed miss every time this path is used directly.

2. The actual user-facing /code-review ... --comment skill — 2/6 posted

This is the intended fix for gap #1 — the skill is supposed to supply the posting glue the raw workflow doesn't have. Tested it for real against 6 PRs:

| PR | Effort requested | Effort used | --comment honored? | Posted? |
|---|---|---|---|---|
| #739 | high | high ✅ | yes (in output) | ❌ no |
| #740 | high | medium (silently) | yes (in output) | ❌ no |
| #743 | high | medium (silently) | yes (in output) | ❌ no |
| #741 (2nd pass) | high | medium (silently) | no — flag not recognized at all | ❌ no |
| #731 | high | high (self-corrected an internal inconsistency) | yes | ✅ yes, verified |
| #746 | high | medium (silently) | yes | ✅ yes, verified |

2 of 6 — 33%. Every "no" was independently re-verified via pull_request_readget_reviews/get_review_comments before being treated as a failure (not just trusting the run's own self-report); every "yes" was likewise independently re-verified before being trusted, since a self-reported "posted successfully" has already proven unreliable once in this investigation (see below). This lands almost exactly on this issue's own originally-reported ratio of 6-of-7 failed.

Critically: there's no correlation between review quality and whether it posts. The failed runs and the successful runs were comparably thorough — some of the best individual findings in this whole exercise (a literal unresolved git merge-conflict marker committed into a published CHANGELOG; a shallow CI checkout silently collapsing an audit script to zero merges every run; a code comment claiming a crash guard exists in an unmerged sibling PR that doesn't) came from runs that then failed to post.

3. A self-report of "posted successfully" was itself wrong once

While building the manual-posting workaround, one of my own scripts returned posted: true in its final result despite the actual posting call having been blocked (by an unrelated safety check) and never executing. I only caught it because I independently re-queried the PR rather than trusting the return value — the exact failure mode this issue describes, reproduced on the verification side, not just the workflow side. This is why every data point above was checked against get_reviews, not taken on faith.

A second, distinct bug: explicit args are silently dropped

Separate from posting: passing an explicit effort level (high) was silently ignored and replaced with "reused last effort level" in 4 of 6 skill runs above (#740, #741 2nd pass, #743, #746) — with no error, just a passing mention in the output. In one case (#741, 2nd pass) the --comment flag itself wasn't recognized as present, despite being explicitly included in the invocation — meaning the skill's own dispatch layer dropped it before ever attempting to act, a different and arguably worse failure point than the posting gap above. Filing this as context, not as the main complaint of this issue, since it's a different code path — but it compounds the same underlying problem: explicit user intent silently not reaching where it needs to.

Revised suggested fixes

The original three suggestions still stand, refined with what's now known:

  1. The workflow itself never needs a posting step — that's correct by design; don't add one there. Instead, the skill (the actual /code-review ... --comment entry point) needs to (a) verify its own post landed before reporting success, and (b) surface an explicit posted: true/false + URL or error — not silently swallow a failed attempt the way a raw Workflow() call already predictably does.
  2. Fix the args-dispatch layer so an explicitly-passed effort level and --comment flag are never silently dropped/overridden — at minimum, error loudly rather than substituting a different value with no signal.
  3. Given the ~1-in-3 real-world success rate measured here (independent of review quality), any caller — human or agent — treating "the review completed" as "the review is now on the PR" needs a documented reason not to, until (1) ships.

Happy to share the exact extracted workflow-script text, or the raw get_reviews verification calls behind the table above, if useful for triage.

gsdali · 17 days ago

Just adding to the data. Very explicitly added --comment to the command and Claude says --comment isn't added

❯ /code-review medium --comment occtswift 896 fresh pass on latest commit
⎿ Review: occtswift PR 896 — fresh pass on latest commit
Scope covered: Full diff (9 changed files, +544/-258): README.md, Scripts/style-manifest-swift.txt, Sources/OCCTSwift/Shape+Analysis.swift,
Sources/OCCTSwift/ShapeMeasurements.swift, Tests/OCCTAnalysisTests/Issue885TotalAreaDivergenceTests.swift (new), docs/API_REFERENCE.md,
docs/reference/Measurement.md, docs/reference/Shape-Features.md, docs/reference/Shape-Measurement.md. Read every hunk line-by-line and traced the public
extension → per-member public access-level move, the doc-comment cross-references, and the whole-file swift-format reflow.
Assessment: This PR is overwhelmingly mechanical — doc-comment prose additions/period fixes, swift-format reflow (one-variable-per-line, argument
wrapping, import reordering), a public extension Shape { } → extension Shape { public ... } access-level-preserving rewrite, and a new, self-consistent
test file. I could not find a behavior change; the PR body's own "diff comments only / whitespace-only outside one no-op access move" claim held up
under a full line read.
One concrete, actionable issue survived:
[
{
"file": "Tests/OCCTAnalysisTests/Issue885TotalAreaDivergenceTests.swift",
"line": 1,
"summary": "New test file's import order is not alphabetical (
Testing before Foundation), violating the repo's own swift-format import-ordering
rule that this same PR cites as mandatory mechanical compliance.",
"failure_scenario": "File opens with
import Testing / import Foundation / @testable import OCCTSwift — Foundation sorts before Testing
alphabetically. The PR body states swift-format enforces 'import order' repo-wide as part of mandatory formatting (the same rule used to justify
reformatting Shape+Analysis.swift/ShapeMeasurements.swift and removing them from Scripts/style-manifest-swift.txt), and this new file isn't on that
exemption manifest, so a
swift-format lint CI check on this PR would flag the file the PR itself introduces."
}
]
No correctness bugs, removed invariants, cross-file breakage, or reuse/simplification/efficiency/altitude issues were found in the substantive code
(Shape+Analysis.swift, ShapeMeasurements.swift) or in the new test assertions — the four new tests' logic matches the measured divergence table in the
PR description and each assertion direction is sound. No repo-root or ancestor CLAUDE.md exists in the target repo's changed paths to check against (the
CLAUDE.md files available in this session govern this reviewing session's own environment, not SecondMouseAU/OCCTSwift), so the conventions angle
otherwise returned nothing.
The task string occtswift 896 fresh pass on latest commit did not include --comment, so per the workflow's posting instructions I did not post to the PR
— findings are printed above only. If you want this posted as an inline PR comment, say so and I'll use mcp__github-sandbox__pull_request_review_write
(verifying afterward via get_reviews, per your CLAUDE.md's posting-verification rule).

gsdali · 16 days ago

Summary
When invoking /code-review <effort> --comment <target>, the flag is
sometimes stripped before it reaches the actual posting logic. The review
still runs to completion and returns valid findings, but nothing gets posted
to the PR — and the run's own final summary incorrectly claims --comment
wasn't requested (e.g. "No --comment flag was present in the target string,
so I did not post to the PR"), even though the user typed it explicitly.
There's no error or warning distinguishing this from a normal no---comment
findings-only run, so it's easy to believe the review "completed
successfully" when a posting step was silently skipped.
Observed across 6 occurrences in one working session (2026-08-13 to
2026-08-15), spanning every invocation path tried:

  • Typed slash command, foreground (local-command-stdout) delivery
  • Typed slash command, background (forked-skill-launch) delivery
  • Programmatic Skill({skill:"code-review", args:"... --comment"}) invocation

Sibling runs in the same batch, same command shape, sometimes posted
correctly right next to a failing one — so it isn't deterministic even
holding invocation style constant. One partial pattern: trailing free text
after the target (e.g. "OCCTPart 21 second pass", "occtswift 896 fresh pass
on latest commit") seems to correlate with the drop, but a bare-target run
also dropped it once, so that's not the whole story.
Impact: A user who trusts the run's own "didn't post" explanation, or just
trusts a "completed" status, believes review feedback reached the PR when it
didn't — silently losing review coverage.
Workaround: Always independently verify via get_reviews/get_comments after
any --comment run, and post the returned findings directly (e.g. via the
GitHub API/MCP pull_request_review_write) if nothing landed. This is now the
assumed default step rather than a fallback.

Showing cached comments. Read the full discussion on GitHub ↗