fix(web): a command you stop stays in the timeline - #13790
Conversation
Stopping a turn mid-command marks the command interrupted, which the work log maps to "stopped". The timeline treated stopped calls as neutral (neither success nor failure) and filtered them out like empty rows, so the command vanished once the run settled. Stopped is an outcome, so keep it visible, as mobile already does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a narrowly scoped web timeline bug fix that preserves stopped command rows without changing command execution or other lifecycle behavior. A focused regression test covers the interrupted-command case, and no product-default or static-analysis configuration is modified. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
43b480b
into
t3code/codex-turn-mapping
When you stop a turn while a command is running, the command disappears from the timeline once the run settles. You see "Running sleep" while it runs, then after Stop only the "Run interrupted" marker is left, with no trace of the command that was cut short.
Seen live on Codex 0.156.1 (gpt-6-luna). The prompt was
sleep 90 && echo slept, stopped mid-command. The projection keeps thecommand_executionturn item (status: "interrupted",input: "/bin/bash -lc 'sleep 90 && echo slept'", no output), but the DOM has no row for it:Why
interruptedandcancelleditems map to the work-log statusstopped.workEntryIsVisibleInGrouphides tool rows that are "neutral", meaning neither success nor failure, which is meant for empty or incomplete rows.workEntryIndicatesToolSuccessexplicitly excludesstopped, so every stopped tool counted as neutral and was filtered out of settled rows. The labels already have a stopped outcome ("Stopped vp", "Stopped clicking in the preview browser"), and mobile'sthreadFeedActivityIsVisiblealready keepslifecycleStatus === "stopped"rows. Only web dropped them.Fix
workEntryIsVisibleInGroupkeeps entries whose lifecycle status isstopped. Nothing else changes: success and failure markers, folds, and in-progress rows behave as before.Verification
MessagesTimeline.logic.test.ts("hides the interruption request while keeping intervening work and the result"): it builds a stopped command followed by the interrupt result for an interrupted latest run. It fails on the base (expected [ 'interrupt-result' ] to deeply equal [ 'stopped-command-entry', … ]) and passes with the fix.vp test run src/components/chat/MessagesTimeline.logic.test.ts src/session-logic.test.ts: 177 passed.vp test run src/components/chat/MessagesTimeline.test.tsx src/components/chat/timelineMinimapItems.test.ts src/session-logic.runtime-diagnostics.test.ts: 81 passed.vp exec tsc --noEmit -p .inapps/web: clean.vp lintandvp fmton the two touched files: clean.Model: Claude Opus 5.5 (Claude Code)
🤖 Generated with Claude Code