Skip to content

Hold thread folds on the host so every client shows the same list - #496

Merged
Tryanks merged 1 commit into
mainfrom
sync-thread-folds
Sep 21, 2026
Merged

Tryanks merged 1 commit into
mainfrom
sync-thread-folds

Conversation

@Tryanks

@Tryanks Tryanks commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Behaviour

Which parent threads have their child rows folded in the thread list is now host state shared by every client, like the project-group folds already were. A phone attached to a desktop host sees exactly the desktop's folds, and folding or expanding on either side shows on the other. Previously the fold set was client-local and seeded once at sidebar construction from whatever index the client had; a phone attaches before its index arrives, so it seeded nothing and every thread with agents opened expanded on each launch.

The startup rule is unchanged, just moved: host start folds every thread that already has a visible child. Selecting a thread on any client asks the host to unfold its ancestors, so the restored selection is on screen as before (and now also when a hidden child is reached through search).

Changes

  • core: Settings.collapsed_threads (absent in older files, skipped when empty; kept across a settings reset with the other sidebar state).
  • protocol: Command::SetThreadCollapsed { session_id, collapsed }. Additive, as with earlier command additions.
  • runtime: AppState::set_thread_collapsed persists and replicates; the command is rejected with unknown_session for an unknown thread; delete_session prunes the fold; startup_collapsed_threads seeds at host start.
  • ui: WorkspaceStore exposes the replica (collapsed_threads, is_thread_collapsed) and the intent; SessionsSidebar loses its local fold set and the duplicate seeding rule, and every fold read or toggle goes through the store.

"Show more" expansion past the collapsed limit and the settled-section toggles stay client-local; they are view state, not list content.

Tests

  • runtime: host_start_folds_only_parents_with_visible_children (leaves, parents of only archived children, and parent ids no session carries stay unfolded), thread_fold_is_host_state_shared_over_the_pipe_and_pruned_with_the_thread (ack, unknown_session, settings replication, prune on delete); reset_settings_... also asserts the new field survives.
  • ui: host_folds_hide_child_rows_and_selecting_a_child_unfolds_on_the_host (a fold from the settings topic hides the child; selecting it sends SetThreadCollapsed(parent, false) instead of unfolding locally); the disclosure part of compact_families_keep_activity_order_indent_and_collapse now asserts the request and drives the rows from the host's settings. The removed startup_folds_only_existing_visible_parents_outside_the_active_chain unit test tested the client-side seeding function; its rule is covered by the runtime test and the active-chain exception by the new ui test. The tests that set the local set directly now send it on the settings topic.

Checks run

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets --locked -- -D warnings
  • cargo nextest run --workspace --locked (904 passed, 6 skipped)

Not run locally: iOS/Android/Web builds (CI). Not exercised on a device.

The thread list's parent folds (which threads' child rows are hidden)
were client-local: SessionsSidebar seeded them once at construction from
the index it had at that moment and toggled them in memory. A phone
attaches before its index arrives, so it seeded an empty set and every
parent with agents opened expanded on each launch, and no two clients
ever agreed on the list.

The fold set now lives in Settings as collapsed_threads, replicated on
the settings topic like collapsed_projects. Clients change it through
the new SetThreadCollapsed command (rejected for an unknown thread), a
deleted thread leaves no fold behind, and host start folds every thread
that already has a visible child, which is the startup rule the client
used to apply. The sidebar reads folds from the settings replica and,
whenever a thread is selected on any client, asks the host to unfold its
ancestors, which also restores the previously client-side exception for
the restored selection. The one-for-one clone of the seeding rule and
the local fold set are gone from the sidebar.

Tests: host_start_folds_only_parents_with_visible_children and
thread_fold_is_host_state_shared_over_the_pipe_and_pruned_with_the_thread
(runtime); host_folds_hide_child_rows_and_selecting_a_child_unfolds_on_the_host
and the reworked disclosure part of
compact_families_keep_activity_order_indent_and_collapse (ui) drive the
fold through the protocol instead of the removed local set.
@Tryanks
Tryanks merged commit 63e2918 into main Sep 21, 2026
7 checks passed
@Tryanks
Tryanks deleted the sync-thread-folds branch September 21, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant