Skip to content

fix(viewer): make the feedback loop trustworthy#8

Open
benvinegar wants to merge 1 commit into
mainfrom
feat/viewer-loop-trust
Open

fix(viewer): make the feedback loop trustworthy#8
benvinegar wants to merge 1 commit into
mainfrom
feat/viewer-loop-trust

Conversation

@benvinegar

Copy link
Copy Markdown
Member

What

Four fixes from a UI/UX pass of the viewer, all centered on the product's hardest invariant — feedback is never silently lost — and on awareness when the user isn't staring at the tab.

  1. A failed comment send no longer destroys the message. Previously the composer cleared the input before the POST and a failure showed nothing — the user's words were just gone, with no sign anything went wrong (verified by simulating a network failure). Comments now echo into the thread immediately (dimmed pending style until the POST confirms, deduped against the SSE refetch by comment id), and on failure the text is restored to the input with an error toast. Both composers (snippet thread and session thread) now share one wireComposer().
  2. New snippets stop yanking the scroll position. scrollIntoView fired unconditionally on every published snippet, stealing the viewport mid-read. The stream now only follows when the user is already near the bottom; otherwise a "new snippet ↓" pill appears, which jumps to the card on click and clears itself when the user scrolls down on their own.
  3. Background activity badges the tab title. Activity the user isn't looking at — another session, or any session while the tab is hidden — adds to the unread set, and the title shows (n) sideshow. Returning to the tab (or selecting the session) clears it. Previously a backgrounded tab gave zero signal that the agent had published or replied.
  4. SSE reconnects now resync. onopen only recolored the live dot, so events that fired during a connection gap were permanently missing from a live-looking board. On reconnect the viewer refetches the session list and reconciles the selected session's snippets (pruning deleted cards) and comments — both paths dedupe, so a resync with nothing missed is a no-op.

Tests

Four new e2e tests (chromium + webkit): failure-restores-input then retry succeeds, optimistic echo with a held-open POST settles into exactly one confirmed comment, pill-instead-of-yank with reading position asserted, and the title badge lifecycle. 18/18 e2e pass; unit tests, both typecheck programs, lint, and format all green. Reconnect resync is code-reviewed but not e2e-covered (would need to kill the SSE stream mid-test).

Also verified live in a browser against seeded demo data: simulated failed send, pill appearance/click, and title badge from a cross-session publish.

🤖 Generated with Claude Code

Four fixes from a UI/UX pass, all guarding the publish-comment loop:

- A comment that failed to send was silently lost: the input cleared
  before the POST and a failure showed nothing. Comments now echo
  immediately (pending until confirmed; deduped against the SSE
  refetch by comment id) and on failure the text returns to the input
  with an error toast.
- New snippets always scrollIntoView, yanking the user mid-read. The
  stream now only follows when already near the bottom; otherwise a
  "new snippet" pill offers the jump and clears on click or on
  scrolling to the bottom.
- Activity the user isn't looking at (another session, or any session
  while the tab is hidden) badges the tab title with the unread count;
  returning to the tab clears the selected session.
- SSE reconnects only recolored the live dot, so events from the gap
  were silently missing from a live-looking board. onopen now refetches
  the session list and reconciles the selected session's snippets and
  comments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant