fix(review): deliver code-review findings to the Review panel - #170
Merged
Conversation
A PR review run reported its findings and the panel stayed empty. Three defects stacked up between the agent's tool call and the ingest path. 1. collectOutput picked the streaming reader off a hand-listed subset of the callbacks (onTurn / onThinking / onToolResult). A review request sets none of those, so it fell through to the batch read, which re-scans the logs with an empty streamCallbacks and drops every callback. The findings were on the stream with nothing listening. Replaced with an exhaustive streamCallbacks.any(), which also restores stream-derived activity events for requests that set only OnActivity. 2. Tool inputs reached callers only as summarizeToolInput's chat-facing summary, which is empty for any tool it has no case for — including ReportFindings. Added ToolUse.Raw / onToolUseRaw / OnToolUseRaw so a caller that needs to decode arguments gets the verbatim JSON, and pointed the review runner at it. 3. Review runs forked the built-in /code-review command into a silent subagent instead of running it inline. Inline requires CLAUDE_CODE_REPORT_FINDINGS plus an available ReportFindings tool, so review mode now drops that tool from the batch disallow list and passes the env via --settings. Container env is applied *under* the user's settings file, so a host CLAUDE_CODE_SUBAGENT_MODEL would otherwise overwrite ours; --settings lands in a scope that wins. Tests cover the raw channel, the streaming gate per callback, and a review-shaped request end to end, plus the real findings payload. Docs updated to describe ReportFindings as the default reporting channel with the MCP tool as the override path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A PR review run reported its findings and the Review panel stayed empty. Three defects stacked up between the agent's tool call and the ingest path — fixing any one alone would not have surfaced a comment.
1. The stream reader dropped the callbacks
collectOutputchose between following the container's logs live and reading them once at exit based on a hand-listed subset of the callbacks:A review request sets only a tool-use callback, so it fell through to the batch read — which re-scans the logs with an empty
streamCallbacksand discards everything. The findings were sitting in the stream with nothing listening.Replaced with an exhaustive
streamCallbacks.any(), so a callback can't be silently ignored by omission again. This also fixes a latent case: a request setting onlyOnActivitywas losing stream-derivedmodelandapi_retryevents for the same reason.2. Tool inputs reached callers only as a lossy summary
extractToolUsespassedsummarizeToolInput's chat-facing summary, which returns""for any tool whose schema it doesn't know — includingReportFindings. AddedToolUse.Raw,onToolUseRawandAgentRequest.OnToolUseRawso a caller that has to decode arguments gets the verbatim JSON, and pointed the review runner at that instead.3. The review command forked into a silent subagent
The built-in
/code-reviewcommand runs inline only whenCLAUDE_CODE_REPORT_FINDINGSis set andReportFindingsis callable; otherwise it forks. A fork emits nothing on the parent stream — the run looks hung for minutes — and its findings never reach a tool call the parent can observe.Review mode now takes
ReportFindingsout of the batch disallow list and passes the env through--settingsrather than container env vars. Settings scopes are applied overprocess.envin a fixed order, so a container env var ranks below the user's settings file — which is bind-mounted into every agent container. A hostCLAUDE_CODE_SUBAGENT_MODELwould otherwise overwrite ours and quietly downgrade the model;--settingslands in a scope that wins.Verification
Reproduced against a real review run, whose
ReportFindingspayload is now a test fixture. Before: sessionready, 0 comments. After: both findings render in the panel.go test ./...cleanmake coverage-check→ 100.0%make lint→ 0 issuesTests added cover the raw channel, the streaming gate per callback, and a review-shaped request end to end. Docs now describe
ReportFindingsas the default reporting channel with the MCP tool as the override path for non-slash review prompts.