Skip to content

lody: the rail files a session under its repository, and its headings work (RAIL-1/2/3/4, WT-TERM-1/2) - #157

Merged
pythonlearner1025 merged 4 commits into
mainfrom
lody-rail-fixes
Sep 1, 2026
Merged

lody: the rail files a session under its repository, and its headings work (RAIL-1/2/3/4, WT-TERM-1/2)#157
pythonlearner1025 merged 4 commits into
mainfrom
lody-rail-fixes

Conversation

@pythonlearner1025

Copy link
Copy Markdown
Member

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 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.

The name now comes from the daemon at the write.
readLocalProjectRepoFullName asks local-project/git-state, and
workdir-default.ts completes the ProjectRef with the answer. The backfill
gains 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: buildSessionListRows already sets isWorktree.
SessionRowWorktreeIndicator is rendered by upstream's own Local Projects
rows and by nothing inside SessionList, which is the only session row a
BlitzOS rail has.

Seam patch 9, four additive hunks in
vendor/lody/packages/components/src/components/session-list.tsx, declared
in BLITZ-PATCHES.md with an upstream-PR sketch. The placement is copied
from 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 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 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. buildGroups takes chatsCollapsed
and skips the rows itself.

RAIL-4 — no "+" on a repo heading (minor)

onNew draws the hover "+". It opens the landing, because the landing's
project 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. onMoveRepo
makes the handle render, and the order persists through upstream's own
repoOrderAtom — one localStorage key per workspace, already scoped by
currentWorkspaceIdAtom, which SessionSurface publishes. Nothing new is
persisted. Discovery is append-only, so a repo whose sessions are all
archived keeps its saved position.

Tests

packages/webapp/test/lody-rail-groups.test.tsx drives the real vendored
SessionList through the real SessionRailSidebar, daemon-free, with only
the 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.ts covers the write and the backfill, including
the refusal and no-remote branches. lody-project-control-frames.test.ts
pins the repo-name read against a real captured daemon answer.

Gates

  • npm run typecheck — pass
  • npm run lint:gate — pass (74 anti-slop, 0 blitz-house, unchanged)
  • BLITZDEV_MANAGED=1 npm test — 769 passed. lody-session-rail and
    lody-sharing-relay hit the known daemon boot-timeout on a shared box; both
    pass on the retry, which reported killing an orphaned daemon.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN

pythonlearner1025 and others added 4 commits September 1, 2026 20:38
…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
pythonlearner1025 merged commit ad08bea into main Sep 1, 2026
10 checks passed
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>
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