Repository navigation
Conversation
…ish review hooks Connect the interactive review findings pane to Step 7 render by writing curated findings and keep answers to disk beside the findings file, omitting skipped general observations from render serialization, and relocating the register doc comment. - Record findingsPath from Step 6 disposition command in state atom - Sync <file>.curated.json and <file>.curated.keep on action/edit changes - Omit unanchored findings with action skip in serializeFindingsForRender - Move register doc comment above export function register - Update review-flow.md Step 7a/7b to read curated files when present
|
up for review |
potiuk
left a comment
There was a problem hiding this comment.
Thanks for picking up the #1992 notes: the docstring move and the skip filter are good. This change decides what actually gets posted, though, and the wiring can post something the maintainer dropped, so the inline comments below need answering first. Please also cover $.fs.write in docs/setup/secure-agent-setup.md: it runs outside the sandbox, this is its first use in a Magpie mod, and docs/when-to-use-mods.md requires those trade-offs to be documented.
The keep file overrides the picker (plugins/magpie-pr-management/skills/code-review/review-flow.md:347)
handleBashToolCall writes the curated files at disposition, before anyone curates, so .curated.keep normally holds ALL. This line then passes it whenever it is present. A maintainer who answers 1,3 at the picker still sends ALL, so an inline comment they dropped gets posted. The PR also removes the sentence saying only the picker's answer reaches render, and nothing now says which one wins. Please write these files only after a real curation action, and state which answer takes precedence.
The pane's own buttons do not sync (plugins/magpie-pr-management/hooks/review-findings.ts:1079)
The sync is added to handleUiPress, but the pane's row toggles and All/None buttons use their own onPress callbacks in renderFindingsPane (lines 222, 298, 372 and 381), and those call only setReviewFindingsState. The pane then shows one selection while render gets another. The new test calls handleUiPress directly, so it does not catch this. One shared helper that sets the state and syncs would cover both paths.
Re-running disposition wipes curation (plugins/magpie-pr-management/hooks/review-findings.ts:1213)
Every disposition re-reads the original findings and overwrites the curated files with fresh state. review-flow.md requires a re-run after [E]dit and after CI actions, so those ordinary paths lose the maintainer's edits and selections. Hydrating should not overwrite existing curation for the same findings.
Smaller observations
- See inline comments on
plugins/magpie-pr-management/hooks/review-findings.ts:880,plugins/magpie-pr-management/hooks/review-findings.ts:1312.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
Contributing guide.
| ``` | ||
|
|
||
| When `<file>.curated.json` was written beside the findings file during Step 7a curation, pass that file to `--findings` so maintainer edits and omitted general observations reach `render`. | ||
| When `<file>.curated.keep` is present, pass its contents to `--keep`. |
There was a problem hiding this comment.
The keep file overrides the picker
handleBashToolCall writes the curated files at disposition, before anyone curates, so .curated.keep normally holds ALL. This line then passes it whenever it is present. A maintainer who answers 1,3 at the picker still sends ALL, so an inline comment they dropped gets posted. The PR also removes the sentence saying only the picker's answer reaches render, and nothing now says which one wins. Please write these files only after a real curation action, and state which answer takes precedence.
There was a problem hiding this comment.
Fixed. Initial disposition no longer writes curated files to disk upfront - they are only written after an explicit curation action in the pane or via command.
We also updated review-flow.md Step 7b to make the precedence rule clear: the answer typed by the maintainer at the Step 7a picker prompt always takes precedence and goes directly to --keep <answer>.
| if (targetIdx !== -1) { | ||
| const updated = toggleFindingActionInState(state, targetIdx); | ||
| await setReviewFindingsState($, updated); | ||
| await syncCuratedStateToDisk($, updated); |
There was a problem hiding this comment.
The pane's own buttons do not sync
The sync is added to handleUiPress, but the pane's row toggles and All/None buttons use their own onPress callbacks in renderFindingsPane (lines 222, 298, 372 and 381), and those call only setReviewFindingsState. The pane then shows one selection while render gets another. The new test calls handleUiPress directly, so it does not catch this. One shared helper that sets the state and syncs would cover both paths.
There was a problem hiding this comment.
Fixed. Created a shared helper updateAndSyncReviewFindingsState that updates the state atom and writes to disk.
All in-pane button onPress callbacks (row toggles, All, None) now route through this helper. Added a test that directly invokes these button callbacks to verify disk synchronization.
| }); | ||
| }; | ||
| await setReviewFindingsState($, nextState); | ||
| await syncCuratedStateToDisk($, nextState); |
There was a problem hiding this comment.
Re-running disposition wipes curation
Every disposition re-reads the original findings and overwrites the curated files with fresh state. review-flow.md requires a re-run after [E]dit and after CI actions, so those ordinary paths lose the maintainer's edits and selections. Hydrating should not overwrite existing curation for the same findings.
There was a problem hiding this comment.
Fixed. Added findMatchingExistingFinding during disposition hydration.
When disposition re-runs after [E]dit or CI checks, it matches incoming findings to previous state by ID, file:line, rule, or body, preserving any existing actions (skip, edit) and customized notes.
| await $.fs.write(curatedKeepPath, keepContent); | ||
| return { jsonPath: curatedJsonPath, keepPath: curatedKeepPath }; | ||
| } catch { | ||
| // Fail-open: do not throw or halt execution on file write failure |
There was a problem hiding this comment.
Failed writes are silent
A failed write returns null and every caller ignores it, while the two files are written separately, so they can end up mismatched or stale, and Step 7b trusts them. Please tell the maintainer when the sync fails. Also, when findings are rewritten to [], the earlier curated files stay behind and Step 7b can pick them up.
There was a problem hiding this comment.
Fixed. Added syncError to state. If a disk write fails, an explicit warning is displayed in the pane footer and /magpie-findings status.
Also:
- If a write fails midway, any partial file is cleaned up so
.curated.jsonand.curated.keepnever end up mismatched. - When findings become empty (
[]), existing curated files are automatically deleted from disk so stale findings are not used.
| } | ||
|
|
||
| const keepMatch = rawArgs.match(/^keep\s+([0-9,\s]+)$/i); | ||
| const keepMatch = rawArgs.match(/^keep\s+([a-zA-Z0-9,\s]+)$/i); |
There was a problem hiding this comment.
keep and drop now accept letters
Widening the pattern for g1 means keep abc, which used to be rejected, now skips every inline comment, and keep g1 does the same. Please reject tokens that are neither numbers nor gN, and decide whether keep g1 should touch anchored findings at all. review-flow.md should also mention the gN form.
There was a problem hiding this comment.
Fixed. Added parseFindingTokens with strict validation: every token must match ^\d+$ or ^[gG]\d+$. Invalid strings like abc are rejected with an error message without changing state.
We also decoupled them:
keep 1,3only updates anchored inline comments and leaves general observations untouched.keep g1only updates general observations and leaves anchored comments untouched.
Mentioned the gN form in review-flow.md Step 7a as well.
…ration bridge Address review comments from @potiuk on PR apache#2005: - Do not write curated files to disk upon initial disposition run - Reconcile and preserve existing maintainer curation across disposition runs - Clean up orphaned curated sidecars when findings become empty - Route in-pane button onPress callbacks through updateAndSyncReviewFindingsState - Enforce strict token validation for keep and drop commands and decouple gN observations - Surface sync errors in pane footer and status command - Clarify picker prompt precedence in review-flow.md Step 7b - Document $.fs.write unsandboxed boundary in docs/setup/secure-agent-setup.md
…ration bridge Address review comments from @potiuk on PR apache#2005: - Do not write curated files to disk upon initial disposition run - Reconcile and preserve existing maintainer curation across disposition runs - Clean up orphaned curated sidecars when findings become empty - Route in-pane button onPress callbacks through updateAndSyncReviewFindingsState - Enforce strict token validation for keep and drop commands and decouple gN observations - Surface sync errors in pane footer and status command - Clarify picker prompt precedence in review-flow.md Step 7b - Document $.fs.write unsandboxed boundary in docs/setup/secure-agent-setup.md
c5a4699 to
ed9df03
Compare
Summary
Follow-up to #1992 and maintainer review on #2005 for the
magpie-pr-managementcode-review mod:<file>.curated.jsonand<file>.curated.keepbeside findings upon maintainer curation actions, allowing Step 7renderto consume curated comments directly.onPresscallbacks throughupdateAndSyncReviewFindingsStateto keep UI state and disk in sync.syncErrorin pane footer and/magpie-findings statusif disk writes fail, cleans up partial files on write errors, and removes orphaned sidecars when findings are empty.keepanddroparguments (^\d+$or^[gG]\d+$), rejects arbitrary strings likeabc, and decouplesgNgeneral observations from anchored inline comments.$.fs.writeboundary: Added a dedicated subsection indocs/setup/secure-agent-setup.mddetailing unsandboxed mod write boundaries, rationale, locality constraints, and fail-open design.Type of change
.claude/skills/<name>/)tools/<system>/*.md)tools/*/withpyproject.toml)docs/,README.md,CONTRIBUTING.md)projects/_template/)prek, workflows, validators)plugins/magpie-pr-management/hooks/)Test plan
claude plugin test plugins/magpie-pr-managementpasses all 71 unit and integration tests (0 failures).claude plugin validate --strict plugins/magpie-pr-managementpasses static analysis with 0 errors and 0 warnings.python tools/dev/add-license-headers.py --checkpasses cleanly.onPresscallbacks verified to sync state and disk files.keep abc) and decouple general observations (keep g1).syncError, clean up partial files, and display visible warnings.crlf=0) across all touched files.RFC-AI-0004 compliance
/magpie-findingscommand curate drafted findings for the maintainer; review posting remains gated on maintainer confirmation in Step 7b and Step 8.$.fs.write..curated.*path for the Claude Code mod while preserving the standard sequential text picker prompt for other harnesses.render./magpie-findingscommand.Linked issues
Refs #1887
Follow-up to #1992
Notes for reviewers (optional)
Directly addresses @potiuk's review comments on PR #2005:
onPresscallbacks for row toggles, All, None) now route throughupdateAndSyncReviewFindingsState.syncErrorin pane footer and/magpie-findings status, partial files are cleaned up on write errors, and orphaned sidecars are purged when findings become empty.keepanddropenforce strict token validation and decouple general observations (gN) from anchored inline comments.docs/setup/secure-agent-setup.mdcovering the$.fs.writeunsandboxed host boundary.