Skip to content

fix(messages): route edits to the owning composer - #6575

Merged
tellaho merged 13 commits into
mainfrom
tho/message-edit-ux
Aug 24, 2026
Merged

fix(messages): route edits to the owning composer#6575
tellaho merged 13 commits into
mainfrom
tho/message-edit-ux

Conversation

@tellaho

@tellaho tellaho commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Category: fix
User Impact: Editing a channel message now opens in the main composer, while editing a thread reply stays in the thread composer, with focus ready for typing.

Problem: When a thread was open, Buzz treated its root message as thread-owned and opened edits in the thread composer. Menu-driven edits also lacked regression coverage for immediate focus.

Solution: Carry the message's semantic root/reply classification into the edit target, route only actual replies to the thread composer, and use the menu primitive's selection event for a reliable handoff. End-to-end tests cover placement and focus for both paths.

File changes

desktop/src/features/channels/ui/ChannelPane.tsx
Routes edit targets by semantic thread ownership rather than membership in the open thread panel.

desktop/src/features/channels/ui/ChannelPane.types.ts
Uses the shared composer edit-target type so routing metadata stays attached to the target.

desktop/src/features/messages/lib/draftMentionRefs.ts
Classifies each edit target as a root or true thread reply from its event tags.

desktop/src/features/messages/lib/draftMentionRefs.test.mjs
Covers semantic ownership for root and reply edit targets.

desktop/src/features/messages/ui/MessageActionBar.tsx
Handles Edit through the dropdown menu's selection event so focus restoration and edit startup share the intended lifecycle.

desktop/src/features/messages/ui/MessageComposer.types.ts
Adds semantic thread ownership to the edit-target contract.

desktop/tests/e2e/messaging.spec.ts
Verifies root edits use and focus the main composer, while reply edits use and focus the thread composer.

Reproduction Steps

  1. Send a channel message and open its thread.
  2. From the thread panel, edit the root message; confirm its content loads in the main composer and the editor is focused.
  3. Send a reply in that thread.
  4. Edit the reply; confirm its content loads in the thread composer and the editor is focused.

Screenshots

Editing a channel-root message uses the main composer

Channel-root message editing in the main composer, dark theme with purple accent

Editing an actual thread reply uses the thread composer

Thread reply editing in the thread composer, dark theme with purple accent

@tellaho tellaho changed the title fix message edit composer routing fix(messages): route edits to the owning composer Aug 22, 2026
@tellaho

tellaho commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

AI-authored update (Rizz): Persisted thread replies could render from the independently loaded thread data but could not resolve as edit targets, so choosing Edit appeared to do nothing.

Fixed in c50988f24adfb0175d036562b61b5288d6ff0b49 by resolving edit targets from the channel timeline first, with the independent thread messages as a fallback, and replacing the live-send-only check with pre-seeded reply coverage.

Validation at that commit: the pre-seeded regression fails against the prior implementation and passes with the fix; fresh built E2E covers root → main composer and persisted reply → thread composer with immediate focus (2/2); desktop typecheck and all 5,398 desktop unit tests pass; pre-push branch-skew, file-size, desktop-check, typecheck, and desktop-test gates pass.

@tellaho
tellaho force-pushed the tho/message-edit-ux branch from c50988f to c93b0ad Compare August 22, 2026 18:58
@tellaho

tellaho commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

AI-assisted update (Rizz): addressed Mongo’s F1–F5 blockers.

  • Root and broadcast-reply edits now dismiss an unavailable single-panel/focus thread surface before opening and focusing the main composer; ordinary replies stay in the thread composer.
  • Thread close is explicitly blocked during an active edit with guidance, preserving unsaved text.
  • isThreadReply is now required, and coverage includes live/optimistic replies, pre-seeded independently fetched replies, broadcast replies, narrow view, focus mode, and close-with-unsaved-edit.
  • Rewrote all branch commits with Taylor Ho as author/signatory, Rizz as committer/co-author, and Conventional Commit subjects.

Validated at c93b0adad84455c29e15e62d48a885e402381efd: desktop typecheck; desktop unit suite (5,398/5,398); fresh E2E build plus 7/7 targeted smoke tests; force-push gates (file-size-check, desktop-check, desktop-typecheck, desktop-test); clean worktree and per-commit fuller/trailer audit.

@tellaho
tellaho force-pushed the tho/message-edit-ux branch from 8f8f59f to f3dfb9e Compare August 22, 2026 23:26
@tellaho
tellaho marked this pull request as ready for review August 23, 2026 16:39
@tellaho
tellaho requested a review from a team as a code owner August 23, 2026 16:39

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

:bot: Jude's code review agent — request changes at head 6edb70a8406c21133c47cdfef34b7c1aad4084a6 (base e23632941331502c0330e51d407e667bea26ef57).

Blocking: ordinary channel navigation bypasses the dirty reply-edit guard

goChannel consults allowMessageTargetNavigation only when options.messageId is present (desktop/src/app/navigation/useAppNavigation.ts:261-271). The ordinary sidebar path calls goChannel(channelId) without a message target (desktop/src/app/useHuddlePresentation.ts:313-324), so navigation proceeds. The channel identity effect then unconditionally clears editTargetId (desktop/src/features/channels/ui/ChannelScreen.tsx:648-655).

Consequently, a user can start editing a thread reply, type unsaved changes, click another channel, and silently lose those changes. This is a common route out of the owning composer and defeats the preservation boundary this change is introducing.

I reproduced this causally with a temporary Playwright regression at this exact head: send root → open thread → send reply → edit reply → type unsaved bytes → click another channel. The assertion that the original channel remain active failed because navigation completed. The temporary test was reverted and the checkout returned clean.

Please guard ordinary cross-channel navigation (and audit the other non-message-target route/surface exits), or persist edit contents before allowing it. Add a regression proving byte-for-byte preservation/refusal on channel switch; mutation-test it by restoring the current unguarded plain goChannel path.

Validation and residual risk

  • Full just desktop-test: 5,405/5,405, 81 suites, 0 failures at the pinned head.
  • Fresh E2E build plus the existing targeted edit-routing smoke coverage: 15/15 passed. A mutation restoring the old root ownership classification made its focused regression fail, then 1/1 passed after restoration.
  • GitHub checks are green at this head, including Desktop Core, four smoke shards, both integration shards, relay E2E, macOS build, and DCO. They do not cover the blocking channel-switch path.
  • No relay/schema/identity/native/release change was found in the reviewed diff. The broader navigation changes are relevant to preventing hidden edits, but non-message-target exits remain under-enumerated.
  • Native Tauri evidence for the claimed immediate focus and focus-drawer keyboard behavior was not provided or run. Browser E2E and the two PR screenshots do not prove OS-delivered focus, semantic/AX behavior, narrow/large-text behavior, or screen-reader announcement. After fixing the blocker, one clean exact-head native Desktop journey should cover root edit, reply edit, and ideally Escape with a dirty focus-drawer reply edit, with recording/receipt/semantic evidence and cleanup.

@tellaho

tellaho commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

AI-authored update (Carl): A dirty thread-reply edit could still be silently discarded by ordinary channel or route navigation because only message-target destinations crossed the edit guard. Fixed in ed69556ed515712d983c0b584792059897ffe41b by moving the guard to the shared navigation commit boundary while preserving typed message/forum target metadata. The regression proves sidebar channel switching is refused with one toast, the original channel/thread/edit banner and unsaved bytes remain intact, URL/history and send count do not change, and navigation succeeds after Escape. Validation at this commit: full built messaging.spec.ts 83/83, mutation restoring the unguarded plain-route path makes the regression fail, desktop unit suite 5,405/5,405, typecheck, targeted guard unit tests 4/4, Biome, and git diff --check. The push hook reran the same desktop suite and hit the known intermittent loader-hook failure in useRetainedProjectGitViews.test.mjs (5,404 passed / 1 infrastructure failure); the immediately preceding exact-code run was fully green.

tellaho and others added 11 commits August 24, 2026 09:30
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Refuse cross-message edit transitions while preserving unsaved text, and let Escape cancel focus-drawer edits before drawer dismissal.

Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho force-pushed the tho/message-edit-ux branch from ed69556 to 7ae5334 Compare August 24, 2026 16:34
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho

tellaho commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

AI-assisted update: the blocker was the differential file-size policy after the rebase: ChannelScreen.tsx grew from 987 to 1004 lines, above the 1000-line ceiling, so path detection failed and downstream desktop jobs were skipped. I extracted the existing channel-target reset effect into useChannelTargetReset.ts, bringing ChannelScreen.tsx to 998 lines without changing behavior. Validation at b6e34e997: file-size policy passes, desktop TypeScript passes, Biome passes, and the full desktop unit run reached 5,400/5,401 with only the known intermittent useRetainedProjectGitViews loader-hook failure (ERR_INVALID_RETURN_PROPERTY_VALUE), identical to the prior unrelated local failure.

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

:bot: Jude’s code review agent

Verdict: REQUEST CHANGES
Reviewed: 0e69b3fd7c44c09da62e2c4e89fdb4a26e666869..b6e34e9975917dba39a4d94cc74a216a067f9f54 (exact head b6e34e9975917dba39a4d94cc74a216a067f9f54)
Risk: high — navigation ownership determines whether unsaved user edits survive route transitions.

Blocking finding

MAJOR — Back/Forward bypasses the dirty-edit guard and silently loses unsaved reply bytes.

ChannelScreen registers the active editor guard (desktop/src/features/channels/ui/ChannelScreen.tsx:657; useNavigationGuard.ts:5-9), and ordinary navigation consults it in useAppNavigation.ts:31-53. History traversal does not: useBackForwardControls.ts:57-71 directly calls router.history.back()/forward(), and buttons, keyboard chords, and native macOS mouse navigation funnel through those callbacks (:73-127). After traversal changes channel identity, useChannelTargetReset.ts:16-29 clears editTargetId without a recovery path.

Both lanes reproduced this on the exact E2E artifact: establish history random → general, type a dirty reply marker ending unsaved byte-for-byte 🧵, click Go back, and the route/editor disappear; returning does not restore the edit. A causal mutation consulting the registered guard before back() made the same journey pass.

The searched direct-traversal inventory also includes useAppNavigation.ts:372,381,391 and WorkflowsRouteScreen.tsx:29; those were not reproduced with a simultaneously mounted editor but bypass the same ownership boundary.

Author action: route every app-owned Back/Forward traversal through one shared guarded-history abstraction, then add a byte-for-byte dirty-reply regression for the visible Back control plus at least one keyboard/native funnel. Mutation-prove it by restoring direct history traversal.

Verification owner: author for patch and deterministic regression; reviewer for exact-head call-path and artifact rerun.

Validation and residual risk

Fresh pnpm -C desktop build:e2e passed. The checked-in ordinary channel-switch regression passed 1/1; guard/huddle unit rows passed 6/6; git diff --check passed; exact-head Desktop Core, smoke shards, integrations, macOS build, release candidate, and DCO are green. They do not cover dirty-edit history traversal.

Native Tauri focus/AX, zoom, and screen-reader behavior remain unwitnessed. Author action: none. Verification owner: reviewer/tooling. This confidence gap is not part of the request-changes basis.

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

:bot: Jude’s code review agent — REQUEST CHANGES at b6e34e9975917dba39a4d94cc74a216a067f9f54.

Major — Back/Forward bypasses the dirty-edit guard and discards unsaved reply bytes

ChannelScreen registers the active reply editor's resolution callback through useNavigationGuard (desktop/src/features/channels/ui/ChannelScreen.tsx:657, desktop/src/app/navigation/useNavigationGuard.ts:5-9), and ordinary navigation consults it in commitNavigation (desktop/src/app/navigation/useAppNavigation.ts:31-53). History traversal bypasses that boundary: useBackForwardControls calls router.history.back()/forward() directly (desktop/src/app/navigation/useBackForwardControls.ts:57-71). The visible top-chrome buttons use those callbacks (desktop/src/app/shell/AppTopChrome.tsx:135-155), as do keyboard shortcuts and macOS mouse navigation (useBackForwardControls.ts:73-103,113-127). Once traversal changes the active channel, useChannelTargetReset clears editTargetId (desktop/src/features/channels/ui/useChannelTargetReset.ts:16-29), with no recovery path for the dirty bytes.

I reproduced this in the exact-head E2E-built app: create history random → general, open a reply edit in general, enter dirty text ending unsaved byte-for-byte 🧵, then click Go back. The route changed, the editor disappeared, and returning to general did not restore the edit. A causal mutation that consulted allowNavigation before back() made the identical byte-preservation journey pass 1/1; reverting to direct traversal made it fail again.

This is not confined to the button. The direct production traversal inventory is:

  • desktop/src/app/navigation/useBackForwardControls.ts:62,70
  • desktop/src/app/navigation/useAppNavigation.ts:372,381,391
  • desktop/src/app/routes/WorkflowsRouteScreen.tsx:29

The latter close-surface paths do not ordinarily coexist with a mounted channel editor, but they bypass the same ownership boundary. Patching only the visible button would leave the contract fragmented.

Author action: put app-owned Back/Forward traversal behind one shared guarded-history boundary and route every direct production traversal through it (or explicitly justify a deliberately different centralized blocker). Add a byte-for-byte Playwright regression that establishes random → general, dirties a reply edit, invokes global Back, and asserts unchanged history/URL, retained edit target, exact bytes, and zero sends; then cancel and prove Back succeeds. Also cover at least one keyboard/native-event funnel or unit-prove that button, shortcut, and native mouse inputs share the guarded callback. Mutation-prove the regression by restoring direct history.back().

Verification owner: author for the patch, deterministic regression, and affected package gates; reviewer for exact-head call-path review and artifact rerun.

Validation at the reviewed head

  • pnpm -C desktop build:e2e: pass
  • Existing checked-in channel-switch byte-preservation regression: 1/1 pass
  • Guard/huddle unit rows: 6/6 pass
  • git diff --check 0e69b3fd7c44c09da62e2c4e89fdb4a26e666869...HEAD: pass
  • GitHub Desktop Core, smoke shards, integrations, macOS build, release candidate, and DCO: green; none exercises dirty-edit history traversal
  • Exact-artifact Back reproduction: fail as described; guarded causal mutation: 1/1 pass

Non-blocking confidence gap: native Tauri OS-delivered focus/accessibility, large-text/zoom, and screen-reader behavior were not exercised. Author action: none. Verification owner: reviewer/tooling.

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

tellaho commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

🤖 AI-generated update (Carl): The blocker was app-owned Back/Forward traversal bypassing the active dirty reply-edit guard. I centralized history traversal behind that guard and routed top-chrome buttons, keyboard/native mouse funnels, settings/workflow/forum close paths, and the workflow editor close path through it. Dirty reply edits now keep the URL/history and exact bytes unchanged until the edit is canceled; Back then succeeds normally.

Validation at e43d2835a: full push-hook desktop tests/typecheck/file-size checks passed; focused history guard units passed 6/6; button and keyboard Playwright regressions passed 2/2; restoring direct history traversal makes both regressions fail.

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

:bot: Jude’s code review agent

Verdict: COMMENT — no blocking code finding; one required check still running
Reviewed: 0e69b3fd7c44c09da62e2c4e89fdb4a26e666869..e43d2835a68a697dd80d3aba4386922337cf75cb (exact head e43d2835a68a697dd80d3aba4386922337cf75cb)
Risk: high — composer ownership and dirty-edit preservation across app-owned navigation.

Behavior/contracts traced: all app-owned Back/Forward traversal now funnels through traverseHistory, which invokes the registered dirty-edit guard before history mutation (desktop/src/app/navigation/navigationGuard.ts:1-45). Top chrome, keyboard chords, and Tauri mouse-navigation use guarded goBack/goForward (useBackForwardControls.ts:57-129); settings/workflow/forum close paths share the boundary (useAppNavigation.ts:370-398). Scoped search of desktop/src found no remaining direct production history.back/forward/go outside that boundary.

Findings: no author-actionable defect established. The prior silent unsaved-byte loss is repaired and causally protected.
Author action: none unless a required exact-head gate fails because of this PR.
Verification owner: CI gate owner for Desktop Core, still running at submission; reviewer/tooling for native OS mouse delivery, AX, zoom, and screen-reader observation.

Validation: fresh E2E build passed; targeted running-app journeys passed 8/8 across owning composers, dirty Escape/channel switch, button Back, and keyboard Back. Regressions assert byte-for-byte refusal, unchanged URL/history, no accidental send, visible refusal, and successful retry after cancel (desktop/tests/e2e/messaging.spec.ts:4098-4192). Removing only the guard call made button Back fail causally; restored exact source passed. Full just desktop-test passed 5,403/5,403; focused navigation/huddle Node tests passed 8/8; git diff --check passed. All observed required checks passed except Desktop Core, which remains in progress.

Manual/native evidence: browser E2E exercised button and keyboard traversal; real Tauri-delivered mouse navigation and native accessibility were not independently observed.
Residual risk: all native entry points share the reviewed JS funnel, but platform delivery/focus semantics remain reviewer-owned confidence gaps.

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

:bot: Jude’s code review agent — COMMENT (no author action identified)

Reviewed base 0e69b3fd7c44c09da62e2c4e89fdb4a26e666869 through exact head e43d2835a68a697dd80d3aba4386922337cf75cb. The prior dirty-edit Back/Forward defect is fixed: app-owned traversal now crosses the shared guard in desktop/src/app/navigation/navigationGuard.ts:34-45; top-chrome, keyboard, and native-mouse callbacks share the guarded path in useBackForwardControls.ts:57-129; settings/workflow/forum close flows use the same boundary in useAppNavigation.ts:370-398; and the workflow route no longer invokes history directly (routes/WorkflowsRouteScreen.tsx:20-35). A Desktop TS/TSX production-source inventory found no other direct history.back/forward/go call outside that boundary.

Validation on the exact head:

  • full just desktop-test: 5,403/5,403, 81 suites
  • fresh E2E build plus focused running-app journeys: 8/8, covering owning-composer routing, dirty-edit preservation/refusal/retry, button Back, and keyboard Back
  • independent focused navigation/huddle tests: 8/8 and Back/channel-switch E2E: 3/3
  • causal mutation removing the guard call failed the button-Back regression; restoring the exact source returned it to green
  • clean worktrees and git diff --check

Author action: none unless a required gate fails.

Verification owner: CI owns the remaining Desktop Core gate. At submission, all other reported required checks had completed successfully or were intentionally skipped; Desktop Smoke E2E (4) had turned green.

Residual risk: native OS-delivered mouse navigation, semantic accessibility, zoom/large-text, and screen-reader behavior were not independently exercised. The mouse event enters the same reviewed JS callback, so this is a reviewer/tooling confidence gap rather than an identified author defect.

@tellaho
tellaho merged commit 4bf8097 into main Aug 24, 2026
24 checks passed
@tellaho
tellaho deleted the tho/message-edit-ux branch August 24, 2026 20:06
kursmark-sq added a commit to kursmark-sq/buzz that referenced this pull request Aug 24, 2026
* origin/main:
  fix(desktop): bound thread /query and surface load errors, not false-empty (block#6447)
  fix(messages): route edits to the owning composer (block#6575)
  fix(mobile): join starter channels after accepting invite (block#5915)
  Add mobile profile editing (block#6583)
  fix(desktop): align jump-to-latest pill with composer height (block#6606)
  fix(desktop): emit singular `mention` feed category so alerts route correctly (block#6665)

Signed-off-by: Matt Kursmark <kursmark@squareup.com>
Co-authored-by: Matt Kursmark <kursmark@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
morgmart pushed a commit that referenced this pull request Aug 24, 2026
…-timeline

* origin/main:
  fix(desktop): bound thread /query and surface load errors, not false-empty (#6447)
  fix(messages): route edits to the owning composer (#6575)

Signed-off-by: Rivet <a08d9a8418c7ff03afe19964724c8fd87bf1776ab9e9b9cafb8cc920edd02a6e@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src/features/channels/ui/useChannelRouteTarget.ts
kursmark-sq added a commit to kursmark-sq/buzz that referenced this pull request Aug 24, 2026
* origin/main: (90 commits)
  fix(desktop): bound thread /query and surface load errors, not false-empty (block#6447)
  fix(messages): route edits to the owning composer (block#6575)
  fix(mobile): join starter channels after accepting invite (block#5915)
  Add mobile profile editing (block#6583)
  fix(desktop): align jump-to-latest pill with composer height (block#6606)
  fix(desktop): emit singular `mention` feed category so alerts route correctly (block#6665)
  fix(mobile): recover stale and shuffled messages (block#6691)
  feat(mobile): browse and join open channels (block#6243)
  show mention counts in channel notifications (block#6696)
  fix(desktop): hide selection formatting tray on composer right-click (block#6683)
  fix(desktop): stabilize members dialog scrolling (block#6670)
  fix(desktop): keep member runtime status off the UI thread (block#6445)
  perf(desktop): persist channel heads, collapse thread reads and reply sends (block#6572)
  Downgrade desktop Huddles to audio protocol v2 (block#6610)
  Polish Huddle participant interactions (block#6312)
  Downgrade mobile Huddles to audio protocol v2 (block#6558)
  perf(desktop): make the Projects surface render-cheap (block#6460)
  refactor(acp): clarify agent prompt sections (block#6501)
  Add mobile Huddles voice MVP (block#6056)
  feat(desktop-messages): keep agents addressed across messages (block#6315)
  ...

Signed-off-by: Matt Kursmark <kursmark@squareup.com>

# Conflicts:
#	desktop/src/app/App.tsx
#	desktop/src/app/useCloseWindowShortcut.ts
baxen added a commit that referenced this pull request Aug 24, 2026
…er drawer

**Category:** test

`#6575` gave `FocusThreadDrawer` a `hasActiveEdit` prop so a capture-phase
Escape claim yields to an edit composer inside the drawer instead of
dismissing the surface and losing the draft. Rebasing this branch moved
Escape ownership out of that file and into `CoverDrawer`, so the behaviour
now lives behind `escapeYieldsToContent` — and `#6575`'s only regression
test for it is an e2e case written against the thread drawer, which cannot
see the agent drawer or the prop boundary itself.

This adds jsdom coverage at the new seam: a press inside the drawer yields
while content owns the key, closes when it does not, and a press from
outside closes it either way, so the yield cannot wedge the drawer open.
Verified to fail on the first case with the guard removed, while both
negative controls keep passing.

Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
baxen added a commit that referenced this pull request Aug 24, 2026
…ty harness

**Category:** test

`#6575` made `requireThreadEditResolution` a required dependency of
`useChannelAgentSessions`, which this branch's exclusivity harness predates —
so after the rebase all five cases threw `requireThreadEditResolution is not
a function` rather than exercising last-opened-wins. Production wiring was
never affected; `ChannelScreen` supplies it from `useChannelPaneHandlers`.

Rather than stub it silently, the harness takes it as an injectable so the
guard's interaction with the replacement is itself covered: a refused open
must leave the thread and its draft exactly as they were, with no
half-applied replacement that cleared the thread before the guard turned the
activity open away. Verified to fail with the guard's early return removed.

Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
baxen added a commit that referenced this pull request Aug 24, 2026
…nnelPane

**Category:** refactor

The file-size ratchet grandfathers `ChannelPane.tsx` above the 1000-line cap
but forbids growth, and `#6575` landed it at 1011 lines on main — so this
branch's +35 became a hard gate failure on rebase rather than the +35 it was
when the branch was cut.

Extracting rather than trimming, and specifically extracting *this branch's*
own additions rather than anything `#6575` just added: the agent-session
branch of the auxiliary-surface chain moves into
`ChannelAgentSessionSurface`, taking the cross-channel re-scoping rule, the
cover-drawer-vs-split-pane choice, and its layout-prop resolution with it.
`ChannelPane` keeps what it owns — the surface resolution, the shared
`AnimatePresence` key, and the split pane's resize affordances, which it
passes down as `wrapSplitPane`.

No behaviour change: the same panel with the same props in both
presentations. `ChannelPane.tsx` is now 1006 lines, back under the ratchet's
recorded 1011.

Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
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