Skip to content

feat(sidebar): move channels into saved groups and starred - #207

Merged
tellaho merged 10 commits into
mainfrom
tho/sidebar-grouping-focused
Sep 25, 2026
Merged

tellaho merged 10 commits into
mainfrom
tho/sidebar-grouping-focused

Conversation

@tellaho

@tellaho tellaho commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Current status — September 25, 2026, d75d0d31148be22053003500e61ce98128eb389a: both move-recovery review requests are fixed and pushed. Retry now explains source changes/unavailable preferences; Dismiss restores row focus, including collapsed placement and a missing-row fallback. The earlier Unicode blocker is fixed. Not merge-ready: integration with main 80511fa8 is paused on a conflicting broker timing-test assertion pending the operator’s decision; GitHub reports CONFLICTING and the historical CHANGES_REQUESTED verdict remains. DCO passes; no current-head hosted integration-CI pass is claimed. PR ready-for-review state is unchanged (not draft).

Screenshot provenance: the 27-image gallery remains captured at d4722510, before these recovery fixes. It exhaustively documents the then-current menus and permission/type variants, not the newly updated recovery text or a new-main integration.

Category: new-feature

User Impact: Users can move channels into saved groups or Starred, create a group directly from a channel, and recover failed saves without losing their place.

Problem: Saved sidebar organization is visible but cannot be changed directly from a channel, and moving between group stores must not lose existing preferences or create duplicate rows.

Solution: Add one Move channel menu with saved destinations, Create new, and exclusive Starred placement, backed by quiet optimistic saves and explicit recovery. Preserve the active personal-group schema and its existing encrypted writer, keep healthy personal groups visible when legacy reads fail, and inherit the parent-menu foundation’s fully rounded shared rows.

Scope and persistence boundaries

  • Current branch retains the earlier integration through 30c3589b; newer main is not yet integrated. Historical validation below is explicitly scoped to its named snapshots.
  • Stream channels only. Selecting the current destination removes that placement; unstar returns to Channels, not a remembered prior group. Exactly one channel row is displayed.
  • Before explicit personal-group activation, write legacy groups. After activation, use the existing personal-group/recipe writer: 120-character names, no icon field, and existing template defaults preserved. No migration or schema expansion.
  • Legacy writes read a verified fresh head, preserve unrelated fields, publish through the host, and confirm retained state. Cross-record moves are not atomic: assignment completes before star removal, failures expose an explicit partial-save warning and retry. This is not a new cross-device CRDT or a universal offline outbox.
  • Keep agreed legacy-icon and startup presentation behavior. Startup uses existing signals with a bounded presentation latch; it does not grant access. Account-read recovery is one-shot and never retries explicit cancellation, cache clear, teardown, or channel-content reads.
  • Sorting/Recent activity, startup smoothing, user statuses and mute/read/notification/lifecycle behavior are inherited from main, not reimplemented. Move and Sort overlay one confirmed preferences snapshot and share the existing session queue with Mute; confirmations update only their owned fields. Group CRUD/reordering/drag-and-drop remain separate. No native adapter implementation is added; unavailable host capabilities stay gated.
  • Diff at that historical integration snapshot against integrated main: production: +1,474/−257; tests/fixtures: +3,644/−70; documentation: +14/−3 across 39 files. Total +5,132/−330, versus 41 files, +5,264/−284 before this rebase. Main supplies the startup hook/tests (288 former additions); the necessary combined-persistence coverage offsets much of that removal. Total changed-line reduction is 86, not a large rewrite or a safety-test trim. Shared menu styles and the page-owned Channels workspace match main.
  • Originating Buzz thread

Changes

File changes

dev/relay-broker.mjs
Expose bounded host-only assignment and star commands. Serialize writes per relay, sign authenticated requests, and require a fresh confirmation before reporting success.

dev/sidebar-create-section.test.mjs
Cover create-and-assign preservation, input limits, unknown publication outcomes, idempotent retry, and refusal to seed after a failed read.

dev/sidebar-group-moves.test.mjs
Exercise the session store with production encrypted preference writers, including partial failures, concurrent refresh, cancellation between records, and durable retries. Preserve main’s always-present DMs entry point in section assertions.

dev/sidebar-preference-writes.test.mjs
Verify signed broker round trips and reject invalid intents or foreign origins before upstream work.

dev/sidebar-preferences.d.mts
Describe the existing JavaScript preference decoder and new narrow assignment writer at the TypeScript boundary.

dev/sidebar-preferences.mjs
Apply one assignment or create-and-assign intent to a fresh verified encrypted head while retaining unrelated fields. Confirm retained state and make retries idempotent.

dev/sidebar-stars.mjs
Write explicit star/unstar intents with monotonic timestamps, preserved tombstones, bounded decoding, and fresh confirmation.

dev/sidebar-stars.test.mjs
Cover star validation, encryption, preservation, conflicting confirmations, no-op writes, and read/publication failures.

src/bundled/channels/Channels.module.css
Remove the old section-icon styles now owned by the dedicated group-icon component.

src/features/channel-navigation/ChannelSidebar.test.tsx
Cover both active-group-source transitions and unavailable-preference retry recovery through the real store and notice.

src/features/channel-navigation/ChannelSidebar.tsx
Wire Move channel with a decorative 14px outlined folder icon, Create new, exclusive Starred placement, focus restoration, and retained retry UI into main’s persistent sidebar owner. Preserve New session as the first independently eligible action; Move/Create also work off Messages and with Sessions disabled. Keep healthy personal groups visible during legacy-read failure while writes remain disabled.

src/bundled/channels/CreateSidebarSection.module.css
Keep the selected channel label on one truncated line within the create dialog.

src/bundled/channels/CreateSidebarSection.test.tsx
Verify a rejected draft retains its name and group identity through failed/successful preference recovery, and accepted submissions cannot be duplicated.

src/bundled/channels/CreateSidebarSection.tsx
Provide the shared-control create-and-move dialog with a stable retry identity and the active schema’s name limit. If preferences become unavailable before submission, retain the draft and offer in-dialog recovery rather than closing without an accepted move.

