Skip to content

fix(web): restore draft images after prompt recall

MacroscopeApp / Macroscope - UI Consistency failed Aug 23, 2026 in 1m 46s

UI Consistency: 1 new finding, 1 unresolved

New finding

  • apps/web/src/components/chat/ChatComposer.tsx (L2183-2185): the prompt-history arrow-key handler returns true for any ArrowUp/ArrowDown while an attachment restore is pending, before the modifier/composition guards. Shift+Arrow selection and Cmd/Alt+Arrow caret motion are swallowed, and because materializeComposerPromptHistoryAttachments can fetch remote preview URLs with no timeout, the window is unbounded. Posted inline.

Still unresolved from a prior run (not re-posted)

  • apps/web/src/components/chat/ChatComposer.tsx (~L3386-3395): the new always-mounted attachment-strip wrapper animates grid-template-rows and margin-bottom, but visibleComposerImages.length > 0 gates both the row classes and the children. Removing the last attachment unmounts the thumbnails in the same render that flips to grid-rows-[0fr], so the height collapse is instant while the 12px mb-3 continues animating for 200ms
    edal markup did not have. Code is byte-identical at this head (49e1e3a).

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Scope reviewed: apps/web/src/components/chat/ChatComposer.tsx, apps/web/src/components/ComposerPromptEditor.tsx, apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/composerPromptHistory.ts(.test.ts), apps/web/src/types.ts.

Methodology:

  • Diffed merge base 30be311 to head 49e1e3a and reviewed each commit in the branch individually to confirm which prior findings were addressed.
  • 535089d finding (ArrowUp clamped at the oldest entry still consuming the key) is fixed: navigateComposerPromptHistory now returns null when offset >= entries.length - 1, and isCaretOnVisualEdge gates navigation from a multiline caret. No further comment needed.
  • 44d9ae7 finding (attachment-strip collapse transition) verified unchanged at head via git_grep on data-chat-composer-image-attachments.
  • Head commit 49e1e3a only swaps the unmount-time draft restore to restoreComposerPromptHistoryDraft plus a focused test; no styling or primitive changes.
  • No shared-primitive, Tailwind-ownership, theme-variant, or scroll/mask violations found: the raw <button> around the thumbnail is a pre-existing image target (intentional exception), the new wrapper keeps geometry local as static Tailwind classes with motion-reduce:transition-none, no global CSS was touched, and no hidden focusable content is left behind when the strip is collapsed (children render only when attachments exist).
  • ChatComposer has a single call site (ChatView.tsx), which passes the new required promptHistoryEntries prop.

πŸ” Agent activity β€” 8 tool calls

πŸ’­ I'm checking the current state of the attachment grid transition in ChatComposer.tsx, since prior runs flagged the transition collapse issue and history clamp problem. I want to see if the code at the current head has actually addressed those concerns.

1. git_tools β€” 30be311..49e1e3a

2. git_tools β€” data-chat-composer-image-attachments

3. git_tools β€” 30be311..49e1e3a

4. git_tools β€” data-chat-composer-image-attachments

πŸ’­ That transition markup issue I already flagged at line 3390 hasn't changed since the commit I reviewed, and the current head just restores draft images after prompt recall, so it's unrelated. I shouldn't repost that duplicate β€” instead I'm now checking if the head commit introduces any new UI-relevant issues compared to the earlier flagged commit.

5. git_tools β€” 49e1e3a

πŸ’­ This new commit only touches logic, not UI styling, so the prior findings still stand without needing a repost. I'm checking whether there's any new UI-consistency issue worth flagging, like whether the always-rendered attachment container (even with no images, using the collapsed grid-rows and opacity trick) introduces any layout side effects. I conclude the collapsed container is safe since children only render when images exist, so there's no hidden focusable content issue. I want to verify whether promptHistoryEntries being a new required prop on ChatComposerProps breaks other call sites, and double-check that the arrow-key history navigation clamp fix from the earlier commit properly consumes the key press. Now I'm looking at whether ArrowUp/ArrowDown gets improperly swallowed while a pending attachment fetch from prompt history is in flight β€” during that async window the keys do nothing even if unrelated to history, which is a mild but real UX concern worth flagging.

6. git_tools β€” <ChatComposer

7. browse_code β€” apps/web/src/components/chat/ChatComposer.tsx

πŸ’­ I'm noticing that the early return swallows all ArrowUp/ArrowDown key events unconditionally while a restore is pending, even ones with modifiers like Shift or Cmd that should behave differently (e.g. selection extension) β€” since it fires before the modifier checks, that's a real bug in how keyboard input is handled during the async attachment restore. I want to trace whether this pending flag actually clears reliably: it's set true in applyComposerPromptHistory and cleared on promise resolution or onPromptChange, so any slow fetch (remote preview URLs vs. fast local file paths) extends the window where arrows are dead. This looks like a genuinely new issue introduced by this PR rather than something previously flagged, and it falls squarely under the keyboard-behavior/interaction-semantics part of the UI-consistency review, so I'm now checking exactly which commit introduced this pending-swallow logic. I'm weighing whether to add a comment about the pending-swallow behavior β€” checking the visual edge helper, confirming cursor-to-end after recall matches expected shell behavior, and re-verifying the transition issue at head is genuinely unfixed since the code is identical. I'm also considering whether a fresh composer with pre-restored images would show an unwanted mount animation, but that seems fine since it already renders expanded. The real question is whether swallowing all arrow keys, including modified ones, during an async attach counts as a concrete enough violation to flag. This does seem concrete: swallowing arrows while a restore is in flight breaks Shift+Arrow selection and can strand the composer if the fetch never resolves. The simplest fix would be moving the pending check inside the guard block after the modifier checks so modified arrows fall through, rather than returning false and letting the caret move into text that's about to be replaced. I'll post that as one comment and fail the check, citing both this and the still-open transition regression. Since that prior finding remains unaddressed, this should fail. I'll add the inline comment on lines 2183-2185, which are on the new side of the diff.

8. modify_pr β€” One new keyboard-behavior finding in the arrow-key history handler. The attachment-strip collapse transition flagged on 44d9ae7 (apps/web/src/components/chat/ChatComposer.tsx, grid-rows-[1fr]/grid-rows-[0fr] wrapper) is unchanged at this head, so that finding still stands and is not repeated inline here.


Agent Credits: 66 credits