Skip to content

feat(solo): smooth chat recency reordering - #3502

Merged
tellaho merged 4 commits into
mainfrom
tho/solo-recency-motion
Nov 13, 2026
Merged

tellaho merged 4 commits into
mainfrom
tho/solo-recency-motion

Conversation

@tellaho

@tellaho tellaho commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Category: improvement
User Impact: Solo chats move between recent-activity positions with the same short slides and fades as Team channels.

Problem: Activity-sorted Solo chats jump abruptly when another conversation becomes active, making it difficult to follow a row.

Solution: Reuse the existing channel sidebar motion for each Solo workspace's chat list. Nearby moves slide, distant moves fade at their endpoints, and reduced motion applies the new order immediately.

Changes

File changes

src/bundled/channels/SoloWorkspaces.tsx
Wrap each workspace's listed chats with the existing motion owner, preserving collapse, drag, rename, cap and composed-workspace behavior. Focus restoration skips exiting copies.

src/features/channel-navigation/SoloInventory.tsx
Skip inert exit copies when choosing activity triggers and focus successors. End focus ownership at logical removal, before the retained row becomes inert, while preserving the guard against taking focus from another control.

src/features/channel-navigation/SoloInventory.test.tsx
Cover batching, retained focus and live reduced motion in standalone and combined Solo hosts.

src/bundled/channels/SoloChatName.tsx
Discard unsubmitted rename drafts on presence exit instead of treating the resulting native blur as a save.

src/bundled/channels/SoloWorkspaces.test.tsx
Extend the existing workspace-move test to place an inert exit copy before the live destination. Await the intended entry fade in the workspace-deletion journey.

tests/browser/solo-motion.spec.mjs
One native-browser journey covers nearby transforms without scale/fade, distant endpoint-only fades, retained DOM identity/focus, and live reduced motion with a frozen clock.

tests/browser/solo-rename.spec.mjs
Interact only with live copies during fades while preserving complete-unmount assertions. Wait for the converted editor to leave before double-clicking a neighbor whose position is still changing. Assert no signing request for an unsubmitted draft on conversion; cover native focus handoff and its no-steal guard with normal and reduced motion.

docs/buzz-help.md
Document Solo motion parity and reduced-motion behavior.

Coverage audit

Measure Initial patch Current patch
New component cases 2 2
New browser journeys 2 2
New Chromium/WebKit executions 4 4
Test diff +233 / −2 lines +292 / −7 lines

Production is +28/−14 lines ignoring indentation (+71/−57 including the wrapped row map); help adds two lines. The current test total includes the +12/−5-line adaptation of existing rename journeys and a +50-line lifecycle regression update: ten lines extend the existing conversion case, and one 40-line journey covers native focus handoff with both motion preferences and the no-steal guard. The earlier consolidation reduced duplicate motion executions from four to two; the focus regression adds two distinct engine executions. The two component cases exercise different host compositions. Shared controller tests already cover batching bounds, cancellation, removal/reappearance and media-subscription teardown; this port does not duplicate those cases.

Removed assertion mapping:

  • Duplicate nearby/distant order, identity and focus checks remain in the single motion-enabled browser journey.
  • Reduced-motion “no transform, no fade, immediate order” moves to a live preference change in that journey. A frozen clock prevents a delayed animation from passing as immediate; standalone/combined component cases retain the pending-batch flush contract. Existing channel browser coverage retains startup reduced motion.
  • The distant row's zero-translation check remains alongside its endpoint geometry check. Nearby siblings may still slide into their slots.

The five-chat fixture is the minimum used here to express a greater-than-two-slot distant move. No existing browser journey was removed, no engine was skipped, and no assertion tolerance or timeout was relaxed.

Validation

  • Hosted CI run 43498574843 passed at 75beb4f7a38ae60e7883fcb6c70964c748a8c3a4, including CI required, DCO, all Chromium/WebKit journeys and flake checks. Windows native validation was skipped by the existing workflow.
  • At 75beb4f7a38ae60e7883fcb6c70964c748a8c3a4, mandatory pre-commit and pre-push checks passed: TypeScript/related units (33.12 s), design types/guards (6.31 s), and scope/policy gates. The untouched Rust lane correctly skipped.
  • Chromium and WebKit: all 20 executions in the existing Solo chat journey file passed after mainline integration; both executions of the consolidated motion journey passed with the final test source. Production sources match the published head in both runs.
  • Falsifiability: removing the Solo wrapper fails both host component cases; removing active-copy filtering fails the workspace-move focus assertion. In an isolated checkout, disabling the production reduced-motion gate makes both engines fail the consolidated journey's frozen-clock immediate-order assertion.
  • The complete rename file passes all 24 Chromium/WebKit executions with the final 75beb4f7a38ae60e7883fcb6c70964c748a8c3a4 source. The original CI rename failure reproduced in both engines before the selector repair; a conversion followed immediately by another rename also exposed a missing actual-unmount boundary. Both preserve their full original assertions.
  • Browser cases added relative to main: 2 journeys / 4 engine executions. Existing cases removed: 0. Both engines and the original geometry tolerance remain enabled.

