mirror of
https://github.com/block/buzz.git
synced 2026-10-28 13:01:10 +00:00
403c19f6734259cc22ef8ac0c90162ffceeec796
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd0896f5c0 |
fix(desktop): read channel metadata and member lists from writer after writes (#7999)
🤖 This fixes two problems with the same cause. Since #3268, the relay can answer an unpinned `/query` from the Aurora read replica, as long as the replica has proved it's within `BUZZ_REPLICA_READ_MAX_AGE_MS` (1000 ms) of the writer. That's fine for display reads, but it doesn't guarantee a client sees its own write. **Problem 1: channel creation (Wes's report).** Right after creating a channel, the desktop read back the channel's kind:39000 metadata by `#d`. If that read landed on a replica that hadn't replayed the event yet, it failed with `channel created but metadata not yet available`. The channel existed, but the chosen template (canvas, agents) was never applied. **Problem 2: member lists.** After any membership change, the member-list refetch could also hit a lagging replica. The relay returned the list from before the change, and the desktop cached it as fresh for five minutes (`CHANNEL_MEMBERS_STALE_TIME_MS`). Someone just removed could still show as a member, or someone just added could be missing. ## Fix 1: metadata read-backs go to the writer `channel_metadata_filter` is a shared builder that adds `"consistency": "strong"`, so the relay serves the read from the writer. It follows the same pattern as the canvas head reads. All four metadata read-backs that follow a write use it: `create_channel`, `update_channel`, `fetch_starter_channel_metadata` (its retry and fallback are unchanged) and the open-DM refetch in `dms.rs`. A unit test fails if the flag is removed from the builder. The template's agent-add step also reads channel members (kind:39002) right after create. `get_channel_members` takes an opt-in `read_your_writes` flag that sends `"consistency": "strong"`. Only `createChannelManagedAgents` sets it on that path, so the agent-add step sees the creator's membership. ## Fix 2: a 31-second writer-read window after membership changes Every membership write the desktop makes calls `noteChannelMembershipChange` for each channel it changed: - the native write wrappers `createChannel`, `openDm`, `joinChannel`, `leaveChannel`, `addChannelMembers`, `removeChannelMember` and `changeChannelMemberRole` - the Bestie conversation open - huddle agent add and remove, for both the huddle channel and its parent - `ensure_starter_channels` and `sync_agents_to_active_huddle`. Both return every channel they created, joined or changed in `changed_channel_ids`, including ones that landed before a later step failed. The original error text is rethrown unchanged. - live join, leave, removed and `admin_kick` system messages, and member-added and member-removed notifications - a report kick resolved from the Admin Console, once the relay confirms it succeeded and only when the report's channel is in the active community. The kick goes through the admin HTTP API, not a channel event. Ban, timeout and their lifts only change `community_bans`, not channel membership, so they need no record. For 31 seconds after a change, measured on `performance.now()`, `getChannelMembers` for that channel sends `readYourWrites`. Why 31 seconds: the relay caps its replica staleness budget at `FENCE_STALENESS` (30 s), so once the window closes, no supported configuration can serve the pre-change list. The constant's comment ties it to `FENCE_STALENESS`. One app-level listener cancels any roster fetch already in flight and refetches. When it registers, it also refreshes every channel whose window is still open. All other member-list reads still use the replica. **Community switch.** The window map is cleared when the community changes. Each awaited write captures a generation through `beginChannelMembershipWrite()` before its first native call, and the reset advances it. So a write that settles after a community switch records nothing in the new community. Live events don't need this fence, because the reset disconnects the relay client first and frames from the old connection are dropped. ## Coverage - A Rust test drives `ensure_starter_channels` against a stub relay that accepts the creates but never serves metadata, and checks that both created starter channels are still reported. - Desktop tests cover the writer-read window, the Admin Console kick, and writes that settle after a community switch. - The desktop E2E test bridge (`desktop/src/testing/e2eBridge.ts`) mirrors the strong reads and `changed_channel_ids`, so E2E runs exercise the fixed behavior. This doesn't address the smaller race in the relay's per-pod accessible-channels cache, and it doesn't change mobile. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> |
||
|
|
dad5a33865 |
fix(desktop): keep packaged frontendDist relative so Windows embeds assets (#7177)
## Root cause
`tauri-command.mjs` points `frontendDist` at a `mkdtemp` directory so
concurrent OSS/internal packages cannot overwrite each other's assets.
On Windows that is an absolute path with a drive letter.
`FrontendDist` is an untagged serde enum whose **first** variant is
`Url(Url)`, and `C:\Users\...` is a valid WHATWG URL with scheme `c:`,
so serde selects `Url`. `tauri-codegen` then does:
FrontendDist::Url(_url) => Default::default(), // embed nothing
A missing *directory* panics with a clear message; a URL is silent. The
build exits 0 and produces an installable app with no frontend assets,
which boots to `ERR_FILE_NOT_FOUND` in the WebView.
Linux and macOS are unaffected — `/tmp/...` has no scheme, so it falls
through to `Directory`.
This affects every Windows build that goes through `pnpm tauri build`,
including `release.yml`'s NSIS job and `windows-canary.yml`.
## Fix
Pass the path relative to the config's own directory. `tauri-codegen`
resolves `frontendDist` with `config_parent.join(path)`, so a relative
path reaches the same directory and cannot parse as a URL. When the temp
directory is on another drive there is no relative form, so the scratch
root is created beside the config instead.
`BUZZ_PROTECTED_BUILD_OUTPUT` still receives the absolute path, and
cleanup is unchanged.
## Testing
`tauriCommand.test.mjs` asserted against the value it had just been
handed, so it could not observe this. Its fake CLI also resolved
`frontendDist` against the process cwd, which is not what Tauri does.
- Fake CLI now resolves against the config directory, matching
`config_parent.join(path)`.
- New case asserts the packaged `frontendDist` is not absolute and does
not parse as a URL. The absolute check is what fails on Linux/macOS, so
the regression stays covered on every platform.
- Verified the new case fails on the unpatched wrapper and passes with
the fix; the two existing cases pass either way.
- Desktop suite: 5844 passed. `useDocumentVisible` has a pre-existing
load-dependent flake that also reproduces on an unmodified checkout.
- Biome check clean on both files.
Verified end to end by rebuilding the Windows NSIS installer: embedded
asset keys in `buzz-desktop.exe` went from 0 to 490, and the app
launches.
---------
Signed-off-by: Jeff Hedlund <jhedlund@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
ac5a18697c |
feat(desktop): add persistent Bestie experience (#7223)
## Summary - add a persistent, community-scoped Bestie designation for local managed agents - surface the designated agent in the sidebar, agent library, profile actions, message toolbar, and draggable floating shortcut - bloom the floating shortcut into a lightweight compact composer that reuses the normal DM timeline, reactions, presence, and send behavior - support message handoff with a bounded snapshot and a full Buzz thread link so the agent can retrieve the complete conversation ## UX details - the floating avatar and expanded panel stay above app chrome and drag as one aligned surface - closing the expanded panel returns it to its top-right anchor - each mini-composer opening starts visually fresh while messages sent during that opening remain conversational - the designated Bestie's duplicate DM entry is hidden from the regular DM list - Bestie actions are suppressed inside the mini timeline to avoid recursive handoff ## Reliability and maintainability - preserve existing retention database paths across upgrades - serialize assignment and deletion, clearing matching assignments across community scopes before an agent is removed - fence async conversation resolution against workspace and assignment changes - validate stale assignments against existing local agents before hiding DMs - share lightweight assignment state across agent cards and keep protected-feature behavior out of the shared timeline API ## Testing - `pnpm --dir desktop test` — 5,886 tests passed - `pnpm --dir desktop exec tsc --noEmit` - `pnpm --dir desktop exec biome check ...` - `cargo clippy --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings` - focused native retention and Bestie assignment/command tests — 34 passed - `VITE_BUZZ_BESTIE=1 pnpm --dir desktop build:e2e` - `VITE_BUZZ_BESTIE=1 pnpm --dir desktop exec playwright test --project=smoke tests/e2e/bestie.spec.ts` - pre-commit and differential pre-push hooks ## Rollout The UI remains gated by the `bestie` build feature. Screenshots covering setup, empty, assigned, floating, and message-handoff states are included in the PR discussion. --------- Signed-off-by: Arjun Mahanti <arjun@squareup.com> Co-authored-by: Codex <noreply@openai.com> |
||
|
|
5673c3307e |
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 <arjun@squareup.com> Signed-off-by: Fizz <fizz@buzz.local> Signed-off-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Fizz <fizz@buzz.local> Co-authored-by: Fizz <dae5f6af70b8695a8b83c8deae555f63be41630ec2b8cd493e41a439c9527dd8@buzz.block.builderlab.xyz> |