Summary
A plan review re-opens for a plan that was already decided, in two situations. Both reproduce on main (56df64c7, v0.23.1), run from source.
Case 1 — ExitPlanMode: identical plan submitted twice opens two reviews
EVENT='{"tool_name":"ExitPlanMode","session_id":"sess-abc","tool_input":{"plan":"# Add caching layer\n\n- add redis client\n- wire cache into handler\n"}}'
echo "$EVENT" | plannotator # review opens -> approve it
echo "$EVENT" | plannotator # a second review opens for the identical plan
Observed: two separate review servers/sessions. There is no dedup on this path — the plan text is read straight from event.tool_input.plan and handed to startPlannotatorServer.
Case 2 — Codex Stop: a bookkeeping-only turn re-opens the previous turn's plan
The Stop hook fires at the end of every turn and scrapes the transcript for the latest plan. If the next turn doesn't propose a new plan (e.g. the agent only wrote a file or recorded a decision), the previously-approved plan is still the latest one in the transcript, so it gets reviewed again.
Repro: send a Stop event whose rollout contains a <proposed_plan> block, approve it, append a non-plan assistant message to the rollout, then send a second Stop event with a new turn_id. A second review opens for the same plan.
getLatestCodexPlan does guard against this, but only within a turn — it requires stop_hook_active and a <hook_prompt marker in the transcript (apps/hook/server/codex-session.ts:244, and the unchanged-plan comparison below it). Once the turn boundary is crossed, neither condition holds and the guard doesn't apply.
Expected
A plan that was already approved isn't re-reviewed unless it changes — at least within the same agent session. saveToHistory already dedups identical resubmissions for version history, but nothing consults a prior decision before opening a session.
Impact
The user is asked to approve the same unchanged plan more than once. In an agent loop where turns end frequently (Codex Stop), this fires on turns that did no planning at all.
Environment
- Plannotator
main @ 56df64c7 (v0.23.1), run from source via bun apps/hook/server/index.ts
- macOS, bun 1.3.14
- Reproduced with
PLANNOTATOR_BROWSER=/usr/bin/true and an isolated PLANNOTATOR_DATA_DIR, approving via POST /api/approve
Note
Happy to send a PR if this is worth fixing and you have a preference for the shape — I have a working patch that records the approval keyed by (project, session id, normalized plan) and skips re-opening on an exact match within the same session, but I didn't want to presume the design. Branch: https://github.com/jpvarbed/plannotator/tree/jas-248-hook-decision-reuse
Summary
A plan review re-opens for a plan that was already decided, in two situations. Both reproduce on
main(56df64c7, v0.23.1), run from source.Case 1 —
ExitPlanMode: identical plan submitted twice opens two reviewsObserved: two separate review servers/sessions. There is no dedup on this path — the plan text is read straight from
event.tool_input.planand handed tostartPlannotatorServer.Case 2 — Codex
Stop: a bookkeeping-only turn re-opens the previous turn's planThe
Stophook fires at the end of every turn and scrapes the transcript for the latest plan. If the next turn doesn't propose a new plan (e.g. the agent only wrote a file or recorded a decision), the previously-approved plan is still the latest one in the transcript, so it gets reviewed again.Repro: send a
Stopevent whose rollout contains a<proposed_plan>block, approve it, append a non-plan assistant message to the rollout, then send a secondStopevent with a newturn_id. A second review opens for the same plan.getLatestCodexPlandoes guard against this, but only within a turn — it requiresstop_hook_activeand a<hook_promptmarker in the transcript (apps/hook/server/codex-session.ts:244, and the unchanged-plan comparison below it). Once the turn boundary is crossed, neither condition holds and the guard doesn't apply.Expected
A plan that was already approved isn't re-reviewed unless it changes — at least within the same agent session.
saveToHistoryalready dedups identical resubmissions for version history, but nothing consults a prior decision before opening a session.Impact
The user is asked to approve the same unchanged plan more than once. In an agent loop where turns end frequently (Codex
Stop), this fires on turns that did no planning at all.Environment
main@56df64c7(v0.23.1), run from source viabun apps/hook/server/index.tsPLANNOTATOR_BROWSER=/usr/bin/trueand an isolatedPLANNOTATOR_DATA_DIR, approving viaPOST /api/approveNote
Happy to send a PR if this is worth fixing and you have a preference for the shape — I have a working patch that records the approval keyed by (project, session id, normalized plan) and skips re-opening on an exact match within the same session, but I didn't want to presume the design. Branch: https://github.com/jpvarbed/plannotator/tree/jas-248-hook-decision-reuse