Skip to content

Right rail follow-ups: focus across the fold, early fold choice, tablet cost, created files (#14) - #101

Merged
derekhearst merged 5 commits into
mainfrom
feat/14-right-rail
Sep 24, 2026
Merged

derekhearst merged 5 commits into
mainfrom
feat/14-right-rail

Conversation

@derekhearst

Copy link
Copy Markdown
Owner

Follow-up to #92. These four commits are the independent review's fix round for #14. They were committed after #92's head was pushed, so #92 merged without them.

What they fix

All review items are addressed on top of the reviewed HEAD (fd44705). The must_fix is fixed where the data is made. In src/lib/engine/tool-result-details.ts, a Write create with an empty structuredPatch (the SDK's real shape: patch [], originalFile null) now becomes its content as one all-added hunk. The hunk stays inside MAX_DIFF_LINES and a new MAX_CREATED_FILE_CHARS budget. Every line counts as an addition, git's counts still win when present, and a create is never 'no_change'. Replies saved before this fix stored creates as 'no_change', so changed-files.ts still lists a create whatever its details say. FileEditCard no longer calls a created file unchanged. Both specs now build their fixtures through toolResultDetails from real SDK payloads and assert that a Write-created row appears with the 'new' badge. The e2e spec also checks the created file's card shows its 12 added lines. The should_fix items are also done: the tablet header now shows the cost chip; focus moves to the control that replaces the pressed one when the rail expands, folds, opens a file from Files, or closes a preview; a new RailHeaderButton carries aria-expanded and a label that matches what it will do; and step E.3 is gone from research.md. Two of the reviewer's minor notes are also fixed: setOpen's early return that could leave the database saying "folded", and holdRailOpenPref leaving a preferences row behind.

Review items addressed

  • src/lib/chat-console/changed-files.ts:95 — Files never lists a file the agent created with Write. I checked what the bundled Agent SDK (claude-agent-sdk-win32-x64/claude.exe) returns for a new file: {type:"create", ..., structuredPatch: [], originalFile: null}. fileEditDetails in src/lib/engine/tool-result-details.ts:218-221 turns an empty patch on a non-update into unavailable: 'no_change' with additions 0. collectChangedFiles then drops every no_change block (if (details.unavailable === 'no_change') continue). I ran the real path, toolResultDetails('Write', {type:'create', filePath:'/w/new.ts', content:'a\nb\nc\n', structuredPatch:[], originalFile:null}) followed by collectChangedFiles, and got []. So new files, probably the agent's most common change, never appear, and the 'new' badge can only show when an Edit follows the create. Both specs miss this because their fixtures use a shape the engine never produces: tests/chat-console.changed-files.spec.ts edit(..., {changeType:'create'}) has unavailable 'none' and additions 10, and tests/chat.rail.spec.ts seedChatWithEdits has unavailable:'none', additions 12. (The same misclassification makes FileEditCard say "Created … No changes — the file already matched" for every new file. That part is older than this branch, but Files is what exposes it.)
  • src/routes/chat/[id]/+page.svelte:1445 — At tablet widths (48rem to 80rem) the metered cost no longer shows anywhere. The desktop topbar that now carries it is hidden desktop:grid (80rem and up), and .console-mobile-chips only displays below 48rem. The tablet header got the ring but not the cost. Before this branch the rail's stats footer showed cost at tablet widths, because the rail column is visible there. docs/chat-console/chat-console.md says context and cost are in "the chat's header on every screen size", which is now wrong for tablets.
  • src/lib/chat-console/ChatConsoleRail.svelte:52 — Keyboard focus is lost on every expand or collapse. 'Expand rail', 'Show Preview' and 'Show Files' live in the {#if collapsed} branch, and 'Collapse rail' lives in the other one. Activating any of them swaps the whole , so the focused button is destroyed and focus drops to . The tablet header toggle (+page.svelte:1487) keeps a static aria-label "Open chat rail" and has no aria-expanded, even though it now also collapses the rail.
  • docs/research/research.md:87 — The merge of main (fd44705) kept step E.3: "the right-hand console's Research tab lists the chat's five most recent runs". That tab no longer exists, and step D.5 in the same file now says the rail lost the Research tab in Rethink the right sidebar — blank most of the time #14. The implementer predicted this conflict in follow-up Rework the setup / first-run flow #2 but did not drop the line.

Verification

  • bun run check: 0 errors; bun run build: passes
  • After merging current main: tests/chat.rail, chat-console.changed-files, engine.tool-result-details, chat.shell-output-render, chat.page-state — 119 passed, 13 project-scoped skips, both desktop and mobile.

Refs #14

🤖 Generated with Claude Code

derekhearst and others added 5 commits September 23, 2026 20:11
#14)

The SDK reports a Write that creates a file with an empty structuredPatch and
originalFile null: there is no "before" to diff. fileEditDetails read that as
unavailable 'no_change' with 0 additions, so the rail's Files tab dropped
every created file and its edit card said "No changes — the file already
matched". A create with no patch is now its content as one all-added hunk,
inside MAX_DIFF_LINES and a new MAX_CREATED_FILE_CHARS budget, with every
line counted (git's counts still win), and is never 'no_change'.

Replies saved before this stored creates as 'no_change', so Files still lists
a create whatever its details say, and the card no longer calls one
unchanged. The specs now build their fixtures with toolResultDetails from the
SDK's real payloads instead of hand-written shapes the engine never emits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#14)

With this browser's copy saying expanded and the database saying folded,
opening a preview before getRailOpen answered hit setOpen's "already open"
early return, so nothing was saved and the next load folded the rail again.
setOpen now also saves when the value it matches is not known to be stored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e cost (#14)

Expanding or folding the rail swaps the strip for the full rail, which
destroyed the pressed button and dropped keyboard focus to the page. Focus
now moves to the control that took its place: the requested tab or the
collapse button on expand, the expand button on fold, the Preview tab after
opening a file from Files or closing a preview.

The chat header's rail button (RailHeaderButton) carries aria-expanded and a
name for what it will do: "Open chat rail" on a phone, "Expand/Collapse chat
rail" on a tablet. Tablet widths had lost the metered cost with the rail's
stats footer; the header shows it there now.

The rail spec seeds its edits through toolResultDetails from the SDK's real
payloads, checks a created file's card, pins focus, the header button and
the tablet cost, and no longer leaves a preferences row behind for a user
who had none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… size (#14)

Drop research.md's step E.3, which still described the rail's Research tab,
and renumber. chat-console.md says where context and cost sit at each width,
how the header button and focus behave, and how created files are listed;
the parity row mentions the "new" badge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derekhearst
derekhearst merged commit c54cbf6 into main Sep 24, 2026
1 check passed
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