src/bundled/channels/SidebarGroupIcon.module.css
Give group icons a stable, bounded slot and loading placeholder without overlapping labels.

src/bundled/channels/SidebarGroupIcon.test.tsx
Cover custom media resolution, failed or missing icons, literal icons, and source/session changes.

src/bundled/channels/SidebarGroupIcon.tsx
Resolve legacy custom icons through session-owned media and use a stable placeholder rather than leaking raw shortcodes.

src/bundled/channels/SidebarSectionIcon.tsx
Remove the superseded icon component; its caller uses SidebarGroupIcon.

src/bundled/channels/useChannelRowMenu.ts
Pass rendered placement to the action composer while preserving main’s stale-menu retirement and item-count eligibility.

src/bundled/channels/useSidebarPreferences.ts
Expose session-owned mutation, writability, and retry commands to the sidebar view.

src/features/channel-templates/capability.test.ts
Cover cancellation before preparation/enqueue and retained durable delivery after enqueue.

src/features/channel-templates/capability.ts
Accept an optional operation signal during save preparation while leaving enqueued delivery owned by the existing outbox/session.

src/features/relay/session.ts
Compose active-store routing and refresh with the existing catalog and preference owners. Share the existing one-shot account-read recovery with catalog reads after roster invalidation, excluding caller cancellation, cache clear, teardown, and channel-content reads.

src/features/relay/sidebar-moves-store.test.ts
Verify immediate placement, serialized records, protection against older failures, retained retry, and stable create identities. Cover both Move/Mute and Move/Sort save orders, failed operations, cancellation/cache-clear/disposal, pending overlays and a field-only confirmation completing during failed preference recovery.

src/features/relay/sidebar-personal-groups.test.ts
Exercise schema-preserving personal-store saves, source changes, template-default preservation, startup cancellation recovery, and cancellation/cache-clear boundaries.

src/features/relay/sidebar-personal-groups.ts
Select the explicitly activated group store and reuse the existing recipe writer for personal assignments. Reject stale-source intents rather than migrating or writing hidden legacy groups.

src/features/relay/sidebar-preferences-store.test.ts
Cover retained confirmed state, mutation/refresh races, session isolation, teardown, explicit star changes, and write gating throughout failed reads and retries.

src/features/relay/sidebar-preferences-store.ts
Own optimistic placement and serialized persistence in the relay session. Keep one confirmed preference state beneath pending Move and Sort overlays; each confirmation updates only its fields and cannot erase a failed full-read retry. Preserve main’s refresh-during-sort behavior and confirmed-only mute policy; fence deferred catalog refresh across clear/disposal.

src/features/relay/sidebar-preferences.test.ts
Keep exact legacy decoder/security assertions while modeling the separate personal-catalog lookup used for active-store selection.

src/features/relay/sidebar-preferences.ts
Define narrow assignment/star mutation contracts and an in-memory active-source marker without changing the persisted legacy schema.

src/features/relay/sidebar-sorting-store.test.ts
Adapt the constructor call to the composed owner without changing main’s sorting assertions.

src/features/relay/transport.ts
Expose capability-gated broker mutation calls and validate returned preference projections.

src/features/relay/work-sessions.ts
Require the writable outbox for generic saved-record delivery confirmation rather than channel-creation authority. Preserve main’s channel-addition capability, cancellation, and retry checks.

src/features/relay/work-sessions.test.ts
Cover saved-record confirmation when channel creation is unavailable.

tests/browser/fixture.mjs
Add opt-in icon data and grouping publication retention to main’s signed personal/sorting fixtures. Compose sort/group/star/mute/read handling and exact injected-failure accounting without duplicate handlers; retain distinct personal-group IDs and keep default fixtures small.

tests/browser/navigation-group-icons.spec.mjs
Verify actual browser media loading, non-overlapping icon geometry, missing-icon presentation, and single-line dialog layout.

tests/browser/navigation-groups.spec.mjs
Exercise real menu/dialog keyboard behavior, optimistic move/create/star, partial-failure recovery, encrypted persistence and reload, both schema paths, and independent personal-group presentation on legacy failure. Preserve main’s persistent-sidebar navigation/retention journey; add off-page Create/Move coverage with Sessions disabled. Explicitly dismiss the independently eligible New session menu before recovery, and control the personal record clock instead of relying on elapsed interaction time. Extend the existing menu/reload journey with a held Sort followed by Move, checking pending placement and persistence of both after reload; no additional browser case.

docs/channels.md
Describe persistent-sidebar ownership, independently eligible actions, one confirmed snapshot under Move/Sort overlays, recoverable full-read errors and confirmed-only mute policy.

tests/browser/channel-lifecycle.spec.mjs
Preserve existing lifecycle behavior assertions while expecting Move alongside New session and attention actions, without adding a lifecycle separator before authority resolves.

tests/browser/navigation-mute-read.spec.mjs
Preserve main’s mute/read journey, including Sessions toggling, while expecting the independently available Move action.

Reproduction Steps

  1. Open Messages in a supported browser-broker host with a saved group and at least two stream channels. Right-click a channel, or focus its row and press Shift+F10, then open Move channel.
  2. Select a saved group. The row moves immediately, the menu closes, keyboard focus follows the channel, and no success toast interrupts navigation. Reload after confirmation and verify the placement remains.
  3. Select Starred. Verify the channel appears only in Starred. Select Starred again or Remove from Starred and verify it returns to Channels, not its previous group.
  4. Choose Create new…. Cancel once and check focus restoration; reopen, enter a name, and choose Create and move. Verify the new group and placement survive reload.
  5. Repeat with personal groups activated. Verify their 120-character/icon-free schema and template defaults are retained, with no new legacy group write.
  6. Use the checked-in browser journeys below to hold/fail assignment, star, or legacy-read requests. Verify immediate optimistic state, visible rollback/retry after write failure, idempotent create retry, and healthy personal groups remaining visible while unsafe moves are disabled.
  7. Check the shared menu: New session precedes Move channel when both are available; mute/read and lifecycle actions remain independent siblings. Every row retains main’s shared styling. Switch Messages → Projects → Messages and verify sidebar DOM, group placement and scroll are retained.
  8. Disable Sessions in Settings → Plugins. From Projects, Create new and move a channel; confirm that the saved placement survives reload without navigating away from Projects.
  9. Choose Recent from a section’s More actions → Sort, then move a channel. Verify both the placement and section sort survive confirmation and reload; injected failures roll back only the failed operation.

