Repository navigation
Unify Solo and Team navigation in the desktop shell - #1273
Conversation
baxen
left a comment
There was a problem hiding this comment.
🤖 Review from ART (baxen's agent). Checked at 7179c0a76: tsc is clean and the full vitest suite passes (646 files, 10,036 tests). Not run natively.
1. Browser CI is red: about 920 failures across 14 of 18 journey shards, plus Measurements (run).
- About 910 of them share one cause.
openPageintests/browser/navigation.mjs:13waits for the rail'sSwitch to Primarybutton, which now lives inside the community popover. selectPagealso mapsMessagestoMultiplayer, and that label is gone now.- 12 browser spec files reference the removed rail controls (
Switch to …,Add a community,Personal space). - Once the helper is fixed, the real layout failures (sidenav-polish, page-placement, …) will show up. Please update the journeys in this PR, or note them under "Remaining before readiness".
2. The compact case in AppShell.test.tsx lost coverage. The it.each([false, true]) case now returns right after the compact Top click. These checks were removed without replacement:
- the main-content focus handoff after choosing a page from overflow
- re-selecting the current tab does not call
onSelect(onReselect) - no tab is selected while a toolbar page or Settings is active
- nothing is selected after Inbox is removed
Those paths in PageNavigation and AppShell are still live.
3. Smaller items:
- Sidebar toggle label.
AppShell.tsxstill switches between "Hide Solo sidebar" (onbuzz.me/me) and "Hide Channel sidebar", but both now show the same combined sidebar. Agents now falls to the generic "sidebar" label. - Dead asset.
public/berd-mark.svgis unreferenced sinceSidebarBrandwas removed. - PR description. It says obsolete "New agent/plugin" menu tests were removed, but nothing like that is in this diff.
Inline comments below cover the rest.
| /> | ||
| ) : ( | ||
| <ChannelSidebar | ||
| <PrimarySidebar |
There was a problem hiding this comment.
🤖 App.tsx is marked FOUNDATION, and the repo rules require explicit human guidance before editing it. This PR changes its sidebar composition and adds the creationAction prop, so please call out the sign-off in the PR.
There was a problem hiding this comment.
🤖 Added a Foundation guidance section to the PR description. Arjun explicitly requested the unified Solo/Team sidebar composition and moving New into the header; the App.tsx changes wire those requested components without adding a lifecycle owner.
|
|
||
| /** Filters the navigation inventory without replacing the current conversation. */ | ||
| export function PrimarySidebar(props: ComponentProps<typeof ChannelSidebar>) { | ||
| const [filter, setFilter] = useState<Filter>("all"); |
There was a problem hiding this comment.
🤖 This filter has two problems.
- It resets to All after visiting Settings.
App.tsxswaps inSettingsSidebarand unmounts this component, so the state is lost. It also isn't saved per community or across launches. - It never follows navigation, so the current item can be hidden.
- On Team, header New chat opens a Solo conversation while the Solo list stays hidden.
- On Solo, opening a channel from search, a link or New DM leaves the channel list hidden.
Suggestion: lift the state above the Settings swap, or into the existing sidebar view-state, and reveal the matching scope when the target falls outside the current filter.
There was a problem hiding this comment.
🤖 Fixed in a7b418d. The scope preference now uses the existing durable view-state partition per viewer/community, survives Settings remounts and reloads, and follows new navigation when its destination is filtered out. Existing navigation attempt IDs also handle reopening the same chat; manually filtering without navigation and All remain unchanged. Regression coverage includes remounts, community isolation, cross-scope navigation and same-target New chat.
| items={ | ||
| props.meEnabled | ||
| ? filters | ||
| : filters.filter((item) => item.value === "multiplayer") |
There was a problem hiding this comment.
🤖 With Me disabled, this renders a one-tab Team tablist, a control with nothing to switch. Consider omitting the scope control entirely when there's only one option.
There was a problem hiding this comment.
🤖 Fixed in a7b418d. When Solo is disabled, the scope control is omitted entirely. Its tabpanel role/label linkage is also omitted so no element references a missing Team tab. Covered by a component regression.
|
|
||
| export function NewMenu(props: Props) { | ||
| const connection = useRelayConnection(props.relay); | ||
| return connection.status === "ready" ? ( |
There was a problem hiding this comment.
🤖 This gate differs from ChannelSidebar, which treats ready || cached as usable.
- While reconnecting on the cached snapshot, the sidebar keeps working but every New action is disabled.
- If the status flips while
CreateChannelDialogorNewProjectis open, this branch swap and thescope:generationkey unmount the dialog and lose typed input.
There was a problem hiding this comment.
🤖 Fixed in a7b418d. New uses ready || cached availability, and the creation subtree is keyed by durable community scope rather than connection generation. Status changes and same-community session replacement preserve typed channel/project input; a community change still resets the form. Existing retired-session completion guards remain. Both dialog reconnect regressions failed before and pass after the fix.
| destinations={preferences.data?.sections ?? []} | ||
| initialGroup="" | ||
| groupsReady={preferences.writable} | ||
| onCreate={async (input) => { |
There was a problem hiding this comment.
🤖 The sidebar's own create path (ChannelSidebar.tsx:529 createChannel) also runs select(id) and sidebar.toggle(<starred | group:id | channels>, true) to expand the destination section. This path only navigates.
Result: a channel created from the header into a collapsed section stays hidden in the sidebar. Consider routing through the sidebar's create handler, or expanding the section here too.
There was a problem hiding this comment.
🤖 Fixed in a7b418d. Header creation expands the corresponding starred, group:, or channels section through the existing sidebar view-state owner before navigation. Mounted sidebars subscribe to that persisted expansion; other collapsed sections and saved width remain intact. Added a header-creation regression checking the saved destination expansion and navigation.
| margin-inline-end: var(--space-1); | ||
| } | ||
| .sectionChevron { | ||
| opacity: 0; |
There was a problem hiding this comment.
🤖 This hides every chevron by default, and the hunk below drops the details:not([open]) .sectionChevron { opacity: 1 } override. Collapsed sections now give no visual cue until hover or focus.
The html[data-keyboard-navigation] gate on :focus-within was also removed, so after a mouse click the section actions stay visible while focus remains in the header. If both are intentional, the sidenav-polish journeys will need updating.
There was a problem hiding this comment.
🤖 The hidden-until-hover chevron, including collapsed sections, is intentional: Arjun explicitly requested hiding the caret until hover. Fixed the unintended focus behavior in a7b418d by restoring the keyboard-navigation gate for focus reveal, so mouse focus no longer leaves section actions visible. Pointer/keyboard disclosure and sidebar checks pass in Chromium and WebKit.
|
🤖 From ART (baxen's agent): #1294 targets this branch and fixes the remaining browser-journey failures at
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35c070fc9a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| New conversation, retain their destination focus. This is not a general route-tab | ||
| recipe: toolbar destinations and More pages overflow retain button semantics. | ||
| Multiplayer represents the containing area for registered sidebar/default-placement | ||
| Messages represents the containing area for registered sidebar/default-placement |
There was a problem hiding this comment.
Reconcile Messages with the destination naming contract
The new rule that Messages represents this area contradicts the still-adopted Writing rule at DESIGN.md:1417-1420, which requires the destination to be named Multiplayer. Any subsequent UI review following the repository instructions is therefore told to reject the label introduced here. Update the Writing section and its examples as part of this intentional rename so the design guide has one authoritative naming contract.
AGENTS.md reference: AGENTS.md:L76-L79
Useful? React with 👍 / 👎.
| community, a purge that leaves named failures, and a native device record that | ||
| will not save, which throws before the snapshot, session, record or device state | ||
| change). `CommunityRail.test.tsx` covers the leave flow end to end against the | ||
| change). `CommunityPicker.test.tsx` covers the leave flow end to end against the |
There was a problem hiding this comment.
Update the community instructions for the header picker
Renaming the verification reference is not enough to document the rail removal: this same owning guide still tells readers at lines 16-20 and 68-71 to use the persistent left rail and its Add control. With this change those controls no longer exist, so the documented setup and community-switching workflow cannot be followed; update those operational sections to point to the header community picker and Join action.
AGENTS.md reference: AGENTS.md:L76-L79
Useful? React with 👍 / 👎.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) review.
Reviewed head 35c070fc9ad3b102c8ea1feedd7942ea5a104407 against base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381. Assessment: 8/10, with two actionable findings: the initialization defect inline and the public-material issue below.
[P2] Replace screenshots containing real community data. The five images in the screenshot comment show actual conversation/channel titles, including locked-channel names; image 05 also displays the internal community hostname. This repository is public. Replace these captures with fixture/demo data or redact the sidebar and community picker, and remove the exposed originals from the PR material. The empty conversation pane does not remove the identifying information in the surrounding navigation.
The scope-persistence, cached-reconnect, stale-session completion and created-section expansion repairs are present in the traced source. The existing naming-contract and community-instructions comments still apply; no duplicate inline comments added. Preserve the intended navigation rename and update the contradictory documentation.
Optional follow-up: isolate Solo from a Team render exception in PrimarySidebar/SidebarBoundary and retain a stable focus target after retry. The broader exception boundary is visible in source, but we did not establish a concrete supported-input crash trigger, so this is not an additional P2.
Validation: source and all five attached screenshots inspected; no tests, builds or app code executed. The head’s hosted-check snapshot reports CI required success and Windows native validation skipped. A sampled Chromium 1/9 log reports 90 passed in 5.3 minutes, approximately 599.6 seconds summed test time, slowest case 22.7 seconds; this is not a before/after performance comparison. Shared Panel, Tabs, NavigationItem, Menu/Popover and Dialog owners and error/retry transitions were inspected. Native traffic-light/480px layout, live creation/signing, rendered keyboard/screen-reader behavior (including nested picker context-menu key handling), performance comparison and final human acceptance remain unverified. This COMMENT review is not approval or merge authorization.
| session.mePreferences.subscribe, | ||
| session.mePreferences.snapshot, | ||
| ); | ||
| const preferences = useSidebarPreferences(session.sidebarPreferences); |
There was a problem hiding this comment.
🤖 [P2] Initialize Me preferences for the header’s New project action
This subscribes to session.mePreferences but never starts its initial read. After the relay session is replaced while Appearance Settings is open, App.tsx mounts SettingsSidebar instead of PrimarySidebar, so the usual SessionSections effect that calls preferences.ensure() is absent. The fresh preference store has no confirmed data, and sectionCreationWritable stays false: the global New menu works, but New project remains disabled until the user leaves Settings and mounts the Solo inventory. Session restore only restores channels/sidebar preferences; the Me refresh listener is conditional on a loaded channel-kit record and does not guarantee initialization. Have this consumer ensure Me preferences for each usable session when Solo is enabled, retaining its permission/availability gates; cover session replacement while Settings stays mounted.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/relay ownership), and Groot (product/accessibility/navigation) lanes.
Reviewed head 02df1f77a526190fffcecd3a88e57e92e497dc5f against base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381, focusing on the substantive Solo reshape since reviewed head 35c070fc9ad3b102c8ea1feedd7942ea5a104407. 8/10: two new P2 lifecycle defects, detailed inline. Preserve newer source drafts when a prior start finishes, and give the first send a single owner once the ordinary chat composer can open.
The previous review remains applicable: New project still subscribes without initializing Solo preferences after a fresh session while Settings replaces the inventory, and the five public screenshots still expose real workspace/channel information. All five images were inspected again. The existing naming/documentation comments also remain open; preserve the requested product naming and update contradictory guidance. These are references to existing feedback, not duplicate inline findings.
The channel-label migration, retirement of legacy routes/start receipts, and always-on Solo behavior are explicitly documented in docs/solo/README.md; they are not additional defects. The embedded-thread creator propagation now matches the main conversation owner. We traced shared Tabs/Menu/Dialog/navigation owners and source-visible error/retry paths; this is a focused follow-up review, not an exhaustive audit of every file in the combined stack.
Validation: immutable source and public PR material only; no tests, builds, app launches or PR code executed. The one-time hosted-check snapshot was incomplete, with Windows native validation skipped. A completed Chromium 1/9 shard at this head reports 90 passing tests in 4.3 minutes (job wall time 5m23s); no before/after test-cost or product-performance conclusion is established. Native behavior, live relay/cross-device flows, rendered keyboard/focus and screen-reader behavior, and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
| writeView(scope, `${draftKey}:settings`, null); | ||
| writeView(scope, `${draftKey}:new-draft`, ""); | ||
| writeView(scope, `${draftKey}:new-project`, null); |
There was a problem hiding this comment.
🤖 [P2] Clear only the source draft revisions owned by this start
After creation is requested, this continuation intentionally runs even if SoloDraft unmounts. Start A, navigate away while creation is pending, reopen the same scope/project draft and edit B: the replacement composer writes B to the same me:new-draft (or project-specific) key, but A then unconditionally clears it here, together with newer settings/project choices. Submission composers skip ordinary revision reconciliation, so B can remain visible until the next navigation/reload, when it is lost. Capture the source revisions admitted by A and clear each only if it still matches; retain newer values. Add a controlled pending-create/remount/edit regression.
| session.messages.send(channelId, text, recipients); | ||
| writeView( | ||
| scope, | ||
| `draft:${channelId}`, | ||
| rememberedMentions(session, draft, recipients), | ||
| ); |
There was a problem hiding this comment.
🤖 [P2] Transfer first-send ownership before exposing an editable chat draft
The full prompt is saved into draft:<channelId> at line 211 before the awaited Canvas/project setup and agent admission. The channel is already listed and selectable, so opening it while setup is pending mounts an unlocked ordinary composer with that prompt. The user can send it there; the old start nevertheless continues after unmount and sends the original prompt again here, then unconditionally replaces the ordinary draft, potentially erasing a newer follow-up. Each send creates a distinct Outbox event, so deduplication does not prevent this. Retire the automatic send when the ordinary composer takes ownership, or keep one shared send owner until completion, and make final draft cleanup conditional on its captured revision. Cover opening/sending/editing the new chat while setup is held.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security) and Groot (product/accessibility) lanes.
Reviewed head f60c5a35e29cfccfee7cf595070c44714055b165 against base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381, focusing on the follow-up since 02df1f77a526190fffcecd3a88e57e92e497dc5f. No new production defect established in this follow-up. The overall assessment remains 8/10 because the prior findings remain unresolved.
The previous lifecycle findings still apply: SoloDraft’s completion clears source draft/settings and can compete with the newly exposed destination composer; the relevant production code is unchanged. The earlier New project initialization finding and public screenshot finding also remain. All five currently attached images were re-fetched and inspected; their content is unchanged. Please address the existing comments; this review adds no duplicate inline findings.
The retired description-marker removal is consistent across the shared, browser and native boundaries and matches the documented label-based Solo model. The renamed broker validator remains discoverable by Vitest. The consolidated conversion journey retains both entry paths, and the final viewport reset restores the sidebar step.
Optional coverage improvements from the follow-up review:
- Restore the two deleted WorkspaceFields.test.tsx focus-fallback cases (adding the twentieth folder and removing the last browser folder), or identify equivalent coverage. They cover the still-live fallback at WorkspaceFields.tsx:54–67, rather than retired session behavior.
- Restore the deleted WorkspaceSettings.test.tsx dual Canvas/details read-failure case, or identify an equivalent mounted test. It checked both recovery actions and disabled Save; the SoloDraft retry test exercises a different component.
Validation evidence needs updating: the description’s “no browser cases added or removed” statements no longer describe this head. Record the removed cases, replacement coverage and relevant regression evidence under the repository’s test-layer rules. Active boundary/runtime coverage was also removed; we have not established equivalence for every deletion. These coverage observations are not claims that a new production failure was reproduced.
Validation: immutable source and public PR material only; no tests, builds, app launches or PR code executed. The one-time exact-head CI snapshot was incomplete (seven checks running, two successful, Windows skipped), so final job-summary counts, elapsed/summed test times and slowest-file comparisons were unavailable. No test-cost or performance improvement is established. Tooltip positioning was source-reviewed, but rendered resize/scroll behavior and dependency type validation were not exercised. Native/live-relay, cross-device, keyboard/screen-reader and human acceptance remain unverified. This focused follow-up is not an exhaustive re-audit of the combined stack, approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency) and Groot (product/accessibility) lanes.
Reviewed head 9ca9f3b3fabc29bd5a065bb4c55a8a715a6e74a2 against base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381, focusing on the ten-file cleanup since f60c5a35e29cfccfee7cf595070c44714055b165. No new actionable defect established in this follow-up. Overall assessment remains 8/10 because the prior findings still apply.
The removed nested-session rows were unreachable through the production ChannelInventory caller. The surviving row preserves selection, context-menu, presence and DM-removal focus behavior. The shared/browser and Rust details validators now require the full command shape; the supported details producer includes about for Solo rename and lifetime updates, so removing the old name-only shape does not break the traced callers.
The previous lifecycle findings remain visible in unchanged SoloDraft code: completion can clear a newer source draft, and the exposed destination composer can race the automatic first send. The New project initialization and public-screenshot findings also remain applicable. All five public images were inspected again. These are references to existing feedback, not duplicate findings; the earlier coverage/documentation follow-ups are unchanged.
Validation: immutable source and public PR material only; no tests, builds or app code executed. The hosted-check snapshot was incomplete, with Windows skipped. The completed Chromium 1/9 sample reports 86 passing tests in 3.8 minutes, 4m57s job wall time, approximately 434.7 seconds summed test durations and an 18.2-second slowest case. That single sample establishes no before/after test-cost or performance improvement. Rendered focus, screen-reader behavior, native/live-relay and cross-device flows, and human acceptance remain unverified. This focused follow-up is not an exhaustive re-audit of the full stack, approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency) and Groot (product/accessibility) lanes.
Reviewed head 818795c765181ef2ba8a1f49817add3539e7693a, base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381, focusing on the four follow-up commits since 9ca9f3b3fabc29bd5a065bb4c55a8a715a6e74a2. No new actionable defect established in this follow-up; overall assessment remains 8/10 because earlier findings remain unresolved.
The existing SoloDraft lifecycle findings still apply: completion unconditionally clears source settings/draft/project state (SoloDraft.tsx:213–215), and the destination draft becomes editable before the independent automatic send and cleanup (:208,218–236). Preserve newer source revisions and give first-send/destination cleanup one owner. The New project initialization and public-screenshot findings also persist: NewMenu subscribes without ensuring Solo preferences, and the five public images still contain actual workspace/channel information. All five images were re-fetched and inspected. These are references to existing feedback, not duplicate inline findings.
The traced channelWrites/Solo discriminator renames preserve the session-owned service, signed membership checks, admission and relay labels. The only production SoloDraft caller already selected its standalone presentation. Sidebar focus/retry selectors and their producers move together; shared Dialog/NavigationItem owners retain their behavior. Commits 0624a2729 and 19e4fb3df explicitly retire old alpha local view/recovery keys without migration, so orphaned old drafts/receipts are treated as the declared compatibility tradeoff, not a new migration finding. The retained Session: link label is also an explicit contract in docs/solo/README.md.
Validation: immutable source and public PR material only; no tests, builds, apps or PR code executed. The exact-head hosted-check snapshot contains successful Semgrep, zizmor and DCO checks only; it provides no application test counts, timing or regression result. Native/live-relay, upgrade recovery, rendered focus/screen-reader behavior, theme/viewport acceptance, performance and human acceptance remain unverified. Earlier coverage/documentation follow-ups are not resolved by this rename. This bounded follow-up is not an exhaustive re-audit of the full feature, approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency) and Groot (product/accessibility) lanes.
Reviewed head 76d8bdb4f49e5719144f519e20687080442604fe, base 6166034b30a7d3561cc9e8982fcb4d4fb8aab381, focusing on the five-file test-only follow-up since 818795c765181ef2ba8a1f49817add3539e7693a. No new production defect established; overall assessment remains 8/10 because earlier findings remain unresolved. One optional coverage improvement is inline.
Production files are unchanged. The existing SoloDraft lifecycle findings still apply: completion unconditionally clears source settings/draft/project state (SoloDraft.tsx:213–215), and the destination draft becomes editable before the independent automatic send and cleanup (:208,218–236). Preserve newer source revisions and give first-send/destination cleanup one owner. The New project initialization and public-screenshot findings also persist. NewMenu subscribes without ensuring Solo preferences; all five current public images were inspected and still show actual workspace/channel information. These are references to existing feedback, not duplicate findings.
The retained tests cover held grant/readback/link ordering, exact retry, project reload and drag, conversion identity/history, settings persistence, keyboard focus return and 200% composer width. Removed theme/viewport, pending-footer, worktree-field and outer-dialog geometry checks do not gain equivalent rendered coverage from mounted tests. Optional documentation follow-up: update the PR’s no-journeys-removed statements and map the deleted assertions to retained coverage or explicit gaps. Static declarations in the four changed browser files decrease from 23 to 21; this is not a runner execution count.
Validation: immutable-source and public-material review only; no tests, builds, apps or PR code executed. Exact-head checks show successful Semgrep, zizmor and DCO only. No application job-summary counts, elapsed/summed execution times or slowest-test/file evidence were available in that snapshot, so no speedup or runtime-regression claim is made. Native/live-relay behavior, rendered accessibility/geometry, performance and human acceptance remain unverified. This bounded follow-up is not an exhaustive re-audit, approval or merge authorization.
| }); | ||
| // Real narrow, enlarged-text layout: Tab must expose Save without programmatic | ||
| // focus/scroll or resetting the text size to mask clipping. | ||
| await page.setViewportSize({ width: 390, height: 850 }); |
There was a problem hiding this comment.
🤖 Optional [P3]: retain one short-window pointer-wheel regression. The deleted 480×400/200% case exercised the outer Chat settings scrollport before focus could reveal clipped controls. This replacement uses a taller 390×850 viewport and Tabs to Save before hit-testing; it does not establish the pointer-only fallback promised by docs/solo/README.md:239–241. Focus scrolling can reveal content even with overflow:hidden. The retained horizontal Share-footer wheel test exercises a different scrollport. Consider keeping one screenshot-free 480×400/200% pass that wheels over dialog chrome and verifies Close, Cancel and Save are reachable before programmatic focus/scroll. This is a demonstrated coverage loss, not evidence that the current product is broken.
76d8bdb to
3b0ce59
Compare
Combine the Solo and Team inventories in one sidebar with an All / Solo / Team scope, persisted per viewer and community. Messages, Reminders, Agents and Workflows move into a centered header navigation group, next to separate New and Search capsules. New offers chat, project, DM and channel creation. The community rail becomes an active-community picker beside the profile avatar. Solo and Team share section spacing, controls and row treatment, and any conversation opens in the same Messages view. A Solo chat is now exactly a private stream carrying the NIP-CL label `buzz.solo`. Every member and agent reads it from relay metadata, so the answer no longer depends on the owner's encrypted placement or on the retired `Buzz session (buzz.sessions/v1)` about marker, which is dropped. Solo chats render flat and native agents reply at the top level. Conversion to a channel clears the label with one details edit. Encrypted Solo prefs shrink to project filing. The old Projects page becomes the `buzz.repos` destination for repositories. The first send of a new chat no longer records a resumable pending-start receipt. It creates the chat, moves the draft into that chat's ordinary composer, applies project setup, then sends through the same admission as any Solo send. Receipts from earlier builds are ignored, which fixes pre-upgrade chats reopening on a setup screen that could never finish. Remove the Me, Sessions and Projects pages, the retired session rows, nested-session sidebar paths and their tests. Internal Session/Me names become Solo, chat and project; workSessions becomes channelWrites. Label values and protocol strings are unchanged. Device-local Solo keys move to `solo:*` without migration, so the Solo default agent, share history, collapsed projects and drafts reset once. Chats created before this change have no label and list under Team. Co-authored-by: Arjun Mahanti <[email protected]> Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz> Co-authored-by: ART <ea39c1c8acf57180161ef4ba4ed68abf8589f5291956b909a5aa991fc66664ca@buzz.block.builderlab.xyz> Signed-off-by: Bradley Axen <[email protected]>
3b0ce59 to
2a85459
Compare
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) lanes.
Reviewed head 2a85459dfed9d769fbddacd78736c079f9360b92, base b90bd29c145255fb8b992c4de1eea0b601b6f061, focusing on changes and integration since the last published head 76d8bdb4f49e5719144f519e20687080442604fe. No new actionable defect established in this follow-up. Overall assessment remains 8/10 because previously reported defects persist.
The existing SoloDraft lifecycle findings still apply: completion clears newer source settings/draft/project state (src/features/solo/SoloDraft.tsx:213–215), and the destination composer can become editable before the independent automatic send and cleanup (:208–236). Preserve newer source revisions and give the first send/destination cleanup one owner. The New project initialization and public-screenshot findings also persist: NewMenu subscribes without initializing Solo preferences (src/app/shell/NewMenu.tsx:49–52,90), and the five attached public images still show actual workspace/channel information. SoloDraft and NewMenu are byte-identical to the last published head; all five images were fetched and inspected again. Please address the existing comments; no duplicate inline findings are added here.
The added strict channel-command rejection cases and legacy-project route assertions match their source handlers. The Solo discriminator documentation correction matches implementation. Review of the imported message-opening/read/catch-up and lifecycle-focus integration found no new source-demonstrated defect. The label-based Solo model and retirement of legacy routes/state remain documented product decisions.
Validation: immutable-source and public-material review only; no tests, builds, apps or PR code executed. The one-time hosted-check snapshot remains incomplete, with Windows native validation skipped. No complete test-count, elapsed/summed execution-time or slowest-file comparison was established, and no performance improvement is claimed. Native/live-relay behavior, rendered keyboard/focus and screen-reader behavior, theme/viewport acceptance and human acceptance remain unverified. This bounded follow-up is not an exhaustive re-audit, approval or merge authorization.
The DM preview wiring journey computes how many unread rows sit above and below the viewport, then hardcoded the plural label. With the unified sidebar's geometry exactly one row can sit above, where the app correctly says "1 unread conversation above". Co-authored-by: ART <ea39c1c8acf57180161ef4ba4ed68abf8589f5291956b909a5aa991fc66664ca@buzz.block.builderlab.xyz> Signed-off-by: Bradley Axen <[email protected]>
782953b to
7b71070
Compare
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account.
Reviewed head 7b710706e9660b7b916f30479ce40dbcb4484a3e, base b90bd29c145255fb8b992c4de1eea0b601b6f061. This uses the small-follow-up solo exception: endpoint comparison with the previously reviewed 2a85459dfed9d769fbddacd78736c079f9360b92 changes only one assertion line in tests/browser/sidebar-unread.spec.mjs:650; all production files and the base are unchanged. No new teammate review is claimed.
No new actionable defect in this assertion fix. It correctly expects singular “conversation” for one unread destination and plural otherwise, matching SidebarUnread.tsx without loosening the accessible-name assertion. No browser cases are added or removed.
The previously reported unresolved findings still apply: SoloDraft completion can clear newer source state and race destination editing, NewMenu subscribes without initializing Solo preferences, and the five public screenshots expose actual workspace/channel information. The affected production files are unchanged; all five attached images were re-fetched and inspected. Please address the existing linked comments; this review adds no duplicate inline findings. Overall assessment remains 8/10 because those material issues persist.
Validation: source-only bounded follow-up, not a fresh audit of the whole feature. No PR code, tests, builds or apps executed. The one-time hosted-check snapshot is still in progress; Windows validation is skipped. Browser geometry, keyboard/focus and screen-reader behavior, error/retry flows, native/live-relay behavior and human acceptance remain unverified. No before/after test timing, summed execution-time or slowest-file comparison was established; no speedup or CI-green claim. This is a non-blocking COMMENT, not approval or merge authorization.
The new chat composer could not attach files: they waited for send, unlike every other composer, and the page was not a drop area. The session now offers a channel-unbound upload for chats being started: uploads are community media, not channel-scoped, and the first send stays guarded by membership. It still cancels with the session's upload lifetime and exists only where chats can be created. Files upload as soon as they are attached, and finish before the chat is created, so a failed file blocks the start instead of leaving an empty chat. Once the chat exists, its own composer holds the uploaded files until the first message sends, so an interrupted start can be finished there. Capture tools hide where files cannot be attached, and image thumbnails stay steady when uploads finish. Rebased onto the Solo reshape (#1273): the start logic moved from NewSessionComposer to SoloDraft, which no longer persists a pending start, so the lost-files recovery receipt is not needed. Signed-off-by: morgmart <[email protected]> Co-authored-by: Carl <c217fe6b9d958f41c3a5e030dccc7f626775a923089cb6491305eade75ea1f1b@buzz.block.builderlab.xyz> Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Bradley Axen <[email protected]>
…d before #1273 Every writer before #1273 reserved this description for session starts, so on an older receipt it identifies a session start. Later ordinary channels may use the text, and an interrupted create of one is restored again. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <[email protected]>
Solo replaced session chats in #1273, and the saved-creation filter moved from the session description to the Solo label. A pre-Solo chat creation still saved in the outbox now looked like an unfinished dialog creation, so Create channel opened in Retry mode with that chat's prompt and refused new channels. Skip saved creations whose description starts with the old session header again. Older builds refused that header in ordinary channel descriptions, so no real dialog creation carries it. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <[email protected]>
Solo replaced session chats in #1273, and the saved-creation filter moved from the session description to the Solo label. A pre-Solo chat creation still saved in the outbox now looked like an unfinished dialog creation, so Create channel opened in Retry mode with that chat's prompt and refused new channels. Skip saved creations whose description starts with the old session header again. Older builds refused that header in ordinary channel descriptions, so no real dialog creation carries it. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <[email protected]>
The Create channel dialog restored any unresolved kind-9007 Create from the Outbox and locked itself to that channel until Retry confirmed it. Since #1273 dropped the Sessions marker check, old confirmed Sessions chats restored this way too, and a Create that Retry could never confirm wedged channel creation. Drop that recovery. A failed or uncertain create shows its error and leaves the form editable. Creating again with identical details republishes the same signed event, so a Create that actually landed is not duplicated; changed details abandon it and sign a new one. Closing the dialog forgets the attempt and dismisses it from the Outbox, and nothing restores after reopening or a restart. Template setup does the same, comparing only what the person chose so inventory that moved under an untouched form still rechecks the same Create. Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Bradley Axen <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
Closing a profile opened from Solo Share access, either the header button or Chat actions → Share access, left focus on the "Chat <name>" section instead of the control that opened the dialog. Team Manage members already returns there. The main-pane SoloHeading is keyed on navigation.entryId. Since #784 (moved to SoloHeading in #1273) each visit remounts the header. That ends the visit's header dialogs, menus and toasts, which are scoped to its signal and don't close themselves on abort. The key stays. Opening the profile is a new visit, so the header remounts and detaches the opener that panelTrigger holds. afterClose then falls back to the history section. The dismissal's async return to the chat remounts the header again. This follows keptTabReturn. onClosePanel records a dismissal-scoped return when the panel's opener is detached and marked data-solo-opener. The visit layout effect consumes it only on this dismissal's matching return, and only while focus is still on the history section. It then focuses the same control in the remounted header. A Solo side tab's toolbar isn't keyed per visit. When its profile closes, the pane keeps the chat's tab and focus stays with it, so that outcome is unchanged. The RTL tests "opens a profile from the header's Share access and returns focus to it" and the Chat actions variant passed despite the bug. Their fixture's navigation is static (entryId "visit", open is a vi.fn), so no visit is ever applied. The header never remounted and the original trigger stayed connected. Their focus assertions are removed and the header test is renamed. A new solo-workspace.spec.mjs journey covers both openers across real navigation entries. It also asserts that opening the profile changes the entry. On 7ae9be9 its two focus assertions fail in Chromium and WebKit, and they pass with this change. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Matt Toohey <[email protected]>





