Skip to content

Sync fork with upstream block/buzz (610 commits) - #2

Merged
elijamesku merged 611 commits into
eli/github-connectorfrom
eli/upstream-sync
Sep 16, 2026
Merged

elijamesku merged 611 commits into
eli/github-connectorfrom
eli/upstream-sync

Conversation

@elijamesku

@elijamesku elijamesku commented Sep 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

Brings the fork current with upstream block/buzz main — 610 commits. Everything the fork added (Workforce roster, trust dial / earned autonomy, agent coworker profiles + performance cards, huddle transcripts + summaries, GitHub connector, Integrations + Local Setup panels, just quickstart) survives on top of it.

What upstream brings in

  • ACP agent sessions — per-agent session scope, thread-context dedup, Buzz Pi agents with skills + base prompt
  • Mesh LLM upgrades (mesh-llm 0.76, Qwen 27B recommended)
  • Mobile push gateway 0.3.0, notification cache, perf work
  • Agent trading cards (mintable snapshot PNGs, NIP-44 lock)
  • Multi-repo projects (kind 30621), default-branch management
  • Refreshed desktop onboarding, Buzz Term panel, voice notes

Conflict resolutions (5 files)

File Resolution
crates/buzz-core/src/kind.rs Upstream took 48104 for KIND_HUDDLE_LIVENESS; fork's KIND_HUDDLE_TRANSCRIPT / KIND_HUDDLE_SUMMARY renumbered to 48107 / 48108
crates/buzz-relay/.../event.rs Metric-label allowlist extended to cover the new kinds
desktop/src-tauri/src/commands/meetings.rs Constants updated to match
desktop/.../SettingsPanels.tsx Upstream's consolidated AgentsSettingsPanel replaces the fork's hand-rolled agents panel; Integrations + Local Setup panels kept
desktop/.../ChannelScreenHeader.tsx Meeting-notes button coexists with upstream's terminal button + endActions slot
build.rs, commands/mod.rs Both sides' env vars and modules kept

klopez4212 and others added 30 commits August 21, 2026 19:13
## Summary
- align iOS back controls and affected titles across channel details,
settings, and pairing
- make channel star and mute actions reflect their state immediately
- animate locally sent channel, thread, and DM messages from behind the
composer with a 300ms ease-out

## Testing
- `just mobile-check`
- full mobile test suite (1,573 tests)

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
## Why

The Buzz-native runtime could stop a solo agent after one turn even when
a scripted follow-up event was queued or already running. That could
turn a harness timing race into a benchmark failure.

Follow-up to block#6448.

## What

- Treat solo tasks with scripted events separately from ordinary
one-turn tasks.
- Wait until turn counts and authored message IDs remain idle and
unchanged for several polls before stopping the agent.
- Remove the message-count shortcut that could stop an active turn.
- Add focused regressions for a delayed follow-up turn and an
already-running turn with a `DONE:` message.

## Testing

- `pytest -q tests/test_container_runtime.py -k "solo_turn_end or
scripted_events"` — 3 passed
- `ruff check` on the three touched Python files
- `ruff format --check` on the three touched Python files
- Local `buzz-native-solo-luna.yaml` Harbor run, one attempt per
affected task:
- `cross-thread-requests` — reward 1.0; all 6 task-specific checks
passed
- `interleaved-agent-reports` — reward 1.0; all 7 task-specific checks
passed
  - 2 completed trials, 0 exceptions, 56 seconds total

## Risk

Low. This only changes completion detection for solo benchmark tasks
with scripted events. Ordinary solo tasks retain immediate completion
after their first turn ends.

---
**Update Aug 21, 13:07 EDT:** Replaced the fixed settle delay with exact
delivery receipts after [review
feedback](block#6487 (comment)).

- ACP now records the event IDs delivered by each completed turn; the
runtime also recognizes existing successful-steer receipts.
- Scripted trials stop only after every expected event ID is
acknowledged and no turn is active. Missing receipts wait for the trial
budget instead of producing partial evidence.
- TDD regression delayed delivery beyond the old five-poll boundary and
failed before the implementation; the receipt parser and Rust receipt
format are pinned independently.
- Focused verification: 31 container-runtime tests passed, 6 ACP
delivery tests passed, plus Ruff, rustfmt, and Clippy.
- Receipt-gated Luna run: 2 completed trials and 0 exceptions.
`interleaved-agent-reports` scored 1.0. `cross-thread-requests`
completed both calculations and thread isolation but Luna omitted the
user mention on ALPHA, so that model-output dimension scored 0.
- Risk remains low: the ACP production change adds delivery receipt
logging and restores a missing turn-end log on a
completed-before-control race; it does not change queue dispatch
behavior.

Generated with Codex

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…FECYCLE/DELEG/CONF) (block#5946)

## What

Comprehensive NIP-FI against `main`: one normative core plus four
separately
claimable profiles, replacing the single-document structure of block#3726
(which was
based on block#1485's branch, not `main`). Six documents, 1,975 lines, docs
only.

- **`NIP-FI.md` (core, 632 lines)** — issuer-qualified identity `(iss,
sub)`,
independent Nostr proof, client-attached assertion, partial bijection
with
durable tombstones, atomic final admission, bounded leases, private
denials
  with a closed response vocabulary, retire/revoke/rotate, two contract
identities (`assertion_policy_id`, `transport_contract_id`), per-policy
  `skew` / `maximum_assertion_age` / `maximum_status_age` with missing
configuration denying, a closed token-class rule (`at+jwt`,
`nip-fi+jwt`,
  named compatibility; ID tokens always deny), declared freshness class
  (`offline-jwt` | `current-status`), server-declared body authorization
  relevance (NIP-98 payload-binding fix, including a `payload` tag on an
irrelevant-body operation), BCP 14, "equivalent" defined over identity /
bounds / provenance classes, a compact non-normative worked wire
example,
  and a non-normative comparison with DPoP, mTLS-bound tokens, and HTTP
  Message Signatures. FI-INV-01..16 are normative core text. The
behavioral-oracle table lists exactly 30 oracle IDs, one per row, with
no
  shorthand.
- **`NIP-FI-EDGE.md`** — trusted-edge surface: the
`trusted-proxy-hmac-v2`
envelope + canonicalization, or a private authenticated-edge adapter
under a
reviewed contract; `authorization_domain_id` derivation (exact 16 RFC
9562
UUID bytes); `proof_transport_code` registry (0x01 NIP-42, 0x02 NIP-98;
  0x03 Git smart-HTTP and 0x04 Blossom reserved pending their transport
contracts; 0x05–0x7f unassigned pending published stable specifications)
  + extension procedure; body-acquisition bounds; three normative test
vectors. An independent Nostr proof (the NIP-98 event in
`Authorization`,
  which reaches the verifier byte-identical, or the NIP-42 event after
connect) is the only decision input outside the MAC; absent or
incomplete
  provenance on an edge-required route is `missing_evidence`,
  present-but-failing provenance is `evidence_rejected`.
  Header-trust-without-provenance is nonconformant.
- **`NIP-FI-LIFECYCLE.md`** — provision / disable / re-enable /
administrative
expiry (`binding_not_after`) / pending-replacement lineage, one
conformance
trace per privileged transition; every binding-creating transition
declares
whether it continues or establishes a grant; a private-condition table
for
  CONF enumeration agreement.
- **`NIP-FI-DELEG.md`** — delegated agents; explicit temporal boundaries
matching core's inclusive-`nbf`/exclusive-`exp` idiom, with the
delegated
`skew` configured by this profile; lease deadline anchored to the lease
  issue instant; strict path separation — a delegated request carries no
assertion or provenance field, so it cannot traverse an edge-provenance
  route and uses ingress on which NIP-FI-EDGE is not required.
- **`NIP-FI-CONF.md`** — conformance evidence: an immutable claim tuple
  including the governing document revision and exit fixture digest; the
  complete 16-row denial-fixture enumeration with three mechanical
  enumeration-agreement checks; mutation adequacy with a countable
  denominator — one retained killed mutant per literal oracle-table row
(30 core + 6 EDGE + 11 LIFECYCLE + 7 DELEG + 4 CONF = 58), rows selected
structurally by their first cell, never by section title, with the
release
gate and CONF's own oracle rows stated in the same listed-oracle terms
and
  a mutant defined for CONF's own report- and suite-subject oracles; an
  interoperability exit test compared over signing inputs (per-transport
NIP-01 serialization for the NIP-98 and NIP-42 proofs; decoded protected
header and claims as JSON values for the assertion), with a shared exit
  fixture pinning complete pre-signature header/claim JSON and complete
unsigned event fields for both transports, and mandatory negative
controls.
  `FI-CONF-INTEROP-EXIT` is `deferred` with reason
`no-independent-implementation` until a second independent
implementation
  exists; the canonical fixture is editor-authored at
`docs/nips/fixtures/nip-fi-conf-exit.json` and is **not in this PR** —
until
it is published a claim records `pending-canonical-fixture`, valid only
  while the exit test is deferred. Explicit not-applicable dispositions,
including `offline-jwt` deployments for the two current-status oracles
and
  absence of a revocation-bounded external capability projection for
  `FI-TRACE-CAPABILITY-REVOCATION`.
- **`NIP-FI-MODEL.md`** — non-normative companion; defines no
requirement or
  conformance claim and is not claimable.

## Why

The prior draft rated 9 (soundness) / 6 (minimalness) / 7 (elegance) /
7 (correctness) in adversarial + comparative review. This restructure
keeps the
two-invariant spine untouched, makes everything else a claimable
profile, and
collapses five stacked versioning mechanisms into two contract
identities.

Mutation adequacy counts one mutant per literal oracle-table row — a set
two
implementers enumerate identically — instead of "each normative
requirement,"
which had four defensible readings.

Resolved product calls (owner-approved):
1. Enrollment/denial posture is private — boolean enrollment discovery,
TOFU
extension claim not self-advertised, `key_mismatch →
authorization_denied`
   joins the denial anonymity set, and replayed evidence is classed
   `authorization_denied` so resubmission reveals nothing about commit.
2. Revocation honesty — only `current-status` deployments may advertise
an
   unconditional residual-revocation bound; `offline-jwt` advertises
unbounded/unknown. Access tokens keep RFC 9068 `at+jwt`; `nip-fi+jwt` is
   reserved for a separately minted Buzz assertion.

## Acceptance bar

- Nothing in core is deletable without losing a stated core guarantee.
- From the core document plus the CONF exit fixture, a second
implementer can
produce a valid request equal over the request compared object (signing
  inputs), and a byte-exact public denial per class — no reference
  implementation.
- Every oracle-table row ships a retained killed mutant satisfying only
the
  entry it was selected for.
- Both deployment profiles (trusted proxy = EDGE, client-held OIDC =
core
  client-attached) pass the same lifecycle conformance suite.

## Status

Ready at head e720a5c. Every revision below is on this branch: the
2026-08-17 and 2026-08-18 review laps (Wren, Dawn, Perci, Sami, Mari,
Quinn)
closed at 513e03b, 17d455a, and 4f913a8; the 2026-08-20 external
line-by-line review (R1–R10, R12) closed across 56e7414..772ba7a;
the
2026-08-20/21 adversarial lap (block#6437) squash-merged as b8db13d; the
round-3
external review (R13, R14), the DELEG×EDGE composition note, and three
terminology nits closed at e720a5c; R11 is this description. Oracle
census: 58 (30 core, 6 EDGE, 11 LIFECYCLE, 7 DELEG, 4 CONF).

Known follow-ups, filed after merge and out of scope here: adapter-only
edge
deployments and FI-EDGE claimability; an EDGE private-condition table
for
CONF's enumeration-agreement check; an enumerable definition of the
positive/negative oracle sets used by the global mutation controls;
NIP-OA's clock-free verification versus NIP-FI-DELEG's wall-clock
expiry.

Supersedes block#3726 as the spec vehicle; block#1485 remains the design-history
anchor.

---------

Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Signed-off-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Signed-off-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Signed-off-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Signed-off-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Co-authored-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Co-authored-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
## Why
`buzz-admin deletions` runs inside bb-public relay pods, where S3
credentials are provided by the pod credential chain rather than static
`BUZZ_S3_ACCESS_KEY` / `BUZZ_S3_SECRET_KEY` values. The deletion CLI was
requiring those two env vars to be non-empty before constructing the
shared media storage client, so it could not reach the existing default
AWS credential chain.

## What
- Treat missing/blank deletion S3 access key and secret key as an empty
credential pair so `MediaStorage::new` can use `Credentials::default()`.
- Keep the existing static-credential path unchanged when both values
are non-empty.
- Keep deletion unit tests deterministic by covering only deletion env
normalization for missing/blank pair, trimmed static pair, and
partial/whitespace-partial outputs; shared media tests continue to own
credential-pair enforcement.

## Risk Assessment
Low and scoped to the operator-only community deletion CLI startup path.
The shared media storage credential validation still owns
static-vs-default credential selection and still rejects mixed partial
credentials.

## Testing
At committed head `0a86c2914b1f97caf4788a771048aa8d9d9d88ac` with a
clean worktree before and after (`git rev-parse HEAD` before/after
matched):
- `just fmt-check` — passed.
- `cargo test -p buzz-deletion` — passed: 12 passed, 9 ignored.
- `cargo test -p buzz-media` — passed: 120 passed;
`static_creds_round_trip_against_minio` remained ignored because it
requires live MinIO.
- `cargo test -p buzz-admin` — passed: 1 passed.
- `cargo clippy -p buzz-deletion --all-targets -- -D warnings` — passed.
- Startup smoke at the same head: built `buzz-admin`, then ran
`target/debug/buzz-admin deletions drain` with `BUZZ_S3_ACCESS_KEY=` and
`BUZZ_S3_SECRET_KEY=' '` plus `AWS_ACCESS_KEY_ID` /
`AWS_SECRET_ACCESS_KEY` fallback credentials; command exited `0`,
proving startup transitions past deletion S3 key validation and
exercises the shared default credential-chain branch using AWS env
fallback credentials.
- `git push origin HEAD:seiler/deletion-irsa-credentials` — passed;
pre-push hooks passed.

Not run: the full `TESTING.md` live-local relay workflow. Docker Desktop
currently refuses CLI access on this machine with `Sign in to continue
using Docker Desktop. Membership in the [squareup] organization is
required.`

## References
- Buzz channel:
`buzz://message?channel=9e4aabc6-414c-4978-aba7-b9f5228776de&id=177c5b8ad9e78a647f438ec7040d25f0c20a7c2b8678dd0e34768effe053f7f4`

Generated with Codex

---------

Signed-off-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
Co-authored-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
…ock#6456)

Switching channels triggered a full-roster fetch (kind:39002 plus a
kind:0 profile batch with every member pubkey as an author) in the
common case, and several render paths walked the full roster per render.
None of this scales past a few hundred members; the product target is
10k+.

- **Members query staleTime 30s → 5min.** Every membership change the
client can observe already invalidates the key explicitly: live
join/leave system messages for the active channel, member-added/removed
notifications for the current identity, and all membership mutations —
including previously-uncovered direct write paths (moderation kick,
agent-deletion cleanup), which now invalidate through a shared helper.
The 30s window bought correctness we already had and charged a roster
fetch per switch.
- **ChannelMembersBar no longer mounts the roster query for non-DM
channels** — the count renders from the channel summary, and the
private-channel huddle gate accepts `channel.isMember` (derived from the
same kind:39002 event as the roster's self entry).
- **Roster-derived lookups are cached on roster identity**
(`rosterDerivations.ts`): role map, agent-member subset, member/bot
pubkey sets. These were rebuilt O(members) on every live message /
profile re-key. React Query's structural sharing keeps the roster
identity stable, so each derivation computes once per distinct roster.
- **Backend: the kind:0 profile join in `get_channel_members` is capped
at the first 500 members** (roster order). Members past the cap keep
`display_name: None` (UI falls back to pubkey labels and profile
caches); `role=="bot"` agent flags are roster-derived and unaffected.
Full roster pagination is the structural follow-up.
- **Composer keystroke path**: `useCanAddChannelMembers` re-scanned
channels + roster per keystroke; now memoized on data identities,
sharing the cached pubkey set.

### Measured / estimated impact

| metric | before | after |
|---|---|---|
| roster fetches while switching (live trace) | nearly every switch | ≤1
per channel per 5 min |
| roster fetch cost on the wire (live, 51-member channel) | 273ms per
fetch | amortized away |
| kind:0 `authors` filter size at 10k members | ~670KB per request (~67
B/pubkey) | capped at 500 authors (~34KB) |
| warm-switch longtask at 10k members (mock harness, 4× throttle) |
364ms | 318ms |
| per-render roster walks (role map, agent sets) at 10k members |
O(members) per live message | once per distinct roster |

Deferred deliberately: protocol-level roster pagination and removing
`memberPubkeys` from channel summaries (needs relay support).

---------

Signed-off-by: Max Lampert <maxwell@squareup.com>
…ng after leave (block#6458)

Entering Projects fires a large fan: an exhaustive paginated relay
enumeration (projects/repos/tombstones), five 2,000-event work-item
queries plus assignment-operation scans, per-repo activity summaries,
and a local-repository filesystem scan. Measured on a large community
(101 issues / 258 PRs):

| query | measured cost |
|---|---|
| work-items (5 × 2,000-event REQs + assignment scans) | 3.5–3.9s |
| activity summaries | 4.1s |
| repository activity | 1.0–2.2s |
| local repository scan | 1.7s |

Two lifecycle bugs made the fan far more expensive than it needs to be:

- **Freshness windows guaranteed a full refetch on nearly every
re-entry** (60s enumeration, 30s work-items/activity, 10s local scan) —
i.e., the costs above were re-paid on almost every visit. Every local
write path already invalidates its keys explicitly (issue/PR mutations,
project creation, repo sync), so the short windows only served
remote-actor freshness. Raised to 5m/2m/2m with a 30m enumeration cache:
re-entries now paint from cache, and the fan re-runs at most every 2–5
minutes.
- **Leaving Projects left the whole fan running**, competing with the
next surface's channel fetches on the same relay connection. AbortSignal
is now threaded through the enumeration and assignment pagination loops
(optional params — behavior identical without a signal), and leaving the
surface cancels the work-items query. Deliberately NOT cancelled: the
enumeration (the always-mounted sidebar projects section observes it and
its 30m cache is valuable), repo snapshots and local scans (native work
that can't abort — cancelling would discard the finished result and
force the same clones again), and activity summaries (a single bounded
request).

Abort behavior is covered by red-first unit tests on both pagination
loops. Remaining follow-up (out of scope): the queries themselves want a
relay-side aggregate instead of shipping thousands of events to compute
counts client-side.

---------

Signed-off-by: Max Lampert <maxwell@squareup.com>
**Category:** new-feature
**User Impact:** Workflow authors can build filtered, runtime-aware
automations, understand them at a glance, and get a clear warning before
turning on workflows likely to run often.
**Problem:** Workflow setup exposed raw configuration without enough
help composing message templates, filtering triggers, or understanding
saved behavior; activation could also make a broadly triggered workflow
live without explaining its likely frequency.
**Solution:** Batch 3 adds local, deterministic template variables,
trigger filters, and semantic summaries, then refines cards and
activation around configured behavior and a risk-aware warning boundary.
Scheduling remains the already-shipped implementation, advanced
expressions remain lossless, and network-backed identity/message
enrichment stays in Batch 4.

| Message inputs | Trigger filters |
| --- | --- |
| Caret-aware, keyboard-accessible suggestions expose trigger-local
values and safe prior-step outputs in `send_message.text`. | Structured
conditions and validated manual IDs block invalid submission while
preserving advanced expressions. |
| ![Message variable
autocomplete](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/message-variables.png)
| ![Structured trigger
filters](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/trigger-filters.png)
|

| Workflow cards | Risk-aware activation |
| --- | --- |
| Semantic labels, channel-first hierarchy, configured reaction/action
visuals, real step stacks, and compact status controls make behavior
scannable. | Broad message and frequent schedule triggers explain the
risk before **Turn on**; narrowly scoped triggers proceed without
unnecessary ceremony. |
| ![Semantic workflow
card](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/workflow-card.png)
| ![Activation
confirmation](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/activation-choice-v2.png)
|

## Changes

<details>
<summary>File changes</summary>

**desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx**  
Separates direct card status controls from secondary actions while
retaining modal status actions.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**  
Adds semantic behavior, channel-first hierarchy, configured
reaction/action visuals, real subsequent-step stacks, status controls,
and reduced-motion-aware trigger feedback.

**desktop/src/features/workflows/ui/WorkflowDialog.tsx**  
Warns before activating broadly triggered workflows while allowing
narrowly scoped workflows to proceed directly.

**desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx**  
Connects structured trigger filters and template-aware step inputs while
preserving schedules, trigger transitions, and selected YAML authority.

**desktop/src/features/workflows/ui/WorkflowStepCard.tsx**  
Replaces generic labels with deterministic configured-step descriptions.

**desktop/src/features/workflows/ui/WorkflowTemplateTextarea.tsx**  
Adds caret-aware variable suggestions with keyboard navigation and focus
restoration.

**desktop/src/features/workflows/ui/WorkflowTriggerConditions.tsx**  
Adds structured local filters, validated author/message IDs, and a
lossless advanced-expression fallback.

**desktop/src/features/workflows/ui/workflowActivationWarning.ts** and
**workflowActivationWarning.test.mjs**
Classify broad message and frequent schedule triggers for contextual
activation warnings.

**desktop/src/features/workflows/ui/workflowConditionExpression.ts** and
**workflowConditionExpression.test.mjs**
Model and cover parsing, serialization, validation, and
advanced-expression preservation.

**desktop/src/features/workflows/ui/workflowDefinition.ts** and
**workflowDefinition.test.mjs**
Preserve trigger/step configuration and derive deterministic card
metadata across YAML round trips.

**desktop/src/features/workflows/ui/workflowStepDescription.ts** and
**workflowStepDescription.test.mjs**
Generate and cover local step summaries.

**desktop/src/features/workflows/ui/workflowTemplateVariables.ts** and
**workflowTemplateVariables.test.mjs**
Define and cover trigger-specific, order-bounded variables and caret
insertion.

**desktop/src/features/workflows/ui/workflowTriggerDescription.ts** and
**workflowTriggerDescription.test.mjs**
Generate and cover semantic trigger summaries without network lookups.

**desktop/tests/e2e/workflow-local-controls.spec.ts** and snapshot  
Cover filters, IDs, advanced expressions, autocomplete, activation
choices, summaries, and YAML authority.

**desktop/tests/e2e/workflow-reaction-picker.spec.ts**  
Covers configured reaction emoji in workflow nodes and summaries.

**desktop/tests/e2e/workflows.spec.ts**  
Covers risk-aware activation warnings, direct safe creation,
duplication, and card status controls.

</details>

## Reproduction steps

1. Create a message-posted workflow in **Workflows**, add a Send message
step, and type `{{trig`; verify keyboard-selectable variables insert at
the caret.
2. Configure message-text and manual ID filters; verify malformed IDs
block submission and advanced expressions survive Form/YAML transitions.
3. Create a broad message workflow; verify **Back** persists nothing,
**Keep off** saves it disabled, and **Turn on** enables it. Confirm a
narrowly triggered webhook skips the warning.
4. Inspect the saved card; verify its channel, semantic behavior,
configured actions/reaction, real step stack, and status are
understandable without opening YAML.

## Validation

Validated at exact clean head `f99503819889b95ee3c61657c5c3850aae35481e`
on base `24ec6a468ec9d0d425ee58fbfc4d416412c446ad`.

- Focused workflow regressions passed 59/60 locally; the only local miss
was a 438-pixel macOS snapshot drift, while the checked-in Linux
baseline comes from the failing CI artifact. Repository pre-push gates
and E2E build/typecheck passed.
- A broader 36-test smoke invocation had 31 passes and five unrelated
pre-existing expectation/snapshot failures, so it is not claimed as
fully green. Adversarial fixes are recorded in [round
one](block#6470 (comment))
and [round
two](block#6470 (comment)).

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Co-authored-by: Mongo <5398c5fd039b963ce132b3e078e7c4af097dd997517bb5e14c2682fe68c25197@buzz.block.builderlab.xyz>
…pec (block#6517)

`biome check` fails with `lint/correctness/noUnusedVariables` on
`ORIGINAL_CONTENT` in `desktop/tests/e2e/empty-edit-delete.spec.ts`,
which fails `pnpm check` (Desktop Core) for **every PR touching desktop
paths** — e.g. it currently blocks block#6460. It presumably landed while
Desktop Core was path-skipped on the introducing PR.

One-line removal; the constant has no remaining references (the
assertions use `RENDERED_ORIGINAL_CONTENT`).

Signed-off-by: Max Lampert <maxwell@squareup.com>
## Summary

Follow-up to block#5644. Cmd +/- had become a text-only zoom: type scaled
while rem-based padding, gaps, widths, avatars, and controls stayed
frozen, which produced cramped layouts (see [#buzz-frontend
thread](buzz://message?channel=a410ffde-c61f-416a-96e0-c296b5f5ecc9&id=1a758115cf07b00c097f6e988553908c045165325a57637519cfa7ed9c9accec)).

Root cause: block#5644 introduced a virtual typography rem so the **Font
size** preference could change text without moving layout — a good
decoupling — but it also routed **Cmd +/- zoom** through that same
px-valued token and pinned the real root at 16px. One decision ("freeze
layout") was applied to two dials that shouldn't share it.

This PR gives each dial one owner and lets CSS compose them:

| Control | Changes | How |
|---|---|---|
| **Cmd +/- zoom** | Everything — true zoom | Scales the real `<html>`
font-size again (`useWebviewZoomShortcuts`) |
| **Font size preference** | Text only | Sets `data-font-size`;
`typography.css` maps it to a unitless `--buzz-type-scale`, mirroring
how density already works |

`--buzz-type-rem` becomes `calc(1rem * var(--buzz-type-scale))` —
rem-relative, so it rides on zoom automatically. Resulting text px = `16
× zoom × scale × token-ratio`. The 13 / 14 / 15px conversation contract
is unchanged at default zoom. Density and the type ramp from block#5644 are
untouched.

The preference module no longer does px math or knows about zoom; the
zoom hook no longer imports the preference module. Net deletion in
production code.

## Validation

- `pnpm test` — 5,308 desktop unit tests
- `pnpm check:px-text`, `tsc --noEmit`, biome
- Playwright: `top-chrome-zoom-clearance.spec.ts` (native-chrome
clearance stays fixed under root zoom),
`inbox-refactor-screenshots.spec.ts` (zoomed row padding now asserts
`4.4px` instead of the frozen `4px`), and both `profile.spec.ts` zoom
tests (composed zoom × preference, cross-window storage reset)
- Before/after screenshots at 140% zoom in the comment below

---------

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [Swatinem/rust-cache](https://redirect.github.com/Swatinem/rust-cache)
([changelog](https://redirect.github.com/Swatinem/rust-cache/compare/e18b497796c12c097a38f9edb9d0641fb99eee32..6323deb102c322ba6fcbdcafc7e3dddab59af2b6))
| action | digest | `e18b497` → `6323deb` |

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [ubuntu](https://hub.docker.com/_/ubuntu)
([source](https://git.launchpad.net/cloud-images/+oci/ubuntu-base)) |
container | digest | `4fbb8e6` → `561618e` |

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@tauri-apps/api](https://redirect.github.com/tauri-apps/tauri) |
[`2.11.0` →
`2.11.1`](https://renovatebot.com/diffs/npm/@tauri-apps%2fapi/2.11.0/2.11.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tauri-apps%2fapi/2.11.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tauri-apps%2fapi/2.11.0/2.11.1?slim=true)
|

---

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

---

### Release Notes

<details>
<summary>tauri-apps/tauri (@&#8203;tauri-apps/api)</summary>

###
[`v2.11.1`](https://redirect.github.com/tauri-apps/tauri/releases/tag/%40tauri-apps/api-v2.11.1):
@&#8203;tauri-apps/api v2.11.1

[Compare
Source](https://redirect.github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.11.0...@tauri-apps/api-v2.11.1)

<details>
<summary><em><h4>PNPM Audit</h4></em></summary>

```
No known vulnerabilities found
```

</details>

#### \[2.11.1]
##### Enhancements

-
[`916782601`](https://www.github.com/tauri-apps/tauri/commit/9167826011cc3d114bf12dfb301968fae479891f)
([#&#8203;15520](https://redirect.github.com/tauri-apps/tauri/pull/15520)
by [@&#8203;polw1](https://www.github.com/tauri-apps/tauri/../../polw1))
Document that `Monitor.size`, `Monitor.position` and `Monitor.workArea`
are in physical pixels, with examples showing how to convert them to the
logical pixels expected by window creation options via
`toLogical(monitor.scaleFactor)`.

<details>
<summary><em><h4>PNPM Publish</h4></em></summary>

```
> @tauri-apps/api@2.11.1 npm-publish /home/runner/work/tauri/tauri/packages/api
> pnpm build && cd ./dist && pnpm publish --access public --loglevel silly --no-git-checks

> @tauri-apps/api@2.11.1 build /home/runner/work/tauri/tauri/packages/api
> rollup -c --configPlugin typescript

�[36m
�[1m./src/app.ts, ./src/core.ts, ./src/dpi.ts, ./src/event.ts, ./src/image.ts, ./src/index.ts, ./src/menu.ts, ./src/mocks.ts, ./src/path.ts, ./src/tray.ts, ./src/webview.ts, ./src/webviewWindow.ts, ./src/window.ts�[22m → �[1m./dist, ./dist�[22m...�[39m
�[32mcreated �[1m./dist, ./dist�[22m in �[1m883ms�[22m�[39m
�[36m
�[1msrc/index.ts�[22m → �[1m../../crates/tauri/scripts/bundle.global.js�[22m...�[39m
�[32mcreated �[1m../../crates/tauri/scripts/bundle.global.js�[22m in �[1m1.4s�[22m�[39m
npm verbose cli /opt/hostedtoolcache/node/24.16.0/x64/bin/node /opt/hostedtoolcache/node/24.16.0/x64/bin/npm
npm info using npm@11.13.0
npm info using node@v24.16.0
npm silly config load:file:/opt/hostedtoolcache/node/24.16.0/x64/lib/node_modules/npm/npmrc
npm silly config load:file:/tmp/286e8dee195254a4370e608b672019b0/.npmrc
npm silly config load:file:/home/runner/.npmrc
npm silly config load:file:/home/runner/.config/pnpm/rc
npm verbose title npm publish tauri-apps-api-2.11.1.tgz
npm verbose argv "publish" "--ignore-scripts" "tauri-apps-api-2.11.1.tgz" "--access" "public" "--loglevel" "silly"
npm verbose logfile logs-max:10 dir:/home/runner/.npm/_logs/2026-06-17T13_41_23_851Z-
npm verbose logfile /home/runner/.npm/_logs/2026-06-17T13_41_23_851Z-debug-0.log
npm warn Unknown env config "verify-deps-before-run". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "npm-globalconfig". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "overrides". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "_jsr-registry". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm silly logfile done cleaning log files
npm verbose publish [ 'tauri-apps-api-2.11.1.tgz' ]
npm http cache file:/tmp/286e8dee195254a4370e608b672019b0/tauri-apps-api-2.11.1.tgz 0ms (cache hit)
npm notice
npm notice 📦  @tauri-apps/api@2.11.1
npm notice Tarball Contents
npm notice 99.3kB CHANGELOG.md
npm notice 10.2kB LICENSE_APACHE-2.0
npm notice 1.1kB LICENSE_MIT
npm notice 3.5kB README.md
npm notice 5.9kB app.cjs
npm notice 5.4kB app.d.ts
npm notice 5.5kB app.js
npm notice 11.2kB core.cjs
npm notice 6.5kB core.d.ts
npm notice 10.7kB core.js
npm notice 11.0kB dpi.cjs
npm notice 8.8kB dpi.d.ts
npm notice 10.8kB dpi.js
npm notice 5.8kB event.cjs
npm notice 4.9kB event.d.ts
npm notice 5.7kB event.js
npm notice 2.2kB external/tslib/tslib.es6.cjs
npm notice 2.2kB external/tslib/tslib.es6.js
npm notice 3.0kB image.cjs
npm notice 2.4kB image.d.ts
npm notice 2.9kB image.js
npm notice 738B index.cjs
npm notice 1.2kB index.d.ts
npm notice 669B index.js
npm notice 1.1kB menu.cjs
npm notice 451B menu.d.ts
npm notice 717B menu.js
npm notice 3.6kB menu/base.cjs
npm notice 887B menu/base.d.ts
npm notice 3.6kB menu/base.js
npm notice 2.2kB menu/checkMenuItem.cjs
npm notice 1.5kB menu/checkMenuItem.d.ts
npm notice 2.2kB menu/checkMenuItem.js
npm notice 7.4kB menu/iconMenuItem.cjs
npm notice 6.1kB menu/iconMenuItem.d.ts
npm notice 7.4kB menu/iconMenuItem.js
npm notice 5.1kB menu/menu.cjs
npm notice 4.4kB menu/menu.d.ts
npm notice 5.0kB menu/menu.js
npm notice 1.7kB menu/menuItem.cjs
npm notice 1.3kB menu/menuItem.d.ts
npm notice 1.6kB menu/menuItem.js
npm notice 1.1kB menu/predefinedMenuItem.cjs
npm notice 2.6kB menu/predefinedMenuItem.d.ts
npm notice 1.1kB menu/predefinedMenuItem.js
npm notice 7.1kB menu/submenu.cjs
npm notice 4.8kB menu/submenu.d.ts
npm notice 6.9kB menu/submenu.js
npm notice 9.8kB mocks.cjs
npm notice 5.0kB mocks.d.ts
npm notice 9.7kB mocks.js
npm notice 1.8kB package.json
npm notice 22.7kB path.cjs
npm notice 17.7kB path.d.ts
npm notice 21.7kB path.js
npm notice 7.1kB tray.cjs
npm notice 8.5kB tray.d.ts
npm notice 7.0kB tray.js
npm notice 20.7kB webview.cjs
npm notice 23.8kB webview.d.ts
npm notice 20.5kB webview.js
npm notice 8.4kB webviewWindow.cjs
npm notice 4.9kB webviewWindow.d.ts
npm notice 8.3kB webviewWindow.js
npm notice 68.1kB window.cjs
npm notice 64.9kB window.d.ts
npm notice 67.2kB window.js
npm notice Tarball Details
npm notice name: @tauri-apps/api
npm notice version: 2.11.1
npm notice filename: tauri-apps-api-2.11.1.tgz
npm notice package size: 135.7 kB
npm notice unpacked size: 699.0 kB
npm notice shasum: cd6b13fc26403ca095a02e39ecdbec8048d2872d
npm notice integrity: sha512-M2FPuYND2m+wh[...]sUepJWugQCvAA==
npm notice total files: 67
npm notice
npm http fetch GET https://run-actions-1-azure-eastus.actions.githubusercontent.com/113//idtoken/***/***?api-version=2.0&audience=npm%3Aregistry.npmjs.org 200 76ms
npm http fetch POST 201 https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/@tauri-apps%2fapi 674ms
npm verbose oidc Successfully retrieved and set token
npm http fetch GET 200 https://registry.npmjs.org/@tauri-apps%2fapi 54ms (cache miss)
npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
npm notice publish Signed provenance statement with source and build information from GitHub Actions
npm notice publish Provenance statement published to transparency log: https://search.sigstore.dev/?logIndex=1851797040
npm http fetch PUT 200 https://registry.npmjs.org/@tauri-apps%2fapi 2070ms
+ @tauri-apps/api@2.11.1
npm verbose cwd /tmp/286e8dee195254a4370e608b672019b0
npm verbose os Linux 6.17.0-1018-azure
npm verbose node v24.16.0
npm verbose npm  v11.13.0
npm verbose exit 0
npm info ok
```

</details>

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [futures](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
dev-dependencies | patch | `0.3.32` → `0.3.34` |

---

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

---

### Release Notes

<details>
<summary>rust-lang/futures-rs (futures)</summary>

###
[`v0.3.34`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0334---2026-08-11)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.33...0.3.34)

- Preserve cloned waker identity.
([#&#8203;3032](https://redirect.github.com/rust-lang/futures-rs/issues/3032))
- Updato `syn` to 3.
([#&#8203;3028](https://redirect.github.com/rust-lang/futures-rs/issues/3028))

###
[`v0.3.33`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0333---2026-07-18)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.32...0.3.33)

- Fix `ReadLine`'s soundness issue regarding to exception safety.
([#&#8203;3020](https://redirect.github.com/rust-lang/futures-rs/issues/3020))
- Fix unsound `Send` impl for `IterPinRef` and `Iter`.
([#&#8203;3003](https://redirect.github.com/rust-lang/futures-rs/issues/3003))
- Fix stacked borrows violation in `compat01as03` implementation.
([#&#8203;3012](https://redirect.github.com/rust-lang/futures-rs/issues/3012))
- Fix memory leak in `FuturesUnordered::IntoIter`.
([#&#8203;3005](https://redirect.github.com/rust-lang/futures-rs/issues/3005))
- Add `portable-atomic-alloc` feature and use it in `FuturesUnordered`.
([#&#8203;3007](https://redirect.github.com/rust-lang/futures-rs/issues/3007))
- Re-export `alloc::task::Wake`.
([#&#8203;3010](https://redirect.github.com/rust-lang/futures-rs/issues/3010))
- Update `spin` to 0.12.
([#&#8203;3014](https://redirect.github.com/rust-lang/futures-rs/issues/3014))

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [futures-util](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
dependencies | patch | `0.3.32` → `0.3.34` |
| [futures-util](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
workspace.dependencies | patch | `0.3.32` → `0.3.34` |

---

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

---

### Release Notes

<details>
<summary>rust-lang/futures-rs (futures-util)</summary>

###
[`v0.3.34`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0334---2026-08-11)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.33...0.3.34)

- Preserve cloned waker identity.
([#&#8203;3032](https://redirect.github.com/rust-lang/futures-rs/issues/3032))
- Updato `syn` to 3.
([#&#8203;3028](https://redirect.github.com/rust-lang/futures-rs/issues/3028))

###
[`v0.3.33`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0333---2026-07-18)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.32...0.3.33)

- Fix `ReadLine`'s soundness issue regarding to exception safety.
([#&#8203;3020](https://redirect.github.com/rust-lang/futures-rs/issues/3020))
- Fix unsound `Send` impl for `IterPinRef` and `Iter`.
([#&#8203;3003](https://redirect.github.com/rust-lang/futures-rs/issues/3003))
- Fix stacked borrows violation in `compat01as03` implementation.
([#&#8203;3012](https://redirect.github.com/rust-lang/futures-rs/issues/3012))
- Fix memory leak in `FuturesUnordered::IntoIter`.
([#&#8203;3005](https://redirect.github.com/rust-lang/futures-rs/issues/3005))
- Add `portable-atomic-alloc` feature and use it in `FuturesUnordered`.
([#&#8203;3007](https://redirect.github.com/rust-lang/futures-rs/issues/3007))
- Re-export `alloc::task::Wake`.
([#&#8203;3010](https://redirect.github.com/rust-lang/futures-rs/issues/3010))
- Update `spin` to 0.12.
([#&#8203;3014](https://redirect.github.com/rust-lang/futures-rs/issues/3014))

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [http](https://redirect.github.com/hyperium/http) | dependencies |
patch | `1.4.0` → `1.4.2` |

---

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

---

### Release Notes

<details>
<summary>hyperium/http (http)</summary>

###
[`v1.4.2`](https://redirect.github.com/hyperium/http/blob/HEAD/CHANGELOG.md#142-June-8-2026)

[Compare
Source](https://redirect.github.com/hyperium/http/compare/v1.4.1...v1.4.2)

- Fix `uri::Builder` to allow `"*"` as the path when scheme and
authority are also set, used in HTTP/2 requests.
- Fix `Uri` to properly reject `DEL` characters.

###
[`v1.4.1`](https://redirect.github.com/hyperium/http/blob/HEAD/CHANGELOG.md#141-May-25-2026)

[Compare
Source](https://redirect.github.com/hyperium/http/compare/v1.4.0...v1.4.1)

- Fix `PathAndQuery::from_static()` and `from_shared()` to reject inputs
that do not start with `/`.
- Fix `Extend` for `HeaderMap` to clamp max size hint and not overflow.
- Fix `header::IntoIter` that could use-after-free if the generic value
type could panic on drop.
- Fix `header::{IterMut, ValuesIterMut}` to not violate stacked borrows.

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [http-body-util](https://redirect.github.com/hyperium/http-body) |
dependencies | patch | `0.1.3` → `0.1.5` |

---

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

---

### Release Notes

<details>
<summary>hyperium/http-body (http-body-util)</summary>

###
[`v0.1.5`](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.4...http-body-util-v0.1.5)

[Compare
Source](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.4...http-body-util-v0.1.5)

###
[`v0.1.4`](https://redirect.github.com/hyperium/http-body/releases/tag/http-body-util-v0.1.4)

[Compare
Source](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.3...http-body-util-v0.1.4)

#### What's Changed

- Add `Fused` body combinator that always returns `None` once completed.
- Add `BodyExt::into_stream()` to convert a body into a `Stream`.
- Add `Full::into_inner()` to get the full `Buf`.
- Add `InspectFrame` and `InspectErr` combinators.

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [sonner](https://sonner.emilkowal.ski/)
([source](https://redirect.github.com/emilkowalski/sonner)) | [`2.0.7` →
`2.0.8`](https://renovatebot.com/diffs/npm/sonner/2.0.7/2.0.8) |
![age](https://developer.mend.io/api/mc/badges/age/npm/sonner/2.0.8?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/sonner/2.0.7/2.0.8?slim=true)
|

---

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

---

### Release Notes

<details>
<summary>emilkowalski/sonner (sonner)</summary>

###
[`v2.0.8`](https://redirect.github.com/emilkowalski/sonner/compare/v2.0.7...ecce1841c55e4a72dfe139a8992b56498660125e)

[Compare
Source](https://redirect.github.com/emilkowalski/sonner/compare/v2.0.7...v2.0.8)

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4yOS41IiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-trait](https://redirect.github.com/dtolnay/async-trait) |
dependencies | patch | `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.92`](https://redirect.github.com/dtolnay/async-trait/releases/tag/0.1.92)

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

- Resolve double\_must\_use clippy lint in generated code
([#&#8203;303](https://redirect.github.com/dtolnay/async-trait/issues/303))

</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4yOS41IiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ock#6531)

**Category:** fix
**User Impact:** Users can insert mentions earlier in a draft and
continue typing without the caret corrupting the rest of the message.

**Problem:** Caret correction ran after every document change, so typing
a mention before existing text repeatedly advanced across the mention
separator and interleaved spaces into the draft. **Solution:** Limit
correction to the autocomplete settlement it was designed for, with
transaction-level and browser-level regression coverage for known and
unregistered mentions.

<details>
<summary>File changes</summary>

**desktop/src/features/messages/lib/mentionHighlightExtension.ts**
Restricts trailing-space caret advancement to an armed autocomplete
settlement instead of every document change.

**desktop/src/features/messages/lib/mentionHighlightExtension.test.mjs**
Exercises the real ProseMirror plugin state and verifies mid-draft
mention typing, unknown tokens, end-of-message typing, and
completed-mention separators.

**desktop/tests/e2e/mentions.spec.ts**
Reproduces the reported composer workflow in Chromium and covers the
same corruption path for an unregistered `@token`.

</details>

## Reproduction steps

1. Open a channel and enter `hello world` in the composer.
2. Move the caret between `hello` and ` world`.
3. Type ` @bo`, select `bob` from autocomplete, and continue typing
`abc`.
4. Confirm the composer reads `hello @bob abc world` with the caret
after `abc`.
5. Repeat with an unregistered token such as ` @zzq` and confirm the
existing text remains intact.

## Before / After

| Before | After |
| --- | --- |
| Typing after a mid-draft mention walks the caret through the existing
message. | Continued typing stays after the inserted mention. |
| ![Before: mention caret corrupts existing draft
text](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6531/mention-caret-before.gif)
| ![After: caret remains after the inserted
mention](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6531/mention-caret-after.gif)
|

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Mongo <5398c5fd039b963ce132b3e078e7c4af097dd997517bb5e14c2682fe68c25197@buzz.block.builderlab.xyz>
**Category:** improvement
**User Impact:** Buzz-native project, repository, issue, and pull
request links now appear once as compact inline chips, with their
details available on hover.

**Problem:** Buzz-native entity links rendered both an inline chip and a
standalone preview card, repeating the same metadata and adding visual
noise to conversations. **Solution:** Exclude Buzz-native links from the
shared standalone-preview extractor while leaving entity parsing intact
for chip tooltips and preserving external web previews and attachment
cards.

<details>
<summary>File changes</summary>

**desktop/src/shared/lib/linkPreview.ts**
Stops Buzz-native preview candidates after parsing, including same-relay
git clone URLs that normalize to repository entities, while allowing
external URLs through the existing snapshot path.

**desktop/src/shared/lib/linkPreview.test.mjs**
Covers project, repository, issue, pull request, markdown-labeled,
same-relay clone, and mixed external-link extraction behavior.

**desktop/src/shared/ui/markdown/useMessageLinkPreviews.test.mjs**
Confirms sent messages no longer merge a standalone Buzz entity card
while external sender snapshots still render.

</details>

## Reproduction steps

1. Open a desktop channel containing a `buzz://project`, `buzz://repo`,
`buzz://issue`, or `buzz://pr` link.
2. Confirm the link renders as an inline entity chip without a second
standalone Buzz card below the message.
3. Hover the chip and confirm its entity metadata remains available.
4. Post an external HTTPS link and confirm its web preview still
renders.
5. Paste a same-relay `/git/<owner>/<repo>` clone URL and confirm it
uses the repository chip without a duplicate card.

## Screenshots

| Before | After |
| --- | --- |
| Inline chip plus redundant standalone Project card | Inline chip is
now the sole presentation |
| ![Before: project chip and duplicate standalone
card](https://raw.githubusercontent.com/block/buzz/7e1a0d6cfb52382ef636d7331cf30ea334429c4d/pr-6512--before.png)
| ![After: project chip without a standalone
card](https://raw.githubusercontent.com/block/buzz/7e1a0d6cfb52382ef636d7331cf30ea334429c4d/pr-6512--after.png)
|

**After — rich metadata stays available on hover**

![After: dark theme with pink accent and Project tooltip showing
description and repository
count](https://raw.githubusercontent.com/block/buzz/7e1a0d6cfb52382ef636d7331cf30ea334429c4d/pr-6512--after-tooltip-rich.png)

## Verification

At commit `3fa74cdd342ac1f6721b7d56a7f111af31e0e6e9`:

- focused link-preview + Markdown unit suites — 119/119 passed
- targeted registered smoke E2E — 8/8 passed, including labeled
same-relay clone metadata, ordinary-link presentation, and in-app
navigation
- `cd desktop && pnpm exec tsc --noEmit` — passed
- `git diff --check origin/main...HEAD` — passed
- pre-push hooks — desktop check, TypeScript, and full desktop unit
suite passed

---------

Signed-off-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Mongo <5398c5fd039b963ce132b3e078e7c4af097dd997517bb5e14c2682fe68c25197@buzz.block.builderlab.xyz>
…6315)

**Category:** new-feature
**User Impact:** Users can keep selected agents addressed across
consecutive messages without retyping their handles.

**Problem:** Repeated conversations with agents require manually typing
the same mentions on every turn, which adds friction and makes
recipients easy to omit.

**Solution:** The composer can now keep agents automatically addressed
per channel, either from the mention controls or after a successful
inline mention. Addressed agents remain visible in the toolbar, apply to
channel threads, survive send failures safely, and never cross community
boundaries.

## Changes

<details>
<summary>File changes</summary>

**desktop/src-tauri/src/events/message_tags.rs**  
Preserves the automatic-address marker on validated mention reference
tags.

**desktop/src/features/channels/ui/ChannelPane.tsx**  
Wires the appropriate channel, thread, inbox, or forum composer context
without leaking audiences across surfaces.

**desktop/src/features/communities/useCommunityInit.ts**  
Clears composer audience state when the active community changes.

**desktop/src/features/forum/ui/ForumComposer.tsx**  
Wires the appropriate channel, thread, inbox, or forum composer context
without leaking audiences across surfaces.

**desktop/src/features/forum/ui/ForumComposerAutocompletes.tsx**  
Wires the appropriate channel, thread, inbox, or forum composer context
without leaking audiences across surfaces.

**desktop/src/features/home/ui/InboxDetailPane.tsx**  
Wires the appropriate channel, thread, inbox, or forum composer context
without leaking audiences across surfaces.

**desktop/src/features/messages/lib/agentAddressMention.d.mts**  
Defines helpers and types for marked automatic-address mention tags.

**desktop/src/features/messages/lib/agentAddressMention.mjs**  
Defines helpers and types for marked automatic-address mention tags.

**desktop/src/features/messages/lib/agentAddressMention.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/lib/applyEditTagOverlay.mjs**  
Preserves automatic-address metadata when edited message tags are
overlaid.

**desktop/src/features/messages/lib/applyEditTagOverlay.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.


**desktop/src/features/messages/lib/autoPinMentionedAgentsPreference.test.mjs**
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.


**desktop/src/features/messages/lib/autoPinMentionedAgentsPreference.ts**
Stores the preference that keeps explicitly mentioned agents addressed
for later messages.

**desktop/src/features/messages/lib/extractMentionPersonas.ts**  
Separates persona recipients from the composer mention orchestration.

**desktop/src/features/messages/lib/persistentAgentAudience.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/lib/persistentAgentAudience.ts**  
Maintains bounded, in-memory, channel-scoped automatic agent audiences.

**desktop/src/features/messages/lib/useMentionSelection.ts**  
Centralizes mention picker selection state and agent-first selection
behavior.

**desktop/src/features/messages/lib/useMentions.ts**  
Exposes explicit picker origins and selection controls while preserving
inline mention behavior.

**desktop/src/features/messages/ui/ComposerAddressControls.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/ComposerAddressControls.tsx**  
Renders compact addressed-agent avatars and the automatic-mention
management entry point.

**desktop/src/features/messages/ui/MentionAutocomplete.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/MentionAutocomplete.tsx**  
Adds automatic-mention controls and options to the existing mention
picker.

**desktop/src/features/messages/ui/MessageAgentAddressPrefix.tsx**  
Shows which agents were automatically addressed on a sent message.

**desktop/src/features/messages/ui/MessageComposer.tsx**  
Integrates automatic audiences, picker controls, accessible feedback,
shortcuts, and send behavior.

**desktop/src/features/messages/ui/MessageComposer.types.ts**  
Defines the simplified channel audience context shared by composer
hosts.

**desktop/src/features/messages/ui/MessageComposerToolbar.tsx**  
Places automatic-address controls in the composer toolbar without
crowding narrow layouts.

**desktop/src/features/messages/ui/MessageRow.tsx**  
Displays automatic-address metadata alongside sent message content.

**desktop/src/features/messages/ui/MessageThreadPanel.tsx**  
Wires the appropriate channel, thread, inbox, or forum composer context
without leaking audiences across surfaces.

**desktop/src/features/messages/ui/composerAgentKeyboard.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.


**desktop/src/features/messages/ui/persistentAgentAudienceHosts.test.mjs**
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/useAddressMentionPulse.test.mjs**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/useAddressMentionPulse.ts**  
Provides success and failure animation signals for addressed-agent
controls.

**desktop/src/features/messages/ui/useAgentAddressLockPicker.test.mjs**
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/useAgentAddressLockPicker.ts**  
Coordinates adding, removing, and announcing automatically addressed
agents.

**desktop/src/features/messages/ui/useAlwaysAddressShortcut.ts**  
Implements the platform-aware shortcut for toggling automatic
addressing.

**desktop/src/features/messages/ui/useAutoPinMentionedAgents.ts**  
Promotes successfully sent inline agent mentions and provides a single
undoable notification.

**desktop/src/features/messages/ui/useComposerMentionPicker.ts**  
Opens the mention picker without rewriting the current draft.


**desktop/src/features/messages/ui/useMentionSendFlow.helpers.test.mjs**
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

**desktop/src/features/messages/ui/useMentionSendFlow.helpers.ts**  
Merges automatic and inline recipients, marks outgoing tags, and
restores failed sends safely.

**desktop/src/features/messages/ui/useMentionSendFlow.ts**  
Merges automatic and inline recipients, marks outgoing tags, and
restores failed sends safely.


**desktop/src/features/messages/ui/usePersistentAgentMentionHydration.ts**
Removes the prior draft-text hydration approach now that automatic
audiences stay at composer ingress.

**desktop/src/features/settings/ui/AgentsSettingsPanel.tsx**  
Replaces the old global behavior with explicit composer-level
automatic-mention controls.

**desktop/src/features/settings/ui/PreventSleepSettingsCard.tsx**  
Replaces the old global behavior with explicit composer-level
automatic-mention controls.

**desktop/src/shared/lib/keyboard-shortcuts.ts**  
Defines the user-facing automatic-address keyboard shortcut label.

**desktop/src/shared/ui/VideoReviewCommentMarkdown.tsx**  
Allows automatic-address prefixes to compose with video review
timecodes.

**desktop/tests/e2e/persistent-agent-audience.spec.ts**  
Covers the automatic-address behavior and its failure, keyboard, layout,
or persistence boundaries.

</details>

## Reproduction Steps

1. Open a channel with one or more agents and open the mention picker
from the composer.
2. Select an agent for automatic mentions, then send several messages
without retyping the handle; confirm the agent remains in the composer
control and receives each message.
3. Mention another agent inline, send successfully, and confirm the
agent becomes automatically addressed; use the notification's Undo
action to reverse it.
4. Open a thread in the same channel and confirm the same addressed
agents are available there.
5. Remove an agent from the composer control and confirm later messages
stop addressing it.
6. Switch communities and confirm addressed agents do not carry into the
other community.

## Screenshots

All states below use the dark Buzz theme with a selected lilac accent.

### Addressed composer

Selected agents stay visible at the composer ingress without adding
handles to the draft.

![Two automatically addressed agents in the dark composer with a lilac
accent](https://raw.githubusercontent.com/block/buzz/74c2cbbd80ed630a0c6e00c420505a691bd4994a/pr-6315--01-addressed-composer.png)

### Open mention menu

The @ ingress opens the existing mention menu and shows which agents are
already addressed.

![Open mention menu with automatically addressed agents
highlighted](https://raw.githubusercontent.com/block/buzz/74c2cbbd80ed630a0c6e00c420505a691bd4994a/pr-6315--02-open-mention-menu.png)

### Mention options

The inline options pane controls whether a successful one-time agent
mention carries into later messages.

![Automatic mention options expanded above the mention
menu](https://raw.githubusercontent.com/block/buzz/74c2cbbd80ed630a0c6e00c420505a691bd4994a/pr-6315--03-mention-options.png)

### Agent settings

The same preference is available in **Settings → Agents →
Conversations**.

![Automatic agent mentions preference in the Agents settings
pane](https://raw.githubusercontent.com/block/buzz/74c2cbbd80ed630a0c6e00c420505a691bd4994a/pr-6315--04-agent-settings.png)

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
## Summary
- add foreground mobile Huddles on Android and iOS with native Opus
capture/playback, mute, speaker routing, participants, lifecycle, and
minimized drawer UI
- keep mobile Huddle cards and roster state live, including ended rooms,
relay-resolved profiles, and agents
- broadcast desktop agent TTS through the existing Huddle audio protocol

## Scope
Foreground human-to-human voice MVP only. Agent setup/transcripts,
background calling, recording, and advanced device controls remain out
of scope.

## Validation
- `just mobile-check`
- `just mobile-test` — 1,500 passed
- `just desktop-check` and `just desktop-test` — 4,957 passed
- desktop typecheck, strict Clippy, and Tauri tests — 2,445 passed, 15
ignored
- mobile worktree identity contract checks
- physical Pixel/iPhone behavior reviewed during development

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: leader <71e9f2c44a6932b6772caaaccda1911d010463c3e2c6c40410b8329956046801@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Mongo <9cfd347903944d5b85aa6c93d2ab67381b978a92a31914bca69998968752a1d7@buzz.block.builderlab.xyz>
## Why
The ACP prompt puts a machine-specific Workspace prefix before static
base guidance and labels the user-facing agent instruction layer as the
generic System section. Because the cwd varies by launch and worktree,
leading with it reduces reusable prompt-prefix stability.

`[Workspace]` was added in [PR
block#1194](block#1194) as a defensive fix after
a broken `~/.sprout` → `~/.buzz` migration caused agents to scan `$HOME`
and trigger macOS TCC prompts. This change retains that grounding while
shrinking it to the current working directory and moving dynamic
environment context after the static Base prompt.

## What
- Emit the prompt in Base → Workspace → Agent Instructions order
- Reduce Workspace to `Current working directory: <absolute path>`
- Resolve cwd as an absolute native-platform path and preserve Windows
drive/UNC paths instead of checking for a leading `/`
- Emit Agent Instructions for persona and standalone agent instructions
across modern and legacy ACP paths
- Preserve parsing for archived observer frames that used System or the
former Workspace-before-Base order, and align the persona catalog label

## Risk Assessment
Medium-low — this changes prompt framing for every newly created agent
session. Existing archived observer frames remain parseable, and
execution still uses the same ACP working directory. Cwd resolution now
fails clearly instead of substituting `/` when the process directory
cannot be resolved.

## References
- block#1103
- block#1194

Generated with Codex

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Diagnostic profiling on a large community (101 issues, 258 PRs) showed
Projects tab switches taking 2.5–3.6s, dominated by single React commits
of 0.5–1.5s and per-render recomputation — fetch work was already off
the main thread; the cost was building the UI.

### Measured: tab click → painted, per tab

| tab | before | after |
|---|---|---:|
| projects | 3,608ms | 320–580ms |
| repositories | 3,126–3,534ms | 310–410ms |
| tasks | 395–1,101ms | ~115ms |
| reviews | 322–2,603ms | ~96ms |
| activity | 597–741ms | ~148ms |

Single-commit ceiling dropped from 1,541ms to ≤200ms (growth steps
25–40ms). Fixes in profiled-cost order:

- **Profile popover body mounts only while open.** `UserProfilePopover`
carried seven query subscriptions plus interaction hooks per instance
even when closed; grids mount hundreds (five per card in people stacks,
one per row author) — measured **~40ms per card**, the dominant share of
the 1.2s card-tab commits. The always-mounted shell is now just the
Radix root + trigger; trigger markup, hover timing, and keyboard
handling are unchanged, and hover/tooltip event continuity is preserved
because the trigger never remounts.
- **Incremental row mounting.** The first 12 cards / 30 rows render in
the first commit; the rest stream in 36–60-per-frame low-priority
transitions. Grouped lists trim across group boundaries via a pure,
tested slicer; the mounted count survives in-place refetches.
- **Activity feed**: was rebuilt unmemoized on every render,
markdown-flattening every issue/PR/comment body in the community just to
sort and keep 30 items (~360+ flattens per render on the measured
community). Now memoized, and bodies stay raw until after the sort+slice
— 30 flattens, once per data change.
- **Contribution graph** (always-visible rail, so every tab paid for
it): ~180 day cells each wrapped in a Radix tooltip with per-cell Intl
date formatting per render. Now memoized, cells precomputed once per
data change, native `title` tooltips. (The activity-bar segments keep
their styled Radix tooltips — pinned by an existing spec.)
- **Rows/cards memoized with identity-stable props**: per-row selection
arrays were rebuilt per row per render (O(n²) — 258 PRs × 258-item
arrays each render) and are now hoisted and shared; people arrays derive
inside the memoized cards; the rail's stat walk over every issue/PR is
memoized.
- **`content-visibility: auto`** on cards and rows so offscreen entries
skip layout and paint; **tab switches run in a React transition** so the
click stays responsive while the new tree mounts.

Remaining known cost (out of scope): cold-entry data readiness — the
work-item and activity queries ship thousands of events to compute
counts (2–4s on a large community; see the fan-lifecycle PR). The
structural fix is a relay-side aggregate; tracked as follow-up.

---------

Signed-off-by: Max Lampert <maxwell@squareup.com>
## Summary

- downgrade Mobile Huddle authentication and native media configuration
from protocol v3 to the currently deployed relay's v2 contract
- restore the released one-byte relay peer prefix while retaining later
reconnect, roster, and playout-reset reliability fixes
- update Android, iOS, protocol documentation, and focused tests
together

Protocol v2 does not carry v3's occupancy epoch on audio frames, so it
cannot fence the narrow delayed-packet/peer-index-reuse race. This is an
intentional compatibility tradeoff until the relay v3 rollout is ready.

### Related issue

None found.

### Testing

- `just mobile-check`
- `just mobile-test` — 1,661 tests passed
- Android debug build installed and launched on Pixel 10 as
`xyz.block.buzz.mobile.sprout_mobile_profile_settings`; foreground
process verified
- signed iOS Release build installed and launched on iPhone as
`com.buzz.buzzMobile`; running process verified

A live two-device Huddle audio call remains a manual verification step.

Signed-off-by: kenny lopez <klopez4212@gmail.com>
## Summary
- arrange Huddle participants in a responsive, equal-weight cluster with
spring enter/exit motion and a `+N` overflow
- spotlight tapped participants over a blurred call surface, with a
roster for hidden participants and no self-avatar action
- add selection haptics across full-screen and drawer controls,
including both end-call buttons
<img width="1080" height="2424" alt="Screenshot_20260819-151448"
src="https://github.com/user-attachments/assets/00b7fdca-2304-4788-9952-e07224798513"
/>
<img width="1080" height="2424" alt="Screenshot_20260819-151422"
src="https://github.com/user-attachments/assets/a0cfc861-0519-44ff-bb56-4c983ed6344c"
/>

## Validation
- `just mobile-check`
- focused participant, drawer-control, and full-screen end-call widget
tests
- Huddle-focused widget suite (15 tests)
- full mobile Flutter suite (1,538 tests)

## Dependency
Built on block#6056 and contains only the follow-up interaction work. Merge
after block#6056 lands.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: leader <71e9f2c44a6932b6772caaaccda1911d010463c3e2c6c40410b8329956046801@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Mongo <9cfd347903944d5b85aa6c93d2ab67381b978a92a31914bca69998968752a1d7@buzz.block.builderlab.xyz>
## Summary
- negotiate Huddle audio protocol v2 on desktop
- decode the released one-byte peer-index prefix
- retain roster-driven playout resets and document the missing v3 epoch
fence

## Testing
- `just desktop-tauri-fmt-check`
- `just desktop-tauri-clippy`
- `just desktop-tauri-test`

Signed-off-by: kenny lopez <klopez4212@gmail.com>
… sends (block#6572)

## Summary

Lands the build-now items from the desktop latency plan
(#ui-performance-deep-dive) as one change. Every perceived-latency hot
path a user hits on launch, channel open, thread open, and reply send
drops one or more round trips.

**A1 — persisted channel heads (the big one).** Native WAL SQLite cache
(`desktop/src-tauri/src/channel_head_cache.rs`) keyed by `{pubkey,
relayUrl}` scope, 32 rows/scope LRU, 1 MiB per-row drop cap,
schema-version reset, corrupt-row tolerance, checkpointed on shutdown.
Three blocking-pool commands: `channel_head_cache_load` / `_store` /
`_clear`. On the renderer side, `CommunityQueryProvider` kicks off
hydration of up to 12 heads when it constructs the query client — the
app, splash and relay preconnect mount immediately; only
`useChannelMessagesQuery` awaits the seed (`channelHeadHydration`), then
consumes a one-shot hydrated gate so a hydrated channel pays **zero**
`get_channel_window` calls on mount and exactly **one** on the
post-subscription refresh, whose response replaces page zero wholesale.
That refresh fires whether live-subscription setup succeeds or fails,
and is sequenced behind hydration so it is always a distinct
authoritative fetch (see Review follow-ups). Bounds-only persisted heads
(zero rows) are not hydrated and take the cold loading path. The
timeline loading latch recognizes native-hydrated rows as restart-safe
so they paint immediately instead of holding a skeleton. The cache is a
paint accelerator only — the relay response is always authoritative.
Replaces the legacy localStorage `messageSnapshot.ts` (removed, -401
lines).

Kill switch: `VITE_BUZZ_CHANNEL_HEAD_CACHE=off` at build time or
`localStorage["buzz-channel-head-cache"] = "off"` at runtime. Cache is
cleared on community removal and scoped per identity, so a replaced
signer never sees the previous identity's rows.

**B1 — thread aux in one response.** Relay thread filters accept
`include_aux`; the bridge appends the same authorized two-hop
reactions/edits/deletions closure a channel window gets
(`build_aux_query` shared with the window path). Renderer
`useThreadReplies` drops its two follow-up aux fetches. `next_cursor` is
computed from reply-kind rows only since aux rows are unpaged.
Documented in `docs/bridge-channel-window.md`. Thread queries keep
`staleTime: 0` (`bcfe04e2f`): an earlier revision raised it to 30s,
which CI's `thread-unread.spec.ts` caught — once the user leaves a
channel, the live subscription stops feeding that thread's cache, so a
reopen must always take the (now single) authoritative read.

**B2 — cached root on reply send.** `send_channel_message` gains
`root_event_id`; when the renderer already holds the parent (channel or
thread cache) it passes the NIP-10 root, and native signs without the
relay round trip that `resolve_thread_ref` used to make. Strict hex
parse; `root_event_id` requires `parent_event_id`; absent root falls
back to the existing relay resolution. The renderer never sends a
guessed root.

**B4** general HTTP pool idle 10s→300s, max idle per host 1→2. **B5**
relay preconnect fires as soon as identity is ready instead of waiting
for `requestIdleCallback`. One e2e test (`relay-reconnect.spec.ts`
"service restart close resets accumulated backoff") had been relying on
the idle-callback batching to skip past its own seeded dial failures
before the channel list painted; `8133d70bb` makes it wait for the
connected state instead (test-only, still fails with the 1012 backoff
reset disabled). **B6** profile freshness 60s→10 min (both the in-memory
entry check and the query `staleTime`). Tradeoff: another user's
display-name/avatar edit can take up to 10 min to propagate to a client
that already holds their profile (relay reconnect refetches
`users-batch` but resolves from the still-fresh per-pubkey entry); your
own edits still evict the entry immediately (`evictUsersBatchEntries` in
`useUpdateProfileMutation`).

### Related issue
Follows block#6456/block#6457/block#6459/block#6460 (already merged). block#6455 is the
measurement instrument and is intentionally not folded in. No duplicate
PR found.

### Review follow-ups
Addressing Carl's reviews
[5001114109](block#6572 (review))
and
[5002596542](block#6572 (review)),
each pushed as new commits (no rebase):

- `4f06b7770` fix(desktop): mount app while channel heads hydrate;
always revalidate — provider no longer gates children on the cache load;
`refreshAfterSubscribe` runs on subscribe failure too; bounds-only heads
skipped at seed; seed merges into an existing window store. +3 tests.
- `35834cb31` fix(relay): drain aux closure hops across the page clamp —
`query_all_pages` walks the `(created_at, id)` keyset via
`until`/`before_id` until a short page (`AUX_PAGE_LIMIT` =
`DEFAULT_MAX_PAGE_LIMIT`, `AUX_MAX_PAGES` = 64 warn+truncate) so
one-shot `limit: 1000` newest-first no longer drops the oldest
edits/deletions. +3 tests; `docs/bridge-channel-window.md` updated.
- `db21b0531` merge of `origin/main` `e23632941` (block#6558, block#6312 — no
overlap).
- `5a5566c0f` fix(desktop): sequence post-subscribe refresh behind
channel head hydration — `refreshChannelWindowMessages` awaits
`channelHeadHydration()` and, for a hydration-seeded query (`data !==
undefined && dataUpdatedAt === 0`), the in-flight snapshot fetch before
invalidating. Without this, a subscription that settles before the
SQLite load invalidated a data-less in-flight query; TanStack dedupes
that onto the existing fetch (`query-core` `fetch()` only cancels when
`state.data` exists), which returned the seeded snapshot — 0
authoritative fetches. Regression test reproduces Carl's exact ordering
(fails at `35834cb31` with 0 calls), plus a cold-channel guard that the
fix does not double-fetch.
- `b129231c8` fix(desktop): let concurrent post-hydration refreshes
share one window fetch — found independently by Max and Wren reviewing
`5a5566c0f`: subscribe settlement + reconnect both wake on the same
snapshot promise and both invalidate; the second (default
`cancelRefetch: true`) cancelled and replaced the first authoritative
fetch (3 queryFn calls, not 2, and the cancelled Tauri invoke still hits
the relay). The seeded branch now invalidates with `cancelRefetch:
false` so a second waker joins the in-flight fetch; cold/warm keep the
default (`test_canceled_stale_fetch_cannot_overwrite_catch_up_window`
relies on it). Concurrent regression test fails at `5a5566c0f` with 3.

### Testing
At `b129231c8` (PR head; verified in one shell with `git rev-parse HEAD`
= `b129231c8`): `pnpm check`, `tsc --noEmit`, desktop unit 5,393 / 0,
Playwright `boot-splash` + `channel-head-restart` + `relay-reconnect` +
`relay-reconnect-affordance` + `thread-unread` 34 / 34 on a fresh
`build:e2e`, pre-push hooks green.

At `5a5566c0f`: `pnpm check`, `tsc --noEmit`, desktop unit 5,392 / 0,
Playwright `boot-splash` + `channel-head-restart` + `relay-reconnect` +
`relay-reconnect-affordance` + `thread-unread` 34 / 34 on a fresh
`build:e2e`, pre-push hooks green.

At `35834cb31`: desktop unit 5,390 / 0; `cargo test -p buzz-relay --lib`
910 / 0; fmt + clippy `-D warnings` clean; Playwright 32 / 32 (same
specs minus affordance); GitHub CI green on every job except Smoke (3)
(unrelated project-review row-count + messaging timing flake, per Carl)
and Unit Tests (sherpa cache skeleton, below).

Earlier, all at `8133d70bb` (this PR head is `0c492366d` = 8133d70 + a
comments-only commit correcting two `profile/hooks.ts` freshness
comments from 60s to 10 min; pre-push desktop check/typecheck/test
5,387/0 re-ran at 0c49236) in one shell; `origin/main` = `040b203f7`
at PR open, since moved to `4baccd539` (block#6558, mobile only — zero file
overlap, `git merge-tree` clean):

- `just desktop-test` — 5,387 passed / 0 failed (includes new hook-level
call-count test: cold = 1, stale-prefetched = 1, hydrated = 0 on mount
then 1 on invalidate with wholesale replacement)
- Playwright smoke `relay-reconnect.spec.ts` + `thread-unread.spec.ts` +
`channel-head-restart.spec.ts` — 30/30 (thread-unread was 8/13 at
`7acbf951b`; relay-reconnect was 15/16 at `bcfe04e2f`). The restart spec
persists a head, reloads into a fresh mock relay with the head fetch
held 5s, asserts the persisted row paints within 2s, exactly one
`get_channel_window` after open, and the stale row is removed when the
authoritative page lands.
- `pnpm typecheck`, `pnpm check` — clean

At `7acbf951b` (everything except the two-line `useThreadReplies.ts`
staleTime revert and the test-only `relay-reconnect.spec.ts` change),
also green in one shell:
- `just desktop-tauri-test` — 2,859 passed / 0 failed across the
workspace (channel_head_cache: wire shape, LRU+caps, schema reset,
corrupt-row skip)
- `just test-unit` — 632 passed (buzz-core/auth); `cargo test -p
buzz-relay --lib` — 908 passed / 0 failed
- `just check` components: fmt-check, clippy, desktop-check,
desktop-typecheck, desktop-tauri-fmt-check, desktop-tauri-clippy,
web-check, mobile-check, file-size-check — all green
- `just desktop-build`, `web-build`, `desktop-tauri-check`,
`mobile-test` (1,661 passed) — all green

CI note: the "Unit Tests" job goes red on this PR and on `main` whenever
it hits a poisoned `rust-cache` entry (an empty-directory skeleton of
`target/sherpa-onnx-prebuilt` that `sherpa-onnx-sys` build.rs trusts),
surfacing as `could not find native static library sherpa-onnx-c-api` in
`buzz-voice` — a crate this PR doesn't touch. Deleting the cache entry
and rerunning turned the job green at `0c492366d` (28/28); it re-poisons
on the next `main` push until the workflow clears that directory after
cache restore.

Reviewed in-channel by Wren (9 / 9 / 9.5) and Eva (9 / 9 / 9), and
line-by-line by me before opening; the staleTime fix re-verified by Wren
and me independently; the relay-reconnect test fix bisected and verified
by me.

---------

Signed-off-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Signed-off-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Signed-off-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
Co-authored-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
## Summary
- skip managed-agent runtime discovery when the members sidebar has no
local managed bots
- run runtime listing disk, process, and mutex work on Tauri’s blocking
pool
- preserve local managed-bot status and Start/Stop behavior with
positive and negative E2E coverage

Opening Add people in a human-only channel could invoke synchronous
native runtime discovery before the sidebar painted, leaving the macOS
app beachballed. Human invites do not depend on that data.

## Why
I have seen slowness opening this dialog in the UI


https://github.com/user-attachments/assets/1955eb5e-ee47-4edf-8e5c-606d11ffbc25


### Related issue
Related overlap: block#4851 is a broader managed-agent lifecycle change that
includes a similar native offload. This draft is intentionally limited
to the sidebar critical path and adds the human-only query gate.

### Testing
I have verified the pause in the video goes away after this change.

- `just ci`
- `just desktop-check`
- `just desktop-test` (5,241 passed)
- `just desktop-tauri-fmt-check`
- `just desktop-tauri-clippy`
- `just desktop-tauri-test` (2,702 passed; 18 ignored)
- focused Playwright: human-only sidebar skips runtime discovery
- focused Playwright: local managed bot retains status and Stop/Start
controls

No visual styling changed, so screenshots are not applicable.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
## Summary

- Keep virtualized member rows measurable by removing
`content-visibility: auto` from the measured row subtree.
- Use the member card's 60px baseline as the virtualizer estimate while
retaining deferred rendering for eager search and archived-member lists.
- Cover large rosters with a regression test that checks stable scroll
extent across the list and verifies the final member remains reachable.

### Related issue

None found.

### Testing

- `just ci`
- `pnpm -C desktop build:e2e`
- `pnpm -C desktop exec playwright test tests/e2e/channels.spec.ts
--grep 'members sidebar virtualizes large channel rosters'
--repeat-each=5`

#### Before


https://github.com/user-attachments/assets/a5fcc040-6872-4200-bcc3-7b4197a4dd23

#### After


https://github.com/user-attachments/assets/f2c97f2f-3719-4c2a-b17a-2450c6c70a55

Signed-off-by: Matt Toohey <contact@matttoohey.com>
loganj and others added 25 commits September 11, 2026 11:19
…ock#7385)

<!-- Draft PR body for block#7385 · fix(mobile): bind same-name mentions to
exact selected identities · block#7385 -->

🤖

## Summary

If two people in a channel share a display name, mobile couldn't tell
them apart in mentions: picking the second could overwrite the first's
selection, a rendered mention linked whichever same-name person matched
first, and a later rename or a shorter name could re-bind the text to
the wrong recipient. This PR binds every mention to the exact selected
identity:

- Each same-name selection keeps its own recipient instead of
overwriting by name; conflicting picks get a qualified label like `Name
(key…)`.
- The longest matching label wins, so a shorter or interior name can
never claim part of a longer one and steal its identity.
- Rendering resolves recipients by the signed identity key from the
event's tags — never from message text alone — so qualified labels stay
correct regardless of tag order and survive later renames; an untagged
ambiguous label blocks shorter mentions instead of silently re-binding.

Ports the landed Desktop exact-recipient behavior (see
`docs/mention-editor.md`).

### Related issue

- Fixes: N/A. No mobile issue; Desktop's landed exact-recipient fixes
are the reference this ports.
- Independent base (`main`). block#7387 (child) persists these exact
selections in saved drafts.
- Landing note: branches in this series overlap in the composer — when
rebasing, keep exact/durable mention bindings, the explicit
invite/reference-only choice, the account/visit/revision fences, and
authorization before membership preparation and publication; don't
resolve conflicts by taking either side wholesale.
- Draft — not requesting merge yet; the security advisory run for this
range timed out without results (no verdict).

### Testing

- Regressions cover same-name collisions, prefix/overlap, removal, tag
order, and renames.
- At `acd841354a692243f1cb4c04059baad42f1d2abb`: `just mobile-check` and
full `just mobile-test` pass (2,082 tests). The earlier full `just ci`
receipt linked below is reused only for unchanged non-mobile
code/tooling, not claimed as a rerun at this head.
- Previous-head evidence: `just mobile-check`, the full mobile test
suite, and full local `just ci` all pass — receipts in the [exact-head
evidence
comment](block#7385 (comment)).
- Verification is widget-test level; no native device or simulator run
is claimed.

To see it: mention two teammates with the same display name — both stay
distinct, the second shows a qualified label, and the rendered message
keeps both correct even after either renames.

### Screenshots

Flutter production-widget test renders — not native-device screenshots
or acceptance captures.

| Scenario | Before | After |
|---|---|---|
| Qualified mention chip for same-name recipients, at 200% text scale
(deliberate stress fixture) | ![Before: the short chip is followed by
the distinguishing key spilling out as raw
text](https://github.com/user-attachments/assets/f1e40acc-24f1-47f7-b2f7-e3ba2348c169)
| ![After: the full qualified label wraps inside the bounded chip,
keeping the @ and robot glyph
visible](https://github.com/user-attachments/assets/b949e44f-e3f6-4c72-98ff-68139b2e1ab3)
|

<details>
<summary>Capture provenance</summary>

Rendered by the Flutter widget engine in a `flutter test` run
(production widgets, production theme; no device or simulator). Before:
this PR's declared base `3c7f288c60d67df78577b237e27c3dfc8831aaa1`.
After: its head `39afd73b0adfde14164f4b10dbd089cb498312b6`.

</details>

Signed-off-by: Logan Johnson <loganj@squareup.com>
## Overview

**Category:** fix

**User Impact:** Agent avatars and empty agent-team placeholders now
keep the same intentional squircle silhouette at every size on desktop,
while human avatars remain circular.

**Problem:** Desktop agent avatars used percentage-rounded rectangles,
which made the silhouette vary by surface and required each avatar
implementation to recreate the shape. Empty team placeholders also drew
a regular CSS border inside the clip, leaving straight inset edges that
looked like a cropped square. **Solution:** Reuse one normalized SVG
clip path across desktop artwork. Empty team placeholders use a
separately clipped squircle outline behind the clipped surface, so both
the fill and outline follow the canonical silhouette.

> **Scope correction:** Mobile is deferred from this PR because a real
Flutter capture could not be obtained reliably in the current build
environment. Previously attached mobile images were hand-composed
synthetic layouts, not captures from the running app; they have been
removed and must not be treated as validation. The mobile implementation
is being reverted in one follow-up commit so it can be reapplied and
verified separately.

### Related issue

Follow-up to block#7106.

## Changes

<details>
<summary>File changes</summary>

**desktop/src/features/agents/ui/AgentCreationPreview.tsx**
Applies the shared squircle clip to agent creation preview images and
fallbacks.


**desktop/src/features/agents/ui/AgentSessionToolItem/CompactMessageSummary.tsx**
Uses the shared agent-avatar silhouette in compact session summaries.

**desktop/src/features/agents/ui/IdentityInitialsAvatar.tsx**
Clips agent initials with the normalized squircle instead of a
percentage radius.

**desktop/src/features/agents/ui/TeamIdentityCard.tsx**
Uses the shared squircle for agent identities and gives empty teams a
separately clipped squircle outline instead of a regular inset border.


**desktop/src/features/agents/ui/activityRenderClasses/UserMessageBubble.tsx**
Keeps agent avatars in activity message bubbles on the canonical
silhouette.

**desktop/src/features/home/ui/InboxListPane.tsx**
Applies the shared clip to agent avatars in the inbox list.

**desktop/src/features/home/ui/InboxMessageRow.tsx**
Applies the shared clip to agent avatars in inbox message rows.

**desktop/src/features/huddle/components/ParticipantList.tsx**
Uses the normalized squircle for agent participants while preserving
circular human avatars.

**desktop/src/features/messages/ui/MessageRow.tsx**
Clips agent message avatars through the shared definition.

**desktop/src/features/messages/ui/SystemMessageAvatars.tsx**
Uses the canonical agent shape in system-message avatar groups.

**desktop/src/features/messages/ui/TypingIndicatorRow.tsx**
Uses the canonical agent shape in typing indicators.

**desktop/src/features/profile/ui/ProfileAvatar.tsx**
Scales the same squircle to the larger agent profile avatar.

**desktop/src/features/profile/ui/SelectedRecipientChip.tsx**
Uses the shared shape for selected agent recipients.

**desktop/src/features/projects/ui/IssueAssigneesRow.tsx**
Applies the agent squircle to issue assignees without changing human
avatar geometry.

**desktop/src/features/projects/ui/ProjectCards.tsx**
Uses the canonical shape for agent avatars on project cards.

**desktop/src/features/projects/ui/ProjectEntityListRow.tsx**
Uses the canonical shape for agent identities in project entity lists.

**desktop/src/features/projects/ui/ProjectsActivityFeed.tsx**
Uses the shared clip for agent avatars in project activity.

**desktop/src/features/projects/ui/ProjectsOverviewRail.tsx**
Uses the shared clip for agent avatars in the project overview rail.

**desktop/src/main.tsx**
Mounts the single shared SVG clip-path definition once for the desktop
application.

**desktop/src/shared/lib/cn.ts**
Registers `rounded-squircle` in the border-radius class group so
shadcn-style `cn(...)` composition resolves it against `rounded-full` by
normal last-class precedence.

**desktop/src/shared/styles/globals/utilities.css**
Registers the reusable Tailwind `rounded-squircle` utility and
references the normalized SVG clip path without agent-specific CSS
selectors.

**desktop/src/shared/ui/AvatarClipPaths.tsx**
Owns the reusable normalized object-bounding-box `rounded-squircle` path
so all desktop sizes reuse one definition.

**desktop/src/shared/ui/UserAvatar.tsx**
Routes the existing squircle shape option through the shared SVG clip.

**desktop/tests/e2e/agents.spec.ts**
Verifies team facepile and empty-team placeholder surfaces/outlines use
the canonical clip without a rectangular border.

**desktop/tests/e2e/messaging.spec.ts**
Verifies agent message and profile avatars reuse one clip definition and
scale across rendered sizes.

</details>

## Reproduction steps

1. Run the desktop app and open a channel containing both agent and
human messages.
2. Compare agent avatars in the message list, inbox, huddle
participants, projects, and profile panel. Agent images and fallbacks
should share one smooth squircle silhouette at each size; human avatars
should remain circular.
3. Open **Agents** and inspect an empty agent-team card. Its placeholder
fill and outline should both be smooth squircles, with no straight inset
cropped-square edges.
4. Open an agent profile from a message and confirm the larger profile
avatar keeps the same proportions as the smaller message avatar.

## Testing

- Desktop Biome check passed for the changed empty-team component and
Agents E2E spec.
- Desktop typecheck and differential file-size check passed.
- Full desktop unit suite passed: 6,453 tests.
- Full Agents integration spec passed: 37/37, including the empty-team
outline regression.
- Post-rebase pre-push gates passed at `304b159a2`: desktop checks,
TypeScript typecheck, differential file-size gate, and all 6,453 desktop
unit tests.
- The shadcn-aligned `rounded-squircle` registration passed changed-file
Biome, desktop TypeScript/build, and pre-push desktop checks at
`27e0c12d3`; the full desktop unit suite passed 6,459/6,459.

## Screenshots

Screenshots are temporarily omitted. The previous captures used the
desktop E2E mock bridge and were not evidence from a live running app,
so they were removed.

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
…k#7584)

## Summary

`crates/buzz-acp/src/base_prompt.md` carries a hand-maintained `Group |
Key commands` table of the `buzz` CLI. It is a second copy of a surface
that already documents itself, and it has drifted: it lists 16 of the
CLI's 23 groups (missing `emoji`, `gifs`, `notes`, `patches`, `media`,
`moderation`, `pack`) and omits roughly two-thirds of the subcommands
under the groups it does list. its hard to keep it in sync.

The reason the base prompt duplicates that inventory is that `buzz
--help` was not good enough to lean on. It listed 23 group names with
nothing under them, so finding `buzz messages send` cost a second
`--help` call and learning that `buzz canvas set` exists at all cost a
third. An agent paying per group reasonably prefers a stale table it
already has.

This PR fixes the help output so the prompt can point at it instead.
`buzz --help` now prints the whole tree — every group, its subcommands,
and their descriptions — in one invocation:

**Before**

```
Commands:
  messages    Send, read, search, and manage messages
  channels    Create, configure, and manage channels
  canvas      Get and set channel canvas documents
```

**After**

```
Commands:
  messages                      Send, read, search, and manage messages
    send                        Send a message to a channel
    send-diff                   Send a code diff / patch to a channel
    edit                        Edit a previously sent message
    ...
  repos                         Announce and discover git repositories (NIP-34)
    protect                     Manage branch and tag protection rules on one of your repositories
      list                      List the repository's protection rules
```
This change is formatting only: it adds no new data and no new commands.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…table (block#7586)

## Summary

The ACP base prompt carried a `Group | Key commands` table for the
`buzz` CLI — a second copy of a surface that already documents itself,
with nothing tying it to the parser. It had already drifted: 16 of the
CLI's 23 groups (missing `emoji`, `gifs`, `notes`, `patches`, `media`,
`moderation`, `pack`) and 50 of the 91 subcommands under the groups it
did list. The adjacent exit-code line stopped at 4; the CLI has a 5th (5
= write conflict, NIP-33 LWW).

block#7584 was the prerequisite: `buzz --help` now renders the full command
tree — every group, its subcommands, and their descriptions — in one
invocation (199 lines, 13 KB), generated from clap's own command
definition, so it cannot drift. `buzz -h` still prints the group-level
summary. Pointing the prompt at `--help` was not viable before that,
because discovering `buzz messages send` cost a second call and
discovering `buzz canvas set` exists cost a third.

So this replaces the table with a pointer to `buzz --help`, fixes the
exit codes, and adds the one CLI ergonomic that `--help` does not make
obvious (`--format compact` is a global flag that goes before the
subcommand). Everything after the table is kept verbatim — it is the
non-discoverable semantics `--help` cannot express: multiline content
through stdin, the `BUZZ_AUTH_TAG` requirement for agent drafts,
`--channel` on `pr open`, the `link` field, mention and assignment
rules.

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Summary

PR block#6732 taught the ACP harness to honor `BUZZ_ACP_SESSION_POLICY`, but
the desktop exposed that policy as one global experiment. Turning it on
changed every managed agent at once, even though conversation scope is
part of how an individual agent should behave. Some agents need
continuity across a channel, while agents such as validators may need
clean context for each thread.

This moves the choice onto the agent definition under Advanced as
**Conversation context**, with **Entire channel** and **Each thread**
options. **Entire channel** remains the default, so existing definitions
keep their current behavior.

The policy now travels through create and update IPC, returned agent
summaries, persona events, snapshots, teams, and community catalog
copies. Launches pass the effective definition value to the harness.
Editing a running agent uses the same lifecycle as a model edit: it
shows the restart-required state, leaves the deployed process untouched,
and applies the new policy on restart.

The global Thread Scoped ACP Sessions experiment and its desktop
command/state have been removed because the setting no longer has a
useful global meaning. There is intentionally no migration for the old
preview override. Users who enabled it can choose **Each thread** for
the agents that need it.

Unknown or null policy values degrade to **Entire channel** across
stored agents, persona events, and catalog projections. This keeps
forward-version data from dropping complete agent records.

### Related issue

No matching issue found. Builds on block#6732.

### Testing

- Focused Playwright create flow selected **Each thread** and verified
`create_persona` received `sessionPolicy: "thread"`.
- Focused Playwright catalog flow added a thread-scoped agent and
verified the local copy stored `session_policy: "thread"`.

Generated with Codex

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
## Summary

CI is failing in `main` before tests start because Docker Hub denies
pulls for `minio/minio` and `minio/mc`. Retrying the failed jobs
produced the same errors.

Use MinIO’s Quay images in the development, harness, deployment Compose,
and Helm configurations. Pin each image to its multi-platform digest and
retain the release tags already used by deployment templates. Update the
architecture reference to match.

### Related issue

No duplicate issue or PR found. Addresses the image-pull failures in
[main CI attempt
2](https://github.com/block/buzz/actions/runs/34645306855/attempts/2).

### Testing

- Pulled both pinned images for Linux ARM64 and AMD64.
- Started an isolated Compose stack derived from the updated MinIO
service definitions, once per architecture (AMD64 under local
emulation).
- Verified the existing health check passed and the bucket initializer
exited with code 0.
- Uploaded an object with `mc cp`, read it with `mc cat`, compared its
content, and deleted it with `mc rm` on both architectures.
- Confirmed the initialized bucket was private and removed the temporary
stack and volume.

Generated with Codex

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
## Summary

Handle missing Pi adapter setup and update its install guidance.

### Related issue

None found.

### Testing

No manual testing.

Generated with Amp

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Co-authored-by: Amp <amp@ampcode.com>
…#7606)

Posted by Brain, Wes Billman’s AI assistant, on behalf of `wesbillman`.

## Summary

Add an opt-in `databricks::DatabricksConnection` over the existing
PKCE/coordinator and v2 catalog machinery. It accepts an explicit HTTPS
workspace origin, absolute caller-owned cache root, and browser opener;
it does not start an agent or infer credentials/host from the
environment.

- Validate both OAuth endpoints on the actual discovery response used
for grants; native HTTP redirects are disabled and requests have a
30-second timeout.
- Keep strict cache/single-flight state in a separate namespace. Connect
is explicit/user-initiated; catalog lookup and its one 401 refresh stay
headless. Tokens are not exposed by the connection API.
- Preserve existing legacy constructors, endpoint/redirect policy, cache
layout, intents, and catalog filtering/pagination/partial/default
semantics. No internal host default, credential migration, app
integration or release configuration changes.

### Intentional shared changes

OAuth success/discovery JSON is capped at 1 MiB; error JSON at 16 KiB.
Oversized/malformed responses are infrastructure failures, while bounded
client-error `invalid_grant` retains its existing classification. OAuth
diagnostics omit raw bodies/URLs/opener/callback details. Overflowing
token expiry returns an infrastructure failure. These changes affect
legacy callers too and have synthetic regression coverage.

See [the reuse contract](crates/buzz-agent/DATABRICKS_REUSE.md) for API,
compatibility and caller obligations. Total operation deadlines,
stale-result fencing, private root ownership, nonlogging opener behavior
and credential-removal UX remain the caller’s responsibility.

### Related issue

Related discovery work: block#6918. Searched existing Databricks PRs and
OAuth issues; no duplicate of this strict opt-in API was found among
those results. This is a new reuse boundary, not a claim of a live
credential leak.

### Testing

Published head: `cf33eb2f4f267d5808e068e35127d5504f0bc674`, based on
main `78618804ec86a014524ad7d1fb55928e8f5c3edf`.
Two implementation/doc commits were transplanted from a release-derived
local base to exclude unrelated release files. `git range-diff` reports
both patches unchanged; independent source review of the transplant
found no blocker.

**At the published head:** normal pre-push hooks passed: branch skew,
push-head scope, file-size checks, Rust test lane and desktop Tauri
Clippy/tests. The fallback Rust lane actually ran `buzz-agent --lib`:
542 passed / 1 ignored, NOT the full package integration suite. Hosted
full package/repository CI remains pending. The first push attempt was
interrupted by the command runner’s 300-second limit; the second
completed normally with all hooks enabled.

**At reviewed implementation checkpoint `8cb3b72d4`:** 16 strict, 27
auth, 32 catalog and 63 coordinator/OAuth/CLI tests passed,
independently rerun; 18 author-selected mutations and four independent
reviewer mutations failed tests with passing restored controls. The
subsequent `539319411` delta changed only two doc-comment blocks. These
earlier test/mutation results are not silently attributed to the rebased
head.

Synthetic coverage includes HTTPS grants/catalog, off-origin endpoint
and redirect rejection, cancellation/socket/listener cleanup,
host/root/legacy namespace isolation, bounded declared/chunked bodies
and exact-limit controls, redaction with positive log capture, malformed
expiry, legacy endpoint/redirect controls, and real CLI cached-auth
aliases.

Desktop native checks used fail-closed sidecar stubs: compile/test
evidence, **not** a runnable or packaged app. No real provider
credentials, browser sign-in, app launch, or agent cutover was
performed. Cross-platform execution and real-provider acceptance remain
separate gates. No merge or downstream adoption is requested by this PR.

---------

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Apple Silicon simulator builds fail because MLImage and MLKit contain
device-labelled ARM64 objects.

Enable the Flutter ML Kit package's upstream compatibility helper, which
restores device labels for iPhone builds. This preserves the MLKit-based
functionality (avatar background removal) and complements the
notification-extension linker isolation in block#7187.

Adds a complete iOS simulator build to CI to catch this build
regression.

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
## Summary
- apply the refreshed card layout across desktop onboarding
- update identity backup, recovery, and key presentation flows
- clarify AI connection choices and default model settings
- simplify the backup ceremony from creation through optional
verification
- bring the harness and provider setup flow forward with validation,
preserved state, and consistent navigation
- fix action alignment and stray card scrolling in the refreshed layout

## Validation
- pre-push desktop lint, typecheck, frontend tests, and native tests
passed
- focused onboarding Playwright coverage passed
- manually reviewed the refreshed onboarding and backup flow in the
native app
- just ci passed all sections except one unchanged process-cleanup
timing test; its exact rerun passed

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: Clay Delk <clay.delk@gmail.com>
## Summary

Document how agents should read Buzz’s semantic turn envelope. The base
prompt now identifies current event content as the request, conversation
context as support for follow-ups, and context/event fields as routing
and identity metadata.

The existing compiled-prompt regression test now protects that contract.
The lockfile also updates rustls to 0.23.45 to clear RUSTSEC-2026-0285
from the security gate.
…k#4665)

### What changed?

Buzz mobile checks the app-store age signal at launch and hard-blocks
the app behind a full-screen 18+ notice when the store says the
signed-in person is under 18.

No age signal (e.g. declined permission, indeterminate value,
unsupported OS versions) results in no block.

The age value is never persisted. It is read, used to compute one
boolean, and discarded. Nothing is written to disk, and neither the age
value nor the range is logged or sent to analytics.

Platform notes:
- **New dependency `com.google.android.play:age-signals:0.0.4`.** This
is the only way to read the Play signal. Its AAR declares `minSdkVersion
23`, below the app's 24, so it forces **no minSdk bump**, and it
self-declares its own consent activity, so **no AndroidManifest change**
is needed.
- **iOS entitlement and linking.** `DeclaredAgeRange` autolinks from the
import. `Runner.entitlements` now declares
`com.apple.developer.declared-age-range`, and the call remains behind
`#available(iOS 26.0, *)`.

### Why?

App stores now expose a declared-age range, and Buzz's Terms require
users to be 18 or older. This wires the store signal to that rule with
the smallest change that is defensible.

Absent signals, declined or undeterminable results, and unsupported OS
versions allow the app through. A transient native request failure does
not become evidence that access is allowed: the app remains gated until
a retry produces a result. Only an affirmative under-18 signal produces
the permanent restriction screen.

### How is it tested?

Added tests:

-
[`age_signal_provider_test`](https://github.com/block/buzz/tree/main/mobile/test/features/age_gate)
covers the 17/18 boundary, open-ended ranges, no-signal, transient
recovery, bounded retry exhaustion, malformed payloads, and request-once
behavior
-
[`age_gate_app_test`](https://github.com/block/buzz/tree/main/mobile/test/features/age_gate)
proves authenticated content remains unmounted while the signal is
pending or retryable, and verifies the retry path
-
[`age_restriction_page_test`](https://github.com/block/buzz/tree/main/mobile/test/features/age_gate)
asserts the block screen offers no bypass affordance
-
[`community_provider_test`](https://github.com/block/buzz/tree/main/mobile/test/shared/community)
verifies age restriction clears push state, persists inactive leases,
and retries a failed tombstone
-
[`AgeSignalPayloadTest`](https://github.com/block/buzz/tree/main/mobile/android/app/src/test/kotlin/xyz/block/buzz/mobile)
pins the Android success payload to exactly `{status, ageUpper}` and
verifies failures return the distinct retryable platform error

### Deployment note

Enable the Declared Age Range capability and regenerate signing profiles
carrying the entitlement. This relops/App Store Connect task is not
performed by this PR.

*🤖 This PR was authored [with an
agent](codex://threads/019e5128-536b-73b3-8348-88651123f6da).*

| Age restriction screen |
| --- |
| <img
src="https://github.com/user-attachments/assets/5b0f48b1-df9b-4a60-9800-80b33f128535"
alt="Age restriction screen" width="320"> |

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: npub12wpjffj7q5qjsky5jvk4ldwlxmse5xll3d8gytk4wqd0c5y7jvwspg37n6 <538324a65e0501285894932d5fb5df36e19a1bff8b4e822ed5701afc509e931d@buzz.block.builderlab.xyz>
Co-authored-by: npub1tquskdu6yc4h8l7xxtceculxw600grekeq0xg2ukqfrwl7vrzg3quz3gmp <58390b379a262b73ffc632f19c73e6769ef40f36c81e642b960246eff9831222@buzz.block.builderlab.xyz>
Co-authored-by: Codex <noreply@openai.com>
## Summary

Buzz can repeat a thread reply in later prompts after the provider
already received that event as context. The old fix treated every
message signed by the agent key as retained by the current provider
session. That could hide an unseen heartbeat reply because independent
sessions share the same signing key.

This PR now removes only exact event IDs already delivered to the live
ACP session. It uses bounded overfetch so removed events do not shrink
the new-context window, and it preserves unseen same-key replies from
other sessions.

The context header reports `truncated=true` whenever session history was
omitted. The harness calls `/count` only when the relay query finds a
sentinel beyond its fetch window.

This deliberately does not parse event IDs from shell output. A reply
that the agent just published may appear once in the next context delta;
after that event reaches the provider as context, later prompts omit it.

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
## Summary
- restore neutral identity guidance icons and reveal-first private-key
copying
- keep runtime availability sections contiguous and restore primary
onboarding colors
- route API-key setup directly to Buzz provider configuration, including
slow discovery and signed-out states

## Testing
- `pnpm check`
- `pnpm test` (6,501 passed)
- focused Playwright onboarding coverage (API routing 3/3; visual flow
1/1)

Signed-off-by: kenny lopez <klopez4212@gmail.com>
When a channel screen updates, Buzz Mobile can parse and format a
message again even when its text has not changed. This repeated work
runs on the same thread that handles taps and updates the screen.

The current Markdown library, `gpt_markdown` 1.2.1, checks whether the
objects used to render mentions, emoji, and channel links have changed.
Buzz creates new objects on every message rebuild, so the library parses
the message again. This change reuses those objects while their inputs
stay the same. Changes to labels, mention targets, emoji, media details,
or available actions still update the message. Taps continue to use the
latest action handlers.

In a synthetic test with the production message widget, ten unchanged
rebuilds caused 30 parser calls before this change and zero after it.
The first render still requires parsing. This test measures repeated
parsing, not overall screen speed.

Validation:

- All 91 focused message tests and 2,127 mobile tests passed. The new
regression test fails with the original code. Tests also cover changed
message data and current tap actions.
- Static checks across the repository, desktop and Tauri tests, and
desktop and web builds passed. The full local test run hit an existing
Rust ACP keepalive timing failure. Its exact retry passed, and all
checks skipped after that failure were run separately and passed.

Signed-off-by: Tom Brow <tomb@block.xyz>
When new messages arrive in a mobile channel, the app updates the list
of loaded messages on the UI thread. It currently sorts that list twice.
The second sort is needed only when the app has retained messages opened
through a link to a specific message.

This change uses the first sorted list when there are no retained
messages to merge. It reduces work during message bursts and keeps the
existing merge and ordering behavior for message links.

A controlled debug test with 2,000 loaded messages and 1,000 incoming
messages reduced processing time from 446 ms to 266 ms. This measures
the message update code, not screen rendering or release-device
performance. All 26 focused tests pass, including a regression test that
fails if the extra pass returns. Tests also cover message order and
retained messages.

Repository checks and downstream test/build suites passed, apart from
unrelated Rust timing failures in the full local run; each passed an
isolated retry. GitHub CI passed after retrying an unrelated desktop
attachment test failure.

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
The mobile app loads user profiles to show names, avatars, and agent
ownership. Some profiles include a signature that proves who owns the
agent. Checking these signatures for a batch of profiles can block
interaction because the checks run on the same thread that draws the
screen and handles input.

This change moves profile batch parsing and signature checks to a
background worker. It processes one batch at a time and combines queued
profile requests. It keeps the same signature checks, preserves newer
profiles that arrive while a batch runs, and discards results after a
community change. Individual live profile updates still use synchronous
verification.

Tests cover newer live updates, community changes, overlapping requests,
stale malformed events, and UI timer responsiveness through the
production parser. The responsiveness test fails if parsing is moved
back to the UI isolate. A regression also exercises a confirmed profile
save while an older batch is paused, including preservation of verified
ownership. All 38 focused tests, all 2,132 mobile tests, and the
analyzer pass.

With 500 valid owner signatures, an AOT test reduced the main-isolate
timer delay from about 3.4 seconds to less than a millisecond. Total
verification time stayed similar. This measures verification work, not
overall screen speed.

GitHub CI passes. The full local test run failed on two timing-sensitive
ACP tests in unchanged Rust code; both passed isolated retries. All
other local checks passed, including the downstream tests and builds run
after that failure.

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
Make the push gateway origin configurable across the relay, gateway,
mobile client, and deployment chart.

This is a fresh deployment. The gateway has only run on personal
development infrastructure, and push has no existing enabled users.
Legacy migration, configured-to-unconfigured mobile transitions, and
rolling upgrades from pre-launch gateway binaries are not supported.

Populated pre-launch databases are rejected with an informative error
before migrations run; their data is untouched. Mobile builds may omit
the gateway URL, leaving push unavailable. Once push is enabled,
subsequent builds must retain that configuration.

### Validation

- All applicable CI checks pass at
`5f546cfaf403f0386f146d213adfb4392f4ec29c`, including Rust,
mobile/Swift, desktop/integration, security, image builds, and Helm
checks. An unrelated agent cancellation test passed on retry.
- PostgreSQL CI passed 384 tests, including the production-entry-point
regression for refusing populated pre-launch databases before
migrations, fresh initialization, and subsequent initialized
deployments.
- Focused local validation passed all 10 gateway PostgreSQL tests under
the CI discovery filter and all 3 unconfigured-mobile tests.
Repository-wide PostgreSQL discovery validation and the complete
pre-push hooks passed.
- Physical-device APNs/App Attest behavior and deployment to a live
cluster were not verified in this work.

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Codex <noreply@openai.com>
)

On iOS, Buzz stores verified profile and channel information for the
notification extension. The extension uses this cache to show sender and
channel names. Loading profiles or channels also updates the cache.

Cache updates currently check event signatures on the UI thread, even
when the caller does not wait for the update. This can delay taps and
screen updates. This change moves those checks to a background worker.
Signature checks, event selection, community boundaries, and the order
of native writes are preserved.

The worker accepts up to eight batches. When it is busy, later profile
requests stay coalesced before fetching; profiles already loaded remain
available immediately. Overlapping channel updates trigger a fresh
joined-channel cache snapshot after the current export finishes, without
delaying or restarting the channel screen. Queue saturation gets up to
five retries per operation. Pending updates get their own recovery
attempt even if the preceding export fails. Recovery fetches
joined-channel data once and retries cache admission without repeating
relay reads. It does not fetch the open-channel directory. Verified
payloads are split into native-sized writes (256 profiles or 512 paired
channels), keeping the same export ordering. Native profile/channel
write failures retry the same verified chunk while retaining the
export's queue position. All chunks share five retries with 7.75 seconds
total backoff; other native errors fail immediately. Terminal failures
are recorded, and later successful writes do not hide them. Captured
batches keep their original community. Pending channel refetches are
retired on a community switch and refreshed when the user returns. The
cache remains best effort; prolonged failures can still prevent
delivery.

Tests through the production APIs reduced UI delay from 27–31 ms to
below 0.3 ms for four profiles, and from 59–60 ms to below 0.3 ms for
four channel and membership pairs. The native payloads were identical.
This does not measure overall screen speed.

Validation: 2,225 mobile tests passed (one skipped), along with 18
focused export tests, 12 recovery tests, 39 native Swift tests, 35
focused profile tests, and static analysis. Production regressions cover
13-entity bursts, invalid newer events, community rebuilds, reentrant
refreshes, and terminal failures. Regression tests fail when producer
recovery controls, terminal-failure draining, or member-only recovery
scope are removed.

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
## Summary

Allow a naturally expired push lease to be replaced by a newer lease for
the same author and installation.

## Failure mode

Expiry cleanup marked the old lease inactive but left active-only fields
populated. The push_leases_check constraint requires those fields to be
NULL when a lease is inactive. When the client later registered a
replacement lease, the cleanup ran before the replacement and violated
the constraint with SQLSTATE 23514. The transaction rolled back, so the
replacement failed instead of taking over the expired lease.

## Fix

Clear all active-only fields as part of natural-expiry cleanup,
preserving the existing constraint and replacement flow. No schema
change is required.

## Testing

- Passed the focused Postgres regression test: cargo test -p buzz-db
replacing_naturally_expired_lease_replaces_old_state -- --ignored
- Passed scripts/test-postgres-test-discovery.sh
- Ran just ci: formatting, lint, security, file-size, desktop, web,
mobile, and 12 unit-test lanes passed. The overall run was red only
because existing timing-sensitive buzz-acp tests failed.
- The pre-push test-unit hook reproduced the same unrelated buzz-acp
failures, so the already-run verification was documented and the branch
was published with that hook bypassed.

## Related issue

No matching open issue or pull request was found.

## Scope

One file changed: crates/buzz-db/src/store/push.rs. The test uses the
production accept_lease_event path and identifies the replacement by its
cryptographic source event ID and generation.

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
## Summary
This is a behavior-preserving refactor that gives the desktop relay HTTP
bridge one helper for authenticated request construction. It moves the
repeated `Authorization`, JSON content type, optional `x-auth-tag`,
body, and timeout setup into `build_authenticated_relay_request`.

The helper uses the final URL, auth header, and body bytes passed by the
caller. It does not sign, reserialize, normalize, send, parse, classify
errors, choose a client, or handle rate limits.

Excluded paths: media, WebSocket, Git, agents, mobile, and NIP-FI. The
query send helper only routes through the new request builder so the
timeout and `x-auth-tag` behavior are covered by the same seam.

### Related issue
None found. This prepares for the enterprise identity follow-up to be
smaller than block#7663.

### Testing
- `cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check`
passed at `356676a2f70f6bdf80cfdcb9084f1f7548359ecb`.
- `cargo test --manifest-path desktop/src-tauri/Cargo.toml
relay::tests::authenticated -- --nocapture` passed at
`356676a2f70f6bdf80cfdcb9084f1f7548359ecb`.
- `just desktop-tauri-check` passed at
`356676a2f70f6bdf80cfdcb9084f1f7548359ecb`.
- `just desktop-tauri-test` passed at
`356676a2f70f6bdf80cfdcb9084f1f7548359ecb`.
- `just desktop-tauri-clippy` passed at
`356676a2f70f6bdf80cfdcb9084f1f7548359ecb`.

Generated with Codex

Signed-off-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
Co-authored-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
## What

Name the relay's four Postgres pool roles—writer, reader, audit, and
search—and export one fixed-cardinality utilization metric contract for
all of them. Existing writer and reader gauges remain unchanged.

## Why

Audit and search already use separate pools, but they are missing from
pool pressure telemetry. Operators cannot see all process-level
connection demand before setting a deployment-wide connection budget.

## How

A closed `DbPoolRole` vocabulary now labels
`buzz_db_pool_connections{pool_role,state}` and
`buzz_db_pool_configured{pool_role}`. The relay retains cheap pool
clones for statistics only; ownership, capacities, timeouts, query
routing, and failure behavior do not change. The docs also replace the
stale async search-index description with the generated-column behavior
used today.

This simplifies four ad hoc observability states into one bounded model
without adding a pool manager or changing service boundaries.

## Risk

Low to moderate. This changes relay metrics and pool construction
plumbing, but not SQL execution or routing. Legacy metric names remain
available for current dashboards.

## Testing

- Push gate at `3f5468a0463bdfc5879bcdd3878fa06b42ca84c2`: all 14 Rust
test lanes passed; desktop Tauri checks passed.
- Blox: `cargo test --workspace --all-targets` with repository-declared
Postgres services.
- Blox: `cargo clippy --workspace --all-targets -- -D warnings`.
- Blox: `cargo fmt --all -- --check`.

## Bigger picture

Aggregate deployment budget enforcement remains deferred. This PR
exposes the per-role facts that a later deployment-policy change can
consume.

Generated with Claude Code

---------

Signed-off-by: tornquist <tornquist@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Summary

Argo rollout recovery needs to distinguish an open WebSocket from a
connection that completed NIP-42 authentication and is usable. The relay
currently exposes total WebSocket connections, but it cannot answer
whether authenticated clients recovered after a pod drain or why
authentication failed.

This change adds a bounded recovery contract:

- `buzz_auth_attempts_total{method="nip42"}`
- `buzz_auth_outcomes_total{method="nip42",outcome}`
- `buzz_auth_duration_seconds{method="nip42",outcome}`
- `buzz_ws_authenticated_connections_active`
- `buzz_auth_post_terminal_frames_total{state}`

`buzz_auth_attempts_total` now has one consistent recovery-oriented
unit: a challenge lifecycle successfully queued to the connection
writer. This intentionally replaces the historical unit of AUTH frames
that reached the pending handler. AUTH frames received after a lifecycle
is already authenticated or failed are protocol noise; they use the
separate bounded post-terminal counter and cannot inflate rollout-gating
attempts or outcomes.

Each issued challenge reaches exactly one terminal outcome.
Authentication transitions and active-gauge changes share one short
synchronous state lock, cancellation can claim a pending database-backed
AUTH before a late handler result, and a drop guard reconciles aborted
or panicked connection futures. Accounting is terminalized before writer
joins, while terminal socket delivery has a one-second best-effort bound
so a stalled sink cannot retain the authenticated gauge or connection
permit indefinitely.

Dependency failures are distinct from policy verdicts: allowlist and
relay-membership lookup errors now emit `allowlist_check_error` and
`relay_membership_check_error`, never `allowlist_denied` or
`not_relay_member`. The fail-closed allow/deny policy is unchanged. All
rollout-facing labels come from fixed enums; identities, challenges,
URLs, and raw error strings are never exported.

All fixed counter and histogram label sets, including zero histogram
buckets, counts, and sums, are present on the first real exporter
scrape. This is the first implementation slice of the
rollout-reliability plan. A later PR will consume these metrics from
opt-in Argo Rollout analysis; merging this PR alone does not change
deployment behavior.

### Related issue

None found.

### Testing

Validated at final head `f9992cac835284c25ee0f99e17ddba0b932d7c69`,
which contains current `origin/main`:

- `cargo fmt --all -- --check`
- `cargo clippy -p buzz-relay --all-targets -- -D warnings`
- compiled every `buzz-relay` test target
- release builds for `buzz-relay`, `buzz`, `buzz-admin`, and
`buzz-test-cli`
- 16/16 connection lifecycle/writer/production-dispatch tests
- 7/7 AUTH handler tests
- bounded metric-contract exporter test
- 13/13 relay main-target tests (1 PostgreSQL-only test ignored)
- 9/9 real boot-lifecycle tests, including a production install and
first Prometheus scrape

Mutation checks proved that the production regressions fail when any of
these are removed or reintroduced:

- challenge attempt start in `handle_active_connection`
- authentication series initialization in the real metric installer
- separation of post-terminal AUTH floods from authoritative attempts

The exact-head release binaries were also exercised against the isolated
review database:

1. Started the release relay and verified health/readiness.
2. Created a channel with the regular CLI.
3. Held one authenticated WebSocket subscription open and authenticated
a second WebSocket publisher.
4. Published a message and read it back through the regular CLI.
5. Observed `attempt_delta=2`, `success_delta=2`,
`active_while_subscribed=1`, and `active_after_disconnect=0`.
6. Sent SIGTERM and waited for graceful relay shutdown.

### Local caveat

The full relay library target consistently reached 1,049 passes with 89
intentionally ignored tests, but the untouched
`api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo`
intermittently returned HTTP 504 instead of 200. One isolated rerun
passed; later isolated and full reruns reproduced the 504. No mesh files
are changed by this PR, and all changed-path, main-target,
boot-lifecycle, lint, build, mutation, and live-local checks above
passed at the final head.

Generated with Codex

---------

Signed-off-by: Ravneet Arora <rarora@squareup.com>
Signed-off-by: Tom Brow <tomb@block.xyz>
Brings the fork current with upstream: ACP agent sessions, Buzz Pi agents,
mesh-llm upgrades, mobile push gateway, agent trading cards, multi-repo
projects, and the refreshed desktop onboarding.

Conflict resolutions:
- Huddle event kinds: upstream took 48104 for KIND_HUDDLE_LIVENESS, so the
  fork's KIND_HUDDLE_TRANSCRIPT / KIND_HUDDLE_SUMMARY move to 48107 / 48108
  (relay metric-label allowlist updated to match).
- Settings: upstream's consolidated AgentsSettingsPanel replaces the fork's
  hand-rolled agents panel; the fork's Integrations and Local Setup panels
  are kept.
- Channel header: meeting-notes button coexists with upstream's terminal
  button and endActions slot.
- build.rs / commands mod: both sides' env vars and modules kept.

Signed-off-by: Eli <elijamesau@gmail.com>
@elijamesku elijamesku self-assigned this Sep 16, 2026
@elijamesku
elijamesku merged commit 7f93f28 into eli/github-connector Sep 16, 2026
34 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.