Skip to content

Unify Solo and Team navigation in the desktop shell - #1273

Merged
baxen merged 2 commits into
mainfrom
am-1016-daily-polish
Oct 18, 2026
Merged

baxen merged 2 commits into
mainfrom
am-1016-daily-polish

Conversation

@mahanti

@mahanti mahanti commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

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.

  • Move Messages, Reminders, Projects, Agents and Workflows into a centered header navigation group. Keep Inbox and optional Bestie in the sidebar.
  • Provide separate New and Search capsules. New offers chat, project, DM and channel creation; Search retains its existing modal.
  • Replace the community rail with an active-community dropdown beside the profile avatar, preserving community context actions and join/create entry points.
  • Share sidebar section spacing, controls and row treatment across Solo and Team; use chat icons for Solo conversations, remove sidebar branding, and refine macOS traffic-light positioning.
  • Use shared segmented Tabs and capsule Panel variants. Compact controls participate in flex layout to avoid overlapping native navigation controls. Ignore project-completion navigation after its relay session has been replaced.

Foundation guidance

Arjun explicitly directed combining the Solo/Team sidebar inventories, moving creation into the header, and keeping global destinations in the shell. The FOUNDATION changes in App.tsx implement that human-guided composition: mount PrimarySidebar and pass NewMenu as creationAction. They do not introduce a separate application lifecycle owner.

Review follow-up

  • Persist navigation scope per viewer/community through Settings and reloads; reveal the matching inventory for new navigation, including reopening the same chat. Preserve All and deliberate filtering without navigation.
  • Omit the scope tabs and their tabpanel semantics when Solo is disabled.
  • Keep creation dialogs mounted across same-community reconnects and session-generation changes; permit cached connectivity and retain stale-session completion guards.
  • Expand the saved destination section after header channel creation, preserving other collapsed sections.
  • Keep the requested hover-only disclosure chevrons; restore keyboard-only focus reveal so a pointer click does not leave section actions visible.
  • 51 focused component tests and 38 Chromium/WebKit cases passed. Four new persistence/reconnect regressions failed before the fix and passed afterward. Independent review completed.

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

  • Confirm sidebar visibility on global pages. Current code/docs preserve manual visibility; an earlier request asked for automatic hiding. User clarification is pending, so existing behavior was preserved.
  • Native traffic-light positioning, 480px native header and final human acceptance of the checked snapshot remain unverified. The browser enlarged-text project flow now passes in both engines after reducing the shared decorative disclosure slot from 24px to 16px. Browser preview does not establish native signing, filesystem or IPC behavior.
  • Browser CI repair adds/removes no journeys: existing focus, selection, geometry and scroll contracts now use the active-community dropdown and header navigation. Channel-only scroll restoration explicitly disables the Solo plugin in its fixture; companion geometry waits for the applied resize before capturing its baseline. Tolerances and timeout budgets were preserved.
  • No new browser journeys; the lifecycle regression is colocated RTL/Vitest coverage. Obsolete menu-entry tests were removed with the removed New agent/plugin functionality; creation remains covered at its feature owners.

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.

@mahanti mahanti added the enhancement New feature or request label Oct 16, 2026
@mahanti
mahanti marked this pull request as ready for review October 16, 2026 18:34
@mahanti
mahanti requested a review from a team as a code owner October 16, 2026 18:34
@mahanti

mahanti commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author
01-all-sidebar-light 02-new-menu 03-all-sidebar-dark 04-narrow-navigation 05-community-picker

@baxen baxen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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. openPage in tests/browser/navigation.mjs:13 waits for the rail's Switch to Primary button, which now lives inside the community popover.
  • selectPage also maps Messages to Multiplayer, 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.tsx still switches between "Hide Solo sidebar" (on buzz.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.svg is unreferenced since SidebarBrand was 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.

Comment thread src/app/App.tsx
/>
) : (
<ChannelSidebar
<PrimarySidebar

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/app/shell/PrimarySidebar.tsx Outdated

/** Filters the navigation inventory without replacing the current conversation. */
export function PrimarySidebar(props: ComponentProps<typeof ChannelSidebar>) {
const [filter, setFilter] = useState<Filter>("all");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This filter has two problems.

  1. It resets to All after visiting Settings. App.tsx swaps in SettingsSidebar and unmounts this component, so the state is lost. It also isn't saved per community or across launches.
  2. 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/app/shell/PrimarySidebar.tsx Outdated
items={
props.meEnabled
? filters
: filters.filter((item) => item.value === "multiplayer")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/app/shell/NewMenu.tsx Outdated

export function NewMenu(props: Props) {
const connection = useRelayConnection(props.relay);
return connection.status === "ready" ? (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 CreateChannelDialog or NewProject is open, this branch swap and the scope:generation key unmount the dialog and lose typed input.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/app/shell/NewMenu.tsx
destinations={preferences.data?.sections ?? []}
initialGroup=""
groupsReady={preferences.writable}
onCreate={async (input) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@baxen

baxen commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

🤖 From ART (baxen's agent): #1294 targets this branch and fixes the remaining browser-journey failures at a7b418d7e. Merge it here or cherry-pick 667d9aa7c.

  • Product fix: the compact header was 58px tall at 1× (114px at 2×) instead of the 3.5rem topbar size. That's the shortcuts zoom failure and the layout Projects flake.
  • Test updates: four journeys assumed the old 48px community rail or a single loading status: plugin-import, inbox-refresh-layout, github-metadata and navigation-sorting. Details are in Fix #1273 browser CI: compact header height and geometry journeys #1294.

@baxen
baxen marked this pull request as ready for review October 16, 2026 23:45
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T23:51:35.875808Z 35c070f Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment thread docs/communities.md
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/app/shell/NewMenu.tsx
session.mePreferences.subscribe,
session.mePreferences.snapshot,
);
const preferences = useSidebarPreferences(session.sidebarPreferences);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +216 to +218
writeView(scope, `${draftKey}:settings`, null);
writeView(scope, `${draftKey}:new-draft`, "");
writeView(scope, `${draftKey}:new-project`, null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +235 to +240
session.messages.send(channelId, text, recipients);
writeView(
scope,
`draft:${channelId}`,
rememberedMentions(session, draft, recipients),
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@baxen
baxen force-pushed the am-1016-daily-polish branch from 76d8bdb to 3b0ce59 Compare October 18, 2026 02:04
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]>
@baxen
baxen force-pushed the am-1016-daily-polish branch from 3b0ce59 to 2a85459 Compare October 18, 2026 02:10

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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]>
@baxen
baxen force-pushed the am-1016-daily-polish branch from 782953b to 7b71070 Compare October 18, 2026 02:42

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@baxen
baxen merged commit 3d07994 into main Oct 18, 2026
39 of 47 checks passed
@baxen
baxen deleted the am-1016-daily-polish branch October 18, 2026 03:21
baxen pushed a commit that referenced this pull request Oct 18, 2026
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]>
loganj added a commit that referenced this pull request Oct 19, 2026
…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]>
loganj added a commit that referenced this pull request Oct 20, 2026
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]>
loganj added a commit that referenced this pull request Oct 20, 2026
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]>
baxen added a commit that referenced this pull request Oct 21, 2026
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]>
matt2e added a commit that referenced this pull request Nov 5, 2026
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]>
matt2e added a commit that referenced this pull request Nov 6, 2026
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]>
matt2e added a commit that referenced this pull request Nov 6, 2026
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]>
matt2e added a commit that referenced this pull request Nov 7, 2026
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]>
matt2e added a commit that referenced this pull request Nov 9, 2026
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]>
matt2e added a commit that referenced this pull request Nov 9, 2026
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]>
matt2e added a commit that referenced this pull request Nov 12, 2026
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]>
matt2e added a commit that referenced this pull request Nov 12, 2026
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]>
matt2e added a commit that referenced this pull request Nov 12, 2026
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]>
matt2e added a commit that referenced this pull request Nov 13, 2026
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]>
matt2e added a commit that referenced this pull request Nov 13, 2026
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]>
matt2e added a commit that referenced this pull request Nov 14, 2026
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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants