Repository navigation
fix(desktop): isolate quota backoff and reuse channel discovery rosters - #6998
Conversation
Pinky, an AI agent, updated this description on Wes's behalf after
taking over the startup investigation.
**Category:** fix
**User Impact:** An EVENT refused by WebSocket admission or handler
saturation receives a correlated `OK(event_id, false, reason)` instead
of an uncorrelated NOTICE, so the client can settle that refusal without
waiting for its publish timeout. Rate-limited refusals also arm client
backoff. This fixes a protocol failure mechanism; it does not establish
that every startup send will succeed or that the reported Desktop
startup incident is fully resolved.
**Problem:** Startup opens several live subscriptions and publishes at
once, and the relay's WebSocket admission gate is a fixed 5-second
window (`ws_admission_budget` = `human_ws_events_per_sec * 5`). If that
shared per-principal quota is exhausted, `enforce_ws_admission`
previously rejected an EVENT with a bare `["NOTICE", reason]`. Quota
pressure is a possible trigger, not proof of the original incident's
complete cause.
A NOTICE carries no event id. Both clients settle a pending publish
*only* from an `OK` keyed by event id (desktop `pendingEvents`, mobile
`_pendingEvents`), so nothing settled — and `handle_text_message`
returns early, so no `OK` ever followed either. The send **could not
fail**; it could only time out at `PUBLISH_TIMEOUT_MS` = 25s. That
explains how this rejection mechanism can produce a roughly 25-second
timeout; attributing the original report to it still requires the actual
startup/send workflow.
The handler-semaphore saturation path had the identical defect, and that
one needs no quota burst to fire.
**Solution:** NIP-01 gives each request type its own acknowledgement
channel, and a rejection is only actionable on the same one. Reject a
REQ with `CLOSED`, an EVENT with `OK(id, false, reason)`, and fall back
to `NOTICE` only where no per-request correlation exists. COUNT refusals
now also use `CLOSED(query_id, reason)` per NIP-45, covering both quota
admission and handler saturation (added in
`cd12c93804b87a24b61075dfd171dc471a0a527f`).
Reason strings are unchanged, so the `rate-limited:` prefix and `retry
in {N}s` hint that existing client gates parse keep working (desktop
`parseRateLimitHint`, mobile `RelayRateLimitGate`, buzz-acp
`set_rate_limit_gate`). Only the frame *type* changes, so
`docs/multi-tenant-relay.md` L7 stays satisfied.
Two notes on how this landed, both worth a reviewer's attention:
1. **A survived mutation became a design change.**
`send_admission_result` originally took a `RejectionTarget` parameter,
and reverting the *second* call site (the per-minute message quota)
survived the whole suite — with Redis unreachable the first quota check
short-circuits, so that line is unreachable in test. Rather than test
around it, the parameter is gone: the target is derived from the frame,
so no call site can name the wrong channel.
2. **The relay fix would have caused a client regression on its own.**
Gate arming lived only in the NOTICE branch. Once rejections arrive as
`OK:false`, `handleOk` failed the send without ever backing off — the
client would retry straight into the same quota. Desktop and Mobile now
arm on a `rate-limited:` OK rejection. ACP was subsequently fixed in
`3b06dd32493596ec650f20abf8805791c50fdc24`: it arms the gate and
re-parks only the refused observer frame, preserving other in-flight
frames. Desktop gets `activateRateLimitIfSignalled` as the single owner
of that prefix test, called from both `handleOk` and the NOTICE branch.
<details>
<summary>File changes</summary>
**crates/buzz-relay/src/rejection.rs** (new)
Owns the admission-rejection concern: `RejectionTarget`,
`rejection_target_for`, `request_rejection_message`,
`send_admission_result`, and `enforce_ws_admission`, moved out of
`connection.rs`. Six tests, two of which drive the real
`enforce_ws_admission` against a real `AppState`.
**crates/buzz-relay/src/connection.rs**
Fix the EVENT handler-semaphore rejection to correlate to the event id;
delegate admission to the new module. Add two tests that drive the real
`handle_text_message` with every handler permit held. Down from 1319 to
1116 lines.
**crates/buzz-relay/src/state.rs**
Widen the existing `test_state` helper to `pub(crate)` so the rejection
tests reuse it rather than adding a ninth copy of `AppState`
construction.
**desktop/src/shared/api/relayRateLimitGate.ts**
Add `activateRateLimitIfSignalled` — one owner for the `rate-limited:`
prefix test, since three inbound frame types now carry it.
**desktop/src/shared/api/relayClientSession.ts**
Arm the gate on a rate-limited OK rejection; route the NOTICE branch
through the same helper. Net zero lines, which keeps this
already-oversized file within the differential ratchet.
**desktop/src/shared/api/relayClientPublishRejection.test.mjs** (new)
Four tests against the real `RelayClient`: a rate-limited OK settles the
pending publish and arms the gate; an ordinary rejection does not arm
it; an accepted OK still resolves.
**mobile/lib/shared/relay/relay_session.dart**
Arm the gate in `_handleOk` for a rate-limited rejection.
**mobile/test/shared/relay/relay_session_test.dart**
Two tests driving the real `publish` + `debugHandleMessage` path.
</details>
<details>
<summary>Validation</summary>
**Mutation-tested — 5 mutations, all now killed.** Each production call
site was reverted to the defective behaviour to confirm a test fails.
This caught two false-negative tests:
| # | Mutation | Result |
|---|----------|--------|
| 1 | `rejection_target_for`: EVENT → `Connection` | 4 tests fail |
| 2 | EVENT handler-semaphore call site → bare NOTICE | **survived at
first** |
| 3 | per-minute quota call site → `Connection` | **survived**; fixed by
removing the parameter |
| 4 | desktop `handleOk` gate arming removed | 1 test fails |
| 5 | mobile `_handleOk` gate arming removed | 1 test fails |
Mutation 2 is the lesson: my first saturation test called
`request_rejection_message` directly, so reverting the real call site
inside the `match` arm left it green. It now drives
`handle_text_message` itself and dies on that mutation.
- `cargo test -p buzz-relay` — 928 passed, 1 failed:
`api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo`,
**pre-existing**, reproduced with all changes stashed at `4dd4d73de`.
- `cd desktop && npm test` — 5721 passed, 0 failed (full suite).
- `cd mobile && flutter test` — 1876 passed, 0 failed (full suite).
- `just fmt-check`, `just clippy`, `just desktop-check`, `just
mobile-check`, `just file-size-check` — clean. Desktop's 5 biome
warnings are pre-existing (reproduced with changes stashed).
- All 9 pre-push lanes green, including `rust-tests` and
`desktop-tauri-checks`.
**Not verified:** not reproduced end-to-end against a live relay under a
forced quota burst. The causal chain is source-proven and
mutation-proven at the frame level; the ~25s attribution follows from
`PUBLISH_TIMEOUT_MS` but is not directly measured. A packaged-build
click-through would close that gap.
</details>
Related work: #6957 bounds Desktop HTTP event submission, but safe
retained-operation recovery after exhausted/ambiguous outcomes remains
unfinished. #6998 is the separately reviewable Desktop
readiness/duplicate-subscription slice. Neither is claimed to complete
native before/after startup-send validation.
Diagnosis note: `RESEARCH/DESKTOP_STARTUP_SEND_STALL_2026_08_27.md`
(Brain's workspace).
## Current review disposition (2026-08-28)
The [review on
`cd12c938`](#6961 (review))
identified ACP's missing rate-limited-OK handling. Commit
`3b06dd32493596ec650f20abf8805791c50fdc24` fixes gate arming, re-parking
the specifically refused observer frame, and the stale NOTICE comment.
Two regressions drive the real frame dispatcher. See [the implementation
and validation
response](#6961 (comment)).
The Mobile generation-check inline thread is resolved: its `async
publish` returns a failed Future when superseded; it does not throw
synchronously at invocation. No further production change was indicated
by that comment.
The validation counts above describe the original slice, not a new
rerun. At `3b06dd324`, the current GitHub check rollup has successful
completed test/build checks (non-applicable jobs skipped). The
security-review comment still requires review for the current base/head
range; do not read a green authorization job as a completed security
review. Approval and merge remain human decisions.
---------
Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Signed-off-by: Wes <[email protected]>
Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
* fix: retrieving cold memories; add regression task (#6950) ## Why Evaluating buzz agent memory retrieval by seeding a memory then asking the buzz agent a question it needs that memory. **Bug Found**: System prompt had no inclusion of retrieving cold memories and suggested looking in a mem/*.md directory that does not exist. Updated `system-prompt.md` to include memory CLI tools and usage. Eval Before System Prompt Change: 0/3 Eval After System Prompt Change: 3/3 ## What - Add a `memory-retrieval` benchmark that seeds agent memory with `buzz mem set` before asking a direct question. - Grade the observable threaded answer without inspecting tool calls or exposing the answer in channel history. - Teach agents to use `buzz mem set`, `buzz mem ls`, and `buzz mem get` for cold memory. - Add a wire-debug endpoint configuration for diagnosing ACP tool calls in local runs. - Add fixture, seeding, verifier, and prompt coverage. ## Risk Assessment Low. The runtime changes are limited to the benchmark harness. The production-facing change clarifies existing memory commands in the base prompt; it does not change memory storage, relay behavior, or authorization. ## References - Before the system-prompt changes, 0/3 attempts passed because agents never invoked the `buzz mem` CLI and instead searched a non existent filesystem - After the changes, 3/3 attempts passed. ACP wire logs confirmed that every agent ran `buzz mem ls` followed by `buzz mem get` and returned `net_gpv`. --------- Signed-off-by: Philip Azar <[email protected]> * fix(ci): salvage Codex review output on PTY-shutdown hang (#7042) Codex CLI can leave a PTY descendant holding the action's inherited stdio after the turn completes. The `runCodexExec.ts` wrapper waits on a `close` event that never fires, so the `Review pull request` step hangs until the job timeout kills it — discarding the finished review the CLI already wrote to disk. The CLI writes the completed review to the `--output-last-message` file (exposed as `output-file`) **before** the hang. This PR adds a salvage step that recovers it, and sets the step and job timeouts to preserve the full 30-minute Codex execution budget. **Changes (`codex-security-review.yml`):** - Add `output-file: ${{ runner.temp }}/codex-review.json` to the `Review pull request` step so the CLI writes the result before the hang. (`runner` context is valid in `steps.with`; not in `jobs.env`.) - Add `timeout-minutes: 30` and `continue-on-error: true` to the Codex step — a hang now costs ≤30 minutes instead of 40, and the salvage step still runs. - Set job `timeout-minutes: 40` to give setup, step cancellation, and salvage sufficient headroom without colliding with the Codex execution budget. The original 30-minute job timeout was too narrow: evidence from run [33114428326](https://github.com/block/buzz/actions/runs/33114428326/job/98665369165) shows completed output appearing 28m46s after step start, meaning a 20-minute step timeout could kill a legitimate review before the salvage file exists. - Add a `Salvage review output` step with `if: always()`: prefers `steps.run_codex.outputs.final-message` on a clean exit; falls back to the output file when the step timed out. The output file path is set in the step's own `env` block (`CODEX_OUTPUT_FILE: ${{ runner.temp }}/codex-review.json`), where `runner` is valid. Validates shape (non-empty JSON object, has `overall_risk`); fails the job hard if neither source is present. - Wire the job `outputs.review_json` to `steps.salvage.outputs.review_json`. **Changes (`Justfile`, `ci.yml`):** - Add `actionlint .github/workflows/codex-security-review.yml` to `security-review-check` so expression-validity errors are caught locally. - Provision `actionlint` via Hermit (pinned v1.7.12) rather than a one-off `Install actionlint` curl step, so the same binary is used locally and in CI. **Security posture is unchanged:** the salvage step reads the action's own output and a file written to `runner.temp` — neither is PR-controlled. Credential-stripping env block on the Codex step is untouched. Note this is a temporary workaround until https://github.com/openai/codex-action/issues/169 is addressed --------- Signed-off-by: Will Pfleger <[email protected]> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> * feat: render agent avatars as squircles (#7106) ## Summary - render every agent/AI identity as a 30% squircle across desktop and mobile while keeping human avatars circular - propagate agent identity through message, thread, profile, reaction, member, DM, search, workflow, project, huddle, forum, pulse, and agent-management surfaces - preserve squircle geometry for fallbacks, focus/status treatments, add-agent controls, and overlapping avatar outlines (`calc(30% + 2px)` for the outer background) ### Related issue None found. This change was requested and visually reviewed in the originating Buzz thread. ### Testing - `just desktop-test` — 5,799 passed - `just mobile-test` — 2,008 passed - pre-push gates passed at `0d59d77b120dcb90aac2f918e422c11c9fa5353b`: desktop check, TypeScript typecheck, desktop full test suite, mobile format/analyze and full test suite, Rust tests, Tauri checks, and differential file-size gate - deterministic desktop visual sweep covered channel messages/thread summaries; thread, subthread, and sub-subthread depths; reactions and reactor popovers; hover/full profiles; added-to-channel activity; channel members/settings; agent library/team overlaps; agent creation; mention autocomplete; and DM header/sidebar/settings ### UI evidence The complete labeled visual matrix is available in the originating Buzz review thread. GitHub-hosted copies will be added in a follow-up PR comment using the repository screenshot script. --------- Signed-off-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> Co-authored-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> * fix(acp): wake agents from workflow messages (#6953) > Pinky, an AI agent, is opening this PR on Wes's behalf. ## Summary Workflow-generated messages can contain a valid agent mention but still fail the ACP inbound author gate because the relay signs the event. This keeps the existing wake policy and gives ACP a narrowly verified effective author: - preserve the workflow owner's existing `p` tag and all rendered-mention `p` tags - add explicit `["buzz:workflow-owner", <owner hex>]` provenance to relay-generated workflow messages - add `["buzz:workflow-mention", <agent hex>]` authority only for mentions resolved from the stored, unrendered workflow step template - accept that owner only for a verified kind-9 event signed by the relay's current NIP-11 `self` key, with unique canonical workflow metadata and an explicit workflow mention for the receiving agent - route the verified owner through the existing author and in-flight mode policies in both normal and setup listeners - refresh relay identity after reconnects, retaining the last verified key on transient fetch errors while treating a successful response without `self` as definitive removal Malformed, duplicate, forged, tampered, wrong-kind, and wrong-relay attribution all fail closed to the raw event signer. `respond-to=nobody` remains absolute. Old/mixed-version messages without the explicit provenance retain their current fail-closed behavior. ## Trust boundary The workflow owner means **“scheduled by,” not “authored every rendered word.”** Trigger-controlled substitutions may still produce ordinary `p` mention routing for compatibility, but they cannot mint `buzz:workflow-mention` authority. Only a target named in the durable owner-authored step template can receive that authority. The author gate is not bypassed: after relay signature/provenance verification, the effective owner is evaluated under the same `owner-only`, `allowlist`, DM, and `nobody` policies used for ordinary messages. Owner control commands continue to use the raw event signer. ## Why this PR This is the focused immediate fix for waking an **online** agent from a stored workflow mention. Earlier attempts were not a finished mergeable fix and had materially different or incomplete trust designs. Larry's larger draft stack addresses durable delivery across restarts; that remains valuable future work and can supersede this effective-author path when it lands. ## Validation At exact clean commit `fe5b55619fe44176343eefb4cb7fe180df45a7d8`: - `buzz-relay workflow_sink`: 25/25 passed, including all four ignored PostgreSQL cases - `buzz-acp --lib`: 845/845 passed - `buzz-workflow --lib`: 169/169 passed (2 unrelated PostgreSQL tests ignored) - warnings-denied Clippy passed for the changed Rust packages - `cargo fmt --all -- --check` passed - `git diff --check` passed - repository pre-push gates passed, including branch-scoped Rust tests - CI now selects the ACP library tests and the relay's pure + PostgreSQL workflow-sink tests so these guards cannot silently remain unexecuted The production event-to-author gate is shared by normal and setup listeners and has biting regression tests for accepted explicit attribution, legacy owner-`p` rejection, and forged-attribution rejection. ## Exact-head local relay + ACP proof Following the release-binary/local-relay shape in `TESTING.md`, the exact commit above passed a fresh isolated real-process matrix using: - a freshly recreated Postgres database with migrations - isolated Redis - exact-head release `buzz-relay`, `buzz`, `buzz-admin`, and `buzz-acp` binaries - newly provisioned owner, channel, and bot member through the CLI - workflow creation and triggering through the running relay - a deterministic ACP protocol subprocess capturing actual `session/prompt` dispatches - a NIP-11 `self` value verified against the running relay signer Cases: 1. A stored explicit workflow mention woke an `owner-only` agent exactly once. 2. A workflow message without an agent mention did not wake it. 3. A non-relay signer forging every workflow authority tag did not wake it. 4. Trigger-controlled `{{trigger.text}}` containing `@Wake Agent` retained ordinary `p` routing but received no authority-bearing workflow-mention tag and did not wake the agent. 5. `respond-to=nobody` remained absolute for a valid relay-authenticated workflow mention. The deterministic ACP subprocess isolates and directly proves relay → ACP authorization and prompt dispatch without depending on external model behavior. ## Deployment and residual risk Relay and ACP changes must be deployed together for the new wake behavior; mixed versions fail closed. Production paired-deployment proof remains distinct from the successful local integration run. Setup-mode behavior has automated coverage but was not a separate case in the five-case local matrix. Relay-key rotation is observed at ACP startup/reconnect; transient NIP-11 errors retain the last verified key, an intentional availability tradeoff documented in code. --------- Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz> Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes <[email protected]> Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz> Co-authored-by: LioLionel <[email protected]> Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz> * fix(relay): reject a frame on its own acknowledgement channel (#6961) Pinky, an AI agent, updated this description on Wes's behalf after taking over the startup investigation. **Category:** fix **User Impact:** An EVENT refused by WebSocket admission or handler saturation receives a correlated `OK(event_id, false, reason)` instead of an uncorrelated NOTICE, so the client can settle that refusal without waiting for its publish timeout. Rate-limited refusals also arm client backoff. This fixes a protocol failure mechanism; it does not establish that every startup send will succeed or that the reported Desktop startup incident is fully resolved. **Problem:** Startup opens several live subscriptions and publishes at once, and the relay's WebSocket admission gate is a fixed 5-second window (`ws_admission_budget` = `human_ws_events_per_sec * 5`). If that shared per-principal quota is exhausted, `enforce_ws_admission` previously rejected an EVENT with a bare `["NOTICE", reason]`. Quota pressure is a possible trigger, not proof of the original incident's complete cause. A NOTICE carries no event id. Both clients settle a pending publish *only* from an `OK` keyed by event id (desktop `pendingEvents`, mobile `_pendingEvents`), so nothing settled — and `handle_text_message` returns early, so no `OK` ever followed either. The send **could not fail**; it could only time out at `PUBLISH_TIMEOUT_MS` = 25s. That explains how this rejection mechanism can produce a roughly 25-second timeout; attributing the original report to it still requires the actual startup/send workflow. The handler-semaphore saturation path had the identical defect, and that one needs no quota burst to fire. **Solution:** NIP-01 gives each request type its own acknowledgement channel, and a rejection is only actionable on the same one. Reject a REQ with `CLOSED`, an EVENT with `OK(id, false, reason)`, and fall back to `NOTICE` only where no per-request correlation exists. COUNT refusals now also use `CLOSED(query_id, reason)` per NIP-45, covering both quota admission and handler saturation (added in `cd12c93804b87a24b61075dfd171dc471a0a527f`). Reason strings are unchanged, so the `rate-limited:` prefix and `retry in {N}s` hint that existing client gates parse keep working (desktop `parseRateLimitHint`, mobile `RelayRateLimitGate`, buzz-acp `set_rate_limit_gate`). Only the frame *type* changes, so `docs/multi-tenant-relay.md` L7 stays satisfied. Two notes on how this landed, both worth a reviewer's attention: 1. **A survived mutation became a design change.** `send_admission_result` originally took a `RejectionTarget` parameter, and reverting the *second* call site (the per-minute message quota) survived the whole suite — with Redis unreachable the first quota check short-circuits, so that line is unreachable in test. Rather than test around it, the parameter is gone: the target is derived from the frame, so no call site can name the wrong channel. 2. **The relay fix would have caused a client regression on its own.** Gate arming lived only in the NOTICE branch. Once rejections arrive as `OK:false`, `handleOk` failed the send without ever backing off — the client would retry straight into the same quota. Desktop and Mobile now arm on a `rate-limited:` OK rejection. ACP was subsequently fixed in `3b06dd32493596ec650f20abf8805791c50fdc24`: it arms the gate and re-parks only the refused observer frame, preserving other in-flight frames. Desktop gets `activateRateLimitIfSignalled` as the single owner of that prefix test, called from both `handleOk` and the NOTICE branch. <details> <summary>File changes</summary> **crates/buzz-relay/src/rejection.rs** (new) Owns the admission-rejection concern: `RejectionTarget`, `rejection_target_for`, `request_rejection_message`, `send_admission_result`, and `enforce_ws_admission`, moved out of `connection.rs`. Six tests, two of which drive the real `enforce_ws_admission` against a real `AppState`. **crates/buzz-relay/src/connection.rs** Fix the EVENT handler-semaphore rejection to correlate to the event id; delegate admission to the new module. Add two tests that drive the real `handle_text_message` with every handler permit held. Down from 1319 to 1116 lines. **crates/buzz-relay/src/state.rs** Widen the existing `test_state` helper to `pub(crate)` so the rejection tests reuse it rather than adding a ninth copy of `AppState` construction. **desktop/src/shared/api/relayRateLimitGate.ts** Add `activateRateLimitIfSignalled` — one owner for the `rate-limited:` prefix test, since three inbound frame types now carry it. **desktop/src/shared/api/relayClientSession.ts** Arm the gate on a rate-limited OK rejection; route the NOTICE branch through the same helper. Net zero lines, which keeps this already-oversized file within the differential ratchet. **desktop/src/shared/api/relayClientPublishRejection.test.mjs** (new) Four tests against the real `RelayClient`: a rate-limited OK settles the pending publish and arms the gate; an ordinary rejection does not arm it; an accepted OK still resolves. **mobile/lib/shared/relay/relay_session.dart** Arm the gate in `_handleOk` for a rate-limited rejection. **mobile/test/shared/relay/relay_session_test.dart** Two tests driving the real `publish` + `debugHandleMessage` path. </details> <details> <summary>Validation</summary> **Mutation-tested — 5 mutations, all now killed.** Each production call site was reverted to the defective behaviour to confirm a test fails. This caught two false-negative tests: | # | Mutation | Result | |---|----------|--------| | 1 | `rejection_target_for`: EVENT → `Connection` | 4 tests fail | | 2 | EVENT handler-semaphore call site → bare NOTICE | **survived at first** | | 3 | per-minute quota call site → `Connection` | **survived**; fixed by removing the parameter | | 4 | desktop `handleOk` gate arming removed | 1 test fails | | 5 | mobile `_handleOk` gate arming removed | 1 test fails | Mutation 2 is the lesson: my first saturation test called `request_rejection_message` directly, so reverting the real call site inside the `match` arm left it green. It now drives `handle_text_message` itself and dies on that mutation. - `cargo test -p buzz-relay` — 928 passed, 1 failed: `api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo`, **pre-existing**, reproduced with all changes stashed at `4dd4d73de`. - `cd desktop && npm test` — 5721 passed, 0 failed (full suite). - `cd mobile && flutter test` — 1876 passed, 0 failed (full suite). - `just fmt-check`, `just clippy`, `just desktop-check`, `just mobile-check`, `just file-size-check` — clean. Desktop's 5 biome warnings are pre-existing (reproduced with changes stashed). - All 9 pre-push lanes green, including `rust-tests` and `desktop-tauri-checks`. **Not verified:** not reproduced end-to-end against a live relay under a forced quota burst. The causal chain is source-proven and mutation-proven at the frame level; the ~25s attribution follows from `PUBLISH_TIMEOUT_MS` but is not directly measured. A packaged-build click-through would close that gap. </details> Related work: #6957 bounds Desktop HTTP event submission, but safe retained-operation recovery after exhausted/ambiguous outcomes remains unfinished. #6998 is the separately reviewable Desktop readiness/duplicate-subscription slice. Neither is claimed to complete native before/after startup-send validation. Diagnosis note: `RESEARCH/DESKTOP_STARTUP_SEND_STALL_2026_08_27.md` (Brain's workspace). ## Current review disposition (2026-08-28) The [review on `cd12c938`](https://github.com/block/buzz/pull/6961#pullrequestreview-5052902510) identified ACP's missing rate-limited-OK handling. Commit `3b06dd32493596ec650f20abf8805791c50fdc24` fixes gate arming, re-parking the specifically refused observer frame, and the stale NOTICE comment. Two regressions drive the real frame dispatcher. See [the implementation and validation response](https://github.com/block/buzz/pull/6961#issuecomment-5455032054). The Mobile generation-check inline thread is resolved: its `async publish` returns a failed Future when superseded; it does not throw synchronously at invocation. No further production change was indicated by that comment. The validation counts above describe the original slice, not a new rerun. At `3b06dd324`, the current GitHub check rollup has successful completed test/build checks (non-applicable jobs skipped). The security-review comment still requires review for the current base/head range; do not read a green authorization job as a completed security review. Approval and merge remain human decisions. --------- Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes <[email protected]> Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz> * feat(desktop): add protected-build Bestie experiment (#6902) ## Summary Introduces a protected-build boundary for the default-off Bestie experiment without adding any Bestie product surface. - Official OSS builds select an empty protected-feature module and emit no Bestie/Chief metadata or implementation content. - Protected internal builds select a separate module graph containing the Bestie experiment definition. - Within an internal build, Bestie remains disabled until the user opts in under Settings → Experiments. - The production build runs an artifact matrix and fails if OSS output contains protected content or internal output lacks the Bestie manifest. ## Build contract | Build variant | User opt-in | Result | | --- | --- | --- | | Official OSS | Any/forged | Bestie absent from the compiled artifact | | Protected internal | Off | Bestie available but disabled | | Protected internal | On | Bestie enabled | The companion protected-release change is squareup/buzz-releases#91. It sets `VITE_BUZZ_BESTIE=1`, requires that exact value, forwards it into the signed macOS build, and asserts the contract in release validation. ## Why this is separate This gives later Bestie PRs one build-selected import seam. Protected implementations must be reachable only from the internal module so they never enter the official OSS module graph. ## Non-goals - No Bestie persona or provisioning - No sidebar, app-chrome, or message-toolbar UI - No entitlement or secrecy claim: the source is public; this boundary controls official Block artifacts ## Verification - Exact commit `523cf49ced03cba9be43836a54d6aa5d6923cc82` - Full `just ci`: 5,673 Desktop tests, 2,773 Tauri tests, 1,860 mobile tests, Rust/Tauri/web/mobile static checks and builds - OSS production artifact: scanner confirms no `Bestie`, `Chief of Staff`, or `builtin:bestie` content - Internal production artifact: scanner confirms the protected Bestie manifest is emitted - Both build orders verified; `dist` retains the requested variant for Vite/Tauri packaging --------- Signed-off-by: Arjun Mahanti <[email protected]> Signed-off-by: Fizz <[email protected]> Signed-off-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> Co-authored-by: Codex <[email protected]> Co-authored-by: Fizz <[email protected]> Co-authored-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> * add public descriptions to agent personas (#7126) **Category:** new-feature **User Impact:** People can add a short public description to an agent and see what it does directly on agent cards and profiles. **Problem:** Agent cards previously showed only a model label, so people had to open an agent and inspect its instructions to understand its purpose. Public metadata also needed one trustworthy lifecycle across local edits, relay catalogs, profiles, and portable snapshots. **Solution:** Add an optional owner-authored description with a 280-character visible-text policy, publish it as profile `about`, and prefer it on agent cards while retaining the model fallback. Description metadata is excluded from the spawn-content hash, remains definition-owned, and is validated independently at every untrusted or persistence boundary. <details> <summary>File changes</summary> **desktop/src-tauri/src/commands/agent_config_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/agent_discovery/relay_directory.rs** Updates relay-directory profile test publication for the expanded profile contract. **desktop/src-tauri/src/commands/agent_models_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/agent_models_update.rs** Preserves the effective `about` value when instance edits republish a complete profile event. **desktop/src-tauri/src/commands/agents.rs** Carries the effective authored description into initial managed-agent profile publication. **desktop/src-tauri/src/commands/agents_profile.rs** Adds `about` to profile reconciliation and keeps description, name, and avatar synchronized against relay state. **desktop/src-tauri/src/commands/agents_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/card.rs** Materializes the definition-owned description before minting a portable agent card snapshot. **desktop/src-tauri/src/commands/personas/create.rs** Normalizes and validates raw authored descriptions before persona persistence. **desktop/src-tauri/src/commands/personas/delete_cascade_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/inbound.rs** Validates descriptions at inbound relay ingress and applies accepted values to local definitions. **desktop/src-tauri/src/commands/personas/inbound/catalog_reconcile_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/inbound/inbound_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/mod.rs** Centralizes raw-byte validation followed by trim/empty normalization for description writes. **desktop/src-tauri/src/commands/personas/pending.rs** Revalidates descriptions before preparing public persona publications. **desktop/src-tauri/src/commands/personas/sharing.rs** Carries the optional public description through this managed-agent compatibility path. **desktop/src-tauri/src/commands/personas/snapshot.rs** Materializes definition-owned descriptions into portable instance snapshots without creating a second persisted authority. **desktop/src-tauri/src/commands/personas/snapshot/fidelity_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/snapshot/import.rs** Restores snapshot descriptions onto imported definitions while keeping linked instance copies absent. **desktop/src-tauri/src/commands/personas/snapshot/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/personas/update.rs** Persists persona description edits, republishes linked profiles, and preserves legacy avatars during complete kind:0 replacements. **desktop/src-tauri/src/commands/personas/update/name_propagation_tests.rs** Proves description-only profile sync does not write instance state or clear a legacy avatar. **desktop/src-tauri/src/commands/team_snapshot.rs** Round-trips member descriptions through team snapshots and imported definitions. **desktop/src-tauri/src/commands/team_snapshot/tests.rs** Covers team member description export and import fidelity. **desktop/src-tauri/src/commands/teams/adopt/apply.rs** Starts adopted team catalog members without synthesizing an unauthored description. **desktop/src-tauri/src/commands/teams/adopt/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/teams/pending/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/commands/teams/sharing/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/egress_guard_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/event_sync_team_catalog_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/agent_description.rs** Defines the canonical Rust description resolution used by profile publication and reconciliation. **desktop/src-tauri/src/managed_agents/agent_events.rs** Updates managed-agent record construction for the optional public description field. **desktop/src-tauri/src/managed_agents/agent_snapshot.rs** Includes descriptions as snapshot profile `about` metadata and validates them at decode ingress. **desktop/src-tauri/src/managed_agents/agent_snapshot_envelope.rs** Updates managed-agent record construction for the optional public description field. **desktop/src-tauri/src/managed_agents/agent_snapshot_tests.rs** Covers snapshot description export and rejection of unsafe or overlong imported metadata. **desktop/src-tauri/src/managed_agents/config_bridge/reader_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/definition_validation.rs** Adds the shared 280-character visible-text policy for public descriptions. **desktop/src-tauri/src/managed_agents/discovery/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/effective_config/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/global_config/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/mod.rs** Exports the description resolution and validation helpers to managed-agent consumers. **desktop/src-tauri/src/managed_agents/nest/render_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/parallelism.rs** Updates managed-agent fixtures for the optional description field without changing runtime configuration behavior. **desktop/src-tauri/src/managed_agents/persona_events.rs** Adds description to persona event content while deliberately excluding it from the spawn-relevant content hash. **desktop/src-tauri/src/managed_agents/persona_events/tests.rs** Pins description event round-tripping and proves description-only edits do not change the restart hash. **desktop/src-tauri/src/managed_agents/personas.rs** Initializes built-in persona records without authored descriptions for backward-compatible defaults. **desktop/src-tauri/src/managed_agents/personas/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/readiness.rs** Updates managed-agent fixtures for the optional description field without changing runtime configuration behavior. **desktop/src-tauri/src/managed_agents/restore.rs** Includes the effective description in launch-time profile reconciliation. **desktop/src-tauri/src/managed_agents/runtime/test_fixtures.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/runtime/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/spawn_snapshot/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/team_catalog/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/team_snapshot.rs** Updates managed-agent record construction for the optional public description field. **desktop/src-tauri/src/managed_agents/teams_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/managed_agents/types.rs** Adds optional description metadata to persona and managed-agent records and their compatibility projections. **desktop/src-tauri/src/managed_agents/types/requests.rs** Accepts optional descriptions on persona create and update IPC requests. **desktop/src-tauri/src/managed_agents/types/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/migration_avatar_tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src-tauri/src/persona_catalog.rs** Parses and validates descriptions at the untrusted community-catalog boundary. **desktop/src-tauri/src/persona_catalog_tests.rs** Covers valid catalog descriptions plus rejection of malformed, invisible, and overlong values. **desktop/src-tauri/src/relay.rs** Publishes and queries kind:0 `about` so relay profiles preserve authored descriptions. **desktop/src-tauri/src/relay/tests.rs** Updates managed-agent/persona fixtures for the optional description field while preserving the behavior under test. **desktop/src/features/agents/AGENTS.md** Documents description ownership, validation, snapshot, hashing, and display invariants for future changes. **desktop/src/features/agents/lib/agentDescription.test.mjs** Pins Unicode counting, paste clamping, trimming, and empty authored-description behavior. **desktop/src/features/agents/lib/agentDescription.ts** Provides shared display resolution, Unicode-scalar counting, and paste clamping for descriptions. **desktop/src/features/agents/lib/personaCatalogRelay.ts** Maps validated catalog descriptions into catalog persona projections. **desktop/src/features/agents/ui/AgentDefinitionDialog.tsx** Adds the description draft to create and edit submission while extracting identity fields from the large dialog. **desktop/src/features/agents/ui/AgentDescriptionField.tsx** Renders the public description input, helper copy, and Unicode-aware near-limit counter. **desktop/src/features/agents/ui/AgentIdentityCard.tsx** Generalizes the card second line to show a two-line description or the existing model fallback. **desktop/src/features/agents/ui/UnifiedAgentsSection.tsx** Prefers authored descriptions on persona cards and retains model labels when no description exists. **desktop/src/features/agents/ui/personaDialogState.test.mjs** Verifies edit and duplicate drafts preserve authored descriptions. **desktop/src/features/agents/ui/personaDialogState.ts** Seeds authored descriptions into edit and duplicate dialog drafts. **desktop/src/features/agents/ui/usePersonaActions.ts** Preserves descriptions when copying catalog personas into local definitions. **desktop/src/shared/api/personaTypes.ts** Defines description-bearing persona wire types in a focused module split from the size-constrained API type file. **desktop/src/shared/api/tauriPersonas.test.mjs** Verifies raw persona descriptions map into the frontend model and absent values become null. **desktop/src/shared/api/tauriPersonas.ts** Maps description fields across Tauri and preserves raw authored bytes for authoritative Rust validation. **desktop/src/shared/api/types.ts** Re-exports the extracted persona types without changing consumer import paths. **desktop/src/testing/e2eBridge.ts** Extends mock persona create, update, publication, and catalog parsing with production-shaped description behavior. **desktop/tests/e2e/agents.spec.ts** Verifies an edited description persists and appears on the agent card. </details> ### Reproduction Steps 1. Open **Agents**, edit a custom or built-in agent, and enter a sentence in **Description**. 2. Save the agent and confirm the sentence appears as the second line on its card. 3. Reopen the agent and confirm the authored description is restored; clear it and confirm the card returns to the model label. 4. Paste more than 280 Unicode characters and confirm the field keeps the first 280 characters and shows the near-limit counter. 5. Share or export/import the agent and confirm the description survives in the catalog/profile or snapshot without showing a restart-required badge for a description-only edit. ### Screenshots / Demo The focused Playwright flow `built-in persona edits persist` exercises the edited dialog, persisted value, and resulting card subtitle. Screenshots can be added after review if the field placement or two-line card treatment needs visual iteration. ### Verification - `cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib` — 3,029 passed - `cd desktop && pnpm test` — 5,805 passed - `cd desktop && pnpm exec tsc --noEmit` - Focused Playwright: `built-in persona edits persist` — passed - Pre-push desktop, Tauri, typecheck, test, file-size, and branch-skew gates — passed --------- Signed-off-by: tulsi <[email protected]> * fix(desktop): back split thread headers (#7137) ## Summary - render an auxiliary panel's requested header backdrop in docked/split mode - preserve explicit transparent-backdrop behavior - cover a populated, scrolled thread pane so timeline content cannot bleed through its header ## Root cause `RightAuxiliaryPane` correctly paints above the channel's shared header backdrop so close/edit controls remain visible. The docked `AuxiliaryPanelHeader` branch, however, ignored its `backdrop` request, leaving scrolled thread content in that higher stacking context unbacked. ## Verification - desktop unit suite: 5,801 passed - desktop TypeScript: passed - Biome checks: passed (existing unrelated repository warnings only in the earlier full run) - targeted Playwright scroll regression: passed - ultrawide thread-pane Playwright coverage: passed Signed-off-by: Wintermute <c0fc581234c3585602139eec347ced7b82af65b6f6c10728348515c0c06c51c3@buzz.block.builderlab.xyz> Co-authored-by: Wintermute <c0fc581234c3585602139eec347ced7b82af65b6f6c10728348515c0c06c51c3@buzz.block.builderlab.xyz> * docs: add review-proven failure-path & async-state rules to AGENTS.md (#7061) Mining the last 25 PRs' review threads (45 substantive findings, 11 reviewed PRs, avg **4.8 review rounds** each) shows **53% of findings are repeats** of five clusters: swallowed failures, stale-async-state races, tests that don't bind the production seam, unbounded resources/retry loops, and non-atomic multi-step persistence. PR #6956 alone burned 4 rounds converging on one of these classes. A second, independent mining pass over **71 agent-review rooms (303 findings, Aug 18–29)** confirmed the same clusters and added outcome data — how often authors actually fix each finding class once flagged: test-seam binding and unbounded-resource findings **100%**, swallowed errors **90%**, stale-state races **70%**. It also surfaced two clusters the GitHub-thread pass under-sampled: **assistive-semantics defects** (44 findings, second-largest cluster) and **input-modality divergence** (27 findings), now rules 7–8. This PR distills those clusters into eight imperative rules in AGENTS.md so agents apply them **before writing code**, adds one client-consumption invariant to ARCHITECTURE.md §5, and places the test-quality rule in TESTING.md (per the team decision that testing docs are the canonical guide for review standards), cross-referenced from AGENTS.md. Each rule cites the PRs where it was litigated. Raw mining data: `reviews.jsonl` / `comments.jsonl` + `backfill/buzz-review-findings.jsonl` (review-mining artifacts, not committed). No code changes. CLAUDE.md is a symlink to AGENTS.md and picks this up automatically. 🤖 Drafted by Jude's agent from automated mining of this repo's last 25 PRs' review threads and 71 agent-review rooms; every rule cites the PRs where it was litigated. Jude reviews and owns the result. Mining method + raw cluster data available on request. --------- Signed-off-by: Jude Edwards <[email protected]> * feat(buzz-acp): give each channel thread its own agent session (#6732) ## What this does In a channel, people often run several unrelated conversations at once (separate threads). Today the agent treats the whole channel as one conversation, so unrelated threads share the same running session — their context bleeds together and independent tasks can step on each other. This change gives the agent a **separate session per thread** inside a channel. Direct messages stay as one conversation (unchanged). The channel is still the boundary for who is allowed in and what is visible — only the agent's working context is now split by thread. ## How it is turned on Off by default. Operators opt in with one setting: - `BUZZ_ACP_SESSION_POLICY=channel` — default, current behavior - `BUZZ_ACP_SESSION_POLICY=thread` — new per-thread behavior Being behind a flag means we can enable it for a few agents, watch how it behaves, and roll back instantly without a code change. ## Key design decisions - **Decide the thread once, up front.** When a message arrives we work out which thread it belongs to a single time and tag it. Everything after that (which line it waits in, which session runs it, what history it sees) uses that tag instead of re-guessing later, which avoids mismatches. - **Default stays identical to today.** Under the default setting a "thread" is just "the whole channel," so existing behavior and every existing test are unchanged. The new, riskier behavior is strictly opt-in. - **Give the agent only its thread's history.** On a reply the agent sees that thread's messages (including ones that did not mention it), not the whole channel transcript — less noise and smaller prompts. - **Don't let one channel use more memory than before.** More threads means more live sessions, so the existing per-channel limit now caps all of a channel's threads together — splitting into threads can't multiply how much work is held. ## Bugs found and fixed while iterating (from review) - **Same thread, two sessions.** If the worker already holding a thread's session was busy, a new message for that thread could start a *second* session on another worker and split its history. Now it waits for the right worker instead of forking. - **Interrupting the wrong thread.** A follow-up meant for thread A could interrupt thread B in the same channel. Interrupts now target the exact thread. - **Stuck thread after a crash.** If a thread's turn crashed, its slot wasn't cleared and stayed blocked for up to ~2 hours. It now clears right away and retries. - **Lost the original request.** When a thread was interrupted and then had to wait for a busy worker, only the follow-up was kept and the original request was dropped. The full request is now preserved on retry. - **Same thread seen as two.** Two spellings of the same thread id (upper/lower case) could be treated as different threads. Normalized so they count as one. ## Not in this PR - The desktop Settings toggle and rollout wiring for managed agents — https://github.com/block/buzz/pull/6909 - One pre-existing retry edge case (present today without this flag, unrelated to this change) — tracked separately so this PR stays focused. ## Testing The full `buzz-acp` test suite passes (830+ unit and integration tests), plus new focused tests for thread routing, session reuse, interrupt targeting, crash recovery, and request preservation. Behavior with the flag off is unchanged. --------- Signed-off-by: Salman Mohammed <[email protected]> Signed-off-by: Leo <5faf251baee50ee6bcde338aef6acdd70bb3e60115664c2cd490d94a55dfc488@buzz.block.builderlab.xyz> Co-authored-by: Leo <5faf251baee50ee6bcde338aef6acdd70bb3e60115664c2cd490d94a55dfc488@buzz.block.builderlab.xyz> * feat(db): add NIP-FI identity and final-admission schema foundation (#6994) PR 2 of the NIP-FI plan: the schema foundation. Establishes the durable server-side identity ledger and final-admission surface that the runtime phases build on. All of Phase A's migrations live here; later phases own their own deltas. Depends on nothing — PR 1 (#6776, merged) owned zero migration files. This PR's relations are shaped to store exactly what PR 1's verifier produces: issuer-qualified identity and the four denial classes. They meet in a later PR that writes a verified assertion into these tables in one transaction. ## Two internally-ordered migrations - `0041_nip_fi_identity_foundation.sql` (migration A) — core identity + base-lifecycle relations (5 tables): issuer-qualified `(iss, sub)` bindings, lifecycle history/selectors, enrollment policies, and operation receipts. Applies cleanly to current `main`. - `0042_nip_fi_authorization_foundation.sql` (migration B) — the final-admission surface (10 tables): authorization events + capacity, admission results, replay/receipt guards, audit, invalidation domains/floors, protected-object authority, authority epochs, and restore version deltas. Applies to A's resulting state. Fifteen NIP-FI relations total, zero dangling foreign keys. Identity is issuer-qualified throughout — no single-global-issuer assumption in any relation, no `Block`-hardcoding. A single deployment may run one issuer; that is config, not schema. ## Durable, immutable ledger posture All 15 relations are append-only (immutable `no_delete`/`no_truncate` triggers) and carry `community_id` as provenance, not ownership. Both migrations widen the single SQL source of truth `community_write_fence_excluded_table` so the relations are never fence-attached, never purged on community deletion, and never counted as tenant-scoped drift by the deletion control plane's exact-set catalog check — the same posture main already applies to `product_feedback` and `rate_limit_violations`. `schema/schema.sql` keeps one consolidated definition of that function whose exclusion array byte-matches `0042`, guarded by a parity assertion so a future consolidation cannot silently drop NIP-FI relations from the ledger. This makes a tenant's identity/authorization ledger survive community deletion, per the spec's `FI-INV-02` (durable binding) and `FI-INV-03` (tombstone monotonicity) and `NIP-FI.md`'s "durable server state" ruling. `communities(id)` FK never dangles: community rows become permanent tombstones, never hard-deleted. ## Authorization shape and cardinality contracts Authenticated `OperatorDenied` events (`actor_kind` 1–3, non-null `request_fingerprint`) carry a null `semantic_fingerprint` and commit without a denial-attempt row. The denial-attempt cardinality and shape guards are scoped to unresolved pre-auth kind-9 events (`actor_kind = 4`). Applied and no-op lifecycle receipts (`outcome_code IN (1, 3)`) require exactly one mapped success-transition event; denied lifecycle receipts (`outcome_code = 2`) require zero events from the complete core lifecycle success-transition class (kinds 1, 2, 3, 6: enrolled, revoked, rotated, retired) — any such event paired with a denied receipt would record a transition that never occurred. ## Mined vs. new Re-cut from Franco's #1476 (`0029`/`0030`) and Cea's #4772 committer schema, re-cut along FK topology and renumbered above the live `main` tip. The buzz-auth core of #1476 is Cea-authored; `Co-authored-by` reflects verified per-commit authorship of the mined schema. Zero Rust/`deletion.rs` edits — the migration-only exclusion widening keeps `EXPECTED_SCOPED_TABLES` untouched. --------- Signed-off-by: Will Pfleger <[email protected]> Signed-off-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz> Co-authored-by: Cea Stapleton Cordasco <[email protected]> Co-authored-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz> * fix(model-capabilities): humanize databricks goose model names (#7135) 🤖 ## Summary - add curated human-readable labels for Databricks Goose models that otherwise render as fully qualified identifiers - render `data_workflow_tools.goose.goose-glm-5-3` as `GLM-5.3` - render `goose-claude-4-6-sonnet`, `goose-claude-4-7-opus`, and `goose-kimi-2-7` as `Claude Sonnet 4.6`, `Claude Opus 4.7`, and `Kimi 2.7` - make the Global Defaults closed model picker use the provider-scoped display label while preserving the raw discovered model ID as the persisted value - remove the obsolete `keepSelectedModelValueLabel` escape hatch and its raw-label override path so selected discovered models have one consistent display behavior - classify the exact discovered Goose Claude IDs with their canonical adaptive-thinking capability axes, including Sonnet 4.6's exclusion of `xhigh` - expand Rust and TypeScript alias coverage and regenerate the shared 139-vector capability corpus ## Test plan - `cargo test -p buzz-agent --lib` — 517 passed, 1 ignored - `cd desktop && pnpm test` — 5,821 passed - Desktop TypeScript typecheck — passed - Biome on the changed component — passed - `git diff --check` — passed - targeted Playwright Global Defaults regression — passed on the preceding implementation head; the subsequent commit only removes dead picker-prop plumbing Verified at `b9609d12696173aa309d2dbaf4f093a502756c36`. The hook-bound push exceeded the harness timeout in unrelated Rust doc tests, so the already-verified rebased commit was pushed with hooks bypassed. Follow-up to #6955. --------- Signed-off-by: Kalvin Chau <[email protected]> Co-authored-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> * feat(desktop): add isolated named demo builds (#6407) 🤖 I’m Larry, updating this description on Logan’s behalf. ## Summary Build named macOS demo apps without Finder automation or collisions with installed Buzz. `just desktop-demo-build "PR 6407 Demo"` produces a matching app and DMG, with a fresh build identity even when the same display name is reused. - The headless DMG packager uses `hdiutil`; optional Finder styling is bounded. The existing production release recipe is unchanged. - Each demo has independent app data, keychain, nest, CLI name, voice-model storage, repository discovery, and agent OAuth/config storage. Reset preserves production and sibling-demo state, and retains retry intent when credential removal or root resolution fails. - Native links accept only the active build’s registered scheme, then translate validated entity links into the frontend’s canonical `buzz:` format. - The recipe builds all six executable sidecars. Display names are capped at 31 ASCII characters so the generated identity fits Rust’s build-time limit. **Open delivery requirement:** downloaded demos must run without a Gatekeeper security override. The current recipe is ad-hoc signed and unnotarized; it does **not** satisfy this requirement. Trusted branch-demo signing/distribution remains blocked on establishing an approved signing path. This PR is not being presented as complete download-and-run delivery. ### Related issue N/A — reported in the Buzz DMG-packaging workstream. ### Testing At `11ce21ff97cb387ad676e7caa65b00964097d0bb`, macOS Blox passed the Tauri workspace suite and compiled-flags gate (including the full named-demo state; each library pass: 2,992 passed, 19 ignored), Tauri all-target clippy, the full `buzz-agent` package suite, and frontend lint/typecheck plus 5,733 tests. Regression coverage includes cold-start/running entity-link handling, wrong-build rejection, OAuth deletion failure and retry, unresolved credential roots, and production/sibling preservation. At the same head, an extra full named-demo/mesh-enabled run had 3,092 passing tests and one failure: a pre-existing shared-compute `auto` versus `mesh` expectation, also reproduced on the old published head `a77b25eca`. The ordinary and demo-state matrix above passes; this is not an all-features-green claim. Live macOS Launch Services delivery remains unverified. GitHub CI completed with 30 successful checks and 9 skipped. The exact-range security review has not run; its authorization notice remains open. CI success does not establish trusted signing or downloaded-app launch. Earlier demo artifacts established matching app/DMG names, side-by-side launch, and six non-empty executable arm64 sidecars. These screenshots show an earlier artifact, not a new build of the final repair commit. Signature-integrity checks are not Gatekeeper/notarization evidence. <img width="1032" height="548" alt="Buzz PR 6407 Demo disk image containing the matching app" src="https://github.com/user-attachments/assets/bca0277e-db03-4308-b280-fcad55e6d601" /> <img width="1186" height="821" alt="Buzz PR 6407 Demo running alongside other Buzz installations" src="https://github.com/user-attachments/assets/b4bf4ae5-c341-4e15-8090-9d2ea7c623b6" /> --------- Signed-off-by: Logan Johnson <[email protected]> Signed-off-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Co-authored-by: Other Brother Darryl <cee32d92756729ee0c097c5661b879c6199931cd25315c8cf398dcbf0f155cf1@buzz.block.builderlab.xyz> Co-authored-by: Larry <[email protected]> Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> --------- Signed-off-by: Philip Azar <[email protected]> Signed-off-by: Will Pfleger <[email protected]> Signed-off-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz> Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes <[email protected]> Signed-off-by: Arjun Mahanti <[email protected]> Signed-off-by: Fizz <[email protected]> Signed-off-by: tulsi <[email protected]> Signed-off-by: Wintermute <c0fc581234c3585602139eec347ced7b82af65b6f6c10728348515c0c06c51c3@buzz.block.builderlab.xyz> Signed-off-by: Jude Edwards <[email protected]> Signed-off-by: Salman Mohammed <[email protected]> Signed-off-by: Leo <5faf251baee50ee6bcde338aef6acdd70bb3e60115664c2cd490d94a55dfc488@buzz.block.builderlab.xyz> Signed-off-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz> Signed-off-by: Kalvin Chau <[email protected]> Signed-off-by: Logan Johnson <[email protected]> Signed-off-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: shiv <[email protected]> Co-authored-by: Phil Azar <[email protected]> Co-authored-by: Will Pfleger <[email protected]> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: Arjun Mahanti <[email protected]> Co-authored-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> Co-authored-by: Wes <[email protected]> Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz> Co-authored-by: LioLionel <[email protected]> Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz> Co-authored-by: Codex <[email protected]> Co-authored-by: Fizz <[email protected]> Co-authored-by: tulsi <[email protected]> Co-authored-by: thomaspblock <[email protected]> Co-authored-by: Wintermute <c0fc581234c3585602139eec347ced7b82af65b6f6c10728348515c0c06c51c3@buzz.block.builderlab.xyz> Co-authored-by: Jude Edwards <[email protected]> Co-authored-by: Salman Mohammed <[email protected]> Co-authored-by: Leo <5faf251baee50ee6bcde338aef6acdd70bb3e60115664c2cd490d94a55dfc488@buzz.block.builderlab.xyz> Co-authored-by: Cea Stapleton Cordasco <[email protected]> Co-authored-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz> Co-authored-by: Kalvin C <[email protected]> Co-authored-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Co-authored-by: Logan Johnson <[email protected]> Co-authored-by: Other Brother Darryl <cee32d92756729ee0c097c5661b879c6199931cd25315c8cf398dcbf0f155cf1@buzz.block.builderlab.xyz> Co-authored-by: Larry <[email protected]> Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
49e57ce to
9722532
Compare
🔐 Codex Security Review
|
jedwards27
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Reviewed: 3c7f288c60d67df78577b237e27c3dfc8831aaa1..f8c727a32e8bc3b444bade27f2d21287bd7bd642 (exact head f8c727a32e8bc3b444bade27f2d21287bd7bd642)
Risk: high — relay reconnect ordering affects messaging, Home/unread state, and recovery from missed events.
Blocking defect: auto-heal snapshot queries can escape before replay restores live streams
At head, connect() emits raw connected, launches replay without awaiting it, and returns the connection generation (desktop/src/shared/api/relayClientSession.ts:573-578). The production auto-heal hook is mounted in desktop/src/app/AppShell.tsx:225; it synchronously observes raw degraded → connected transitions (desktop/src/shared/api/useRelayAutoHeal.ts:129-141) and immediately invalidates every active relay-dependent query when the admission gate is clear (:107-121). Those refetches call ensureConnected(), which now returns immediately when wsId exists (relayClientSession.ts:488-490), so history/snapshot REQs can run while later replay REQ batches or repair are still pending.
This defeats the PR's stated ordering guarantee: a snapshot can be fetched before its live stream is restored, leaving a loss window or transiently stale Home/message/unread state. It is PR-caused despite base also emitting connected early: base then awaited replayLiveSubscriptions() before connect() and the shared connectPromise resolved (base relayClientSession.ts:581-585), so auto-heal refetches remained blocked in ensureConnected(). Head removes that effective query gate. The added readiness regression only proves subscribeToReconnects remains silent during held repair (desktop/src/shared/api/relayClientReadiness.test.mjs:177-218); it does not exercise this second production reconnect signal.
Author action: separate AUTH/write readiness from replay/synchronization readiness across production observers. Preserve ordinary EVENT publish progress immediately after AUTH, but keep auto-heal/manual-reconnect snapshot queries from crossing the connection boundary until generation-current live REQs and repair finish. Add a deterministic production-seam regression that holds replay after degraded → AUTH, proves an ordinary publish reaches EVENT/OK while no auto-heal invalidation/history REQ occurs, then releases replay and proves exactly one invalidation/refetch. Mutation-prove it by restoring the current early signal or query-gate bypass.
Verification owner: author for the fix and production-seam regression; reviewer for exact-head mutation review and full Desktop gate rerun.
Other reviewed contracts
The member-channel consolidation itself is bounded: the single existing channel stream retains Home mention kind/recipient/self/member checks and event-ID deduplication (desktop/src/features/channels/useLiveChannelUpdates.ts:245-262). AUTH remains the write boundary, and the dedicated reconnect-listener callback is generation-fenced and replay-complete (relayClientSession.ts:925-946,984-1001). A duplicate replacement-socket REQ after an initial setup-write failure was reproduced, but the same probe fails against the supplied base; it is pre-existing and is not a blocker for this PR.
Validation
At exact clean head f8c727a32e8bc3b444bade27f2d21287bd7bd642:
- Independent full Desktop package run:
pnpm test— 6,471/6,471 passed;just desktop-cipassed;pnpm typecheck && pnpm check && pnpm buildpassed. - CI: Desktop Core, four Desktop smoke shards, relay-backed Desktop integration, macOS/Windows builds, DCO, Semgrep, and zizmor are green.
git diff --checkpassed; source tree was clean and local/remote heads matched.- A second local
just desktop-ciattempt reached 3,164 passed / 19 ignored Tauri tests but failed one unrelated process-discovery test (managed_agents::discovery::bounded_command::tests::returns_when_escaped_descendant_retains_pipe, empty descendant PID parse). The touched paths do not include that subsystem; the independent exact-head full gate and CI passed.
Manual/native evidence: none. No visual/a11y surface changed; packaged native send/mention behavior remains a reviewer/tooling confidence gap, not an additional author defect.
Residual risk: no same-host latency cohort was run, so this establishes request-count and ordering behavior, not a real-world startup/latency improvement.
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: REQUEST CHANGES
Reviewed: 3c7f288c60d67df78577b237e27c3dfc8831aaa1..f8c727a32e8bc3b444bade27f2d21287bd7bd642 (exact head f8c727a32e8bc3b444bade27f2d21287bd7bd642)
Risk: high — this changes authenticated relay readiness, reconnect replay, live subscriptions, and query refresh ordering.
Behavior/contracts traced: AUTH/write readiness; shared connectPromise/ensureConnected; reconnect replay and generation fencing; subscription admission/replacement/cancellation; query auto-heal; member-channel mention/unread/DM dispatch.
Blocking finding — snapshot/query refresh can escape before reconnect replay completes
At desktop/src/shared/api/relayClientSession.ts:573-578, the new flow emits raw connected, launches replay without awaiting it, and resolves the connection generation. The production auto-heal observer mounted by AppShell synchronously handles degraded → connected in desktop/src/features/relay/useRelayAutoHeal.ts:129-141 and invalidates active relay-dependent queries via :107-121. Those refetches now pass ensureConnected() immediately (relayClientSession.ts:488-490) while later live REQ batches/history repair may still be pending. A snapshot can therefore be fetched before its live stream is restored, leaving a loss window or transiently stale Home/message/unread state—the ordering contract this PR claims to preserve.
This harmful ordering is introduced by the readiness split: base also emitted connected early, but awaited replayLiveSubscriptions() before the shared connection promise resolved, so auto-heal refetches remained blocked in ensureConnected(). The new regression only proves reconnect listeners stay silent during held repair; it does not drive the production auto-heal signal.
Author action: Separate AUTH/write readiness from synchronization readiness for all production observers. Preserve authenticated publish progress, but prevent query auto-heal/manual reconnect snapshot requests from crossing the connection gate until generation-current live REQs and replay/repair complete. Add a deterministic production-seam regression that holds replay after AUTH, proves an ordinary EVENT/OK publish progresses while auto-heal invalidation/history requests remain absent, then releases replay and proves exactly one invalidation/refetch. Mutation-prove the regression against the current early-signal/gate-bypass behavior.
Verification owner: author for the bounded code/test fix; reviewer for exact-head mutation review and full Desktop rerun.
Validation at matching clean head: full Desktop package tests passed 6,471/6,471; just desktop-ci passed; focused mounted-hook/readiness/replay suites passed 56/56; pnpm typecheck && pnpm check && pnpm build passed; git diff --check passed. Required affected CI lanes are green. These gates do not exercise the held-replay auto-heal interleaving above.
Manual/native evidence: none. No visual surface changed; reviewer-run packaged behavior remains a confidence gap, not an additional author defect.
Non-blocking note: a duplicate replacement-socket REQ after an initial setup-write failure reproduced identically on the supplied base, so it is pre-existing and is not author action for this PR.
Residual risk: no same-host latency cohort or packaged native journey proves real-world latency improvement; performance/native validation remains reviewer/tooling or release-owner work after the blocking ordering defect is corrected.
Keep WS quota and concurrency CLOSED retries from gating HTTP, and keep HTTP 429 errors out of the renderer WS gate. Preserve damping for an explicitly unavailable shared admission service. Reuse existing channel live streams for Home mention invalidation instead of subscribing to each channel twice. Keep kind, recipient, membership, identity, and replay guards. Add production-path HTTP/WS and mounted-hook regressions. No pacing, reconnect-readiness, replay, routing, or relay policy changes. Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Use the complete membership events already fetched for discovery rather than reading the same rosters again. Query only uncovered directory or pending-owner channels, preserving covered rosters when the tolerant fallback fails. Keep reuse request-local; do not change refresh triggers, channel scope, activity batching, or introduce a cache. Cover real native HTTP requests, pagination, fallback and identity/community changes in regression tests. Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
f8c727a to
83ac81f
Compare
|
Pinky, an AI agent, is commenting on Wes's behalf. The candidate reviewed at The replacement contains transport-specific quota backoff, reuse of existing live streams for Home mention invalidation, and a separate request-local roster-reuse commit. No refresh deletion, scheduler, send-route or replay-policy change. The updated description documents production-boundary tests, mutation evidence, synthetic measurements and limits. CI completed successfully; its tested merge-ref tree matches the new candidate. Browser CI had 13 automatically recovered flaky cases; the video-player retry remains unexplained after an independent boundary trace and is explicitly disclosed. Local full frontend/native gates and 130 selected headless cases passed. Bundled notification acceptance and attribution of the residual send wait remain open. Please re-review the replacement head. The existing requested-changes review still targets |
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: APPROVE
Reviewed: 3c7f288c60d67df78577b237e27c3dfc8831aaa1..83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb (exact head 83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb)
Risk: high — native relay quota/backoff ownership, channel discovery roster reuse, and live mention invalidation.
Behavior/contracts traced: Both lanes traced HTTP-vs-WebSocket quota gates; relay readiness/reconnect behavior; request-local roster discovery/fallback across pages; identity/community freshness; live kind/recipient/self/member-channel guards; pending/removed subscription cleanup; async failure/retry and persistence boundaries.
Findings: no concrete author-actionable defect found. The previous head’s reconnect/readiness blocker is gone: this head restores the base session/replay contract; the remaining relayClientSession.ts delta removes the redundant mention subscription API. Ordinary WS quota/concurrency CLOSED responses remain WS-local, explicit shared-admission failure can damp HTTP, and HTTP 429 still gates subsequent HTTP work (desktop/src-tauri/src/shared/native_relay_client.rs:773-790; desktop/src-tauri/src/commands/relay.rs:318-335). Discovery rosters remain request-local, are sourced from the current identity’s paged #p query, fall back only for uncovered directory/pending channels, and are re-read on every fetch (desktop/src-tauri/src/commands/channels/fetch.rs:201-266,374-447). No cross-community cache or persistence was added. Existing live streams preserve event-kind, exact-recipient, external-author, member-channel, retry, replay-dedup, and disposal guards (desktop/src/features/channels/useLiveChannelUpdates.ts:234-447).
Author action: none.
Verification owner: reviewer/tooling for optional native/browser observation; no merge-blocking external gate identified.
Validation
At matching clean exact head:
pnpm test/just desktop-test— pass, 6,457/6,457.just desktop-check— pass, 2,660 files clean.just desktop-typecheck— pass.just desktop-tauri-fmt-checkandjust desktop-tauri-clippy— pass.just desktop-tauri-test— pass across all workspace/package binaries; lane receipts report 3,175–3,276 passed with ignored tests varying by invocation, zero failures.- Causal mutation: discard discovered roster reuse → paged-roster regression fails due to fallback query.
- Causal mutations: remove mention-recipient boundary or re-arm HTTP for every WS rate-limit CLOSED → corresponding regressions fail. All mutations restored; trees clean.
- Exact-head Desktop core/smoke/Windows/macOS/integration, Rust lint/Windows, Semgrep, zizmor, and DCO checks — success.
Manual/native evidence: native harness/browser visual pass not run. No widget, navigation, focus, label, or rendered layout changed.
Residual risk: asynchronous Home refresh/send availability and roster presentation were not manually observed in a packaged app. Mounted-hook/native transport tests and causal mutations cover the changed seams; this remains reviewer/tooling confidence work, not author rework.
jedwards27
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Reviewed 3c7f288c60d67df78577b237e27c3dfc8831aaa1..83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb at exact live head 83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb as :bot: Jude’s code review agent.
Risk: high. This changes relay quota/backoff ownership, live subscription behavior, and channel-discovery roster reuse across renderer and native boundaries.
Behavior/contracts traced
- Ordinary WebSocket quota/concurrency
CLOSEDresponses remain WS-local; explicit shared-admission failures can damp HTTP; HTTP 429 continues to gate later HTTP work (desktop/src-tauri/src/native_relay_client.rs:773-790,desktop/src-tauri/src/relay.rs:318-335). The earlier reconnect/readiness concern is resolved: this head restores the base session/replay contract while removing only the redundant mention subscription API. - Discovery rosters are request-local and identity-bound, sourced from the current identity’s paged
#pquery. Fallback reads are limited to uncovered directory/pending channels; every fetch re-reads relay state, with no persistent or cross-community cache (desktop/src-tauri/src/commands/channels/fetch.rs:201-447). - Existing per-channel live streams now invalidate Home mentions while retaining event-kind, exact-recipient, external-author, member-channel, replay-dedup, retry, and disposal guards (
desktop/src/features/channels/useLiveChannelUpdates.ts:234-447). - HTTP 429 remains surfaced to existing UI error handling, while WS publish cooldown remains independently enforced (
desktop/src/shared/api/tauri.ts:276-292,desktop/src/shared/api/relayRateLimitGate.ts:1-26). No widget, navigation, focus, label, or rendered-layout contract changed.
Findings: no blocking or non-blocking code defect found.
Author action: none.
Verification owner: none. Exact-head code and test review is complete.
Validation at clean exact head
- Full Desktop frontend suite:
pnpm test/just desktop-test— 6,457/6,457 passed. - Native package suite:
just desktop-tauri-test— all workspace/package targets passed (independent runs reported 3,276 passed, 20 ignored and 3,175 passed, 19 ignored under their respective target enumeration). just desktop-check— 2,660 files clean;just desktop-typecheck,just desktop-tauri-fmt-check, andjust desktop-tauri-clippypassed.git diff --checkpassed; final worktrees were clean and remained at the exact head.- Causal mutations failed the intended regressions: disabling discovered-roster reuse failed
member_rosters_are_reused_including_every_discovery_page; broadening WS quota closure into HTTP backoff failedpersistent_ws_quota_does_not_withhold_http_reply; bypassing the mention-recipient guard failedmention signal retains kind, recipient, self and member-channel boundaries. All mutations were restored before final verification. - Live GitHub checks were re-read at submission: all current non-skipped checks succeeded, including Desktop core/smoke/integration, macOS and Windows builds, Rust lint/Windows, DCO, Semgrep, and zizmor.
Manual/native evidence: no native-harness or browser visual run. The diff adds no rendered control or accessibility surface; affected asynchronous behavior is covered at mounted-hook and native transport boundaries.
Residual risk: the performance claim is proven as fewer relay reads under bounded synthetic fixtures, not as quantified same-host production wall-clock improvement. No unresolved author-actionable defect remains.
* origin/main: Configure ACP session scope per agent (#7578) refactor(buzz-acp): point agents at buzz --help instead of a command table (#7586) feat(buzz-cli): render an agent-friendly command tree in --help (#7584) fix(avatars): scale agent squircles from normalized paths (#7307) fix(mobile): bind same-name mentions to exact selected identities (#7385) fix(desktop): isolate quota backoff and reuse channel discovery rosters (#6998) test(desktop): isolate login-shell probe measurements (#7570) feat(git): add default-branch management to relay and CLI (#7562) fix(acp): integrate the Buzz Pi adapter fork (#7552) fix(markdown): align mention chip wrapping (#7501) fix(relay): reject presence updates when Redis storage fails (#7532) fix(desktop): let inbox title and message author names truncate under narrow panes (#7550) fix(buzz-acp): report missing models without retrying (#7538) fix(desktop): require a Codex adapter with Astra support (#7427) fix(desktop): order unnamed roster members by full canonical npub (#7503) fix(mobile): standardize public-key identity display on npub (#7493) fix(desktop): npub identity controls across profile, agents, and workflows (#7489) fix(desktop): npub identity displays for mention, member, and workflow surfaces (#7495) fix(desktop): shared npub identity foundation (canonicalNpub, PubKey gate, strict parser) (#7488) fix(mobile): render push notification sender identity as npub (#7494) Signed-off-by: Sol <478bb5a31222ea2b28a3d1afb8b1d598940628f19c2a87efc3c4b822299eeec6@buzz.block.builderlab.xyz> # Conflicts: # desktop/src-tauri/src/commands/media_download.rs
* origin/main: feat(buzz-agent): add opt-in workspace-scoped Databricks reuse (#7606) fix(acp): improve hints in pi agent setup guide (#7594) fix(ci): pull pinned MinIO images from Quay (#7599) Configure ACP session scope per agent (#7578) refactor(buzz-acp): point agents at buzz --help instead of a command table (#7586) feat(buzz-cli): render an agent-friendly command tree in --help (#7584) fix(avatars): scale agent squircles from normalized paths (#7307) fix(mobile): bind same-name mentions to exact selected identities (#7385) fix(desktop): isolate quota backoff and reuse channel discovery rosters (#6998) test(desktop): isolate login-shell probe measurements (#7570) feat(git): add default-branch management to relay and CLI (#7562) fix(acp): integrate the Buzz Pi adapter fork (#7552) Signed-off-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz> # Conflicts: # Cargo.lock
* origin/main: (110 commits) feat(buzz-agent): add opt-in workspace-scoped Databricks reuse (#7606) fix(acp): improve hints in pi agent setup guide (#7594) fix(ci): pull pinned MinIO images from Quay (#7599) Configure ACP session scope per agent (#7578) refactor(buzz-acp): point agents at buzz --help instead of a command table (#7586) feat(buzz-cli): render an agent-friendly command tree in --help (#7584) fix(avatars): scale agent squircles from normalized paths (#7307) fix(mobile): bind same-name mentions to exact selected identities (#7385) fix(desktop): isolate quota backoff and reuse channel discovery rosters (#6998) test(desktop): isolate login-shell probe measurements (#7570) feat(git): add default-branch management to relay and CLI (#7562) fix(acp): integrate the Buzz Pi adapter fork (#7552) fix(markdown): align mention chip wrapping (#7501) fix(relay): reject presence updates when Redis storage fails (#7532) fix(desktop): let inbox title and message author names truncate under narrow panes (#7550) fix(buzz-acp): report missing models without retrying (#7538) fix(desktop): require a Codex adapter with Astra support (#7427) fix(desktop): order unnamed roster members by full canonical npub (#7503) fix(mobile): standardize public-key identity display on npub (#7493) fix(desktop): npub identity controls across profile, agents, and workflows (#7489) ... Signed-off-by: Alessandro Joabar <[email protected]>
…eway-origin * origin/main: (23 commits) feat(buzz-agent): add opt-in workspace-scoped Databricks reuse (#7606) fix(acp): improve hints in pi agent setup guide (#7594) fix(ci): pull pinned MinIO images from Quay (#7599) Configure ACP session scope per agent (#7578) refactor(buzz-acp): point agents at buzz --help instead of a command table (#7586) feat(buzz-cli): render an agent-friendly command tree in --help (#7584) fix(avatars): scale agent squircles from normalized paths (#7307) fix(mobile): bind same-name mentions to exact selected identities (#7385) fix(desktop): isolate quota backoff and reuse channel discovery rosters (#6998) test(desktop): isolate login-shell probe measurements (#7570) feat(git): add default-branch management to relay and CLI (#7562) fix(acp): integrate the Buzz Pi adapter fork (#7552) fix(markdown): align mention chip wrapping (#7501) fix(relay): reject presence updates when Redis storage fails (#7532) fix(desktop): let inbox title and message author names truncate under narrow panes (#7550) fix(buzz-acp): report missing models without retrying (#7538) fix(desktop): require a Codex adapter with Astra support (#7427) fix(desktop): order unnamed roster members by full canonical npub (#7503) fix(mobile): standardize public-key identity display on npub (#7493) fix(desktop): npub identity controls across profile, agents, and workflows (#7489) ... Signed-off-by: Tom Brow <[email protected]>
…6961) Pinky, an AI agent, updated this description on Wes's behalf after taking over the startup investigation. **Category:** fix **User Impact:** An EVENT refused by WebSocket admission or handler saturation receives a correlated `OK(event_id, false, reason)` instead of an uncorrelated NOTICE, so the client can settle that refusal without waiting for its publish timeout. Rate-limited refusals also arm client backoff. This fixes a protocol failure mechanism; it does not establish that every startup send will succeed or that the reported Desktop startup incident is fully resolved. **Problem:** Startup opens several live subscriptions and publishes at once, and the relay's WebSocket admission gate is a fixed 5-second window (`ws_admission_budget` = `human_ws_events_per_sec * 5`). If that shared per-principal quota is exhausted, `enforce_ws_admission` previously rejected an EVENT with a bare `["NOTICE", reason]`. Quota pressure is a possible trigger, not proof of the original incident's complete cause. A NOTICE carries no event id. Both clients settle a pending publish *only* from an `OK` keyed by event id (desktop `pendingEvents`, mobile `_pendingEvents`), so nothing settled — and `handle_text_message` returns early, so no `OK` ever followed either. The send **could not fail**; it could only time out at `PUBLISH_TIMEOUT_MS` = 25s. That explains how this rejection mechanism can produce a roughly 25-second timeout; attributing the original report to it still requires the actual startup/send workflow. The handler-semaphore saturation path had the identical defect, and that one needs no quota burst to fire. **Solution:** NIP-01 gives each request type its own acknowledgement channel, and a rejection is only actionable on the same one. Reject a REQ with `CLOSED`, an EVENT with `OK(id, false, reason)`, and fall back to `NOTICE` only where no per-request correlation exists. COUNT refusals now also use `CLOSED(query_id, reason)` per NIP-45, covering both quota admission and handler saturation (added in `cd12c93804b87a24b61075dfd171dc471a0a527f`). Reason strings are unchanged, so the `rate-limited:` prefix and `retry in {N}s` hint that existing client gates parse keep working (desktop `parseRateLimitHint`, mobile `RelayRateLimitGate`, buzz-acp `set_rate_limit_gate`). Only the frame *type* changes, so `docs/multi-tenant-relay.md` L7 stays satisfied. Two notes on how this landed, both worth a reviewer's attention: 1. **A survived mutation became a design change.** `send_admission_result` originally took a `RejectionTarget` parameter, and reverting the *second* call site (the per-minute message quota) survived the whole suite — with Redis unreachable the first quota check short-circuits, so that line is unreachable in test. Rather than test around it, the parameter is gone: the target is derived from the frame, so no call site can name the wrong channel. 2. **The relay fix would have caused a client regression on its own.** Gate arming lived only in the NOTICE branch. Once rejections arrive as `OK:false`, `handleOk` failed the send without ever backing off — the client would retry straight into the same quota. Desktop and Mobile now arm on a `rate-limited:` OK rejection. ACP was subsequently fixed in `3b06dd32493596ec650f20abf8805791c50fdc24`: it arms the gate and re-parks only the refused observer frame, preserving other in-flight frames. Desktop gets `activateRateLimitIfSignalled` as the single owner of that prefix test, called from both `handleOk` and the NOTICE branch. <details> <summary>File changes</summary> **crates/buzz-relay/src/rejection.rs** (new) Owns the admission-rejection concern: `RejectionTarget`, `rejection_target_for`, `request_rejection_message`, `send_admission_result`, and `enforce_ws_admission`, moved out of `connection.rs`. Six tests, two of which drive the real `enforce_ws_admission` against a real `AppState`. **crates/buzz-relay/src/connection.rs** Fix the EVENT handler-semaphore rejection to correlate to the event id; delegate admission to the new module. Add two tests that drive the real `handle_text_message` with every handler permit held. Down from 1319 to 1116 lines. **crates/buzz-relay/src/state.rs** Widen the existing `test_state` helper to `pub(crate)` so the rejection tests reuse it rather than adding a ninth copy of `AppState` construction. **desktop/src/shared/api/relayRateLimitGate.ts** Add `activateRateLimitIfSignalled` — one owner for the `rate-limited:` prefix test, since three inbound frame types now carry it. **desktop/src/shared/api/relayClientSession.ts** Arm the gate on a rate-limited OK rejection; route the NOTICE branch through the same helper. Net zero lines, which keeps this already-oversized file within the differential ratchet. **desktop/src/shared/api/relayClientPublishRejection.test.mjs** (new) Four tests against the real `RelayClient`: a rate-limited OK settles the pending publish and arms the gate; an ordinary rejection does not arm it; an accepted OK still resolves. **mobile/lib/shared/relay/relay_session.dart** Arm the gate in `_handleOk` for a rate-limited rejection. **mobile/test/shared/relay/relay_session_test.dart** Two tests driving the real `publish` + `debugHandleMessage` path. </details> <details> <summary>Validation</summary> **Mutation-tested — 5 mutations, all now killed.** Each production call site was reverted to the defective behaviour to confirm a test fails. This caught two false-negative tests: | # | Mutation | Result | |---|----------|--------| | 1 | `rejection_target_for`: EVENT → `Connection` | 4 tests fail | | 2 | EVENT handler-semaphore call site → bare NOTICE | **survived at first** | | 3 | per-minute quota call site → `Connection` | **survived**; fixed by removing the parameter | | 4 | desktop `handleOk` gate arming removed | 1 test fails | | 5 | mobile `_handleOk` gate arming removed | 1 test fails | Mutation 2 is the lesson: my first saturation test called `request_rejection_message` directly, so reverting the real call site inside the `match` arm left it green. It now drives `handle_text_message` itself and dies on that mutation. - `cargo test -p buzz-relay` — 928 passed, 1 failed: `api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo`, **pre-existing**, reproduced with all changes stashed at `4dd4d73de`. - `cd desktop && npm test` — 5721 passed, 0 failed (full suite). - `cd mobile && flutter test` — 1876 passed, 0 failed (full suite). - `just fmt-check`, `just clippy`, `just desktop-check`, `just mobile-check`, `just file-size-check` — clean. Desktop's 5 biome warnings are pre-existing (reproduced with changes stashed). - All 9 pre-push lanes green, including `rust-tests` and `desktop-tauri-checks`. **Not verified:** not reproduced end-to-end against a live relay under a forced quota burst. The causal chain is source-proven and mutation-proven at the frame level; the ~25s attribution follows from `PUBLISH_TIMEOUT_MS` but is not directly measured. A packaged-build click-through would close that gap. </details> Related work: block#6957 bounds Desktop HTTP event submission, but safe retained-operation recovery after exhausted/ambiguous outcomes remains unfinished. block#6998 is the separately reviewable Desktop readiness/duplicate-subscription slice. Neither is claimed to complete native before/after startup-send validation. Diagnosis note: `RESEARCH/DESKTOP_STARTUP_SEND_STALL_2026_08_27.md` (Brain's workspace). ## Current review disposition (2026-08-28) The [review on `cd12c938`](block#6961 (review)) identified ACP's missing rate-limited-OK handling. Commit `3b06dd32493596ec650f20abf8805791c50fdc24` fixes gate arming, re-parking the specifically refused observer frame, and the stale NOTICE comment. Two regressions drive the real frame dispatcher. See [the implementation and validation response](block#6961 (comment)). The Mobile generation-check inline thread is resolved: its `async publish` returns a failed Future when superseded; it does not throw synchronously at invocation. No further production change was indicated by that comment. The validation counts above describe the original slice, not a new rerun. At `3b06dd324`, the current GitHub check rollup has successful completed test/build checks (non-applicable jobs skipped). The security-review comment still requires review for the current base/head range; do not read a green authorization job as a completed security review. Approval and merge remain human decisions. --------- Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes <[email protected]> Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
…rs (block#6998) Pinky, an AI agent, is updating this PR on Wes's behalf. ## Targeted repair, not a startup rewrite This replaces the previous readiness/replay candidate. Current head: **`83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb`**, two independent commits on main base `3c7f288c60d67df78577b237e27c3dfc8831aaa1`: 1. **`0b6681de2` — keep quota backoff on its transport.** HTTP 429s retain native HTTP backoff without arming the renderer WebSocket gate. WebSocket quota/concurrency CLOSED retains its retry deadline without damping HTTP's separate quota. The explicit `rate-limited: shared admission unavailable` signal still damps HTTP too. Reuse existing all-channel live streams for Home mention invalidation instead of a second per-channel mention subscription; retain kind, recipient, self, membership, replay-deduplication, notification and unread boundaries. 2. **`83ac81ff6` — reuse complete membership rosters within each channel fetch.** Discovery already returns full paginated rosters. Retain those results and request only uncovered directory/pending-owner channel IDs. Skip empty fallback filters and preserve covered counts/pubkeys if that tolerant fallback fails. The next fetch reads current membership again; there is no persistent cache or new invalidation state. No send-route, AUTH-readiness, replay-ordering, scheduler, pacing, relay policy, dependency, or authorization changes. Refresh triggers and activity batching stay unchanged. Independent tracing did not establish a safe-to-delete duplicate normal-startup refresh; recovery invalidations at different replay stages are not interchangeable. **Size:** 18 files, +1,066/-350 overall; nine production paths +76/-205 (**129 fewer production lines**). The roster follow-up itself touches only `fetch.rs` (+31/-14) and its new 378-line regression file. Test bulk is not new startup machinery. ## Comparative roster measurement Actual native HTTP fetch code against a synthetic Axum loopback fixture: 265 channels × 100 members, deterministic signed events, debug build. Seven iterations per condition; medians below exclude the first warm-up. Baseline is `0b6681de2` production fetch, candidate is `83ac81ff6` production fetch, with the same temporary benchmark harness. | Measure | Baseline | Candidate | | --- | ---: | ---: | | HTTP reads per fetch | 7 | 6 | | JSON response-body bytes per fetch | 4,803,136 | 2,453,380 | | Median, no artificial request delay | 262.9 ms | 149.3 ms | | Median, 25 ms artificial delay per request | 376.7 ms | 282.7 ms | Channel/member assertions and output hash (`fa7cc551bc855e4d`) match throughout. This removes **one batched roster request**, not 265 requests. The measured ~43%/~25% reductions describe this large-roster synthetic fixture, **not production startup latency**. Activity requests run concurrently with roster enrichment, so real savings vary. Counts now use the discovery snapshot rather than a later reread within that same non-atomic fetch. ## Verification At pushed head **`83ac81ff6`**: - All enabled pre-push gates passed without bypass: `push-head-scope`, `branch-skew`, `desktop-check`, `file-size-check`, `desktop-typecheck`, `desktop-test`, `desktop-tauri-checks` (native fmt/Clippy/tests). - Full Desktop frontend suite: **6,457 passed**, zero failures; separate tooling suite: **10 passed**. - Full native Desktop workspace: **3,276 passed**, zero failures, 20 ignored, across unit/integration/doc bins. The main native lib accounts for 3,175 passed / 19 ignored; this is not 3,276 lib tests. - `pnpm build` passed the protected-feature artifact matrix; `pnpm build:e2e` also passed. Existing chunk-size/dynamic-import warnings remain. No full repository `just ci` run locally. - **130 selected headless mock-bridge smoke cases passed across two runs**: messaging, reconnect, reconnect affordances, inbox live updates, sidebar snapshots, send-channel binding, boot splash. The first invocation hit the shell's 300-second limit after 117 passes and no failures; all remaining 13 passed in a separate invocation. This is not a claim the interrupted invocation completed. - Six new tests invoke production `fetch_channels` through the real native HTTP client and cover 265/501-channel pagination (including same-timestamp continuation), exact requests, complete/deduplicated rosters, directory/pending fallback, hidden DMs, repeated membership/identity/relay changes, empty lists and errors. - Falsification in an isolated source copy: restoring the redundant baseline fetch fails four roster regressions; removing missing-roster fallback fails two. Restored candidate passes all six. Earlier transport mutations fail HTTP→WS coupling, WS→HTTP coupling, omitted shared-outage damping and duplicate-mention regressions. No mutation was applied to the committed worktree. - Brain's independent static reviews found no blockers in the transport repair or immutable roster patch. Source tracing confirms relay discovery serializes complete rosters, not projected matching p-tags. This was source review, not independent test execution or approval. ### Hosted CI [CI run 34185670504](https://github.com/block/buzz/actions/runs/34185670504) **completed successfully** for this head. GitHub checked out merge ref `25bcf09627e129887481d4441a1af3c6cb0af1ff`; its Git tree is identical to `83ac81ff6` (`49a01f3c2ebf4e547bbe3cd31406f984ac6cefe8`), verified through the GitHub Git API. The final PR rollup has 33 successful checks and 28 skipped, with none failing or pending. - Desktop Core passed frontend/native suites and compiled-feature verification. Windows Rust tests, Windows Desktop build, macOS `.app`/`.dmg` build, all four smoke shards and both relay-backed E2E job shards passed, as did Rust lint, DCO, Semgrep and zizmor. - Browser job totals: **1,620 passed, 13 flaky cases passing automatic retry block#1, five skipped, zero terminal failures**. Smoke accounts for 1,389 passed / 12 flaky / three skipped; integration jobs report 231 passed / one flaky / two skipped. No manual CI reruns or source changes to obtain green. - The retries cover channel-browser, empty-edit, huddle menu, runtime-install, overscroll, onboarding avatar, video attachment and workflow UI assertions. They are disclosed, not collectively declared unrelated. The video case reaches the changed real TS all-channel hook despite mocking native I/O: independent tracing found no regression mechanism or blocker, but the missing second-video player remains **unexplained**, and an indirect timing effect is not excluded. The self-authored, unmentioned event cannot use either the new mention branch or the removed old mention handler as a delivery path. A passing retry does not diagnose its cause. - The separate “Desktop Release Candidate” check skipped its validation step; it is not additional release validation. Codex security review was skipped, not passed. ## Remaining acceptance limits Wes's earlier manual trial of the transport-only candidate reported improvement; relay readback found both a top-level message and a thread reply. That was not a fingerprinted or timed trial of the new roster commit. The remaining few-second top-level send wait is **unattributed**, and this PR does not claim to resolve every startup delay. No visible app launch, relaunch, laptop input automation, or production test messages during this follow-up. Local native tests use fixtures; browser suites do not run the Tauri backend. CI building an app does not validate bundled macOS alerts or inactive-channel notification delivery. Those bundled real-workflow checks remain outstanding. No visual UI changes or screenshots; no approval or merge performed. Originating conversation: buzz://message?channel=5b130804-d759-40ad-a564-d64cc907fa8e&id=cb432417e290e06a1842639cfe0268f9d43d186defbcb59260930d129a26af83 --------- Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz> Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Pinky, an AI agent, is updating this PR on Wes's behalf.
Targeted repair, not a startup rewrite
This replaces the previous readiness/replay candidate. Current head:
83ac81ff6ae439b0e68f4a3dafd4b2af6dbadcdb, two independent commits on main base3c7f288c60d67df78577b237e27c3dfc8831aaa1:0b6681de2— keep quota backoff on its transport. HTTP 429s retain native HTTP backoff without arming the renderer WebSocket gate. WebSocket quota/concurrency CLOSED retains its retry deadline without damping HTTP's separate quota. The explicitrate-limited: shared admission unavailablesignal still damps HTTP too. Reuse existing all-channel live streams for Home mention invalidation instead of a second per-channel mention subscription; retain kind, recipient, self, membership, replay-deduplication, notification and unread boundaries.83ac81ff6— reuse complete membership rosters within each channel fetch. Discovery already returns full paginated rosters. Retain those results and request only uncovered directory/pending-owner channel IDs. Skip empty fallback filters and preserve covered counts/pubkeys if that tolerant fallback fails. The next fetch reads current membership again; there is no persistent cache or new invalidation state.No send-route, AUTH-readiness, replay-ordering, scheduler, pacing, relay policy, dependency, or authorization changes. Refresh triggers and activity batching stay unchanged. Independent tracing did not establish a safe-to-delete duplicate normal-startup refresh; recovery invalidations at different replay stages are not interchangeable.
Size: 18 files, +1,066/-350 overall; nine production paths +76/-205 (129 fewer production lines). The roster follow-up itself touches only
fetch.rs(+31/-14) and its new 378-line regression file. Test bulk is not new startup machinery.Comparative roster measurement
Actual native HTTP fetch code against a synthetic Axum loopback fixture: 265 channels × 100 members, deterministic signed events, debug build. Seven iterations per condition; medians below exclude the first warm-up. Baseline is
0b6681de2production fetch, candidate is83ac81ff6production fetch, with the same temporary benchmark harness.Channel/member assertions and output hash (
fa7cc551bc855e4d) match throughout. This removes one batched roster request, not 265 requests. The measured ~43%/~25% reductions describe this large-roster synthetic fixture, not production startup latency. Activity requests run concurrently with roster enrichment, so real savings vary. Counts now use the discovery snapshot rather than a later reread within that same non-atomic fetch.Verification
At pushed head
83ac81ff6:push-head-scope,branch-skew,desktop-check,file-size-check,desktop-typecheck,desktop-test,desktop-tauri-checks(native fmt/Clippy/tests).pnpm buildpassed the protected-feature artifact matrix;pnpm build:e2ealso passed. Existing chunk-size/dynamic-import warnings remain. No full repositoryjust cirun locally.fetch_channelsthrough the real native HTTP client and cover 265/501-channel pagination (including same-timestamp continuation), exact requests, complete/deduplicated rosters, directory/pending fallback, hidden DMs, repeated membership/identity/relay changes, empty lists and errors.Hosted CI
CI run 34185670504 completed successfully for this head. GitHub checked out merge ref
25bcf09627e129887481d4441a1af3c6cb0af1ff; its Git tree is identical to83ac81ff6(49a01f3c2ebf4e547bbe3cd31406f984ac6cefe8), verified through the GitHub Git API. The final PR rollup has 33 successful checks and 28 skipped, with none failing or pending..app/.dmgbuild, all four smoke shards and both relay-backed E2E job shards passed, as did Rust lint, DCO, Semgrep and zizmor.Remaining acceptance limits
Wes's earlier manual trial of the transport-only candidate reported improvement; relay readback found both a top-level message and a thread reply. That was not a fingerprinted or timed trial of the new roster commit. The remaining few-second top-level send wait is unattributed, and this PR does not claim to resolve every startup delay.
No visible app launch, relaunch, laptop input automation, or production test messages during this follow-up. Local native tests use fixtures; browser suites do not run the Tauri backend. CI building an app does not validate bundled macOS alerts or inactive-channel notification delivery. Those bundled real-workflow checks remain outstanding. No visual UI changes or screenshots; no approval or merge performed.
Originating conversation: buzz://message?channel=5b130804-d759-40ad-a564-d64cc907fa8e&id=cb432417e290e06a1842639cfe0268f9d43d186defbcb59260930d129a26af83