Validation

Current review follow-up at d75d0d31

  • a7e0ba04: replace the retained error after a stale-source/non-writable retry rejection; preserve the write guard and disable Retry with recovery instructions when preferences are unavailable. d75d0d31 corrects the test fixture’s exact-optional-property typing.
  • 3cce8844: Dismiss expands the channel’s current placement and restores focus, falling back to a visible row/sidebar control if it disappeared.
  • Mandatory hooks at the pushed head: TypeScript, design types/guards and 3,714 Vitest tests / 340 files pass. Unit wall time 35.62s; push hooks 39.67s on local macOS. First push was blocked by the new fixture’s optional-property type error; corrected before publication, with no hook bypass.
  • Notice regression evidence: all three new mounted-sidebar cases fail against the prior implementation: both personal-group source transitions retain the old error, and unavailable Retry remains enabled. They pass at the pushed head through the real preference store and notice UI; rejected retries perform no additional writes.
  • Browser regression evidence: the new keyboard case fails in both Chromium and WebKit without the focus fix. With it, all 18/18 navigation-groups.spec.mjs journeys pass (50.3s), including collapsed-placement dismissal and upstream roster omission → surviving-row focus. Run at a7e0ba04 plus the changes committed unchanged in 3cce8844; later d75d0d31 changes only the mounted-test fixture, not production/browser code.
  • Browser cases: one new case per engine; none removed. Native keyboard activation, disclosure visibility and real row focus after roster refresh justify browser coverage. Source-switch/error matrices remain in mounted Vitest coverage. No retries, sleeps, raised timeouts, or weakened assertions were added.
  • Four-file review delta from d4722510: production +37/−11, tests +157/−2. No persistence format or menu redesign.
  • Remote head matches; hosted DCO Check passes. Current-head hosted integration CI is not established while the PR conflicts. Main’s 80511fa8 introduces a 200 ms hold but retains the independent second.duration < first.duration assertion previously removed here; integration is paused rather than silently discarding that mainline assertion.
  • No approval, review dismissal, merge, PR readiness change, native/live-relay acceptance, or independent-review claim.
# Mandatory push hooks: typecheck, complete Vitest package, design guards
# Browser behavior beyond hooks:
bin/pnpm test:browser navigation-groups.spec.mjs \
  --project chromium --project webkit --no-deps
Historical validation — superseded snapshots, not current merge status

Historical rebase at 0b4e99484be36e5bb766ef2a3fe621439829fca5

  • Base: 30c3589ba57ce926ac19c5526d8b87cde35d6e48. Preserves main’s persistent sidebar, startup/activity/scroll settlement, New session, sorting, mute/read/lifecycle, shared styling and user-status integration. Unmerged sibling follow-ups are not silently imported.
  • Mandatory push hooks passed on this clean head: 340 files / 3,708 unit tests, TypeScript, design-system types and guards. Unit wall time 138.95s; summed test execution 151.28s; hooks 142.79s on local macOS with BUZZ_TEST_WORKERS=2. No hook bypass. An earlier full-package run during conflict integration passed 3,671 tests on 75d681e6 plus integration edits; that is historical, not the final-head result.
  • 112/112 Chromium/WebKit journeys passed on this exact clean head (3.6m): grouping, group icons, sorting, mute/read, New session menu, navigation, sidebar retention, scroll intent, unread, lifecycle, presence and user statuses. Includes Sort pending → optimistic Move → both confirmed → reload through the real frontend and broker; both grouping schemas, rollback/retry, draft recovery and independent menu eligibility remain covered.
  • 4/4 isolated opening measurements passed on this same head (14.6s), serially across Chromium/WebKit: bounded cold opening with held DM labels, warm switching and the 300-author thread contract. These are local acceptance checks, not a comparable performance benchmark against the previous branch.
  • New deterministic unit coverage tests Move→Sort and Sort→Move success/failure, pending overlays surviving unrelated confirmation, queued cancellation, cache clear/disposal (including a deferred catalog refresh), and failed-read Retry surviving Sort. Existing sorting refresh/supersession and Move/Mute regressions remain intact. The first merged implementation retained all 3,671 unit assertions after preserving main’s refresh-during-sort contract; no main assertion was rewritten to bless a resolution.
  • Self-review compared both parents and the replay range. The middle three feature commits replay unchanged; startup hook/tests and main’s unread fixture synchronization drop out because main supplies them. No independent review was requested for this pass, and historical review scores are not current clearance.
  • Remote head matches local. GitHub reports MERGEABLE, draft, and DCO Check passed. At the single post-push snapshot, hosted JavaScript/browser checks were in progress and Rust/tool integration queued; Windows native validation skipped. Required gates remain CI required, DCO and approving/code-owner review. No CI-green or merge-readiness claim.
  • Historical blocker (fixed in 752aaacc): the assignment/star request body collector in dev/relay-broker.mjs still uses raw += part, decoding incoming chunks separately. The earlier reproduced UTF-8 group-name corruption is not repaired by this rebase. Collect bytes, decode once, and add a broker chunk-boundary regression before merge.
  • No browser cases added or removed in this rebase. One existing grouping journey gained the combined Sort/Move integration boundary; failure/order matrices live in unit tests. The new combined assertion passed on its first run; no fail-before/pass-after claim. No retries, weaker assertions, timeout increases or alternate UI harness.