The initial CI repair changed tests only. Both previously failing WebKit shards now pass; toolbar code and its geometry tolerance remain unchanged. Native/human acceptance, a complete theme/width/text-scale inspection and fresh performance profiling remain unverified.

Exit lifecycle validation

  • Rename draft discard: the changed-draft conversion probe failed in Chromium and WebKit at 75beb4f7a38ae60e7883fcb6c70964c748a8c3a4, each recording an unwanted signing request. The presence guard prevents both signing and publication.
  • Focus handoff: both engines failed the new native-focus journey before the presence-aware cleanup. The fixed journey covers handoff to the surviving selected chat and preserving focus moved to the composer, with normal and reduced motion in the same mounted app.
  • At clean acfd1ce3cb947f4a3b1b16a55e887c0850c00b02, all 26 executions of the complete solo-rename.spec.mjs file passed in Chromium and WebKit (36.6 s total runner time). Mandatory push gates passed: TypeScript/related units (32.41 s), design types/guards (5.93 s), and policy gates; unchanged Rust inputs correctly skipped Clippy. Hosted CI for this new head is pending; the earlier green run above applies only to 75beb4f7a3.

Reproduction

  1. Open Solo with several chats listed in a workspace. Cause activity in a chat one or two slots below the top: it should slide into its new position without scaling, fading or losing keyboard focus.
  2. Cause activity in a chat more than two slots away: it should fade between its endpoints rather than sweep across the list.
  3. Enable reduced motion while the app is open, then cause more activity: the order should update immediately.

Additions/removals retain the controller's existing row fades, while neighboring rows reflow immediately. Creating/removing the first/last unfiled chat mounts/unmounts the whole Chats section and still bypasses the row fade; this PR does not expand that behavior.

Screenshots / demos

The selected Solo chat slides up one position after new activity.

Solo sidebar chat moving up after new activity

tellaho and others added 2 commits November 13, 2026 11:45
Reuse channel sidebar motion for workspace chat lists, preserving focus and skipping leaving copies during focus restoration. Cover batching, live reduced motion, native slides and distant endpoint fades.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Interact with active Solo rows while preserving full removal assertions for fading copies. Wait for the converted editor to unmount before double-clicking its moving neighbor.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
@tellaho
tellaho marked this pull request as ready for review November 13, 2026 20:22
@tellaho
tellaho requested a review from a team as a code owner November 13, 2026 20:22

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Two lifecycle regressions reproduced during passive Solo-to-Team conversion.

Comment thread src/bundled/channels/SoloWorkspaces.tsx Resolved
Comment thread src/bundled/channels/SoloWorkspaces.tsx Resolved
tellaho and others added 2 commits November 13, 2026 12:51
Prevent presence-retained editors from signing an unsubmitted name when becoming inert blurs their input. Extend the live conversion journey to verify no signing request or publication.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
End focus ownership at logical removal, matching the existing channel-row presence contract. Exercise native focus recovery and the moved-focus guard with normal and reduced motion in one browser journey.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
@tellaho

tellaho commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

🤖 @kalvinnchau Both exit-lifecycle regressions are fixed at acfd1ce3cb947f4a3b1b16a55e887c0850c00b02:

  • Exiting rename editors reject saving on blur, preserving discard of an unsubmitted draft (93a866096e).
  • Solo rows hand off focus at logical removal, using the existing channel-row presence contract and retaining the guard against stealing focus moved elsewhere (acfd1ce3cb).

Both regressions failed before their fixes in Chromium and WebKit. At the clean final head, all 26 executions of the complete rename file passed (36.6 s), including zero signing requests/publications after passive conversion, surviving selected-row focus, and the no-steal guard under normal and reduced motion. Required push gates passed: TypeScript/related units, design types/guards, and policy checks. No timeouts, tolerances or engines changed.

Both directly addressed threads are resolved. The PR remains ready with its original demo GIF. New-head hosted CI is pending; native acceptance remains unconfirmed.

@kazemek21 kazemek21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Kyle reviewed this PR and the Nexus review-tracker notes and approves.

Posted by Codex (gpt-6.1-sol) on behalf of kylez