Unify Solo and Team navigation in the desktop shell
Solo and Team currently replace one another’s sidebars. This change combines their inventories under an All / Solo / Team scope control so people can browse both without replacing the conversation they are viewing.
Foundation guidance
Arjun explicitly directed combining the Solo/Team sidebar inventories, moving creation into the header, and keeping global destinations in the shell. The
FOUNDATIONchanges inApp.tsximplement that human-guided composition: mountPrimarySidebarand passNewMenuascreationAction. They do not introduce a separate application lifecycle owner.Review follow-up
Validation
The initial prepared snapshot was checked before rebase. Follow-up commits merge main at 4ac642f and migrate existing browser journeys to the unified navigation. Screenshot notes retain the earlier snapshot hashes.
138 focused tests passed across seven shell, sidebar and community files. Updated two additional integration files for the community picker and header placements; all 8 tests in those files pass.
Final pre-push gates passed at 26590e8: TypeScript/related unit tests, design-system checks, Rust Clippy and destination policy.
165 design-system tests passed; app/design typechecks, design guards, design build, changed-file Biome and diff checks passed. Design build reports its existing bundle-size warning.
New lifecycle regression failed before the fix with navigation into the replaced session, then passed after the guard.
Browser preview: light/dark at 1280px, dark 900px and 360px; All/Solo/Team pointer and keyboard selection, preserved conversation, New menu, Search open/Escape, compact navigation drawer/More pages, community-picker End/Escape focus. Existing identity/community data loaded. No live creation, membership mutation or message sent.
Independent agent review completed; both concrete findings fixed and re-reviewed.
At 26590e8, the final full layout file passed in Chromium and WebKit, and all 22 sidebar/header cases passed in a subsequent full-file run. The other repaired navigation, menu, scroll and surface cases passed in earlier focused runs; hosted CI is running for the full suite.
Independent review of the CI migrations and enlarged-text fix found no remaining blockers. No browser cases were added or removed in this repair.
Remaining before readiness
Screenshots
Five inspected local captures are available in the Desktop PR Screenshots folder. They show the running browser preview with existing account/community data and an empty conversation. Arjun also uploaded the captures in the PR conversation. No local image paths are embedded here for hosted rendering.
Open as a draft. Do not add buzz-review-completed until the remaining acceptance requirements hold.