bin/pnpm test:browser --project chromium --project webkit --no-deps \
  tests/browser/navigation-groups.spec.mjs \
  tests/browser/navigation-sorting.spec.mjs \
  tests/browser/navigation-group-icons.spec.mjs \
  tests/browser/navigation-mute-read.spec.mjs \
  tests/browser/channel-lifecycle.spec.mjs \
  tests/browser/navigation.spec.mjs \
  tests/browser/navigation-sidebar.spec.mjs \
  tests/browser/navigation-session-menu.spec.mjs \
  tests/browser/navigation-scroll-intent.spec.mjs \
  tests/browser/sidebar-unread.spec.mjs \
  tests/browser/user-status.spec.mjs tests/browser/presence.spec.mjs

bin/pnpm test:browser tests/browser/channel-opening.spec.mjs \
  --project '*-measurements' --no-deps --workers=1

Historical folder icon at 730c4b6

Added Phosphor FolderSimpleIcon in the existing decorative 14px leading slot for Move channel, retaining its accessible name, chevron and behavior. The existing icon journey gained geometry/accessibility assertions; no icon-only browser case was added. Its 16/16 Chromium/WebKit checks and then-current 2,697-test push gate passed. Later integrations supersede that head’s status; the gallery below is pinned to d4722510.

Historical parent-menu alignment at 169616f9408788bcd592080397fac5c2785e2da0

  • At this historical head, #209 still needed to land first. Its CSS, token guidance and geometry regression matched 88b1bc9. Superseded by the current integration: feat(channels): move session creation into the context menu #209 has landed and its parent-menu behavior is now inherited from main.
  • At that historical head, startup improvements and tests remained in the feature because saved-group arrival is part of initial placement. Now inherited unchanged from main: their removal from this PR’s diff does not remove the experience.
  • Historical blocker (fixed in 752aaacc): the new broker body collector decodes HTTP chunks separately and can corrupt a multibyte group name (Launch 🚀 reproduced as Launch ���� with HTTP 200). This styling-only update does not fix it. Collect bytes and decode once, with a broker regression, before merge.
  • 50/50 design-system browser checks and 16/16 grouping/icon browser checks passed in Chromium and WebKit on the exact product tree committed here; 84 design-system unit tests, design guards/types, frontend and design builds passed. Browser runs were on d73da62 plus these four file edits; commit hooks made no changes.
  • Mandatory push hooks at 169616f: 263 files / 2,697 unit tests, TypeScript and design types/guards passed. DCO is green; hosted CI was queued/running at publication. No polling or CI-green claim.
  • Four-file delta: +41/−33. It extends existing corner/focus assertions rather than adding a new browser journey. Grouping, startup and icon implementation files are unchanged.
  • Screenshots at that stage were refreshed at 8f109a6; the gallery below now supersedes them with d4722510 captures.

Historical review follow-up at d73da62a42da0fd5cc4e0816ad0ecc03b55f8939

  • Fixed a pre-submission admission race: the create dialog could outlive its writable preference snapshot and close without recording a retryable move. The live store gate is now checked before closing; rejected drafts retain name/ID and expose Retry preferences inside the modal. Accepted persistence behavior is unchanged.
  • The new browser regression failed in Chromium and WebKit before the fix, then passed with the draft retained through another failed recovery, successful recovery, create, focus restoration, and reload.
  • Full affected grouping and icon files: 16/16 Chromium/WebKit checks passed at the clean new head (50.4s). This adds one browser case per engine, justified by real modal lifetime, focus, and frontend/store wiring. No cases removed or retries added.
  • Mandatory pre-push hooks: 263 files / 2,697 unit tests passed, TypeScript and design types/guards passed; hooks exited cleanly. The new colocated component test covers retained identity and duplicate submissions. Unit duration 23.82s; hook duration 27.29s (local measurements, not a comparable CI benchmark).
  • Production frontend build/typecheck passed on the same product changes before commit. Remote feature head matches the new commit; current main remains 21ea351.
  • Independent adversarial review: 9/10 at d73da62, with the admission-race blocker resolved. A subsequent scope audit found the separate UTF-8 blocker documented above; this historical verdict is not current merge clearance. This is an agent review reported in the originating work thread, not a GitHub approval. Hosted checks remain pending; the PR stays draft.

Integrated baseline at 2232d43

Validated on clean head 2232d43bb61d18d68d309b5e923f695ab5007b34:

  • Mandatory pre-push hooks: TypeScript, design-system typecheck/guards, 262 Vitest files / 2,696 tests passed; clean exit. Unit execution: 91.01 seconds; full push hooks: 94.64 seconds on local macOS.
  • 56/56 Chromium + WebKit browser checks passed across grouping, icons, sidebar unread, sidebar navigation/retention, and main’s Messages-first launch (1.5 minutes).
  • 4/4 opening measurements passed across both engines: cold opening with held DM labels, warm switching without another head read, and bounded traversal for a 300-author thread (14.3 seconds).
  • Additional Chromium actual-app screenshot journey passed, including confirmed create-and-move and reload.
  • Supplemental actual-app menu geometry check: 2/2 Chromium/WebKit cases passed at the same clean head; outer-facing row corners measure 19px inside a 24px popup with 4px padding and a 1px border, while interior corners remain 10px.
  • git diff --check origin/main...HEAD passed; remote branch and local head match.

Browser commands (after the standard browser build/setup):

bin/pnpm exec playwright test --config tests/browser/playwright.config.mjs \
  tests/browser/navigation-groups.spec.mjs \
  tests/browser/navigation-group-icons.spec.mjs \
  tests/browser/sidebar-unread.spec.mjs \
  tests/browser/navigation-sidebar.spec.mjs \
  tests/browser/launch-home.spec.mjs --no-deps

bin/pnpm exec playwright test --config tests/browser/playwright.config.mjs \
  tests/browser/channel-opening.spec.mjs \
  --project '*-measurements' --no-deps --workers=1

Browser coverage and fail-then-pass evidence

  • The initial feature adds six cases; the retained-create-draft fix adds one; this main integration adds one off-page/Sessions-disabled composition case. Eight feature browser cases at that integration snapshot; the current recovery follow-up adds one, each run in both engines; none removed. Existing sidebar-retention and unread cases remain, adapted to main’s persistent owner rather than restoring an obsolete unmounted-sidebar assertion.
  • Browser-only justification: real Base UI menu/dialog focus and transitions; row relocation and duplicate-row absence; actual image loading/geometry; page remount/reload; and frontend → production broker → signed encrypted publication wiring. Lower-level tests carry validation, preservation, sequencing, source-switch, and cancellation matrices.
  • The additional legacy-read failure assertion first failed in both engines; its checked-in cold and retained-state journey now passes while proving writes remain disabled until recovery.
  • Integrated head 574ba24 initially passed 52/56 browser checks but failed four Chromium grouping cases after roster discovery cancelled the catalog read. 2232d43 shares the existing narrowly guarded recovery and adds session regressions; all 56 then passed. No browser retries or weakened assertions were used to mask it.
  • Fixture changes are opt-in scenario support, not a test-runner performance change. Timings above are local observations, not hosted CI measurements or a comparable before/after setup benchmark.

Remaining gaps

  • These are browser integration journeys using the production frontend and production broker with isolated, signed upstream fixtures—not native-host or live-production-relay E2E certification.
  • Full native builds/tests, real multi-device production convergence, and the entire unrelated browser suite were not run for this handoff.
  • Historical blocker/status notes above describe their named commits, not the current head. The UTF-8 corruption was repaired separately in 752aaacc; the existing PR is no longer draft. Screenshot capture does not establish hosted-CI success, reviewer approval, live-relay/native acceptance, or merge readiness.

Screenshots / Demos

Captured September 25, 2026 at d47225108363093987d31d0cc5ed5c9966d9f328 — 27 images. These replace the old 8f109a6 gallery. Actual production-built app and production broker in Chromium, using ephemeral fixture identities and a modeled, signed upstream relay. Dark appearance uses the app’s real palette/teal shell; no fabricated UI, component showcase, injected CSS, or live user data.

What belongs to this PR: Move channel, saved destinations/Create new, exclusive Starred placement, and their safe persistence/composition. Already merged siblings shown for context: New session, Mute/Unmute, Mark as Read/Unread, Archive/Delete/Leave/DM Hide, and section Sort. Starred is a destination inside Move—not a separate root-menu action. Sort belongs to the section menu—not the channel row.

Example Independent row actions shown Lifecycle actions shown
Stream, sole owner New session · Move channel · attention Archive · Delete; no Leave
Stream, member New session · Move channel · attention Leave; no Archive/Delete
Stream, admin New session · Move channel · attention Archive · Leave; no Delete
Stream, co-owner New session · Move channel · attention Archive · Delete · Leave
DM Attention; no New session/Move Hide conversation
Forum, sole owner New session · attention; no Move Archive · Delete
Sessions disabled, on Projects Move channel · attention; no New session Eligible lifecycle actions remain
Permission lookup unavailable Other independently eligible actions remain Channel actions unavailable · Retry channel permissions

“Attention” means Mute/Unmute and Mark as Read/Unread, depending on state. These are fixture-specific eligible menus, not a grant of authority for every channel or host.

Integrated channel menu

01 · Sole-owner stream: the complete merged order—New session, Move channel, attention, then lifecycle. Leave is correctly absent for the sole owner.

Owner stream menu with New session, Move channel, Mute, Mark as Unread, Archive channel and Delete channel

Grouping, Starred, Create and saved placement — 7 images

02 · Ungrouped stream. Move offers Starred, Work and Create new; there is no removal action before assignment.

Ungrouped stream

08 · Assigned to Work. Work is checked and Remove from Work is available; the merged parent-menu siblings remain visible.

Assigned to Work

09 · Assigned to Starred. Starred is checked and Remove from Starred is available. The selected channel has one rendered placement.

Assigned to Starred

10 · After removing Starred. Launch planning returns to Channels, not its previous Work group. Alpha is a separate fixture channel that remains starred.

After removing Starred

11 · Empty Create dialog. Create and move is disabled until a name is supplied.

Empty Create dialog

12 · Named Create dialog. The real input renders Launch 🚀 · Café · 日本語 and enables Create and move.

Named Create dialog

13 · Confirmed state after reload. Launch planning remains in the new Unicode-named group and appears once; Alpha remains exclusively Starred. The narrow sidebar truncates the long group label normally. This is rendering/reload evidence, not the separate HTTP-chunk regression.

Confirmed state after reload

Merged attention, session destination and section Sort — 3 images

03 · Attention state variants. After muting and marking the channel unread, the same menu offers Unmute and Mark as Read instead of Mute and Mark as Unread.

Attention state variants

07 · New session destination. The inherited action opens the actual New session page. This isolated connection cannot send messages, as the visible composer notice states; no agent session execution is claimed.

New session destination

14 · Section-level Sort. Work → More actions → Sort offers Recent and A–Z, with A–Z selected. This inherited section menu is separate from Move channel.

Section-level Sort

Lifecycle permission variants and confirmations — 7 images

15 · Member. Leave is present; Archive and Delete are absent.

Member

17 · Admin. Archive and Leave are present; Delete is absent.

Admin

18 · Owner with another owner. Archive, Delete and Leave are all present.

Owner with another owner

04 · Archive confirmation. The dialog explains that the channel is archived for everyone, messages are retained, and unarchive requires another supported client. Cancelled after capture.

Archive confirmation

05 · Delete before name confirmation. The destructive action is disabled with an empty confirmation input.

Delete before name confirmation

06 · Delete after exact name match. Entering Launch planning enables Delete channel. Cancelled; no deletion was published.

Delete after exact name match

16 · Leave confirmation. The dialog describes sidebar removal and possible invitation requirements for rejoining a private channel. Cancelled after capture.

Leave confirmation

DM and forum type boundaries — 3 images

19 · DM menu. Mute, Mark as Unread and Hide conversation; neither Move nor New session is offered.

DM menu

20 · DM Hide confirmation. The dialog explains that hiding affects this viewer’s sidebar, retaining messages and membership. Cancelled after capture.

DM Hide confirmation

21 · Forum menu. The sole-owner forum retains New session, attention, Archive and Delete, but excludes Move. This does not extend stream-only grouping to forums.

Forum menu

Recovery, personal groups and Sessions-disabled composition — 6 images

22 · Failed Move and retained retry. A deliberately injected assignment-endpoint 502 rolls Beta back to Work. The real UI warns about possible partial saves and offers Retry move and Dismiss; this is an intentional fixture failure, not a live incident.

Failed Move and retained retry

23 · Retry confirmed, then reloaded. After removing the injected failure and retrying, Beta remains in Channels after reload.

Retry confirmed, then reloaded

24 · Activated personal-group schema. Personal work is selected, with Remove from Personal work and Create new. The active store is preserved, not migrated.

Activated personal-group schema

25 · Personal-group Create dialog. The same dialog has no icon field. The capture journey also checked the input’s existing maxlength=120; the screenshot alone is not evidence of that DOM attribute.

Personal-group Create dialog

26 · Fail-closed lifecycle lookup. Beta is an intentional non-UUID fixture channel, so lifecycle permission validation fails. Channel actions unavailable and Retry channel permissions replace lifecycle actions; independently eligible Move/attention/session actions remain. This is not a successful authorization example.

Fail-closed lifecycle lookup

27 · Grouping remains independent of Sessions. Captured from Projects after disabling Sessions. New session is absent while Move/Starred/Create and eligible attention/lifecycle actions remain; the crop focuses on the sidebar menus.

Grouping remains independent of Sessions

Capture evidence and limits: 11/11 isolated Chromium capture journeys passed in 25.9s, one worker, no retries. No checked-in browser cases or product files were changed for this refresh. Archive/Delete/Leave/Hide dialogs were cancelled; there were no live lifecycle operations. Grouping writes and recovery were exercised only against the modeled upstream. These images do not certify native hosts, live-relay lifecycle completion, cross-device convergence, or complete error/host combinations. Existing whole-record last-write-wins limitations are unchanged. The historical multi-engine validation above is attributed to its own commits, not relabeled as a new run.


Implementation and this description prepared by Carl (AI agent) under the authorizing maintainer’s direction.

@tellaho
tellaho force-pushed the tho/sidebar-grouping-focused branch 2 times, most recently from 5efc4af to 0b4e994 Compare September 25, 2026 02:28
@tellaho
tellaho marked this pull request as ready for review September 25, 2026 04:53
@tellaho
tellaho requested review from a team, comp615 and wesbillman as code owners September 25, 2026 04:53

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Changes requested: one P2 request-decoding defect, detailed inline. Merge criterion: preserve valid Unicode section names across arbitrary HTTP body chunks and add a broker-boundary regression that verifies the persisted and returned name.

Source-only whole-feature review of 7e0a05e2e6bef9d2f49aeb5f9e9b5aec3c7846a3 against 30c3589ba57ce926ac19c5526d8b87cde35d6e48. Existing CI run 36095172384 passed on this head’s integration merge with main df7b7e7f: 3,789 unit tests and 674 Chromium/WebKit journeys, without hosted retries. No reviewer execution or CI rerun. Native/package, live-relay and real restart persistence remain unverified.

The AgentModelPicker selector change retains the pending-state and exact-selection assertions; it is not a blocker. Placeholder/no-shortcode icon presentation follows the originating product discussion, not an unintended fallback regression. Documented cross-record partial saves and whole-record cross-device races remain accepted limitations.

Comment thread dev/relay-broker.mjs Outdated
@tellaho

tellaho commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the UTF-8 group-name corruption in 752aaaccc878eadfdbc92d741342cde41e70a622.

The assignment/Star collector now enforces the existing 2,048-byte limit on incoming bytes, joins them, and decodes once. The broker regression forces one-byte chunks and checks Launch 🚀 · Café · 日本語 exactly in both the HTTP response and decrypted published channel-sections record. Both routes also reject oversized multibyte bodies before upstream work.

Validation: the new regression failed against 7e0a05e2 in both returned and persisted names; at the pushed fix, mandatory hooks passed 3,711 tests / 340 files, TypeScript, and design-system types/guards. Hosted DCO passed. Fresh CI is running; browser/native/live-relay validation was not rerun locally. Two files changed; production delta +6/−4. This fixes the reported defect, not a claim of merge approval.

— Carl, AI agent, posting through Taylor’s account under standing 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.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Source review clear; required CI remains red. The prior Unicode blocker is fixed at 752aaaccc878eadfdbc92d741342cde41e70a622. The shared sidebar assignment/star collector now bounds raw bytes and decodes once. Its new HTTP-boundary regressions force one-byte chunks, verify the exact returned and encrypted/persisted name, and preserve both routes’ byte-limit rejection. No new source blocker or weakened existing assertion found in the two-file change since 7e0a05e2 (base 30c3589ba57ce926ac19c5526d8b87cde35d6e48).

Exact-head CI: all three new regressions and 674 browser journeys passed; JavaScript finished 3,791/3,792 because broker.integration.test.ts:128 failed its first-versus-second publish timing comparison. That test uses the unchanged /publish collector, not this sidebar collector. Its failure cause remains unestablished; this is not a CI-green or merge-ready verdict. Required checks still need to pass.

Source-only review, no execution or reruns. Native/package, live-relay and real-restart persistence remain unverified. This is a follow-up comment, not approval.

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Focused re-review clear at d47225108363093987d31d0cc5ed5c9966d9f328; existing required CI is now green. No actionable blocker found in the one-test change since 752aaaccc878eadfdbc92d741342cde41e70a622.

  • The replacement assertions retain the real broker publication gate, pending outbox, successful delivery of both messages, attachment roundtrip and timing-span continuity. Removing the independent first-versus-second wall-clock comparison does not remove controlled-clock latency coverage. Production code is unchanged in this delta; the previously verified Unicode repair remains intact.
  • CI run 36155055909, attempt 1, passed the repaired broker test, all 3,884 JavaScript tests, 710 Chromium/WebKit journeys, seven measurements and Rust checks. Its tested merge is b3e129815e8e818ff55c4fb9b4276ecd2b70a03f, combining this head with main bebcd66e; merge tree 37cba00a0c0a2f0449dbfd8345972845cd56ecd5 differs from the head tree. This is integration CI evidence, not a head-only run.
  • Remaining gates: GitHub still reports CHANGES_REQUESTED/blocked; this comment is not approval or dismissal of the historical review. Newer main 0d703a60 has not been CI-tested with this head. Windows was skipped; native, live-relay and real-restart persistence remain unvalidated here. Source-only review plus existing hosted evidence, with no execution or CI rerun. I contributed earlier fixes, so this is not independent/code-owner approval.

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Re-review complete at d47225108363093987d31d0cc5ed5c9966d9f328 against 30c3589ba57ce926ac19c5526d8b87cde35d6e48: no blocking defects found. Two non-blocking P3 recovery issues are recorded inline.

  • The earlier Unicode-corruption blocker is fixed. Broker tests now split multibyte names into single-byte chunks and check both the response and decrypted publication. The timing-test repair preserves the real publication gate and delivery assertions; controlled-clock attribution remains covered separately. The UI, shared persistence and broker review lanes have all returned and been integrated.
  • Validation: source-only review; no local builds/tests or CI rerun. CI run 36155055909, attempt 1, is green: 3,884 JavaScript tests, 710 Chromium/WebKit journeys, seven measurements and Rust/tool checks. CI tested merge b3e129815e8e818ff55c4fb9b4276ecd2b70a03f with main bebcd66e, not the head alone or the currently observed main 03366998. Windows was skipped; packaged-native, live-relay and actual restart persistence remain unverified here.
  • GitHub still reports the historical CHANGES_REQUESTED verdict. This comment neither approves nor dismisses it; independent/code-owner review remains a merge gate. I contributed earlier fixes. The stale PR description should also be refreshed, but that is not a code blocker.

Comment thread src/features/relay/sidebar-preferences-store.ts
Comment thread src/features/channel-navigation/ChannelSidebar.tsx Outdated
@tellaho

tellaho commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@wesbillman Both non-blocking recovery requests are fixed and individually answered/resolved at d75d0d3. The earlier Unicode blocker also has a direct resolution reply; no source blocker from those requests remains.

Description refresh: replaced the stale opening status, added current validation and per-request commits, collapsed historical validation, marked the old Unicode blocker as fixed, and preserved all 27 screenshots with their actual d472251 provenance. The images are not mislabeled as captures of the new recovery behavior.

Validation: current-head mandatory hooks pass (3,714 tests / 340 files, TypeScript, design types/guards); hosted DCO passes. All 18 grouping Chromium/WebKit journeys pass on the unchanged production/browser tree subsequently committed in 3cce884. New notice and keyboard regressions have fail-before/pass-after evidence.

Merge conflict / CI: still blocked, not complete. Main 80511fa overlaps the broker timing-test repair, adding a 200 ms hold while retaining second.duration < first.duration. Integration is paused for Taylor’s decision on retaining the observed-hold assertion without reinstating that independent wall-clock comparison. No current-head hosted integration-CI pass, approval, historical review dismissal, or merge is claimed. Native/live-relay acceptance remains unverified.

— Carl, AI agent, posting through Taylor’s account at Taylor’s request.

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

No blocking code findings in this focused follow-up. Retry now explains rejected attempts; the previously reported collapsed-group and missing-row Dismiss cases are addressed. One narrow, non-blocking P3 focus edge remains inline.

Reviewed head d75d0d31148be22053003500e61ce98128eb389a against base/merge-base 30c3589ba57ce926ac19c5526d8b87cde35d6e48, concentrating on d4722510..d75d0d31. I contributed earlier fixes; an independent reviewer checked dismissal and the shared focus effect, and I verified the finding and retry/store wiring. Accepted persistence limitations were not reopened.

Validation: source review only; neither reviewer ran tests. The PR reports 3,714 passing Vitest tests at the pushed head and 18/18 Chromium/WebKit grouping journeys at a7e0ba04 plus the unchanged edits committed as 3cce8844; d75d0d31 changes only fixture typing. Those are author-reported results, not new review runs.

Separate merge-readiness gaps: GitHub still reports CONFLICTING / DIRTY. Exact-head checks are Semgrep, zizmor and DCO only, with no hosted Actions run or current-head integration pass. Resolve the main integration conflict and validate the resulting head before treating it as merge-ready. This COMMENT is not approval and does not clear the historical changes-requested review.

Comment on lines +662 to +664
sidebar.list.current?.querySelector<HTMLButtonElement>(
`[data-channel-id="${CSS.escape(rowFocus)}"]`,
)
?.focus({ preventScroll: true });
) ??

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.

[P3, non-blocking] Let a hidden target use the visible-row fallback

This first lookup accepts an existing but hidden row, bypassing the visible-row fallback. A source-confirmed path remains after the Dismiss fix:

  1. Retain a failed move for an unstarred channel assigned to group A.
  2. Refresh the independent personal catalog with that channel assigned to B, while the full preferences read fails. The catalog subscription requests a full refresh (session.ts:1034–1041), but a legacy-read failure retains the old store data. The sidebar deliberately renders the personal projection when unwritable (ChannelSidebar.tsx:418–425).
  3. Collapse B, then keyboard-activate the move notice’s Dismiss button.

focusChannelPlacement reads the stale store and expands A, not displayed B. This lookup still finds the channel inside collapsed B; .focus() cannot focus it, and removing Dismiss loses keyboard focus instead of invoking the fallback.

Check visibility on the exact target before accepting it, as the nearby lifecycle focus handler already does, and add this case to the browser regression. Alternatively resolve the actual rendered placement, while preserving the synchronous optimistic-snapshot behavior of Move. This edge is traced from source, not browser-reproduced; the new browser case covers healthy preferences only.

@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, automated source reviewer, commenting via Wes’s GitHub account.

No new actionable findings in this focused follow-up. Reviewed head 06b29f21d3e559dcfaff32632c6182351d186c70 against base/merge-base 30c3589ba57ce926ac19c5526d8b87cde35d6e48, concentrating on the delta since the previously reviewed d75d0d31148be22053003500e61ce98128eb389a. This is not a fresh exhaustive audit of the entire sidebar feature.

  • The sole new change restores src/features/relay/broker.integration.test.ts byte-for-byte to the base version (blob 2171434a8404a6666fcc784e2dafdcbbba5b421c). Sidebar production code and its regression tests are unchanged since the previous review.
  • The restored comparison between two real-clock publish durations remains timing-sensitive: holding the first send does not guarantee it takes longer than the second. It is inherited base behavior, not a new sidebar regression; I am not reopening the unrelated timing repair in this feature. Controlled-clock attribution coverage remains in traffic.integration.test.ts:190–239; that does not prove the IPC test cannot flake.
  • The existing non-blocking P3 hidden-row focus comment is unchanged, not resolved or duplicated by this review. Accepted persistence/product limitations are also unchanged.

Validation limits: source analysis only, using pinned Git objects with byte-verified extracts; no dirty source inputs and git diff --check passed. No tests, builds, app launches or CI reruns. The one-time check snapshot at 18:19 UTC shows run 36166318943 associated with this head: JavaScript and CI required failed; WebKit shard 1/2 was cancelled; the other three browser shards, measurements and Rust/tool integration passed; Windows was skipped. JavaScript job logs were unavailable to this review, so failure causation and the tested merge tree are not established. Exact-head runtime reliability, current-main integration and packaged/live-relay behavior remain unverified. This COMMENT is neither approval nor a merge-readiness verdict and does not alter earlier reviews.

tellaho and others added 10 commits September 25, 2026 13:29
Preserve active personal-group schema, exclusive placement, optimistic rollback and retry, legacy icons, and stable startup presentation. Keep healthy personal groups visible when legacy reads fail without enabling unsafe writes.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Share the existing one-shot account preference recovery with personal-group reads. Keep caller cancellation, cache clear, teardown and channel-content reads outside recovery.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Check live move admission before closing Create new. Preserve the name and group identity on rejection and offer in-dialog preference retry; accepted writes keep their quiet optimistic flow.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Use the shared decorative 14px icon slot and retain the submenu chevron. Extend the existing browser geometry check without adding a journey.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
…ions

Keep preference-read failure and retry visible after a mute-only confirmation, including a stale concurrent recovery read. Retain mainline action eligibility, empty DMs entry, deterministic personal saves and off-page grouping coverage after the rebase.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Keep mainline refresh behavior while composing Move and Sort over confirmed preferences. Exercise both save orders, rollback, cancellation, stale recovery and the built-app save/reload boundary.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Collect the bounded assignment/star request as bytes before decoding UTF-8. Exercise one-byte broker chunks and verify both the confirmed response and decrypted published group name, with oversized byte-budget rejection on both routes.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Publish stale-source and unavailable retry errors in the retained move notice. Disable retry while preferences cannot be written and explain the recovery action. Cover both group-source transitions and read recovery through the real sidebar and preference store.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Expand the current placement and hand focus back to the channel row after dismissing a failed move. Fall back to a visible row or sidebar control if the original channel disappeared. Add a real Chromium/WebKit keyboard journey covering a collapsed group and refreshed roster omission.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Match exact optional property semantics in the retry-notice fixture.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho force-pushed the tho/sidebar-grouping-focused branch from 3c0d62e to 4a6fc5e Compare September 25, 2026 20:32
@tellaho
tellaho merged commit c379c33 into main Sep 25, 2026
14 checks passed

@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 GitHub account.

No new actionable findings in this integration follow-up. Reviewed head 4a6fc5ed0d3000c272a5aa2790cec11230a7abc3 against target base 48c9a11da2e732af96b620640d02abb3aae0cf5d (merge base 64be4c2adf21e9920d4a7666354ceab1d784dd44), focusing on changes since the previously reviewed 06b29f21d3e559dcfaff32632c6182351d186c70. This is not a fresh exhaustive audit of the entire 41-file feature.

  • The Create-new handoff now crosses the memoized row boundary: ChannelSidebarItem.tsx:210–214 forwards close completion, and ChannelSidebar.tsx:658–675,1074–1076 opens the pending dialog while suppressing the competing row-focus return. The shared menu wrapper and existing Create/cancel/focus browser journey were inspected as source, not executed.
  • The relocated work-session constructor retains the incoming verified discovery reader (session.ts:904–928), including the distinct discovery contract in work-sessions.ts. The preference store, personal-group adapter, Create dialog, and grouping browser journey remain byte-identical to the previously reviewed head. The unrelated model-picker and broker integration tests now match the target base.
  • The existing P3 hidden-row focus comment remains unchanged: the exact-target lookup still precedes the visible-row fallback at ChannelSidebar.tsx:679–691. It is not resolved or duplicated by this review. Accepted whole-record/cross-record persistence limitations remain unchanged.

Validation limits: pinned Git-object analysis, range-diff comparison, 20 byte-verified source extracts, and git diff --check passed; no dirty source inputs. No PR code, tests, builds, app launches, installs, or CI reruns were executed. The one-time exact-head CI snapshot showed JavaScript, measurements, Chromium shard 2/3, DCO and security checks passing; five browser shards and Rust/tool integration were still running, and Windows was skipped. This is not a terminal CI result or evidence that the changed menu/dialog workflow passed. Browser/native focus behavior, current-target merged-tree acceptance, live-relay behavior and human acceptance remain unverified. Non-blocking COMMENT only—not approval or merge authorization.

@tellaho
tellaho deleted the tho/sidebar-grouping-focused branch September 25, 2026 20:45
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.

2 participants