lody: the rail files a session under its repository, and its headings work (RAIL-1/2/3/4, WT-TERM-1/2) - #157
Merged
Merged
Conversation
…WT-TERM-1) A session created against a /workspace clone filed under "Chats" instead of under its repository heading, and its row's repoFullName was null. The rail groups on resolveProjectGitHubRepo(session.project), which for a local ref reads project.githubRepoFullName. The landing writes that field only when the daemon's name also appears in the workspace's cloud-connected repository list. A box fills that list from itself, late, after the surface opens. A member who picks a project inside that window loses the name for good, because no later pass rewrites a session that already exists. So the name comes from the daemon instead, at the write. readLocalProjectRepoFullName asks local-project/git-state, and workdir-default.ts completes the ProjectRef with the answer. A clone with no GitHub remote answers no name, and its sessions stay in Chats — the same honest degradation the repository sweep already states. The backfill gains the matching half, so sessions created before this fix get the heading they lost on their next open. A refusal is retried; an answer is remembered. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
…patch 9) The QA sweep found 0 [aria-label="Worktree"] nodes in the rail on every load, over three worktree-backed sessions. The data was never missing: buildSessionListRows already sets isWorktree on the row. SessionRowWorktreeIndicator is rendered by loro-app-sidebar's own Local Projects rows and by nothing inside SessionList — which is the only session row a BlitzOS rail has. Four additive hunks in one vendored file, declared as seam patch 9. The placement is copied from upstream's own caller, so a worktree row reads [diff][worktree][PR]. The component returns null for a falsy isWorktree, so a plain row is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
…IL-2/3/4) Three findings, three props upstream already reads and this rail never passed. RAIL-2. The "Chats" heading navigated to the landing instead of collapsing: the header runs onNavigateToNewSession when it has one and its toggle only when it does not, and the rail passed it to both lists. It now goes to the repo list alone. The second half of the same bug: the chats list was handed an empty array while collapsed, which deletes the group that draws the heading — so the heading vanished with its rows and nothing was left to click. buildGroups takes chatsCollapsed and skips the rows itself. RAIL-4. onNew is what draws the hover "+" in a group heading. It opens the landing, because the landing's project picker is the only place a BlitzOS session picks a clone. RAIL-3. onMoveRepo is what makes the drag handle render, and the order it reports persists through upstream's own repoOrderAtom — one localStorage key per workspace, already scoped by currentWorkspaceIdAtom. Discovery is append-only: a repo whose sessions are all archived keeps its saved position. The new test drives the real vendored SessionList through the real rail, with only the session mirror stubbed, and pins all five bug ids. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
The vendor type seam erases every `@lody/*` export, so a direct spread of `store.get(repoOrderAtom)` reads as `unknown`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
pythonlearner1025
added a commit
that referenced
this pull request
Sep 1, 2026
PR #157 landed seam patch 9 (`SessionList` worktree glyph) while this branch was open, so the panel patch becomes 10. The seam patch 1 merge drill now counts both: FIFTEEN files after patch 9, TWENTY after patch 10. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
pythonlearner1025
added a commit
that referenced
this pull request
Sep 1, 2026
…P23-I18N, SP21, SP26) (#158) * lody: the side panel's file surfaces answer again (BUG-1, BUG-2, SP28, SP26) Seam patch 9. Four rows the panels-a QA lane confirmed on a real box, three of them defects in upstream's own desktop branch: - BUG-1: {fileQuickOpenDialog} was mounted only inside the isMobile return, so Ctrl/Cmd+P ran its handler, preventDefault'd the chord and had no dialog to open. Mounted at the desktop root beside the other portalled dialogs. - BUG-2: a failed file-index acquire was terminal. requestKey holds the effect's identity and a reconnect moves none of it, so "Files unavailable" outlived the outage. The hook gains reloadNonce + reload, re-arms on an offline -> online EDGE of the owning machine, and the provider-unavailable panel now draws the same "Try again" the local-error branch already had. - SP28: the desktop file viewer gains "Copy file path", the control MobileFileViewerDrawer has carried since it landed, under the same key. - SP26 (user ruling): Go to Definition and Find References are hidden for v1. A box runs no language service, so both answered every identifier with "Host language service does not support this file". Gated at the ACTIONS, not the callbacks: an action with no callback still sits in the context menu. SP26 rides seam patch 7's shape: one optional prop per level, every one defaulting to today's behaviour, off one new v1-scope field, languageService. BLITZ-PATCHES.md declares all of it, and the seam patch 1 merge drill moves from FOURTEEN diverged files to NINETEEN. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN * lody: three panel fixes that need no vendor edit (BUG-3, SP23-I18N, SP21-KEY) - BUG-3: with the side panel collapsed the panel is 0 wide, so the tab strip's two shrink-0 controls overflowed to the RIGHT of the window — "Add panel" at cx=1911 and "Show sidebar" at cx=1943 in a 1920 viewport. One declaration in blitz-skin.css sends that overflow the other way. It cannot move anything while the strip has room: the scroll area beside those controls is flex-1 and leaves no free space to distribute. The reachable duplicate at cx=1844 is the header toolbar's own copy, which upstream draws only while collapsed. - SP23-I18N: sessions.fileSave.conflictDetail interpolates {{conflict}} and no call site passes one, so the save-conflict banner printed the placeholder. - SP21-KEY (user ruling): sessions.fileViewer.save.withShortcut advertises "Save (⌘S / Ctrl+S)" and this surface mounts no dispatcher for that chord. The title states the action alone. The command layer stays unmounted. Both strings are overridden in i18n.ts rather than in vendor/lody/locales, and each test asserts the VENDORED string still carries the defect — so an upstream fix fails a test and the override is deleted instead of shadowing a fixed string. BLITZ-PATCHES.md records the map beside the other outside-vendor workarounds. lody-panel-fixes.test.tsx pins all seven rows, each at the lowest boundary that can hold it: the real vendored file-tree panel and side-panel strip are mounted and driven, the two strings run through the real i18next instance, and the mounts that need a daemon are pinned at the source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN * lody: name the override test by the file that exists Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN * lody: renumber the panel seam patch to 10 after the rail patch took 9 PR #157 landed seam patch 9 (`SessionList` worktree glyph) while this branch was open, so the panel patch becomes 10. The seam patch 1 merge drill now counts both: FIFTEEN files after patch 9, TWENTY after patch 10. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five confirmed rail findings from the canary QA sweep. Four are integration
props upstream already reads. One needs a vendor hunk.
RAIL-1 + WT-TERM-1 — a worktree session filed under "Chats" (major)
The rail groups on
resolveProjectGitHubRepo(session.project), which for alocalref readsproject.githubRepoFullName. The landing writes that fieldonly when the daemon's name also appears in the workspace's cloud-connected
repository list. A box fills that list from itself, late, after the surface
opens. A member who picks a project inside that window loses the name for
good, because no later pass rewrites a session that already exists.
The name now comes from the daemon at the write.
readLocalProjectRepoFullNameaskslocal-project/git-state, andworkdir-default.tscompletes theProjectRefwith the answer. The backfillgains the matching half, so sessions created before this fix get their
heading on the next open. A refusal is retried; an answer is remembered.
A clone with no GitHub remote answers no name, and its sessions stay in
Chats. That is the honest degradation the repository sweep already states.
WT-TERM-2 — the worktree glyph never rendered (minor)
The data was never missing:
buildSessionListRowsalready setsisWorktree.SessionRowWorktreeIndicatoris rendered by upstream's own Local Projectsrows and by nothing inside
SessionList, which is the only session row aBlitzOS rail has.
Seam patch 9, four additive hunks in
vendor/lody/packages/components/src/components/session-list.tsx, declaredin
BLITZ-PATCHES.mdwith an upstream-PR sketch. The placement is copiedfrom upstream's own caller. A plain row is unchanged.
RAIL-2 — the "Chats" heading could not collapse (minor)
Two causes, both ours. The header runs
onNavigateToNewSessionwhen it hasone and its toggle only when it does not, and the rail passed it to both
lists; it now goes to the repo list alone. The chats list was also handed an
empty array while collapsed, which deletes the group that draws the heading —
so the heading vanished with its rows.
buildGroupstakeschatsCollapsedand skips the rows itself.
RAIL-4 — no "+" on a repo heading (minor)
onNewdraws the hover "+". It opens the landing, because the landing'sproject picker is the only place a BlitzOS session picks a clone.
RAIL-3 — repo groups could not be reordered (minor) — FIXED, not deferred
Upstream supports it through props this rail failed to pass.
onMoveRepomakes the handle render, and the order persists through upstream's own
repoOrderAtom— one localStorage key per workspace, already scoped bycurrentWorkspaceIdAtom, whichSessionSurfacepublishes. Nothing new ispersisted. Discovery is append-only, so a repo whose sessions are all
archived keeps its saved position.
Tests
packages/webapp/test/lody-rail-groups.test.tsxdrives the real vendoredSessionListthrough the realSessionRailSidebar, daemon-free, with onlythe session mirror and the session mutations stubbed: grouping, the glyph on
a worktree row and its absence on a plain one, the collapse toggle, the "+",
the drag handle and the saved order. It also pins the seam-9 declaration.
lody-session-workdir.test.tscovers the write and the backfill, includingthe refusal and no-remote branches.
lody-project-control-frames.test.tspins the repo-name read against a real captured daemon answer.
Gates
npm run typecheck— passnpm run lint:gate— pass (74 anti-slop, 0 blitz-house, unchanged)BLITZDEV_MANAGED=1 npm test— 769 passed.lody-session-railandlody-sharing-relayhit the known daemon boot-timeout on a shared box; bothpass on the retry, which reported killing an orphaned daemon.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN