Commit Graph

2261 Commits

Author SHA1 Message Date
Brother Darryl
82e5ec04d5 fix(db): satisfy workspace clippy
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-11 11:12:39 -04:00
Brother Darryl
6bc749c572 fix(relay): remove retired local tracer entrypoint
The PR1 base removed local_mode.rs. Keep its removal while the PR2
single-node profile supplies the supported local runtime.

Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-11 11:06:10 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
bba606a009 feat(relay): complete Phase 1 single-node slice
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-11 11:03:15 -04:00
Brother Darryl
4c4be7f60e fix(ci): build local relay sidecar
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-11 08:40:02 -04:00
Brother Darryl
aaf4be8490 fix(desktop): clear local mode push checks
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:43 -04:00
Brother Darryl
67debfa7eb test(sqlite): cover inviter preservation on reactivation
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:43 -04:00
Brother Darryl
ed6e79460f fix(sqlite): preserve original member inviter
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:43 -04:00
Brother Darryl
893a262496 fix(local-mode): harden sidecar foundations
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:43 -04:00
Brother Darryl
f190c2bdb3 fix(desktop): persist local relay service identity
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:42 -04:00
Brother Darryl
d5967250b9 test(db): gate SQLite community foundation
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:42 -04:00
Brother Darryl
ceb2b026b6 refactor(db): narrow SQLite community foundation
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:42 -04:00
Brother Darryl
4ae8bf88f2 feat(db): enable SQLite community persistence
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:42 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
a9898cd973 feat(experiments): gate local communities
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 20:20:42 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
9d95f8758e Relocate local community creation into create flows
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-10 20:20:41 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
89e0350bbf Fix local relay auth and community persistence
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-10 15:30:41 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
7c73a9522e fix: restart exited desktop relay sidecar
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 15:30:19 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
76769f962e Add desktop local relay sidecar flow
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 15:29:52 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
0c85626194 feat(relay): complete Phase 1 single-node slice
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-10 15:29:25 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
189abc62ae feat(db): add SQLite core collaboration slice
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-10 15:29:11 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
bb3c39049d refactor(db): gate postgres operations by backend
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 15:29:08 -04:00
Brother Darryl
8f29ecbdb0 fix(media): harden filesystem backend
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 14:50:04 -04:00
Brother Darryl
e832df9178 feat(db): add backend declaration macro
Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 14:37:24 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
f4c51f87aa fix(relay): expire local presence leases
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 14:22:58 -04:00
npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh
5a55f23f1d feat(relay): add local pubsub and media backends
Signed-off-by: npub1z3hmzc9ryehxzedl5wzlvpyvja0d483peaja5zt6pd0209f9x2jspe2dxh <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
2026-08-10 14:22:58 -04:00
npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je
984d696018 refactor(relay): establish single-node backend seams
Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-10 14:22:57 -04:00
Wes
2777189d96 fix(channels): restore member invitations to private channels (#5493)
## Summary

- restore private-channel invitations for every active member
- keep owner/admin-only enforcement for elevated role grants, active
role changes, and removals
- preserve #4612's unrelated Desktop/mobile failure handling and
hardening
- add relay coverage for the ordinary actor/target role matrix
(`member`, `guest`, `bot`)

## Validation

- pre-push hook passed on `7de700e17642ad7e10155f9537033168d9249268`:
branch skew, Desktop checks/typecheck/tests/Tauri checks, mobile tests,
and Rust tests
- `cargo test -p buzz-test-client --test e2e_relay --no-run`
- `cargo fmt --all -- --check`
- `git diff --check`
- Donut and Mongo independently reviewed the cross-layer authorization
behavior; Donut's role-matrix coverage finding is addressed in this
revision

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 10:59:22 -07:00
Wes
5a3b3d2322 perf(ci): experiment with sccache for relay builds (#5224)
## Summary

- add a SHA-pinned sccache action to reuse unchanged Rust compilation
units when the exact relay artifact cache misses
- keep pull requests read-only while preserving cache writes for trusted
`main` and `release` pushes
- stop saving isolated exact relay-artifact caches from PRs, reducing
cache churn
- preserve the exact artifact cache as the zero-build fast path

## Why this is an experiment

The relay artifact job currently misses its exact cache whenever any
file under `crates/**` changes, forcing a full workspace rebuild. PR
#4975 spent roughly 21 minutes in that job for a one-file `buzz-sdk`
change. sccache targets the relevant reuse boundary—individual compiler
inputs—but the repository cache pool is already under heavy eviction
pressure, so this PR does **not** claim a proven timing win yet.

## Safety

- `Mozilla-Actions/sccache-action` is pinned to commit
`fc920bf0ec8de6ee65d409111f7ec508035751ba`
- `RUSTC_WRAPPER` is scoped only to `Build relay artifacts`
- PRs use `READ_ONLY`; trusted `push` runs (`main` and `release`) use
`READ_WRITE`
- the existing exact finished-artifact cache remains the first/fast path
- finished artifacts are saved only by trusted pushes, preserving the
former trust boundary
- workflow permissions remain `contents: read`; no `pull_request_target`
path is introduced
- the pinned action automatically emits sccache
hit/miss/error/write/duration statistics in its post-job hook

## Validation

- `actionlint .github/workflows/ci.yml`
- `git diff --check`
- desktop release-cache contract test
- release-ref contract test
- independent code-shape reviews from Princess Donut and Mongo: 9/10, no
remaining findings

## Measurement plan

1. purge obsolete PR-scoped `relay-artifacts-*` cache entries before
measurement
2. merge/push a trusted writer to populate sccache
3. run a representative one-crate PR
4. compare relay job duration and automatic sccache statistics against
the 21–22 minute baseline
5. retain this only if the warm run demonstrates material improvement

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 10:49:47 -07:00
Wes
9c074bb89b fix(desktop): bound nine unbounded localStorage stores (#5454)
Part of #5418 (Phase 1, lane A). Companion to #5453 (TTL sweep).

## What

Nine localStorage stores grew without bound (full 58-call-site audit in
the tracking issue). Each now has an explicit leak-guard cap, applied
wherever the store is parsed, merged, or written, preserving each file's
merge/versioning semantics:

- **Community icons:** 32 entries, 96 KiB/value (aligned with the
relay's `MAX_WORKSPACE_ICON_DATA_URL_LEN`); touched relay becomes
newest.
- **Channel mutes/stars:** newest-500 cap each, bounded by recency
(`updatedAt`, channel-ID lexical tie-breaker), with the just-written
channel unconditionally preserved for that write (cap−1 recency slots +
the mutated key). A bounded LWW store cannot guarantee permanent
deletion history; the guarantee here is that **the just-written mutation
survives its own bounding** and, as the newest entry, defeats an older
remote `true` through the pre-publish `mergeStores`. Known residual
(accepted): `updatedAt` is whole-second, so two distinct mutations
inside the same second at exact capacity can still evict the earlier one
before the debounced publish — same root cause as the merge-path
same-second tie, tracked for the follow-up precision fix rather than
more preservation machinery. Enforced at parse, post-merge, local state,
and persistence.
- **Forced unread:** newest 500 insertion-ordered, touched channels
refreshed.
- **Persistent agent audiences:** 200-scope LRU. An unchanged-audience
touch (including re-initializing an existing scope) refreshes LRU order
and persists without advancing the scope's revision or emitting; an
already-most-recent touch is a pure no-op (no clone, no write), so
render-path re-initialization causes zero storage traffic.
- **Self profiles:** newest 8 per relay / 32 globally by `updatedAt`,
just-written key always preserved; trim count-gates before parsing
payloads so under-cap writes skip the scan entirely.
- **Sections:** newest 100 + newest 1,000 assignments, orphans removed;
`assignChannel` delete/reinserts the touched channel so a reassignment
becomes newest in insertion order and cannot be evicted by the next
assignment. **Sort prefs:** 104 groups (100 sections + 4 fixed).
- **Feature overrides:** `getOverrides()` filters to current-manifest
boolean ids on read only — no write-back from the render-path getter.

## Review-driven revisions

- `237f25e4` — three narrow changes from the first adversarial review
(no render-path storage write, icon cap aligned to relay constant,
count-gated profile trim).
- `d864ffb0` — fixes for the two GitHub review findings on `237f25e4`:
(P1) mute/star bounding switched from false-tombstone-first eviction to
pure recency, with regressions proving an at-capacity unmute/unstar
survives bounding and the pre-publish LWW merge; (P2) unchanged
agent-audience touches now refresh LRU order (no revision advance, no
emit), with a subscriber-mounted regression.
- `3ddbb26d` — MRU guard from the second adversarial VERIFY: the P2
touch path skips clone/persist entirely when the scope is already
most-recently-inserted, eliminating repeat synchronous localStorage
writes from render-path effects. Test proves a non-MRU identical touch
writes exactly once (scope persisted last) and an already-MRU touch
writes zero times.
- `e220ccd9` — fixes for the second GitHub review round (Carl, on Wes's
behalf): (1) mute/star bounders preserve the just-mutated key so a
same-second mutation at capacity survives its own bounding; merge/sync
call sites unchanged; (2) `assignChannel` delete/reinserts the touched
key so an at-capacity reassignment isn't evicted by the next new
assignment. Regressions at storage and hook level for both;
negative-control run of the 7 new tests against the old sources: 7 fail.

## Validation

- Full desktop suite 4555/4555 at both `d864ffb0` and `3ddbb26d`, plus
desktop-check/typecheck via the push gate; focused storage/audience
tests 62/62 at `d864ffb0`, 14/14 audience suite at `3ddbb26d`.
- Independent adversarial review: APPROVE at `88a55aee` (including 100
smoke E2E specs covering every seeded store, run manually since push
hooks exclude Playwright), then a second VERIFY pass: **VERIFIED at
`d864ffb0`** — P1/P2 confirmed closed via negative-control runs of the
new suites against the old sources, plus smoke Playwright on the
mute/star/audience specs (17 passed). That VERIFY requested one
pre-merge change (no localStorage writes from the render path), landed
as the narrow MRU guard in `3ddbb26d` within the reviewer's stated
no-re-review boundary. A third VERIFY pass: **VERIFIED at `e220ccd9`** —
both findings from the second GitHub review confirmed closed by
sensitivity testing (new tests fail on old sources), hostile same-call
section-trim case constructed and passed, full suite 4562/4562 re-run
independently.

Authored by Meeseeks (agent), reviewed by Beth (agent), integrated by
Rick (agent). Discussion: Buzz channel time-based-localstorage-eviction,
thread 0d85a73ca43e54748128f89c3512a4726131bf5473253395d46bf8f3a7b58bd4.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Meeseeks <2e96988f190ed1bd3c568760103aa4cadb2bc6195b832e252c984392c89039bd@buzz.block.builderlab.xyz>
2026-08-10 10:39:07 -07:00
Wes
bb9aae1065 feat(desktop): time-based sweep for stale localStorage caches (#5453)
Part of #5418 (Phase 1, lane B).

## What

Adds a periodic, whitelist-driven TTL sweep for disposable localStorage
caches so a desktop session left open for days converges to the same
storage state as one restarted nightly.

- New `desktop/src/shared/lib/localStorageSweep.ts`: declarative
`LOCAL_STORAGE_SWEEP_RULES` table — six repaintable pure-cache prefixes
(matching `PURE_CACHE_KEY_PREFIXES` in `localStorageQuota.ts`), all
14-day TTL, keyed on each payload's `updatedAt` (user-label buckets use
their newest nested per-profile timestamp).
- Entries with no trustworthy timestamp are retained, never guessed
stale. `buzz-self-profile.v1:` is deliberately excluded — it is the
load-bearing offline identity fallback (guard comment in the table).
- Scheduler: first sweep deferred off the boot critical path via
`requestIdleCallback` (1.5s timeout) with a 250ms timer fallback, then
hourly and on return-to-visible, debounced to 5 minutes. Throw-safe
throughout (failures `console.warn`, never crash — per `safeStorage.ts`
conventions / #5078).
- Wired in `desktop/src/main.tsx` beside
`recoverLocalStorageQuotaOnStartup()`.

## Validation

- Focused node test 7/7 at HEAD; pre-push gate green (desktop-check,
desktop-typecheck, full desktop-test 4542/4542).
- Manual Playwright (not covered by push hooks):
`relay-connectivity.spec.ts -g "04"` (offline cached identity) passes
1/1 at HEAD — this spec caught and now guards the v1 regression.
- Independent adversarial review: FULL REVIEW (REQUEST CHANGES) then
VERIFIED — PASS at exactly this commit, including whitelist containment
against the 58-site inventory, scheduler tracing, and smoke E2E.

Authored by Summer (agent), reviewed by Beth (agent), integrated by Rick
(agent). Discussion: Buzz channel time-based-localstorage-eviction,
thread 0d85a73ca43e54748128f89c3512a4726131bf5473253395d46bf8f3a7b58bd4.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Summer <1fdd3cc104e2911eb3b2da6f97d1b25f4a7f3550ded4492b24ff1d95acd66766@buzz.block.builderlab.xyz>
2026-08-10 09:47:04 -07:00
Wes
43573d114b ci(release): gate OSS desktop auto-update promotion (#5398)
## Summary

Separate OSS desktop artifact publication from fleet-wide auto-update
promotion.

- retain the exact generated updater manifest as `updater-manifest.json`
on each immutable `desktop-vX.Y.Z` release
- stop the tag-triggered build from mutating
`buzz-desktop-latest/latest.json`
- add a `main`-only manual promotion workflow with one global
concurrency group
- validate stable semver, release/tag commit identity, draft/prerelease
state, exact platform set, signatures, version-bound asset URLs, asset
existence, monotonicity, idempotent retries, and a final stale-state
check before writing
- document the operator flow and pin the split with focused contract
tests

## Safety behavior

Publishing a versioned GitHub release no longer exposes it through the
in-app updater. Operators can install and test those exact
signed/notarized artifacts, then manually run **Promote OSS Desktop
Auto-Update** with the stable version.

Promotion rejects downgrades. A same-version retry succeeds only when
the rolling and candidate manifests are byte-identical. The workflow
re-reads the current rolling version immediately before its only write
and records the actor, source tag commit, previous version, manifest
digest, and run URL.

## Verification

Verified at commit `39caf1603be06bb476905225ec55f7bbbe86b237`:

```text
scripts/test-oss-desktop-promotion.sh
OSS desktop promotion contract passed

scripts/test-release-ref-contract.sh
release ref contract passed

git diff --check origin/main...HEAD
(clean)
```

The repository pre-push hook also passed `branch-skew` for the exact
pushed head; package suites were correctly skipped because this change
only touches release workflows, scripts, and documentation.

Originating conversation: Buzz channel `separate-publish-step-release`,
thread
`8857ce8bbe928e891165eddcf06c666cf6eae16181c3f02a6d8c396d8a536026`.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 09:05:32 -07:00
Wes
c1e20a814b fix(release): pin desktop PR operations to block/buzz (#5212)
## Summary

Pin every GitHub CLI PR operation in the Desktop release helper to
`block/buzz`.

Without an explicit repository, `gh` refuses to create the release PR in
checkouts that have multiple GitHub remotes and no configured default.
This happens after the candidate has already been generated, validated,
committed, and pushed.

Add release-contract assertions covering the list, edit, and create
paths so repository qualification cannot regress.

## Validation

- `bash -n scripts/prepare-desktop-release.sh
scripts/test-release-ref-contract.sh`
- `scripts/test-release-ref-contract.sh`
- pre-push `branch-skew`

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 08:59:15 -07:00
Wes
3c76f682c3 fix(search): surface exact short profile names (#5480)
## Summary

- prioritize exact whole-lexeme matches within short kind-0 prefix
searches
- preserve the existing prefix result set, pagination, community/channel
scope, hydration, and authorization path
- add a Postgres regression where newer noisy `jm…` profiles saturate
the bounded page

## Why

Desktop mention autocomplete starts searching after one character. The
`jm` profile is indexed and matches both `jm:*` prefix search and
standard full-text search, but production prefix search returns a full
50-result page without it. Raw profile JSON supplies enough unrelated
`jm…` lexemes that newer equal-rank matches fill the bounded page before
the exact short display name.

Changing clients would leave deployed Desktop 0.5.8 installations
broken. This shared search-layer compatibility fix changes ordering only
for `Prefix + kinds:[0] + query length <= 2`; message search, longer
profile typeahead, and agent eligibility are untouched.

## Validation

At commit `ff88761135d5045139aeb3da14d08cbfba203169` with a clean
worktree:

- `BUZZ_TEST_DATABASE_URL=postgres://buzz:buzz_dev@localhost:5432/buzz
cargo test -p buzz-search --tests -- --include-ignored` — 22 passed (3
unit + 19 Postgres integration)
- `cargo clippy -p buzz-search --tests -- -D warnings`
- `cargo fmt --all -- --check`
- mutation check: disabling exact-lexeme priority makes
`short_kind0_prefix_prioritizes_exact_lexeme_on_a_noisy_page` fail
- mandatory pre-push hooks: branch-skew, Rust tests, and Desktop/Tauri
checks passed

## Risk

Low. The extra ordering predicate applies only to one- or two-character
prefix searches restricted exactly to kind 0. It does not add
candidates, bypass filters, or alter access control. Exact matches move
ahead of broader prefix matches; all remaining ordering stays relevance,
recency, then event ID.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 08:58:45 -07:00
Wes
563e4346da Reduce repeated ACP session context (#5423)
## Summary

- deliver legacy ACP standing context once per live session, committing
delivery state only after a successful turn
- send only new thread/DM event deltas on later turns, with fail-open
behavior for missing IDs and failed/cancelled prompts
- fence native steer delivery acknowledgements by ACP session identity
so stale acks cannot poison replacement sessions
- keep context hints truthful when a fetch contains only the triggering
event versus history delivered earlier

## Validation

The pre-push hook passed on exact pushed head
`6a768f1bc80fe63c686acf8d730f177fff8add3c`:

- `branch-skew`
- `desktop-check`
- `desktop-typecheck`
- `desktop-test`
- `rust-tests`
- `desktop-tauri-checks`

Focused regression tests were also run while iterating:

- `channel_prompt_commits_delivery_state_only_after_acp_success`
- `in_flight_stale_native_steer_ack_cannot_update_replacement_session`
- thread/DM trigger-only versus previously-delivered context hint tests

## Known limitations and follow-ups

A local Goose smoke timed out at `session/new`. This diff does not
change code that executes at or before `session/new`; its earliest
affected runtime behavior is delivery-state insertion after session
creation succeeds. The smoke failure is therefore bounded as
environmental or pre-existing, but no successful live-provider turn was
obtained. Scripted ACP wire/lifecycle tests carry the regression
coverage.

- #5421 — distinguish post-delta, already-delivered, and fetch-truncated
context counts
- #5422 — define a standing-context re-delivery policy if a legacy
provider compacts it away

Durable process-restart/session resume remains out of scope for this
slice of #5342. #5386 also remains separate pending upstream adapter
support.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-10 08:50:34 -07:00
Will Pfleger
5e4c05f90b feat(desktop): NIP-AM agent-usage backend — P2 emission/transport/archive + P4a aggregation/D6 (#4000)
## What

Implements Phases 2 and 4a of the Usage v2 plan (plan events
`d0268cd0`/`0e95b035`), extending the archive backend to emit,
transport, archive, and aggregate both cache categories and billing
identity fail-closed.

### P2 — emission, transport, archive

**Tri-state accumulators** (`Unseen`/`Exact`/`Unknown`) for cache-read
and cache-write in `buzz-agent` turn and session state. Absent field =
Unknown (never zero) through the full pipeline. No `unwrap_or(0)` on the
cache path. Both cache folds are gated on usage-bearing responses (same
gate as the total-state and identity folds) — a response with no usage
at all must not poison either accumulator.

**Overflow-aware input token parsing and accumulation** — closed
end-to-end from parse through wire to ACP:
- `sum_usage()` returns `SumUsageResult` (`Exact(u64)` | `Overflow`) —
checked arithmetic, never clamps. `anthropic_input_tokens()` returns
`Option<SumUsageResult>` since it sums three fields (`input_tokens +
cache_read_input_tokens + cache_creation_input_tokens`) that can
collectively overflow. Single-field callers (`prompt_tokens`,
`completion_tokens`, etc.) convert via `.into_exact()` — their
single-field sums cannot overflow.
- `LlmResponse.input_tokens_overflowed: bool` propagates the parse-layer
signal into the run loop. When set, `input_tokens` is `None` (clamped
value discarded), the context-gate baseline
(`last_request_input_tokens`) is frozen at its prior reading, and
`turn_input_tokens` is poisoned to `TurnIOState::Poisoned` before any
emission — including mid-turn `emit_usage_update` calls. A dedicated
enum on `LlmResponse.input_tokens` would ripple into ~20 existing test
assertions on `r.input_tokens == Some(...)`; the bool flag confines the
change to the two call sites that check it.
- `TurnIOState` (`Unseen`/`Exact`/`Poisoned`) for input and output:
per-round fold uses `checked_add`; overflow poisons permanently at turn
and session level, no healing. Absence does not poison (pass-2-cleared
contract unchanged). Wire emission omits
`accumulatedInputTokens`/`accumulatedOutputTokens` when poisoned — never
null, never `u64::MAX`. ACP treats absent = publisher-poisoned:
`delta_reliable: false`, null turn fields, null cumulative for that
category; session cumulative stays unknown for all subsequent turns once
poisoned.

**Conditional wire emission** for `accumulatedCachedInputTokens` and new
`accumulatedCacheWriteTokens`: fields are omitted when the cumulative is
Unseen or Unknown. ACP `_goose/unstable/session/update` contract
documented next to the payload with tests for all absence/zero variants.

**`PricingIdentity` stamping (publisher-side)**:
- `pricing_authority()`: canonical parsed-URL endpoint comparison
against the official allowlist — HTTPS only, exact allowlisted host
(lookalike-safe), default port (omitted or explicit :443), required API
base path, rejects userinfo/query/fragment/path-prefix lookalikes.
- Model: the actually-requested `request_model` after mesh/auto
resolution (not `effective_model_str`).
- Turn discipline: identity retained only while ALL usage in the current
turn carries one identical proven identity; any mismatch,
unproven-usage-bearing response, or unpaired cumulative snapshot poisons
to absent; a later matching notification does not heal a mixed turn.

**ACP `UsageTracker` identity fold**: per-in-flight-turn tri-state
identity accumulator replacing last-update-wins. Any absent identity on
a token-advancing notification or exact mismatch poisons to absent;
poison survives later updates; reset in `begin_turn()`/`take()`; reset
also when a request fails (baseline cleared so preflight gate cannot
stay frozen sub-threshold on retries).

**M3 migration**: adds `turn_cache_write_tokens`,
`cumulative_cache_write_tokens`, `pricing_authority`, `pricing_model`,
`pricing_cache_class` to `agent_metric_index`. Additive, idempotent,
guarded per-column by marker. M2 migration also guarded per-column (turn
and cumulative cache-read columns checked and added independently;
marker commits only after both are present). Fresh-DB schema includes
all columns.

**First-turn baselines**: `seed_zero_baseline` seeds `last_input:
Some(0)`, `last_output: Some(0)`, `last_cached_input: Some(0)`,
`last_cache_write: Some(0)`, and `last_total: Some(0)` — all have the
known-zero-at-spawn argument. Absent fields from incoming snapshots
still produce unknown (tri-state unchanged). Sessions buzz-acp did not
spawn (no seed) remain fail-closed on turn one.

**`ReportedUsage` TS mirror**: `cacheReadTokens`, `cacheWriteTokens`,
`freshInputTokens` added to `tauriArchive.ts` as `UsageField` members,
field-for-field with the Rust struct.

### P4a — aggregation layer

**Extended S-1 ladder** to cache-read and cache-write via the same
`ladder_token` path as the existing token fields.

**`freshInputTokens` derivation**: checked arithmetic, fail-closed —
absent cache fields produce Unknown (not zero), overflow and
`cacheRead+cacheWrite > input` both produce `incomplete: true`.
Aggregated as a `UsageField`.

**D6 comparator**: `sort_value()` = provider total when known, else
`input+output` when both known, else `None` (unknown-last). Replaces the
prior total-only comparator for both agent-level and model-level sort.
Ships a pinned test vector that the TS render layer (P5) must match.

## Test coverage

- `buzz-agent`: 440 lib + 15 integration (golden_transcripts) — includes
13 new `cache_total_state_tests`; 14 new `turn_io_state_tests`; 3 new
`sum_usage_*` tests (exact single-field, exact two-field, overflow
signals correctly); 3 new `parse_anthropic_*` tests (overflow flag set +
value cleared, normal sum no flag, absent usage no flag); end-to-end
golden transcript drives real subprocess with Anthropic-shaped
`input_tokens: u64::MAX, cache_read: 1` response and asserts
`accumulatedInputTokens` absent from the emitted `usage_update` — no
logic duplication; 3 wire pin tests; 4 `fold_pricing_identity_*` tests;
`pricing_authority()` explicit-:443 acceptance
- `buzz-acp`: 700 tests (691 lib + 9 integration) — 4 new usage tests
(absent input → unreliable+null; absent output → unreliable+null;
goose-shaped both present unchanged; poison mid-session); 3 ACP behavior
tests; 7 pool lifecycle tests
- Desktop (Rust): 2259+ tests — 14 new P4a pinned tests; 2 M3 round-trip
tests; 1 serde key-shape test; 2 M2 partial-schema migration tests;
first-turn cache round-trip test

## Related PRs

- P1 NIP-AM spec: [#4632](https://github.com/block/buzz/pull/4632)
- P3 pricing table: [#4629](https://github.com/block/buzz/pull/4629)
- UI (P5): [#4001](https://github.com/block/buzz/pull/4001)

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-10 10:47:37 -04:00
Atish Patel
44456e200e fix(desktop): resolve overlapping member mentions (#5225)
## Why
Selecting or typing a member whose display name extends another member's
name, such as `@Fast Fizz Codex`, could emit p-tags for both identities
and wake the wrong agent.

## What
- Resolve overlapping member-name matches by choosing the longest valid
display name at each mention offset
- Preserve separately typed short-name mentions at different offsets
- Add regression coverage for selected team expansions and manually
typed prefix collisions

## Risk Assessment
Low to medium — this changes Desktop mention routing only. Exact
mentions and distinct offsets remain supported; same-length ambiguous
display names remain conservatively tagged because text alone cannot
disambiguate them.

Will resolve https://github.com/block/buzz/issues/2909

Generated with Goose

Signed-off-by: Hardworking Honey <c5c455215c2506cb8ba776518cec804af62d3a0526e32d496a22072e395042b9@buzz.block.builderlab.xyz>
Signed-off-by: Atish Patel <atish@squareup.com>
Co-authored-by: Hardworking Honey <c5c455215c2506cb8ba776518cec804af62d3a0526e32d496a22072e395042b9@buzz.block.builderlab.xyz>
2026-08-10 07:20:54 -07:00
renovate[bot]
119a84897f chore(deps): update react monorepo (#4441)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react))
| [`19.2.17` →
`19.2.18`](https://renovatebot.com/diffs/npm/@types%2freact/19.2.17/19.2.18)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.2.18?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.2.17/19.2.18?slim=true)
|
|
[@types/react-dom](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom))
| [`19.2.3` →
`19.2.4`](https://renovatebot.com/diffs/npm/@types%2freact-dom/19.2.3/19.2.4)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact-dom/19.2.4?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact-dom/19.2.3/19.2.4?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4xMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Wes <wesbillman@users.noreply.github.com>
2026-08-09 09:52:17 -07:00
Wes
d2ebaa95a7 ci(security): allow retired relay pool advisory (#5404)
## Summary

- temporarily allow the informational `RUSTSEC-2026-0243` advisory for
the retired `nostr-relay-pool` crate
- document the exact MeshLLM → `nostr-sdk 0.44.1` transitive path and
removal condition
- keep every other advisory and the global dependency policy enforced

## Why an exception

RustSec provides no patched `nostr-relay-pool` release because the
standalone crate was absorbed into `nostr-sdk >= 0.45`. Buzz inherits it
through pinned MeshLLM v0.74. A direct test bump to `nostr-sdk 0.45.1`
removed the retired crate but produced 13 MeshLLM API compilation
errors, so the durable fix requires an upstream source migration rather
than a lockfile update.

This narrow exception restores the required Security check while that
migration is completed. It must be removed once MeshLLM adopts
`nostr-sdk >= 0.45`.

## Validation

- `bin/cargo-deny --locked check --config deny.toml advisories`
- `bin/cargo-deny --locked check`
- `git diff --check origin/main...HEAD`
- mandatory pre-push Rust and desktop/Tauri checks

## Scope

One four-line `deny.toml` addition. No Rust source, lockfile, runtime,
or release behavior changes.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-09 09:39:21 -07:00
renovate[bot]
c923e89a4b chore(deps): update dependency @tanstack/react-virtual to v3.14.9 (#4439)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@tanstack/react-virtual](https://tanstack.com/virtual)
([source](https://redirect.github.com/TanStack/virtual/tree/HEAD/packages/react-virtual))
| [`3.14.8` →
`3.14.9`](https://renovatebot.com/diffs/npm/@tanstack%2freact-virtual/3.14.8/3.14.9)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-virtual/3.14.9?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-virtual/3.14.8/3.14.9?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>TanStack/virtual (@&#8203;tanstack/react-virtual)</summary>

###
[`v3.14.9`](https://redirect.github.com/TanStack/virtual/blob/HEAD/packages/react-virtual/CHANGELOG.md#3149)

[Compare
Source](https://redirect.github.com/TanStack/virtual/compare/@tanstack/react-virtual@3.14.8...@tanstack/react-virtual@3.14.9)

##### Patch Changes

- Updated dependencies
\[[`a5417b4`](a5417b4b0d)]:
-
[@&#8203;tanstack/virtual-core](https://redirect.github.com/tanstack/virtual-core)@&#8203;3.17.7

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:11:47 -07:00
renovate[bot]
856cdb848b chore(deps): update all non-major dependencies (#3049)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) | Type |
Update |
|---|---|---|---|---|---|
|
[@isomorphic-git/lightning-fs](https://redirect.github.com/isomorphic-git/lightning-fs)
| [`4.6.2` →
`4.6.3`](https://renovatebot.com/diffs/npm/@isomorphic-git%2flightning-fs/4.6.2/4.6.3)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@isomorphic-git%2flightning-fs/4.6.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@isomorphic-git%2flightning-fs/4.6.2/4.6.3?slim=true)
| dependencies | patch |
|
[@vitejs/plugin-react](https://redirect.github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme)
([source](https://redirect.github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react))
| [`6.0.3` →
`6.0.5`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-react/6.0.3/6.0.5)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@vitejs%2fplugin-react/6.0.5?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitejs%2fplugin-react/6.0.3/6.0.5?slim=true)
| devDependencies | patch |
|
[@vitejs/plugin-react](https://redirect.github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme)
([source](https://redirect.github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react))
| [`6.0.3` →
`6.0.5`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-react/6.0.3/6.0.5)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@vitejs%2fplugin-react/6.0.5?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitejs%2fplugin-react/6.0.3/6.0.5?slim=true)
| dependencies | patch |
| [dorny/paths-filter](https://redirect.github.com/dorny/paths-filter) |
`v4.0.2` → `v4.0.3` |
![age](https://developer.mend.io/api/mc/badges/age/github-tags/dorny%2fpaths-filter/v4.0.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/dorny%2fpaths-filter/v4.0.2/v4.0.3?slim=true)
| action | patch |
| [isomorphic-git](https://isomorphic-git.org/)
([source](https://redirect.github.com/isomorphic-git/isomorphic-git)) |
[`1.38.7` →
`1.38.10`](https://renovatebot.com/diffs/npm/isomorphic-git/1.38.7/1.38.10)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/isomorphic-git/1.38.10?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/isomorphic-git/1.38.7/1.38.10?slim=true)
| dependencies | patch |
| [postcss](https://postcss.org/)
([source](https://redirect.github.com/postcss/postcss)) | [`8.5.19` →
`8.5.26`](https://renovatebot.com/diffs/npm/postcss/8.5.19/8.5.26) |
![age](https://developer.mend.io/api/mc/badges/age/npm/postcss/8.5.26?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/postcss/8.5.19/8.5.26?slim=true)
| devDependencies | patch |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>isomorphic-git/lightning-fs
(@&#8203;isomorphic-git/lightning-fs)</summary>

###
[`v4.6.3`](https://redirect.github.com/isomorphic-git/lightning-fs/releases/tag/v4.6.3)

[Compare
Source](https://redirect.github.com/isomorphic-git/lightning-fs/compare/v4.6.2...v4.6.3)

##### Bug Fixes

- IDB interface
([#&#8203;127](https://redirect.github.com/isomorphic-git/lightning-fs/issues/127))
([035e472](035e4725b9))

</details>

<details>
<summary>vitejs/vite-plugin-react
(@&#8203;vitejs/plugin-react)</summary>

###
[`v6.0.5`](https://redirect.github.com/vitejs/vite-plugin-react/blob/HEAD/packages/plugin-react/CHANGELOG.md#605-2026-07-30)

[Compare
Source](f4b549822e...68c0cb8796)

##### Fixed the react compiler preset filter to be linear
([#&#8203;1353](https://redirect.github.com/vitejs/vite-plugin-react/pull/1353))

The improved filter in v6.0.3 was non-linear and caused a performance
regression
([#&#8203;1349](https://redirect.github.com/vitejs/vite-plugin-react/issues/1349)).
The filter was changed to be linear to avoid that.

###
[`v6.0.4`](https://redirect.github.com/vitejs/vite-plugin-react/blob/HEAD/packages/plugin-react/CHANGELOG.md#604-2026-07-22)

[Compare
Source](640fd358a0...f4b549822e)

##### Fixed `$RefreshSig$ is not defined` error when running `vite dev`
with `NODE_ENV=production`

When running `vite dev` with `NODE_ENV=production`, the app errored with
`$RefreshSig$ is not defined`.
This error is now fixed.

</details>

<details>
<summary>dorny/paths-filter (dorny/paths-filter)</summary>

###
[`v4.0.3`](https://redirect.github.com/dorny/paths-filter/blob/HEAD/CHANGELOG.md#v403)

[Compare
Source](https://redirect.github.com/dorny/paths-filter/compare/v4.0.2...v4.0.3)

- [Document safe handling of file list outputs in
workflows](https://redirect.github.com/dorny/paths-filter/pull/326)
- [Escape multi-line filenames in list-files shell and csv
output](https://redirect.github.com/advisories/GHSA-7hc6-8hq5-9q2m)
- [Add 'some-with-excludes' predicate
quantifier](https://redirect.github.com/dorny/paths-filter/pull/322)
- [Add contents permission to PR
example](https://redirect.github.com/dorny/paths-filter/pull/248)
- [Scope base-ignored warning to API
path](https://redirect.github.com/dorny/paths-filter/pull/319)
- [Update outputs in readme to account for the 'every'
predicate-quantifier](https://redirect.github.com/dorny/paths-filter/pull/247)

</details>

<details>
<summary>isomorphic-git/isomorphic-git (isomorphic-git)</summary>

###
[`v1.38.10`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.10)

[Compare
Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.9...v1.38.10)

##### Bug Fixes

- **statusMatrix:** do not traverse symlinks in GitWalkerFs
([#&#8203;1215](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/1215))
([#&#8203;2382](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2382))
([90ea101](90ea101d32))

###
[`v1.38.9`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.9)

[Compare
Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.8...v1.38.9)

##### Bug Fixes

- Preserve binary files when writing conflicted working tree
([#&#8203;2380](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2380))
([b41b1ab](b41b1abc3d))

###
[`v1.38.8`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.8)

[Compare
Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.7...v1.38.8)

##### Bug Fixes

- unsafe symlink from cherry pick
([#&#8203;2377](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2377))
([4664c8e](4664c8e114))

</details>

<details>
<summary>postcss/postcss (postcss)</summary>

###
[`v8.5.26`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8526)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.25...8.5.26)

- Fixed `list.split()` regression (by
[@&#8203;lazerg](https://redirect.github.com/lazerg)).
- Track symlinks in path protection in source map loading (by
[@&#8203;drengir1](https://redirect.github.com/drengir1)).

###
[`v8.5.25`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8525)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.24...8.5.25)

- Fixed 8.5.17 visitor regression.
- Fixed `list.split()` for non-string values (by
[@&#8203;amir-rezaei](https://redirect.github.com/amir-rezaei)).

###
[`v8.5.24`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8524)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.23...8.5.24)

- Preserve the BOM after the processing (by
[@&#8203;hdimer](https://redirect.github.com/hdimer)).

###
[`v8.5.23`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8523)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.22...8.5.23)

- Do not load source map without `opts.from` for security reasons.

###
[`v8.5.22`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8522)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.21...8.5.22)

- Fixed custom property losing semicolon before a comment (by
[@&#8203;sarathfrancis90](https://redirect.github.com/sarathfrancis90)).

###
[`v8.5.21`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8521)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.20...8.5.21)

- Fixed childless at-rule losing semicolon before comment (by
[@&#8203;sarathfrancis90](https://redirect.github.com/sarathfrancis90)).
- Fixed docs (by [@&#8203;isker](https://redirect.github.com/isker)).

###
[`v8.5.20`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8520)

[Compare
Source](https://redirect.github.com/postcss/postcss/compare/8.5.19...8.5.20)

- Fixed missing space if `AtRule#params` is set after (by
[@&#8203;sarathfrancis90](https://redirect.github.com/sarathfrancis90)).
- Fixed mixing AST error on warnings (by
[@&#8203;MahinAnowar](https://redirect.github.com/MahinAnowar)).

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjEyLjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:11:26 -07:00
renovate[bot]
e1ff91ecc1 chore(deps): update rust crate anyhow to v1.0.104 (#4447)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [anyhow](https://redirect.github.com/dtolnay/anyhow) | dependencies |
patch | `1.0.103` → `1.0.104` |
| [anyhow](https://redirect.github.com/dtolnay/anyhow) |
workspace.dependencies | patch | `1.0.103` → `1.0.104` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>dtolnay/anyhow (anyhow)</summary>

###
[`v1.0.104`](https://redirect.github.com/dtolnay/anyhow/releases/tag/1.0.104)

[Compare
Source](https://redirect.github.com/dtolnay/anyhow/compare/1.0.103...1.0.104)

- Update `syn` dev-dependency to version 3

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:09:50 -07:00
renovate[bot]
08de85c592 chore(deps): update rust crate arc-swap to v1.9.2 (#4448)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [arc-swap](https://redirect.github.com/vorner/arc-swap) | dependencies
| patch | `1.9.1` → `1.9.2` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>vorner/arc-swap (arc-swap)</summary>

###
[`v1.9.2`](https://redirect.github.com/vorner/arc-swap/blob/HEAD/CHANGELOG.md#192)

- Document RefCnt must not panic
([#&#8203;208](https://redirect.github.com/vorner/arc-swap/issues/208)).

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:09:26 -07:00
renovate[bot]
12b1f56648 chore(deps): update rust crate async-trait to v0.1.91 (#4458)
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [async-trait](https://redirect.github.com/dtolnay/async-trait) |
dependencies | patch | `0.1.89` → `0.1.91` | `0.1.92` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>dtolnay/async-trait (async-trait)</summary>

###
[`v0.1.91`](https://redirect.github.com/dtolnay/async-trait/compare/0.1.90...0.1.91)

[Compare
Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.90...0.1.91)

###
[`v0.1.90`](https://redirect.github.com/dtolnay/async-trait/releases/tag/0.1.90)

[Compare
Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.89...0.1.90)

- Update to syn 3

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4xMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:08:58 -07:00
renovate[bot]
d7cc724fa5 chore(deps): update rust crate diffy to v0.5.1 (#4466)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [diffy](https://redirect.github.com/bmwill/diffy) | dependencies |
patch | `0.5.0` → `0.5.1` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>bmwill/diffy (diffy)</summary>

###
[`v0.5.1`](https://redirect.github.com/bmwill/diffy/blob/HEAD/CHANGELOG.md#051---2026-07-18)

[Compare
Source](https://redirect.github.com/bmwill/diffy/compare/0.5.0...0.5.1)

##### Fixed

- [#&#8203;85](https://redirect.github.com/bmwill/diffy/pull/85)
  Merge conflict markers are now always placed on their own lines.
  Previously, a conflicting hunk at the end of a file without a trailing
  newline glued the next marker onto its last content line, producing
  unparseable output. This matches `git merge-file --diff3` behavior.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:08:38 -07:00
renovate[bot]
7dd8791d07 chore(deps): update rust crate async-compression to v0.4.43 (#4456)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[async-compression](https://redirect.github.com/Nullus157/async-compression)
| dependencies | patch | `0.4.42` → `0.4.43` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>Nullus157/async-compression (async-compression)</summary>

###
[`v0.4.43`](https://redirect.github.com/Nullus157/async-compression/releases/tag/async-compression-v0.4.43)

[Compare
Source](https://redirect.github.com/Nullus157/async-compression/compare/async-compression-v0.4.42...async-compression-v0.4.43)

##### Other

- Fix hang when decoding a corrupt subsequent zstd frame
([#&#8203;470](https://redirect.github.com/Nullus157/async-compression/pull/470))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4xMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:08:08 -07:00
renovate[bot]
e668c6bb49 chore(deps): update rust crate clap to v4.6.6 (#4465)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [clap](https://redirect.github.com/clap-rs/clap) | dependencies |
patch | `4.6.1` → `4.6.6` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>clap-rs/clap (clap)</summary>

###
[`v4.6.6`](https://redirect.github.com/clap-rs/clap/compare/clap_complete-v4.6.5...clap_complete-v4.6.6)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.5...v4.6.6)

###
[`v4.6.5`](https://redirect.github.com/clap-rs/clap/compare/clap_complete-v4.6.4...clap_complete-v4.6.5)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.4...v4.6.5)

###
[`v4.6.4`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#464---2026-07-21)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.3...v4.6.4)

##### Internal

- Update to syn v3

###
[`v4.6.3`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#463---2026-07-20)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.2...v4.6.3)

##### Fixes

- *(derive)* Allow `"literal".function()` as attribute values

###
[`v4.6.2`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#462---2026-07-15)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.1...v4.6.2)

##### Fixes

- *(help)* Say `alias` when there is only one

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/block/buzz).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4xMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-09 09:07:46 -07:00
Wes
97aa9e3185 fix(desktop): preserve Welcome banner dismissal (#5406)
## Summary

- remove the complete Welcome guidance surface when dismissal reaches
`hidden`
- preserve dismissal across the private and starter Welcome channels for
the active identity
- assert the starter channel's actual `welcome-everyone` title on
re-entry

## Why

PR #5330 introduced two deterministic Desktop E2E failures:

- the inner banner unmounted, but `welcome-composer-guidance-layer`
remained
- the re-entry test expected case-sensitive `Welcome` while navigating
to `welcome-everyone`

The state hook also scoped completion to channel IDs while `ChannelPane`
remounts during navigation. The Welcome guidance is one experience
spanning both Welcome channels, so completion now survives that remount
while remaining identity-scoped.

## Validation

At `b577eb42edffe889f63566f2457eacea720f3593`:

- `pnpm -C desktop typecheck`
- focused Biome check for all four changed files
- E2E build
- both `welcome-everywhere banner` integration tests repeated three
times: **6/6 passed**
- mandatory pre-push desktop check, typecheck, and full desktop unit
suite: **4,535 passed**
- `git diff --check`

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-09 09:05:47 -07:00
Tyler
5bf78671f4 fix(agent): retry LLM completion on malformed 2xx JSON body (#5351)
## Problem

A provider can return HTTP 200 with a **truncated JSON body** — cleanly
closed connection, correct framing, content cut off mid-value. Both LLM
HTTP loops treated this as a terminal error on the first attempt:
`AgentError::Llm("json: EOF while parsing a value")`, surfaced as code
-32000 at the ACP boundary, killing the agent turn before it produced
anything.

Observed live in a tb2.1 bench trial (write-compressor, tb21-twins-1):
deepseek via OpenRouter returned a truncated body, the agent died
mid-prompt with 0 turns completed, and the trial scored 0 on a provider
hiccup.

Meanwhile the same loops already retry timeouts, 429s, 5xxs, 499s, and
mid-body stream stalls — a truncated-but-complete body was the one
transient upstream fault that fell through to terminal.

## Fix

In both `post()` and `openrouter_post()`
(`crates/buzz-agent/src/llm.rs`): when the fully-received success body
fails `serde_json::from_slice`, `continue` the **existing** retry loop
instead of returning terminal — same `MAX_RETRIES` (3) bound, same
`backoff_with_jitter`. On exhaustion, the error goes through
`terminal_llm_error` so it carries cumulative duration + attempt count
like every other retried failure (previously the `json:` error carried
neither).

`post_anthropic` routes through `post()`, so
Anthropic/OpenAI/Databricks/mesh and OpenRouter are all covered.

## Why this cannot re-run a tool call

Hard requirement: tool calls are not idempotent, and this change must
not introduce any possibility of replaying one.

1. **The retry lives inside the HTTP POST helper, below the parse
boundary.** Tool calls are only ever extracted from a *successfully
parsed* response value
(`parse_openai`/`parse_anthropic`/`parse_responses`, all downstream of
these helpers' `Ok` return). A malformed body never parses, therefore no
tool call was ever extracted from it, therefore nothing downstream of it
ever dispatched.
2. **What is re-sent is the completion request itself** — the identical
`body_bytes` captured once at function entry. Sending a completion
request executes no tools; it asks the model for the next message.
3. **Same safety class as existing behavior.** The loop already re-sends
this identical request on 429/5xx/timeout/stream-stall; this adds one
more transient-fault arm to the same loop with the same bytes.

## Tests

Three new tests mirroring the existing 499/dropped-connection fixtures
(raw `TcpListener` stubs):
- `post_retries_malformed_json_body_and_succeeds` — truncated 200 body
on attempt 1, valid JSON on attempt 2; asserts success and **exactly 2**
server-side requests
- `post_exhausts_retries_on_persistent_malformed_json` —
always-truncated body; asserts exactly `MAX_RETRIES` attempts and a
terminal error carrying `json:` + cumulative/attempt context
- `openrouter_post_retries_malformed_json_body_and_succeeds` — same
recovery through OpenRouter's separate loop

Full `cargo test -p buzz-agent` green at e7a5d7bb (430 lib + all
integration targets, 0 failures); `cargo fmt` + `clippy --all-targets`
clean.

Originating conversation: buzz-benchmarking channel, thread 397a992d.

Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
2026-08-08 17:29:06 -04:00
Will Pfleger
f029deafae fix(desktop): welcome banner overlap and missing dismiss control (#5330)
## Problem

The `WelcomeComposerGuidanceLayer` in the `#Welcome` channel was
positioned with `absolute inset-x-0 bottom-full z-[-1]` — outside the
`composerWrapperRef` measurement boundary. `useComposerHeightPadding`
observes `composerWrapperRef`'s block size to set `paddingBottom` on the
timeline scroll container, but the absolutely-positioned layer didn't
contribute to that size. The banner sat directly on top of the newest
message, blocking the thread affordance on that message, and had no
manual dismiss control.

## Fix

**Overlap**: Changed `WelcomeComposerGuidanceLayer` from `absolute
inset-x-0 bottom-full z-[-1]` to `relative` (in normal flow). As a
normal-flow child of `composer-dock`, the layer's full height is now
measured by the ResizeObserver and fed into the timeline's
`paddingBottom`, so the newest message is always fully visible and its
thread affordance is always clickable while the banner shows.

**Dismiss**: Added an `X` close button
(`data-testid="welcome-composer-dismiss-button"`) on the prompt state.
Clicking fires `onDismiss`, which drives `dismissing → hidden`
immediately (same slide-down animation as the auto-dismiss path) and
marks the channel ID as completed in the session ref so the banner does
not reappear on channel re-entry within the session.

**Refactor**: Extracted the banner state machine (refs, timers,
`useEffect`s, and callbacks) from `ChannelPane.tsx` into
`useWelcomeComposerBanner.ts`. This keeps `ChannelPane.tsx` well under
the 1000-line file-size ratchet and makes the state machine
independently testable.

## Changed files

- `desktop/src/features/channels/ui/WelcomeComposerBanner.tsx` —
`WelcomeComposerGuidanceLayer` positioning fix; `onDismiss` prop;
dismiss button; `overflow-hidden` / `mb-0` / `flex-1` cleanup
- `desktop/src/features/channels/ui/ChannelPane.tsx` — remove inline
banner state machine, use `useWelcomeComposerBanner` hook, pass
`onDismiss`
- `desktop/src/features/channels/ui/useWelcomeComposerBanner.ts` — new
hook owning all banner state

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Hayt <41ea58f1e64c243627e8acde7c89be667052ee6e17d8f021c1195be4324ebf04@buzz.block.builderlab.xyz>
2026-08-08 13:00:09 -04:00
Will Pfleger
fbf89e3bed fix(desktop): prevent horizontal clipping in Prompt Context modal (#5324)
The Prompt Context modal (observer feed → check icon under sent
messages) was clipping all content and card right-padding at the dialog
edge.

**Root cause**: `PromptContextDialog` renders inside `DialogContent`,
which is a CSS grid. The child flex wrapper had default `min-width:
auto`, so the widest unbreakable token in the content (64-char hex event
IDs, `Tags: [[...]]` JSON) set the grid track width, blowing it past
`max-w-xl`. `overflow-hidden` then clipped everything at the dialog edge
— including the section cards' right padding.

**Fix**:
- `AgentSessionTranscriptList.tsx`: add `min-w-0` to the `flex
max-h-[85vh] flex-col` wrapper so the grid item can shrink below its
max-content width.
- `PromptSectionAccordion.tsx`: replace `wrap-break-word` with
`wrap-anywhere` on the body text (open and collapsed states) and the
title. `overflow-wrap: anywhere` reduces min-content width, which
`break-word` does not, letting long tokens wrap inside the cards rather
than inflating the track.

The `line-clamp-2` collapsed preview is preserved unchanged.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-08 12:59:41 -04:00
Will Pfleger
6e5c462ac5 chore(release): release Buzz Relay version 0.2.1 (#2856)
## Buzz Relay release v0.2.1

### Changes since relay-v0.2.0:

- fix(sdk): preserve self-mention p tags in message and forum event
builders ([#4975](https://github.com/block/buzz/pull/4975))
([`78c87ae20e`](78c87ae20e))
- feat(desktop): adding rich link previews to messages
([#3818](https://github.com/block/buzz/pull/3818))
([`1922d49cb2`](1922d49cb2))
- feat(relay): accept kind:30179 private managed-agent events at ingest
([#5133](https://github.com/block/buzz/pull/5133))
([`ad923353a2`](ad923353a2))
- fix(media): require authenticated reads
([#4610](https://github.com/block/buzz/pull/4610))
([`769ac70b74`](769ac70b74))
- feat(identity): recover desktop identity from a signed-in phone
([#4845](https://github.com/block/buzz/pull/4845))
([`6eb65919f1`](6eb65919f1))
- ci: prove the relay-driven mesh lifecycle — discover, join, infer,
deny — with real nodes
([#3862](https://github.com/block/buzz/pull/3862))
([`38bf642fcf`](38bf642fcf))
- relay: fuzz WebSocket 1012 restart-close timing on graceful drain
(BUZZ_DRAIN_JITTER_MS)
([#4542](https://github.com/block/buzz/pull/4542))
([`e14fff74d0`](e14fff74d0))
- fix(reactions): support max-length custom emoji
([#3833](https://github.com/block/buzz/pull/3833))
([`2ea9385015`](2ea9385015))
- fix(channels): restrict private-channel invitations
([#4612](https://github.com/block/buzz/pull/4612))
([`efe1893dd3`](efe1893dd3))
- fix(workflow): bind trigger author to the signed event
([#4607](https://github.com/block/buzz/pull/4607))
([`885bed35ee`](885bed35ee))
- fix(git): revoke access for banned relay members
([#4608](https://github.com/block/buzz/pull/4608))
([`997b8caaa4`](997b8caaa4))
- Define private managed agent wire protocol
([#4593](https://github.com/block/buzz/pull/4593))
([`067c085f37`](067c085f37))
- perf(relay): index channel-id lookups and skip trace-only reads
([#4647](https://github.com/block/buzz/pull/4647))
([`bc9e6528a7`](bc9e6528a7))
- Polish mobile inbox and media flows
([#4512](https://github.com/block/buzz/pull/4512))
([`feccf4eabc`](feccf4eabc))
- fix(git): allow deleting the default branch
([#4297](https://github.com/block/buzz/pull/4297))
([`fc598f5f8d`](fc598f5f8d))
- feat(projects): add buzz projects CLI commands (NIP-MP kind:30621)
([#4020](https://github.com/block/buzz/pull/4020))
([`b7bb15122e`](b7bb15122e))
- perf(relay): serve relay-membership checks from the read replica
([#4124](https://github.com/block/buzz/pull/4124))
([`ac4fa13b8e`](ac4fa13b8e))
- fix(relay): allow open relays to set their NIP-11 workspace icon
(kind:9033) ([#3998](https://github.com/block/buzz/pull/3998))
([`5765fc74b7`](5765fc74b7))
- feat(relay): accept kind:30621 multi-repo projects at ingest
([#3171](https://github.com/block/buzz/pull/3171))
([`cb9701cd30`](cb9701cd30))
- feat(relay): raise hosted community limit to five
([#3829](https://github.com/block/buzz/pull/3829))
([`10d5a26414`](10d5a26414))
- fix(relay): align NIP-11 max_limit with REQ ceiling
([#3635](https://github.com/block/buzz/pull/3635))
([`23f0c26b1c`](23f0c26b1c))
- feat(relay): gate kind 30178 team-catalog reads behind the shared tag
([#3358](https://github.com/block/buzz/pull/3358))
([`114d40d9d3`](114d40d9d3))
- fix(db): isolate usage metrics advisory-lock test on scratch DB
([#3670](https://github.com/block/buzz/pull/3670))
([`dba97eecd9`](dba97eecd9))
- perf(presence): reduce heartbeat frequency
([#3783](https://github.com/block/buzz/pull/3783))
([`bf139e8d0b`](bf139e8d0b))
- feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute
(split 1/2 of #3467) ([#3741](https://github.com/block/buzz/pull/3741))
([`4933672eb4`](4933672eb4))
- feat(replica): portable heartbeat-token fence with snapshot-local
reader routing ([#3268](https://github.com/block/buzz/pull/3268))
([`63496cc1d4`](63496cc1d4))
- fix(git): channel binding tooling + author remediation for unbound
repos ([#3626](https://github.com/block/buzz/pull/3626))
([`788b3c002b`](788b3c002b))
- feat: configure S3 URL addressing style
([#3400](https://github.com/block/buzz/pull/3400))
([`7012d86d52`](7012d86d52))
- feat(tracing): correlate trace IDs in relay logs
([#3608](https://github.com/block/buzz/pull/3608))
([`005b5b819a`](005b5b819a))
- fix(relay): avoid subscription lock inversion
([#3413](https://github.com/block/buzz/pull/3413))
([`22be8bb351`](22be8bb351))
- feat(cli): add users set-status command for NIP-38 profile status
([#3253](https://github.com/block/buzz/pull/3253))
([`60158fce3e`](60158fce3e))
- feat(relay): make Postgres pool size configurable, default 50
([#3191](https://github.com/block/buzz/pull/3191))
([`2ce2d71cc3`](2ce2d71cc3))
- feat(tracing): add datastore tracing plumbing
([#2760](https://github.com/block/buzz/pull/2760))
([`e94b9aeda0`](e94b9aeda0))
- feat(invites): add use-limited invite links
([#3141](https://github.com/block/buzz/pull/3141))
([`d500c2d5cf`](d500c2d5cf))
- feat(admin): show reported message content in report detail
([#3149](https://github.com/block/buzz/pull/3149))
([`f069a85503`](f069a85503))
- resolve findings ([#3150](https://github.com/block/buzz/pull/3150))
([`9b0f744804`](9b0f744804))
- Revert "fix(cli,relay): resolve agents by verified owner"
([#3168](https://github.com/block/buzz/pull/3168))
([`a041e2d21e`](a041e2d21e))
- fix(cli,relay): resolve agents by verified owner
([#2615](https://github.com/block/buzz/pull/2615))
([`c3084b36d9`](c3084b36d9))
- fix(security): enforce durable community ban on NIP-43 relay-admin
kinds 9030-9033 ([#3128](https://github.com/block/buzz/pull/3128))
([`e2e0079101`](e2e0079101))
- fix(security): authorize kind:9000 role changes in both directions
([#3017](https://github.com/block/buzz/pull/3017))
([`00ecf2cac7`](00ecf2cac7))
- feat(desktop): handle project work from Inbox
([#3117](https://github.com/block/buzz/pull/3117))
([`c5c4f390b6`](c5c4f390b6))
- feat(relay): make per-owner community limit configurable via
BUZZ_MAX_COMMUNITIES_PER_OWNER
([#2599](https://github.com/block/buzz/pull/2599))
([`2a051a404d`](2a051a404d))
- feat(relay): add author-only-unless-shared read gate for kind 30175
([#2768](https://github.com/block/buzz/pull/2768))
([`ab3af82871`](ab3af82871))
- fix(core): block IPv6 transition SSRF targets
([#2801](https://github.com/block/buzz/pull/2801))
([`c26bf5945d`](c26bf5945d))
- fix(workflow): bypass system proxies for webhooks
([#2800](https://github.com/block/buzz/pull/2800))
([`60a171b19e`](60a171b19e))
- fix(audit): hash created_at at the precision Postgres stores
([#2638](https://github.com/block/buzz/pull/2638))
([`264a56a226`](264a56a226))
- feat(desktop): make pull request reviews actionable
([#2510](https://github.com/block/buzz/pull/2510))
([`9081ab0ec9`](9081ab0ec9))
- fix(relay): decompress gzip-encoded git smart-HTTP request bodies
([#2670](https://github.com/block/buzz/pull/2670))
([`5ca36e7b91`](5ca36e7b91))
- fix(sharing): preserve agent/team snapshot tEXt chunks through media
sanitization ([#2438](https://github.com/block/buzz/pull/2438))
([`b096b0a15a`](b096b0a15a))
- fix(relay): send 1012 restart close to all clients on graceful drain
([#2575](https://github.com/block/buzz/pull/2575))
([`1911c69aa2`](1911c69aa2))
- fix(media): sanitize animated image uploads
([#2524](https://github.com/block/buzz/pull/2524))
([`8f8f5fa5a4`](8f8f5fa5a4))
- fix(channels): strip leading hash prefixes from names
([#2250](https://github.com/block/buzz/pull/2250))
([`d0ab3fdb05`](d0ab3fdb05))
- feat(relay): make Redis pool size configurable, default 16
([#2521](https://github.com/block/buzz/pull/2521))
([`bcc3e13069`](bcc3e13069))
- feat(desktop+acp): spawn a harness per (agent, community) pair at GUI
startup — warm sockets, lazy LLM pool
([#2122](https://github.com/block/buzz/pull/2122))
([`61cc738ee8`](61cc738ee8))
- feat(media): add S3-truth per-community storage sweep
([#2044](https://github.com/block/buzz/pull/2044))
([`bd37a4d584`](bd37a4d584))
- feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests
([#2206](https://github.com/block/buzz/pull/2206))
([`7e34bee62c`](7e34bee62c))
- Revert "feat(relay): inventory unreachable Git objects"
([#2275](https://github.com/block/buzz/pull/2275))
([`0fb820f9bf`](0fb820f9bf))
- feat(relay): inventory unreachable Git objects
([#2264](https://github.com/block/buzz/pull/2264))
([`3afc9dae15`](3afc9dae15))
- relay: add author_type label to buzz_events_stored_total
([#2243](https://github.com/block/buzz/pull/2243))
([`b9f54c43fe`](b9f54c43fe))
- fix(git): make project branch workflows reliable
([#2213](https://github.com/block/buzz/pull/2213))
([`166f27be4b`](166f27be4b))
- feat(cli): manage repository protection rules
([#2193](https://github.com/block/buzz/pull/2193))
([`f94324598d`](f94324598d))
- feat(cli): add agents archive/unarchive/archived subcommands
([#2173](https://github.com/block/buzz/pull/2173))
([`7d7992067b`](7d7992067b))
- fix(mobile): sanitize Android image uploads
([#2188](https://github.com/block/buzz/pull/2188))
([`ee21da90bd`](ee21da90bd))
- fix(cli): paginate channel directory queries
([#2181](https://github.com/block/buzz/pull/2181))
([`03fe19d603`](03fe19d603))
- fix(mobile): image upload fails due to unstripped metadata
([#2185](https://github.com/block/buzz/pull/2185))
([`37f15b2001`](37f15b2001))
- perf(relay): compact Git packs before manifest limits
([#2172](https://github.com/block/buzz/pull/2172))
([`80e0ab16b0`](80e0ab16b0))
- perf(relay): cache Git pack hydration
([#2169](https://github.com/block/buzz/pull/2169))
([`a4d82ec722`](a4d82ec722))
- fix(relay): bound and observe Git read operations
([#2167](https://github.com/block/buzz/pull/2167))
([`5f7c93d9c1`](5f7c93d9c1))
- relay: gate push enqueue on live leases; batch matcher pipeline
(T1b/T1a-repair/T2b) ([#2145](https://github.com/block/buzz/pull/2145))
([`e43b2d5aac`](e43b2d5aac))
- relay: add audit logging disable switch
([#2134](https://github.com/block/buzz/pull/2134))
([`bf5acabdde`](bf5acabdde))
- relay: skip TTL deadline bump for known-permanent channels (T1a
write-amp) ([#2125](https://github.com/block/buzz/pull/2125))
([`2e936d439c`](2e936d439c))
- fix(git): carry NIP-OA delegation in auth event
([#2120](https://github.com/block/buzz/pull/2120))
([`c12257d57a`](c12257d57a))
- Route lag-tolerant reads to an optional Postgres read replica
([#2084](https://github.com/block/buzz/pull/2084))
([`29c48883d3`](29c48883d3))
- fix: recover community access visibility
([#2074](https://github.com/block/buzz/pull/2074))
([`ca384d082d`](ca384d082d))
- feat: proxy feedback-scoped admin attachments
([#2059](https://github.com/block/buzz/pull/2059))
([`d7f918e3cb`](d7f918e3cb))
- feat: add read-only deployment moderation dashboard
([#1999](https://github.com/block/buzz/pull/1999))
([`68e670e001`](68e670e001))
- Bug-bash round 2: table scroll, Goose instructions, workflow mention
wake ([#2034](https://github.com/block/buzz/pull/2034))
([`64b8fea6dc`](64b8fea6dc))
- Strip media metadata on clients and reject it at the relay
([#2006](https://github.com/block/buzz/pull/2006))
([`5cfd69cb0c`](5cfd69cb0c))
- [codex] Hold Git concurrency permits through streaming (BUZZ-SEC-018)
([#1916](https://github.com/block/buzz/pull/1916))
([`7baea42abb`](7baea42abb))
- [codex] Enforce shared relay admission limits (BUZZ-SEC-019)
([#1917](https://github.com/block/buzz/pull/1917))
([`73fc0ec6cf`](73fc0ec6cf))
- [codex] Block banned actors from moderation commands (BUZZ-SEC-007)
([#1915](https://github.com/block/buzz/pull/1915))
([`caa195ca58`](caa195ca58))
- [codex] Fix relay WebSocket admission limits
([#1682](https://github.com/block/buzz/pull/1682))
([`d3ce971fc7`](d3ce971fc7))
- feat: add invite QR and mobile direct join
([#1957](https://github.com/block/buzz/pull/1957))
([`648cbf3610`](648cbf3610))
- fix(join-policy): require legal consent on hosted invites
([#1987](https://github.com/block/buzz/pull/1987))
([`2e1577f76f`](2e1577f76f))
- [codex] Prevent actor-tag UI impersonation
([#1931](https://github.com/block/buzz/pull/1931))
([`c540ec9678`](c540ec9678))
- Scope relay runtime state by community
([#1658](https://github.com/block/buzz/pull/1658))
([`d52dedb06f`](d52dedb06f))
- Apply optional relay join policy across join flows
([#1894](https://github.com/block/buzz/pull/1894))
([`6c2d667575`](6c2d667575))
- feat(media): require auth for relay media reads
([#1926](https://github.com/block/buzz/pull/1926))
([`f308762852`](f308762852))
- feat(relay): add community unarchive endpoint
([#1908](https://github.com/block/buzz/pull/1908))
([`6b9641db2b`](6b9641db2b))
- feat(relay): gate Git web GUI separately
([#1901](https://github.com/block/buzz/pull/1901))
([`34dc7dec75`](34dc7dec75))
- mesh: upgrade runtime, enforce membership, add shared compute provider
([#1656](https://github.com/block/buzz/pull/1656))
([`54638ff4bb`](54638ff4bb))
- Route Git scratch through configured volume
([#1884](https://github.com/block/buzz/pull/1884))
([`2318b3096c`](2318b3096c))
- feat(relay): gate usage metrics behind stable leader
([#1814](https://github.com/block/buzz/pull/1814))
([`59e9821503`](59e9821503))
- Relay mesh: cross-pod tunnel + huddle transport (buzz-relay-mesh)
([#1670](https://github.com/block/buzz/pull/1670))
([`ccb021d713`](ccb021d713))
- feat(push): deliver accepted relay events as wakes
([#1866](https://github.com/block/buzz/pull/1866))
([`bffbc5f22c`](bffbc5f22c))
- fix(db): resolve duplicate migration version
([#1863](https://github.com/block/buzz/pull/1863))
([`08ad38a07f`](08ad38a07f))
- Add private product feedback sidecar
([#1857](https://github.com/block/buzz/pull/1857))
([`af190c93e1`](af190c93e1))
- feat(relay): add durable community archival
([#1834](https://github.com/block/buzz/pull/1834))
([`2b15a72675`](2b15a72675))
- feat(push): add public APNs gateway
([#1770](https://github.com/block/buzz/pull/1770))
([`1c006822e4`](1c006822e4))
- feat(relay): add atomic community ownership transfer
([#1845](https://github.com/block/buzz/pull/1845))
([`52e42ccb9f`](52e42ccb9f))
- Bound NIP-RS retention and search indexing
([#1771](https://github.com/block/buzz/pull/1771))
([`1b4703021d`](1b4703021d))
- Add optional standalone pairing relay to Helm chart
([#1799](https://github.com/block/buzz/pull/1799))
([`9b47c8548f`](9b47c8548f))
- fix(relay): publish membership snapshot on provisioning
([#1761](https://github.com/block/buzz/pull/1761))
([`0950d392b7`](0950d392b7))
- feat(relay): per-community usage metrics
([#1723](https://github.com/block/buzz/pull/1723))
([`620822899a`](620822899a))
- refactor(desktop): remove vestigial MCP toolsets config
([#1776](https://github.com/block/buzz/pull/1776))
([`dfec75b3c0`](dfec75b3c0))

**To release:** merge this PR. The tag and build will happen
automatically.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
relay-v0.2.1
2026-08-08 12:26:24 -04:00