@tellaho
tellaho merged commit ab68be3 into main Nov 13, 2026
135 of 137 checks passed
@tellaho
tellaho deleted the tho/solo-recency-motion branch November 13, 2026 22:47
philazar added a commit that referenced this pull request Nov 13, 2026
…ve-client

* origin/main:
  feat(solo): smooth chat recency reordering (#3502)
  Reject self-mentions that cannot wake another session (#3513)
  feat(status): offer don't clear for every status (#3515)
  Let plugin panels name their tab with panels.useTabTitle (#3251)
  fix(agents): report a conversation wake that fails before its turn starts (#2192)
  fix(usage): read Claude transcripts over 50 MB a page at a time (#3498)
  feat(agents): preview where interrupted agents were working before resume (#3494)
  perf(messages): close the editor and delete dialog on submit (#3493)
  feat(messages): quote selected message text into the composer (#2392)
  perf(toast): scope docked clearance to the toast host (#3489)
  fix(unread): undo exact captured ordinary reads conditionally (#3473)

Signed-off-by: Philip Azar <[email protected]>
wpfleger96 added a commit that referenced this pull request Nov 14, 2026
…y-unreads

* origin/main: (24 commits)
  [1/2] feat(agents): add a recommended agent setup (core) (#3344)
  test(browser): survive the live-stream restart a page-clock jump causes (#3442)
  chore(renovate): hold rusqlite below 0.41 for mesh-llm (#3438)
  test(browser): serve the diffs and CLI reload fixtures outside the navigation budget (#3445)
  test(browser): play the draft clip at rate 0 instead of looping it before the Play click (#3446)
  fix(status): reopen a status whose preset deadlines coincide as Today (#3449)
  fix(messages): tolerate a cancelled reaction-name chunk load (#3450)
  fix(pairing): tolerate /proc/net/tcp rows printed twice or missed (#3451)
  test(browser): wait on the signal each test asserts in local-agent-activity and message-navigation (#3444)
  Expose native channel headings to Solo sources (#3523)
  test(browser-host): run the 100,000-channel broker scale check alone in the measurements lane (#3447)
  fix(solo): keep every contributed destination action (#3516)
  fix(identity): report an issuer that keeps rate-limiting an agent as a limit (#2365)
  fix(identity): let a stuck at-launch sign-in copy its link (#2453)
  fix(profiles): open avatar previews on hover in compact density (#3510)
  feat(solo): smooth chat recency reordering (#3502)
  Reject self-mentions that cannot wake another session (#3513)
  feat(status): offer don't clear for every status (#3515)
  Let plugin panels name their tab with panels.useTabTitle (#3251)
  fix(agents): report a conversation wake that fails before its turn starts (#2192)
  ...

# Conflicts:
#	tests/browser/message-management.spec.mjs
wpfleger96 added a commit that referenced this pull request Nov 14, 2026
* origin/main: (27 commits)
  [2/2] feat(agents): offer Automatic (Recommended) in Create agent and Identity (#3345)
  fix(solo): preserve and resume unsent chat drafts (#3525)
  fix(builderlab): give refused app sign-ins and Identity links a route to Organization sign-in (#3078)
  fix(agents): say why Import an agent can't import here, and link Manage plugins (#3073)
  [1/2] feat(agents): add a recommended agent setup (core) (#3344)
  test(browser): survive the live-stream restart a page-clock jump causes (#3442)
  chore(renovate): hold rusqlite below 0.41 for mesh-llm (#3438)
  test(browser): serve the diffs and CLI reload fixtures outside the navigation budget (#3445)
  test(browser): play the draft clip at rate 0 instead of looping it before the Play click (#3446)
  fix(status): reopen a status whose preset deadlines coincide as Today (#3449)
  fix(messages): tolerate a cancelled reaction-name chunk load (#3450)
  fix(pairing): tolerate /proc/net/tcp rows printed twice or missed (#3451)
  test(browser): wait on the signal each test asserts in local-agent-activity and message-navigation (#3444)
  Expose native channel headings to Solo sources (#3523)
  test(browser-host): run the 100,000-channel broker scale check alone in the measurements lane (#3447)
  fix(solo): keep every contributed destination action (#3516)
  fix(identity): report an issuer that keeps rate-limiting an agent as a limit (#2365)
  fix(identity): let a stuck at-launch sign-in copy its link (#2453)
  fix(profiles): open avatar previews on hover in compact density (#3510)
  feat(solo): smooth chat recency reordering (#3502)
  ...

# Conflicts:
#	src-tauri/src/federated_identity/agent/tests.rs
#	src-tauri/src/federated_identity/mod.rs
#	src-tauri/src/federated_identity/protocol.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants