Repository navigation
Conversation
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> * origin/nexus/build-generic-execution-support-for-native-buzz-33ea2bea: Guard execution settings during agent changes Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Upstream-commit: 4293f6d Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
kazemek21
approved these changes
Nov 2, 2026
kazemek21
left a comment
Contributor
There was a problem hiding this comment.
Kyle reviewed the PR and the Nexus review-tracker notes. Approved with three non-blocking comments.
— Posted by Codex (gpt-6.1-sol) on behalf of kylez
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> * origin/nexus/build-generic-execution-support-for-native-buzz-33ea2bea: Keep manual preference recovery under test control Wait for thread readiness before keyboard input Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> * origin/nexus/build-generic-execution-support-for-native-buzz-33ea2bea: Check retired execution through its process list Preserve execution choice and Pi lifetime Signed-off-by: Daniel Rouleau <drouleau@squareup.com> # Conflicts: # docs/buzz-help.md
gilgtm
reviewed
Nov 4, 2026
gilgtm
left a comment
Contributor
There was a problem hiding this comment.
🤖 [P2] Full review of the current native Codex replacement found a failed-cleanup retry defect, detailed inline. The remote-card host-scope regression is discussed in the existing card thread. Source review only.
Posted by duel-review skill [driver: codex(high), mode: deep-dual, review synthesized by codex(high)]
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
The coordination browser test can report `animated: false` after a real disclosure transition completes between frame samples. Main [run 41693502039](https://github.com/block/buzz-app/actions/runs/41693502039), WebKit job 126119613338, failed this assertion with no geometry failures at `589c2a489fe87ab45315359014d7d46d2df4a240`. Observe the panel's `grid-template-rows` transitionstart event before clicking, and remove the observer in `finally`. Keep the existing frame-by-frame clipping, alignment, settlement, and keyboard assertions. No product changes or browser cases added/removed. Browser coverage remains necessary for actual CSS transitions and rendered geometry. Validation: - At the failing main commit, delaying only test sampling by 350ms reproduced the exact failure while recorded transition events proved motion occurred. The original hosted trace does not record those events, so its precise scheduling cause remains unproven. - The repaired test passes with the same diagnostic delayed sampler in Chromium and WebKit (8.1s / 8.3s test execution; 34.5s local runner). Diagnostic instrumentation is excluded from this change. - Disabled-motion control still fails the animation assertion (WebKit), so an absent transition remains detectable. - Normal repaired test: 2/2 per engine, Chromium 3.7–3.9s and WebKit 4.4–4.7s; 30.1s local runner. Only the affected case ran, with no retries. - At commit `8a53027b3`, the affected test passes in Chromium (4.3s) and WebKit (4.8s), 18.1s runner; head verified before and after. - Independent agent review approved with no findings. The reviewer's reduced-motion control fails in both engines as intended. The review run also inadvertently included measurement dependencies. - Hosted coordination repetition checks passed 10/10 per engine in [run 41701145383](https://github.com/block/buzz-app/actions/runs/41701145383). Attempt 1 hit the separate held-pointer travel test defect (`history-loading.spec.mjs:347`, expected ≥6 steps, got 2), already repaired by unmerged #2250. A single-job hosted retry passed at the unchanged repair head. Attempt 2 completed successfully at 19:37:26 UTC: 39 successful checks, two expected skips, none pending. This PR does not repair the held-pointer defect. No full suite invoked locally; hosted CI supplies broader validation. Native acceptance and a real relay are outside this test-only change. Signed-off-by: Kalvin Chau <kalvin@block.xyz> Co-authored-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> (cherry picked from commit bad2fec) Signed-off-by: Daniel Rouleau <drouleau@squareup.com> Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
kazemek21
added a commit
that referenced
this pull request
Nov 5, 2026
## TL;DR Any agent running on this device can now read and change Buzz settings when you ask it to, through generic `settings_list`, `settings_get` and `settings_set` MCP tools. There is no per-agent switch and no UI change. The feature that owns each setting defines it once in a shared catalog and writes it through its own live setter, so the settings screen, storage and other windows see the change as if you had made it. ## What agents can change | Key | Values | Owner | | --- | --- | --- | | `appearance.mode` | `system`, `light`, `dark` | `shared/theme/settings.ts` | | `appearance.interface_size` | 80–200, steps of 10 (percent) | same | | `appearance.accent` | the accent ids | same | | `appearance.vibe` | `low` (Chillin’), `high` (Buzzin’) | same | | `conversations.thread_placement` | `side`, `main` (new thread tabs only) | `features/messages/thread-preferences.ts` | | `conversations.follow_up_behavior` | `immediate`, `queue` (Solo) | `features/messages/follow-up-preference.ts` | | `conversations.autocorrect` | `true`, `false` (Mac message box) | `features/messages/autocorrect-preference.ts` | | `agents.remember_mentioned` | `true`, `false` | `features/messages/mention-preferences.ts` | `src/app/device-settings.ts` composes the catalog. `createDeviceSettings` exposes one generic API (`list`, `get`, `set`) over string-enum, integer and boolean settings. Adding a setting means adding one definition, with no tool or router edits. Values must match exactly, with no aliases, case folding or clamping. Unknown keys, wrong types and extra arguments are refused, and nothing changes. Each write is read back. When storage refuses it, the answer is `saved: false` with the owner's own reason. **Not covered yet:** Buzz has no shared settings store, so coverage follows which settings already have a synchronous setter that fits this shape. - Notification preferences and keep-awake would each need an adapter, and notifications would also need `services.ts` construction order changed. - Shortcuts take object values. - Plugins' own settings, such as Focus, exist only inside the plugin. - Excluded by design: actions such as sign-in, updates, leaving a community and clearing caches, as well as secrets, grants and consent, decision providers, models and anything destructive. ## Who gets the tools - **Every agent run.** An agent run's handle carries the catalog, and its Buzz MCP lists the three tools (`load: "search"`). Calls go through the same `appClient` check and signal as every other mutating Buzz tool, such as sending a message, and the write is synchronous after that check. A removed agent, a changed connection, or a turn the harness has ended or aborted changes nothing. Stop behaves as it does for those tools in each harness. Where the MCP connection outlives a stopped turn (Goose, and Claude Code without protection), a call already in flight when you press Stop can still land, as a message send can. - **Not plugins or external connections.** A plugin's outside-run `Agents.handle` has no settings. Tools a plugin adds get the agent's client without `settings`. External MCP connections use that non-run handle and also get none. ## Revision An earlier revision gated this behind a per-agent, off-by-default **Change Buzz settings** switch in Agent details. It also added a settings-only Stop check to the Claude Code, Codex, Goose and Pi runtimes. Following product direction, both are removed. The AgentManage, AgentDetails, AgentsPage and ProfilePanel files, the agent record, and the four runtimes and Pi host are back to `main`. The earlier screenshots, how-to-try steps and the runtime and permission test evidence described that design and no longer apply. ## Overlapping work This PR does not build on any of these and changes none of their behavior: - #2211: external auth and catalog. - #1878 and #839 (now on main): Claude and Goose protection, whose pre-tool checks still review a settings call. - #2150 and #2186: execution target. - #2180: themes. Theme selection is left out of the catalog. - #1704: queued follow-ups. This PR only exposes the existing behavior preference. ## Validation Run on a Blox Linux workstation against this exact tree: - `tsc --noEmit` and biome on the touched files pass. - vitest passes for 10 files (922 tests, after rebasing onto #2280). These are the changed tests, plus the Claude Code and Codex runtime tests and `AgentManage`, now back to `main`: - `shared/device-settings`: exact values, booleans, read-back, unsaved and closing. - `app/device-settings`: real `createAppearance` and the three message and agent preferences in jsdom, with persistence, change events and a refused `setItem`. - `buzz-mcp`: the catalog through the router, listing by connection, plugin tools without settings, and `appClient` checking the turn before each call. - `features/agents/service`: settings on every run's handle with no switch, none on a plugin's handle, and an aborted turn signal or agent removal while a call waits for review changing nothing. No browser journeys were added or removed. Deferred: the native app hasn't been run with a live agent turn. The steps below cover that. ## How to try it 1. Ask any agent running on this device to switch Buzz to dark mode. The app should switch at once, and **Settings → Appearance** should show Dark. 2. Ask it to open new threads in the main pane, then open a thread. It should open in the main pane, while open threads stay put. 3. Ask it to queue Solo follow-ups. **Settings → Appearance → Follow-up behavior** should show Queue. 4. Ask it for something outside the list, such as a theme. It should say that setting isn't available, and nothing should change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Kyle Zemek <kylez@squareup.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
dr0uleau
deleted the
nexus/build-generic-execution-support-for-native-buzz-33ea2bea
branch
November 5, 2026 01:42
gilgtm
added a commit
that referenced
this pull request
Nov 5, 2026
…lled-read * origin/main: (28 commits) Run native Codex through plugin execution targets (#2150) test: split Solo access browser scenarios (#2499) feat(agents): let any agent change Buzz settings through the MCP (#2248) Let plugins decorate host sidebar rows and add sort modes (#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (#2083) feat(agents): move version history into settings (#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (#2466) feat(channels): starter channels: admin switch and relay auto_join flag (#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (#2465) feat(plugins): let agents request plugin changes for owner review (#2280) fix(messages): keep the hover toolbar while its menu is open (#2439) feat(workflows): suggest channel members for @ in Send Message text (#2309) AIDA-2344: Exclude muted channels from Dock (#2313) feat(search): add slack-style message search operators on desktop (#2463) test: fix invitation and coordination checks on main (#2517) perf(search): name searched people from the profile search response (#2353) Use the merge queue for pull requests that require it (#2452) fix(browser): load scheme-less address input over https, falling back to http (#2467) fix(identity): stop one-click key unlinks and show the linked backed-up key (#2486) fix(test): observe coordination transition events (#2297) ... Signed-off-by: Gil Birman <gil@squareup.com> Co-authored-by: Claude <noreply@anthropic.com> # Conflicts: # docs/buzz-help.md
cheng-block
added a commit
to cheng-block/buzz-app
that referenced
this pull request
Nov 5, 2026
…ettings-shift-esc * upstream/main: (91 commits) test(browser): click timeline rows only after the timeline settles (block#2560) ci: split Vitest across six shards so 3/4 stops hitting the job cap (block#2571) feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) fix(messages): keep the hover toolbar while its menu is open (block#2439) feat(workflows): suggest channel members for @ in Send Message text (block#2309) AIDA-2344: Exclude muted channels from Dock (block#2313) feat(search): add slack-style message search operators on desktop (block#2463) test: fix invitation and coordination checks on main (block#2517) ... Signed-off-by: Cheng Peng <cheng@block.xyz> Co-authored-by: Cursor <cursoragent@cursor.com>
cheng-block
added a commit
to cheng-block/buzz-app
that referenced
this pull request
Nov 5, 2026
* upstream/main: (22 commits) test(browser): click timeline rows only after the timeline settles (block#2560) ci: split Vitest across six shards so 3/4 stops hitting the job cap (block#2571) feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) fix(messages): keep the hover toolbar while its menu is open (block#2439) feat(workflows): suggest channel members for @ in Send Message text (block#2309) AIDA-2344: Exclude muted channels from Dock (block#2313) feat(search): add slack-style message search operators on desktop (block#2463) test: fix invitation and coordination checks on main (block#2517) ... Signed-off-by: Cheng Peng <cheng@block.xyz> Co-authored-by: Cursor <cursoragent@cursor.com>
cheng-block
added a commit
to cheng-block/buzz-app
that referenced
this pull request
Nov 5, 2026
* upstream/main: (91 commits) test(browser): click timeline rows only after the timeline settles (block#2560) ci: split Vitest across six shards so 3/4 stops hitting the job cap (block#2571) feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) fix(messages): keep the hover toolbar while its menu is open (block#2439) feat(workflows): suggest channel members for @ in Send Message text (block#2309) AIDA-2344: Exclude muted channels from Dock (block#2313) feat(search): add slack-style message search operators on desktop (block#2463) test: fix invitation and coordination checks on main (block#2517) ... Signed-off-by: Cheng Peng <cheng@block.xyz> Co-authored-by: Cursor <cursoragent@cursor.com>
matt2e
added a commit
that referenced
this pull request
Nov 5, 2026
…e Retry ## Problem WebKit's `sidebar-section-creation.spec.mjs:9` "Channels offers empty-section creation with keyboard focus and confirmed persistence" failed at line 167 when clicking "Retry preferences". The click timed out after 10 s. Its call log says "element is not enabled", then "element was detached from the DOM". - clay/bestie-empty-state: run 41547288213, https://github.com/block/buzz-app/actions/runs/41547288213/job/125626193138 - kylez_NEXUS-4082_channel_unread_boundary: run 41553877476 attempt 1, https://github.com/block/buzz-app/actions/runs/41553877476/job/125648251816 (attempt 2 passed) ## Cause The journey's second creation fails the strong channel-sections writer read with an injected 502. `isTransientFailure` counts a 502 as transient, so the preference store publishes the error with `transient`, and relay recovery reads again after `RECOVERY_DELAYS_MS[0]` (1000 ms). That read disables Retry preferences (`disabled={refreshing}`), and its success removes the button. This is intended: recovery owns transient background reads. The trace from run 41547288213 shows the race. The 502 was fulfilled at 153289 ms and the click started at 153482. WebKit's first "visible, enabled and stable" check did not return until 154493. Recovery's read reached the route at 154393, so that check found the button disabled. The button detached at 155188, and the click timed out. Any click that takes more than about a second to land loses the Retry to recovery. ## Fix Inject a 403 instead. A denial is not transient, so `loadState` reports it as settled and recovery leaves it alone. The manual Retry is then the only way out, which is the path this journey exists to exercise. The fixture already uses this reasoning for activity reads ("Activity reads retry a 502 quietly, so their journeys inject a 403"). The failure is recorded under `app.report.relayFailures`, the fixture's allowance for injected relay 403s, rather than `sidebarPreferenceFailures`, which only matches 502s. The check that the alert doesn't show the status now looks for "403". A comment explains why a transient status would race recovery. The existing `writerReads` of 3 after the click now also confirms that no background read ran first. Only the test changes (+7/-4). No other assertions change, and no product code changes or browser cases are added or removed. Open PR #2150 ("Run native Pi agents through plugin execution targets") makes the same 403 and `relayFailures` change in this hunk as part of a feature change. It leaves the alert check on "502". When #2150 rebases, it can take this side of the hunk. ## Validation Local Linux workstation, Playwright 1.63.0, `--no-deps --workers=1 --retries=0`: - Adversarial ordering, using temporary, uncommitted changes: the Retry click was delayed 1.2 s, modelling the slow actionability check, and the first writer read after the injected failure was held for 600 ms. Without the fix: 10/10 failed (5 WebKit, 5 Chromium), all at the Retry click with "element is not enabled" followed by "element was detached from the DOM", the CI signature. Holding the read without delaying the click: 6/6 passed. With the fix: 10/10 passed, and 6/6 passed with a 3.5 s delay, past recovery's first two retries. - Natural contention: WebKit pinned to 4 CPUs shared with 4 busy loops, 2 workers, 24 repeats. Without the fix: 24/24 passed, so load alone did not open the window locally. With the fix: 24/24 passed. - `bin/pnpm test:browser tests/browser/sidebar-section-creation.spec.mjs --project webkit --project chromium --no-deps --workers=1 --grep "empty-section creation" --repeat-each=20`: 40/40 passed. - Full `sidebar-section-creation.spec.mjs`, both engines: 6/6 passed. - `biome check` and `git diff --check` are clean. A green run doesn't prove the flake is gone. Hosted CI covers broad validation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: mtoohey <mtoohey@squareup.com> (cherry picked from commit 69eae17b94b702a9c74c154e37ea147441c7ab11)
ljknight
added a commit
to ljknight/buzz-app
that referenced
this pull request
Nov 5, 2026
…nks-in-browser * origin/main: (138 commits) feat(composer): optional ⌘/Ctrl+Enter to send (block#2331) test: use keyboard activation for reply caret setup (block#2557) test: settle member search before invitation expansion (block#2532) test(agent-command): isolate the copied executable writer (block#2537) test(sidebar): wait for the rolled-back row to leave Starred before collapsing Work (block#2574) test(browser): click timeline rows only after the timeline settles (block#2560) ci: split Vitest across six shards so 3/4 stops hitting the job cap (block#2571) feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) ... # Conflicts: # src/bundled/github/README.md
matt2e
added a commit
that referenced
this pull request
Nov 5, 2026
…2566) ## Summary Six browser journeys each acted before a boundary they depended on: a debounced search landing, a background recovery read (in two journeys), a message reveal taking focus, a cold page load that fetched the fixture module by module, and a pause-then-seek in the same tick. Each commit adds the missing barrier, or removes the race at its source. All six changes are test-only: no assertions are loosened, no retries, sleeps or timeouts change, no browser cases are added or removed, and no product code changes. ### test(channels): let the member search land before the final pointer expansion **Problem** WebKit's `channel-members-focus.spec.mjs:826` "final invitation expansion continues keyboard focus at the first new row" failed 5 times between 2026-11-02 23:00Z and 2026-11-04 11:00Z, on 4 unrelated branches including main. Every failure was in the pointer iteration at :853: "Your other agents" held 8 "Add Helper" rows, never 10. - main, run 41662691884: https://github.com/block/buzz-app/actions/runs/41662691884/job/126010368608 - sol/aida-2436-recipient-search: https://github.com/block/buzz-app/actions/runs/41717923671/job/126203332188 - kylez_NEXUS-4155_solo-model-effort-per-chat: https://github.com/block/buzz-app/actions/runs/41748955704/job/126309380524 and https://github.com/block/buzz-app/actions/runs/41752221861/job/126320136617 (attempt 2 passed) - kylez_NEXUS-4165_agent-create-thinking: https://github.com/block/buzz-app/actions/runs/41799304245/job/126471226006 **Cause** Typing "Helper" shows the local agent rows at once. The relay search runs after `SEARCH_DEBOUNCE_MS` (300 ms) and adds a "People not in this channel" group above "Your other agents". In all five traces, the pointer click started 185–260 ms after the fill, while the list was still `aria-busy`. The click passed Playwright's hit-target check inside Show more's box (y 523–547). The People group then landed and moved Show more to y 543–567, so the press hit Show more and the release hit the row below it, and no click reached the button. **Fix** After filling the search, wait for the Member list's `data-refreshing="false"`, as this file's large-search test already does. The search keeps `loading` true from the moment the text changes until that text's results arrive, so the barrier can't pass early. **Validation** - Adversarial ordering, with a fixture gate that held the relay search until `pointerdown` on Show more and the debounce lowered to 100 ms: without the fix 20/20 failed at :853 with "Received: 8", and with the fix 20/20 passed. - Natural contention, with 4 CPUs shared with 4 busy loops: without the fix 1/24 failed with the CI signature, and with the fix 48/48 passed. - Both engines, `--repeat-each=30`: 60/60 passed. The full file, both engines: 36/36 passed. ### test(channels): deny the failed preference read so recovery can't race Retry **Problem** WebKit's `sidebar-section-creation.spec.mjs:9` "Channels offers empty-section creation with keyboard focus and confirmed persistence" failed at :167 clicking "Retry preferences". The call log said "element is not enabled", then "element was detached from the DOM". - clay/bestie-empty-state, run 41547288213: https://github.com/block/buzz-app/actions/runs/41547288213/job/125626193138 - kylez_NEXUS-4082_channel_unread_boundary, run 41553877476 attempt 1: https://github.com/block/buzz-app/actions/runs/41553877476/job/125648251816 (attempt 2 passed) **Cause** The journey failed the channel-sections writer read with a 502. A 502 counts as transient, so relay recovery reads again after 1 s. That read disables Retry preferences, and its success removes the button. In the trace, WebKit's first actionability check for the Retry click returned 100 ms after recovery's read reached the route. Any click that takes about a second to land loses the Retry to recovery. **Fix** Inject a 403 instead. A denial isn't transient, so recovery leaves it alone, and the manual Retry is the only way out, which is the path this journey exists to exercise. The failure is recorded under `app.report.relayFailures`. The check that the alert doesn't show the status now looks for "403". **Note on main's #2150** #2150 merged to main after this commit was written (as `21f6b97a99`). It makes the same 403 and `relayFailures` change in this hunk, with its own one-line comment, so the cherry-pick conflicted there. The conflict was resolved by keeping this commit's side. On this branch, the commit therefore only replaces that comment with the longer explanation and changes the alert check from "502" to "403". On main that check passes no matter what, because the injected status is already 403. The commit body still refers to #2150 as an open PR. No other adjustment was needed. **Validation** - Adversarial ordering, with the Retry click delayed 1.2 s and the first read after the failure held for 600 ms: - without the fix: 10/10 failed with the CI signature - with the fix: 10/10 passed, and 6/6 passed with a 3.5 s delay - Both engines, `--repeat-each=20`: 40/40 passed. The full file, both engines: 6/6 passed. ### test(inbox): wait for the entry reveal before filling an opened conversation **Problem** WebKit's `inbox-archive.spec.mjs:658` "reply and fresh mention reopen their filters without replacing composer draft" failed on attempt 1, and the same SHA passed on rerun. The composer was empty: `Expected: "Unsent mention retention draft"`, `Received: ""`. - peon/people-relationships-cache, run 41752428902: https://github.com/block/buzz-app/actions/runs/41752428902/job/126320899490 **Cause** Opening a conversation reveals its entry reply. `useMessageReveal` focuses the row two frames after the thread target is ready. The journey filled the composer as soon as it appeared, so on a slow runner the reveal landed during the fill. Playwright focuses the editor and selects its contents, and then inserts text at the selection. In WebKit, the row taking focus clears that selection, so nothing is inserted. A probe that focused the row between the two steps reproduced it in WebKit but not in Chromium. The trace shows the only DOM change during the fill was the entry row gaining `tabindex=-1`. Three more journeys in the file share the race. The existing in-view wait in one of them isn't a barrier, because the row is in view before the reveal runs. **Fix** Add a `revealed()` helper. It waits for the conversation list's `aria-busy` to be false, for the entry row to be focused, and then two frames. All four journeys that fill after Open now call it. The product's focus policy is addressed separately in #2563. **Validation** - Adversarial ordering, with the reveal held 800 ms and run as soon as a fill placed its selection: without the fix 17/24 failed, and with the fix 24/24 passed. - The four journeys, both engines, `--repeat-each=10`: 80/80 passed. The full file, both engines, `--repeat-each=2`: 40/40 passed. ### test(voice-notes): serve the fixture as a build so WebKit's first load fits **Problem** The "WebKit recording (macOS)" lane failed in the first case of `voice-notes.spec.mjs` (:138), in the shared beforeEach. `page.goto(.../tests/fixtures/voice-notes.html)` exceeded the 15 s navigation timeout. - renovate/all-minor-patch, run 41755043277: https://github.com/block/buzz-app/actions/runs/41755043277/job/126329063633 - peon/dnd-stable-transform, run 41757728323 attempt 1: https://github.com/block/buzz-app/actions/runs/41757728323/job/126337712196 (attempt 2 passed) **Cause** The fixture runs the real PluginRuntime, ConversationService, relay session and Voice Notes plugin, and the Vite dev server served that graph module by module. The traces show about 816–818 requests. Vite's median wait was about 50 ms, but the median receive was about 1.0–1.14 s, and the first request to the last response took 13.3–14.5 s. On a cold 3-core macOS runner, WebKit's per-module round trips alone nearly fill the budget. #1971 only warmed the server's transforms. **Fix** - Build the fixture once in `beforeAll` and serve it with `build` and `preview` from `vite-server.mjs`, as four other specs already do. The page now loads in 4 requests instead of 838. - The build keeps development React (`import.meta.env.DEV` and `process.env.NODE_ENV` are defined as `build.mjs` does), so StrictMode's double effects still apply. - The last case used to import `/src/features/messages/attachment-draft.ts` from the dev server. The fixture now exposes `attachmentDraft` bound to its session instead. **Validation** Cold `page.goto` to load, WebKit (WPE), one new browser per run: | CPUs, busy loops | dev server | build | | --- | --- | --- | | 3, none | 1.15–1.23 s | 0.53–0.65 s | | 3, 3 | 2.0–2.85 s | 0.44–1.21 s | | 2, 8 | 3.7–6.8 s | 1.1–2.55 s | | 1, 3 | 5.1–6.1 s | 2.0–2.3 s | - CI config, Chromium (all five cases) and Linux WebKit (the untagged case), `--repeat-each=10`: 60/60 passed. Pinned to 3 CPUs with 3 busy loops, `--repeat-each=5`: 30/30 passed. - **The macOS lane couldn't be validated here.** Its selection (`--project webkit --grep @media-recorder`) can't pass on Linux, because Playwright's Linux WebKit has no MediaRecorder. Before and after this change, those cases fail at the same step locally. Hosted macOS CI is the first real check of the fix. - `tsc --noEmit` is clean, and the flake-check listing test in `tests/integration/flake-check.test.mjs` that reads this spec passes. ### test(github): seek the fullscreen PR video without pausing it in the same tick **Problem** WebKit's `github-body.spec.mjs:35` "PR media plays under the packaged media policy in a narrow GitHub panel" failed at :189. The fullscreen video's `seeked` fired, but `currentTime` was about 0.5 instead of 15. - peon/federated-session-bundle, run 41567557720 attempt 1 (Received 0.533400327): https://github.com/block/buzz-app/actions/runs/41567557720/job/125692945945 (the rerun passed) - renovate/all-minor-patch, run 41683322444 (Received 0.48949321): https://github.com/block/buzz-app/actions/runs/41683322444/job/126083327417 **Cause** The fullscreen `VideoPlayer` autoplays and, on `loadedmetadata`, seeks to the inline video's position. The journey then paused the playing video and set `currentTime` in the same evaluate. There were two candidate mechanisms: - (a) the restore lands after the journey's seek and overwrites it - (b) WebKit completes a seek issued in the same tick as `pause()` on a playing video without updating `currentTime` Local probes support (b). About 0.2% of reloaded samples were unmoved: `seeked` fired, but `currentTime` didn't change. In those samples the restore always came before the journey's seek, and `requestVideoFrameCallback` showed a frame at 15.2 s while `currentTime` still read under 0.2. Across 1,800 reopen samples, `loadedmetadata` never landed after the journey's seek. **Fix** Before the journey opens the viewer, a MutationObserver pauses the fullscreen video as soon as it mounts, so it never plays. The observer also resolves on the video's first `seeked`, which is the restore's. The journey waits for that before its own seek, and no longer calls `pause()` in the seek evaluate. This covers both candidate mechanisms: the video has never played (b), and the restore has already landed (a). The assertion stays exact (`toBeCloseTo(…, 1)`), and the two inline videos still cover playback. **Validation** - Reload A/B, WebKit, 30 repeats × 50 samples per mode, 4 CPUs shared with 2 busy loops: - old: 3/1,500 unmoved, all with the CI signature - new: 0/1,500 unmoved That fits (b), but it isn't statistically conclusive (one-sided p ≈ 0.12). - Reopen A/B: 0/900 unmoved in both modes, and the restore never landed late (0/1,800). - "PR media plays", both engines, `--repeat-each=10`: 20/20 passed. WebKit pinned to 4 CPUs with 4 busy loops, `--repeat-each=16`: 16/16 passed. ### test(channels): deny the retried preference read so recovery can't race the final Retry **Problem** Found in code review, following up the sidebar-section-creation commit above. `navigation-groups.spec.mjs` "Create new retains its draft when preferences fail before submission and recovers in place" injects 502s on `sidebar-preferences` and clicks "Retry preferences" twice, the second time right after `page.unroute`. Recovery's next background read can succeed and remove the alert before that click lands. No CI failure of this journey was looked up. The race was found by reading the code and confirmed with a forced delay. **Cause** - The first 502 starts recovery, which retries after 1 s and again about 2 s later, and the route fails both. - The dialog's Retry calls `preferences.reload`. That cancels recovery's timer but keeps its attempt count, so the next background read is scheduled 2 s or 4 s after the manual Retry fails. - After the unroute, that background read succeeds, and the alert unmounts with its button before a slow final click lands. **Fix** Keep the first failure a 502, so recovery still owns it and shows the "Reconnecting to relay…" notice the journey asserts. From the first manual Retry on, the route answers 403, so recovery stays idle and the final click is the only thing that can recover preferences. The 403s go under `app.report.relayFailures`, and the 502 stays under `sidebarPreferenceFailures`. **Validation** - A forced wait between `page.unroute` and the final click, both engines: - without the fix, 4.5 s: 4/4 failed with the click timing out - without the fix, 1.5 s: 6/6 passed, consistent with the 2–4 s window - with the fix, 4.5 s: 6/6 passed - Both engines, `--repeat-each=10`: 20/20 passed. The full file, both engines: 20/20 passed. - Rebased on main `f4805605f5`: `tsc --noEmit`, `biome check --error-on-warnings` on the seven changed files and `git diff --check` are clean. Biome's one info-level `useLiteralKeys` note is on an untouched line that is the same on main. `node --test tests/integration/flake-check.test.mjs` passes 10/10. In WebKit and Chromium, `--workers=4 --retries=0`, `channel-members-focus`, `sidebar-section-creation`, `inbox-archive`, `github-body` and `navigation-groups` in full passed 84/84. `voice-notes.spec.mjs` under `playwright.ci.config.mjs`, Chromium and Linux WebKit: 6/6 passed. The macOS recording lane was not run, as noted above. A green run doesn't prove the flakes are gone. Hosted CI covers broad validation. ## Coordination - Draft #2532 adds the same `data-refreshing` wait in `channel-members-focus.spec.mjs` and conflicts textually with this branch. It duplicates the first commit, so only one of the two should land. - #2543 (open, head `c1dcf443`) deletes `inbox-archive.spec.mjs` and moves its draft journeys into a new `inbox-mark-read.spec.mjs`. There it works around the same reveal-vs-fill race with a `typeDraft` helper that refills until the text lands (`expect(...).toPass()`). Git reports a modify/delete conflict with this branch. A resolver who just takes the delete drops the `revealed()` fix. Porting the helper into `inbox-mark-read.spec.mjs` would replace the retry loop with a real barrier. - #2150 is merged. Its overlap in `sidebar-section-creation.spec.mjs` was resolved as described in the second commit's section. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: mtoohey <mtoohey@squareup.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
damienrj
added a commit
to damienrj/buzz-app
that referenced
this pull request
Nov 5, 2026
* commit 'a39dba132^': feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) fix(messages): keep the hover toolbar while its menu is open (block#2439) Signed-off-by: damienrj <damien@squareup.com>
ljknight
added a commit
to ljknight/buzz-app
that referenced
this pull request
Nov 5, 2026
* origin/main: (121 commits) feat(composer): optional ⌘/Ctrl+Enter to send (block#2331) test: use keyboard activation for reply caret setup (block#2557) test: settle member search before invitation expansion (block#2532) test(agent-command): isolate the copied executable writer (block#2537) test(sidebar): wait for the rolled-back row to leave Starred before collapsing Work (block#2574) test(browser): click timeline rows only after the timeline settles (block#2560) ci: split Vitest across six shards so 3/4 stops hitting the job cap (block#2571) feat(github): unfurl PR and issue links inline with their title (block#1693) fix(auth): style federated sign-in callback pages (block#2549) fix(agents): align creation model controls with identity (block#2480) Run native Codex through plugin execution targets (block#2150) test: split Solo access browser scenarios (block#2499) feat(agents): let any agent change Buzz settings through the MCP (block#2248) Let plugins decorate host sidebar rows and add sort modes (block#1853) NEXUS-4082: Keep the new-message boundary stable during a visit (block#2083) feat(agents): move version history into settings (block#2374) fix(agents): read goose Activity by saved session ids and render memory bodies on open (block#2466) feat(channels): starter channels: admin switch and relay auto_join flag (block#1624) fix(plugins): read Square HTTPS sources with the Block SSH agent (block#2465) feat(plugins): let agents request plugin changes for owner review (block#2280) ... # Conflicts: # docs/buzz-help.md
dr0uleau
added a commit
that referenced
this pull request
Nov 5, 2026
## Why Native Claude agents need to use a remote execution provider while they keep Buzz tools, hooks, and saved conversations. ## What Run Claude through the shared execution interface. Keep each remote conversation on its saved target across app restarts. Stop cancels setup, active turns, and compaction. ## How The provider owns the target and workspace. Claude uses the target’s installed CLI and authentication. Tools and hooks use its stream-json connection. File reads use the provider. Device credentials stay on the device. Remote Settings use the target defaults or an explicit model. Remote usage totals and transcripts are unavailable. Local Claude keeps its device defaults. ## Risk This changes Claude session lifecycle code that local agents also use. Remote restore failures keep the saved target and require an explicit new session. ## Testing The signed macOS arm64 debug app at `d66fcdc4` passes native Claude acceptance with the checked Nexus plugin. The current head adds only a help correction to this source. - Restore saved sign-in, create a Claude agent, and bind Blox: pass. - Ask Claude to create and read a marker file on Blox: pass. The native chat shows the exact text. An independent remote read confirms the file. - Stop an active terminal tool: pass. The remote process exits and the session returns to idle. - Restart the same app, restore the saved task, and read the existing file: pass. The Claude session ID and Blox workspace stay the same. - Verify Buzz tools and `UserPromptSubmit`, `PreToolUse`, and `PostToolUse` hooks in the remote stream: pass. The operator confirms the native app test passes. No browser journeys are added or removed. This test uses the original approved binary. It does not prove credential access across different builds. ## Bigger picture This uses the execution interface from [PR #2150](#2150). Execution providers keep their own target policy and commands. buzz-review-completed Generated with Codex --------- Signed-off-by: Daniel Rouleau <drouleau@squareup.com> Co-authored-by: Codex <noreply@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Native Codex agents need to run on another computer. Plugins need to manage those targets while Buzz keeps identity keys and tool permissions in the app.
What
Add a plugin execution API and use it for native Codex. Each conversation keeps its target key across turns and app restarts. Start a new session requests a new target. Agents without a binding keep local execution.
How
The harness saves the session key before it opens a target. The plugin supplies process I/O, file reads, workspace resolution, and cleanup. Failed restore requires an explicit new session. Settings and model discovery do not allocate targets. Remote cards open the agent’s scoped model Settings. Activity reads saved remote records.
Buzz requires native custody and idle work before it saves a binding. Retirement waits for old work and cleanup. Failed cleanup blocks the change and permits a later retry. Durable reads stop a stale window from starting local work for a saved remote binding. Plugin grants and callback checks retain the existing authority boundaries.
Risk
Shared admission, storage, and Codex lifecycle code also serve local agents. Protected agents refuse remote bindings. Remote Codex usage totals, transcript views, media download, and HTTP MCP tunnels remain unavailable.
Testing
The signed macOS app at
2d0a01847has the same production code and native build inputs as21022ba298. Against a real relay, native Codex writes a file on its plugin target and reads the exact content with a tool. After a force-quit and reopen, it retains the session key, Codex thread, target, and workspace. A second turn reads and updates that file. Saved credential access works after restart.With the checked adapter artifact
c2642cad1ca8, the app resumes a suspended target. The first turn reports the lost connection. The app's Retry control then completes the same request in the same session, thread, target, and workspace. Native tool output and a separate file read confirm the exact result. The kernel boot changes, the saved launch journal records clean recovery, and the verified receipt is removed. An old receipt without launch proof stays blocked and intact.Remote model cards open the correct agent settings in light and dark themes. The model choices use the target default or a custom ID. The controls also run at 900 and 1440 logical pixels and at 1.5 text scale. The operator sends a tool-read request in the app. It returns the exact content
codex-recovery-7b2ad6d0-resumeand leaves the file unchanged. Human acceptance passes.No browser cases are added or removed. The full message-actions file passes 20 cases across Chromium and WebKit on Blox at
0b21e3ed3. Later changes preserve its production and browser source.buzz-review-completed
Generated with Codex