feat(ship): thread one ChatGPT conversation across a unit's plan and code review - #649
Conversation
…code review chatgpt-review.mjs scopes each session record to one CLI mode+target, so a plan-author-mode session and a pr-mode session were always separate conversations by construction — the "one unit, one ChatGPT session" rule added after #630 phase 5 was broader than the tool actually supports. Add --seed-from-session <handle>: starts a brand-new session for the current mode (its own pass counter) but reopens an existing session's conversation instead of a fresh chat, copying conversationUrl and lastResponseFingerprint so the "recover an uncollected response" check doesn't mistake the seed conversation's last message for this mode's own answer. --session and --seed-from-session are mutually exclusive. Wire it into code-review-pass.workflow.mjs (seedFromSession arg, used only on pass 1) and correct review-loops.md/SKILL.md to describe the real mechanism: same-mode resumes always use --session; crossing modes (plan authoring -> PR code review) uses --seed-from-session once, then --session from there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
code-review-pass.workflow.mjs and plan-review-loop.workflow.mjs told the review-runner agent to redirect chatgpt-review's JSON output to a fixed literal example filename (chatgpt-review-pr.json / chatgpt-review-plan.json) reused across every PR/unit and every pass for an entire /ship run that can span many hours. Observed live on #630 phase 6, pass 2: the review-runner agent's own structured-output step reported an old, already-resolved review (a different PR's, from hours earlier) as this pass's result, even though the real command for this PR/pass had already run and posted a correct comment moments before. The coordinator only caught this by cross-checking the actual posted GitHub comment against the workflow's returned session/SHA/ findings. Derive a unique filename per invocation (PR number + pass, or plan file slug + pass) and require the agent use it exactly, instead of a generic example it's been observed copying verbatim across unrelated passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
|
Added a second, related fix to this branch: This caused a real incident on #630 phase 6, PR #648, pass 2: the review-runner Fixed by deriving a unique output filename per invocation (PR number + pass, |
Summary
Corrects and implements the "one unit, one ChatGPT session" rule added to the
/shipskill after #630 phase 5. That rule's wording ("plan authoring, every plan-review round,
every PR code-review pass... all belong in the SAME conversation") was broader than the
chatgpt-review.mjsCLI actually supports: each session record is scoped to one CLImode + target (
session.mode !== options.modeis a hard rejection), so aplan-author-mode session and apr-mode session were always separate conversationsby construction — confirmed by every phase 1-5 ship-log entry, which each show distinct
conversation URLs for plan review vs. code review.
What changed
scripts/lib/cli.mjs: new--seed-from-session <handle>value flag, mutuallyexclusive with
--session.scripts/chatgpt-review.mjs: when starting a fresh session (no--session) with--seed-from-sessiongiven, copy the named session'sconversationUrlandlastResponseFingerprintinto the new session record, and pass that session throughto the browser driver (previously only
--sessiondid this —--seed-from-sessionalone would have silently opened a fresh chat despite the seeded record).
pageFor()then reopens that existing tab/conversation instead of starting a new one. The new
session still gets its own pass counter for its own mode (a
pr-mode cap still countsonly
pr-mode passes).tests/core.test.mjs: two new tests — the CLI flag itself, and an end-to-endrun()proof that seeding threads the prior conversation through to the browser driver
without mistaking its last message for an uncollected response.
skills/ship/references/code-review-pass.workflow.mjs: accepts an optionalseedFromSessionarg, used only on pass 1, and tightens the retry instructions so amid-pass retry replaces
--seed-from-sessionwith--sessionrather than trying topass both (the CLI rejects that combination).
skills/ship/SKILL.md/skills/ship/references/review-loops.md: rewritten todescribe the real mechanism — same-mode resumes always reuse
--session; crossingmodes (plan authoring → PR code review) uses
--seed-from-sessiononce to thread theconversation, then
--sessionfrom there.skills/chatgpt-review/README.md/SKILL.md: documented the new flag for directuse outside
/ship.Tests
skills/chatgpt-review's own suite: 45/45 passing (43 pre-existing + 2 new). Fullrepository gate (
check:types/check:arch/check:schemas/check:examples/npm test/npm run build): green — this change touches onlyskills/**, outside thecoverage-gated
src/**tree.Scope note
Process/tooling only — not part of #630's own delivery contract, so it ships as its own
PR rather than folding into phase 6's diff, matching the precedent set by #647.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz