Skip to content

Sync upstream Buzz 014562c063ea - #14

Open
dcm-buzz-upstream-sync[bot] wants to merge 12 commits into
dcm-productionfrom
agent/sync-upstream-014562c063ea
Open

Sync upstream Buzz 014562c063ea#14
dcm-buzz-upstream-sync[bot] wants to merge 12 commits into
dcm-productionfrom
agent/sync-upstream-014562c063ea

Conversation

@dcm-buzz-upstream-sync

Copy link
Copy Markdown

Automated upstream sync

This PR integrates the newly mirrored block/buzz:main into dcm-production.

This PR never merges automatically. Review the complete diff, migrations, configuration changes, and all required checks before merging. Merge using Create a merge commit so upstream ancestry is preserved.

Recovery tag: dcm-before-upstream-20260805-184846-014562c063ea
Upstream commit: 014562c063eae6ab1b7c6e3d20f2be3024c5f3a8

Upstream commits (first 20)\n- 014562c fix(desktop): allow shared agent mentions (block#4913)

wpfleger96 and others added 12 commits August 5, 2026 09:51
…ds (block#4802)

User-facing error for missing ACP harness commands has been pointing
released-build users to run `cargo build --release --workspace` and read
TESTING.md — both dead ends for anyone not building from source.

Updated message acknowledges that antivirus software can quarantine
bundled binaries and provides practical remediation steps. Preserves
pointer to TESTING.md for source builds.

Fixes issue context from block#4491.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@buzz.block.builderlab.xyz>
### What changed?

Serializes channel-section relay synchronization so a late relay
`CLOSED` cannot overlap an in-flight retry and install duplicate
subscriptions. Pending subscription results are invalidated and
immediately closed when the manager is disposed or superseded.

### Why?

The startup retry added in block#3004 could race with a late `CLOSED` or
manager disposal, leaking an untracked live subscription. This keeps
retry recovery single-flight and makes the lifecycle boundary explicit.

### How is it tested?

Build and run.

Added tests:

-
[`ChannelSectionsManager`](https://github.com/block/buzz/tree/main/mobile/test/features/channels/channel_sections/channel_sections_manager_test.dart)
interleaving coverage for in-flight retry serialization and disposal
during subscription setup

*🤖 This PR was authored with a Buzz agent.*

Signed-off-by: npub15w828kxsxu2684ynste0uah2jwkgatd99flt7ds4523hzm8ju6cshdr8hh <a38ea3d8d03715a3d49382f2fe76ea93ac8eada52a7ebf3615a2a3716cf2e6b1@buzz.block.builderlab.xyz>
Co-authored-by: npub15w828kxsxu2684ynste0uah2jwkgatd99flt7ds4523hzm8ju6cshdr8hh <a38ea3d8d03715a3d49382f2fe76ea93ac8eada52a7ebf3615a2a3716cf2e6b1@buzz.block.builderlab.xyz>
## Summary

- reserve kind `30179` for owner-private managed-agent aggregates
- define the fail-closed owner-self NIP-44 v2 envelope and versioned
payload codec
- bind runnable identity/configuration to complete signed
`30175`/`30177` recovery projections
- validate NIP-OA owner→agent attestations and reject self-attestation
- document NIP-PMA authority, migration prerequisites, privacy, and
deployment order
- keep generic relay ingest closed until private storage and atomic
aggregate CAS exist

## Safety boundary

This is the inert protocol/codec slice only. It does not publish
secrets, change agent authority, migrate local records, or enable kind
`30179` ingestion. The relay regression test proves generic EVENT ingest
still rejects the kind.

The finalized migration plan adds later prerequisites for relay-private
storage/CAS, runtime lease/fencing, Desktop cutover, and harness
authentication. Those belong in staged follow-up PRs rather than
expanding this inert foundation.

## Validation

At commit `67f0ea4ebb8d3ccba3a3eb9374e89a7178913f74`:

- `cargo test -p buzz-core` — 246 unit + 2 doc tests passed
- `cargo test -p buzz-relay
private_managed_agent_kind_remains_rejected_until_atomic_ingest_exists`
— passed
- push hooks: Rust tests and desktop checks passed (`2145` desktop tests
passed, `14` ignored)
- `cargo fmt --all -- --check`
- `git diff --check`

## Review

Princess Donut cleared security/data integrity with no remaining
high/medium findings. Mongo cleared migration compatibility and wire
grammar. The later runtime lease/fencing protocol was also adversarially
cleared as a plan; implementation slices still require independent
evidence before activation.

Deterministic plaintext/signed-projection/auth-tag interoperability
vectors remain a valuable follow-up, not an S0 merge gate; random NIP-44
ciphertext is intentionally not snapshotted.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
… the turn (block#4896)

## Problem

`buzz-dev-mcp` advertises `view_image` to every agent regardless of
whether the session's model accepts images. When a text-only model (e.g.
DeepSeek V4 Flash) takes the bait, the image lands in session history
and every subsequent LLM request 404s with `No endpoints found that
support image input`. The error was classified as `LlmModelNotFound` and
propagated fatally out of the turn loop — history stays poisoned,
buzz-acp retries the batch with exponential backoff, and the session
burns its entire clock doing no work. In a recent trial run, **all 57
trials that called `view_image` on a text-only model died this way; none
recovered.**

## Fix

Capability-gating the advertised tool isn't reliable — there is no
image-capability metadata at the agent layer across providers. Instead,
recover at the turn loop:

- **Typed error**: new `AgentError::UnsupportedImageInput`, classified
narrowly on the exact provider phrase `No endpoints found that support
image input` on both the generic 404 path and OpenRouter's 404 path.
Unknown-model 404s and OpenRouter parameter-routing 404s keep their
existing classifications. No deterministic retry.
- **In-turn recovery**: on this error, `RunCtx::run` strips every image
block from history — keeping the tool result (and therefore
tool-call/result pairing) intact — marks the result `is_error`, appends
actionable model-facing guidance ("The current model does not support
image input. The image was removed from conversation history so this
turn can continue. Use a text-based inspection tool…"), and continues
the same turn. Base64 never replays again.
- **Loop guard**: recovery only fires when at least one image was
removed; if the provider says "image" and history has none, the error
propagates as before.

## Tests

- Unit: phrase classification (typed, not retried; unknown-model 404
unaffected), idempotent image-to-error history mutation preserving call
IDs and text.
- End-to-end (`fake_llm.rs` + `fake_mcp.rs`): tool call → MCP image
result → 404 unsupported-image → same-turn recovery. Captured requests
prove round 2 carried the image, round 3 replays no image, carries the
guidance text, preserves pairing, and ends `end_turn`.
- Loop guard: typed unsupported-image error with **no** image in history
fails after exactly one provider request instead of spinning —
mutation-testing showed deleting the `removed == 0` guard survived the
suite, and `max_rounds` defaults to unlimited in production, so this
branch needed direct coverage.

Verified at `a210305019b33d5f56677b4c82bab79e4ac52d24`: `cargo test -p
buzz-agent` (full package, 381 unit + all integration suites) green;
`clippy --all-targets -D warnings` green; `fmt --check` green; pre-push
hooks (rust-tests, desktop-tauri-checks, branch-skew) green.

**Scope of the classification guarantee**: the classifier runs in the
shared `post()` (which Anthropic and OpenAI paths route through) and in
`openrouter_post()` — i.e., every 404 path in `llm.rs`. It only runs on
404 responses; providers that reject images with a different status
(e.g. a 400) are out of scope for this PR — see the review-comment
discussion for why broadening the phrase list alone would not cover
them.

Authored by Wren, loop-guard test by Sami, reviewed by Eva.

---------

Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
This change rechecks the durable community ban in the shared Git HTTP
authentication path for advertise, fetch, and push requests. A banned
member is denied even if repository-channel membership still exists, and
restriction lookup errors fail closed.

The additional database lookup happens on every Git HTTP request so
access revocation does not depend on stale session state.

The check also cascades to the NIP-OA owner. Git accepts NIP-OA
attestations on the NIP-98 token, so an agent key can act for its owner
— without the cascade, a banned human would keep clone and push access
through any agent key. This mirrors the NIP-42 gate in `handlers::auth`:
either principal's ban denies the request.

The check runs inside the `GitAuth` extractor, so all three Git routes
inherit it.

## Testing

- `git diff --check origin/main...codex/security-ban-revokes-git`
- Rebased onto `origin/main` at `5c98932`
- `cargo test -p buzz-relay --lib sec005_read_gate_tests`: 8 passed, 7
ignored (Postgres)
- `cargo clippy -p buzz-relay --all-targets -- -D warnings` and `cargo
fmt --check`: clean

Pure tests cover the decision table (agent ban, inherited owner ban, no
attestation). Postgres-gated tests cover the wiring: the real ban row, a
live `compute_auth_tag` attestation, and the 503 fail-closed path.

**Not yet verified:** the three Postgres-gated tests compile and skip
but have not been run — no local Postgres, and CI does not run
`--ignored`. They need `cargo test -p buzz-relay --lib
sec005_read_gate_tests -- --ignored` against a migrated dev database.

Originating Buzz thread:
`buzz://message?channel=3928fe05-df61-4b5d-b9c7-d623b9b10ea1&id=3c6c02312f763fbe0d2bfc33a6c1a362f91d0354f3d18b039cf7a0558c1439d1`

---------

Signed-off-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Eli Foster <efoster@squareup.com>
Co-authored-by: Eli Foster <efoster@squareup.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This change derives `trigger_author` exclusively from the signed event
pubkey. Actor tags remain available as event data but cannot override
the identity used by author-sensitive workflow conditions.

This removes the impersonation path without changing workflow
definitions or requiring stored-data migration.

## Testing

- `bin/cargo test -p buzz-workflow` at `78819df`: 154 passed, 2
Postgres-dependent tests ignored
- `git diff --check
origin/main...codex/security-workflow-trigger-author`

Originating Buzz thread:
`buzz://message?channel=3928fe05-df61-4b5d-b9c7-d623b9b10ea1&id=3c6c02312f763fbe0d2bfc33a6c1a362f91d0354f3d18b039cf7a0558c1439d1`

Signed-off-by: Jordan Mecom <jm@squareup.com>
This change removes the ACP permission-bypass mode, defaults managed
sessions to `dontAsk`, and answers permission requests with
`reject_once` or cancellation in both ACP read loops.

Unattended operations that require interactive approval now fail closed
instead of being silently authorized. Explicit non-interactive modes
that do not bypass a permission request remain available.

Both layers have to change together: `apply_permission_mode` treats an
unsupported mode and a failed `set_config_option` as non-fatal by
design, so a request can still reach the harness even in a
non-interactive mode. Removing `bypassPermissions` from the enum rather
than only changing the default means the mode cannot be restored by
configuration alone.

The scope of the guarantee is that `buzz-acp` never grants approval. An
agent that pre-authorizes tools in its own configuration (for example
Claude Code's `settings.json`) still runs them without asking, which is
outside this harness.

## Testing

- `env -u BUZZ_ACP_LAZY_POOL bin/cargo test -p buzz-acp` at `16fff4d`:
671 library tests and 9 integration tests passed
- `cargo clippy -p buzz-acp --all-targets -- -D warnings` and `cargo fmt
-p buzz-acp -- --check`: clean
- `git diff --check
origin/main...codex/security-acp-shell-auto-approval`

The permission tests previously re-implemented the `reject_once` lookup
in the test body instead of calling the code under test, so they would
have passed unchanged if the harness went back to selecting
`allow_once`. They could not call it directly, because
`handle_permission_request` is a method on `AcpClient`, which owns a
live `Child` and its stdio pipes. The choice is now a free function,
`permission_denial_response`, and the tests exercise it: `reject_once`
preferred over offered allow options, the cancelled fallback when no
`reject_once` exists, an empty option list, and a `reject_once` missing
its `optionId`. The cancelled fallback had no coverage before despite
being the fail-closed backstop.

## Operator notes

- `BUZZ_ACP_PERMISSION_MODE=bypassPermissions` no longer parses, so a
process configured with it fails to start rather than silently
downgrading.
- Desktop managed agents do not set a permission mode, so they inherit
`dontAsk`. The desktop has no permission prompt, so operations needing
approval now fail with no in-app way to approve them.

Originating Buzz thread:
`buzz://message?channel=3928fe05-df61-4b5d-b9c7-d623b9b10ea1&id=3c6c02312f763fbe0d2bfc33a6c1a362f91d0354f3d18b039cf7a0558c1439d1`

---------

Signed-off-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Eli Foster <efoster@squareup.com>
Co-authored-by: Eli Foster <efoster@squareup.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This change requires an active owner or administrator for third-party
additions to private channels. The relay validator and transactional
database authority enforce the same rule, including removed-member
reactivation and role-change paths.

Idempotent self-target behavior remains available, while ordinary
members can no longer extend private-channel access to another identity.

## Testing

- `git diff --check
origin/main...codex/security-private-channel-invite-authority`
- Rebased onto `origin/main` at `5c98932`
- Full CI pending

Originating Buzz thread:
`buzz://message?channel=3928fe05-df61-4b5d-b9c7-d623b9b10ea1&id=3c6c02312f763fbe0d2bfc33a6c1a362f91d0354f3d18b039cf7a0558c1439d1`

---------

Signed-off-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Eli Foster <efoster@squareup.com>
Co-authored-by: Eli Foster <efoster@squareup.com>
## Summary

Redesign the permanent Desktop release flow so unrelated merges to
`main` cannot invalidate an already reviewed, green release candidate.

- Tag the immutable, API-confirmed release PR head instead of its later
squash commit.
- Treat the merged PR—including an authorized owner/admin bypass—as
publication authorization, while requiring trusted check evidence that
was complete at merge time.
- Make tag creation idempotent and collision-safe: an existing tag
succeeds only at the exact candidate SHA, and create races refetch
before accepting equality.
- Replace ancestry-based previous-release discovery with a validated
metadata ledger for side-history candidate tags.
- Compute the next release from the prior frozen base to the new frozen
base, excluding only the prior release squash SHA so unrelated commits
remain in the changelog.
- Preserve schema-1 production-tag migration and reject malformed
metadata or equal/decreasing versions.
- Update operator documentation for the normal squash-merge workflow.

This is the reusable release process for `0.5.6` onward, not the retired
one-shot `0.5.5` recovery path.

### Invariants covered

- Candidate creation → unrelated `main` merge → authorized squash merge
→ immutable candidate tag.
- Trusted producer IDs and merge-time completion timestamps; DCO's
bounded post-merge exception remains isolated.
- Missing/spoofed checks, tampered candidates, ambiguous PR
associations, conflicting tags, and equal/decreasing versions fail
closed.
- Same-SHA retries succeed; different-SHA collisions fail.
- Legacy schema-1 tag-on-main migration and schema-2 side-history
accounting both preserve the correct next-release changelog.

### Related issue

N/A — follows the Desktop release failures in block#4788 and block#4800 and the
recovery revert in block#4808.

### Testing

At clean commit `6a91fbed8147a48cf174997de0c3e4cb2fb26474`:

- `scripts/test-desktop-release-candidate.sh`
- `scripts/test-release-ref-contract.sh`

Both focused suites passed with HEAD unchanged. Princess Donut cleared
the security/provenance surface, including the hostile merge-time
timestamp cases. Mongo cleared the side-history ledger, migration,
version-order, documentation, and contract-test surface.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary

- Polish mobile Home, Activity, Search, and Settings navigation chrome.
- Add progressive Buzz gradients/frost, aligned theme colors, dividers,
typography, and section spacing.
- Refine Search and Settings motion, including automatic keyboard focus
on search activation.

<img width="630" height="1368"
alt="C78FA3CE-F2B3-45F2-B9F5-7EA7500778CC"
src="https://github.com/user-attachments/assets/5935514b-d894-4010-80dd-a938363fee93"
/>
<img width="630" height="1368"
alt="5C058A73-1879-476A-881C-531ACC256D84"
src="https://github.com/user-attachments/assets/5266c841-17ee-49e8-9841-b06d84f4195f"
/>
<img width="630" height="1368"
alt="3F50ADB7-9BDA-4A8D-A81E-20560C3B9EA6"
src="https://github.com/user-attachments/assets/f615f61e-9e96-4bce-b261-ae5ec54db872"
/>
<img width="630" height="1368"
alt="35ECE741-01F3-4B79-80C5-1DDD447121A7"
src="https://github.com/user-attachments/assets/b5145186-9884-44eb-8ebc-f3303831c0a4"
/>

## Validation


- `flutter analyze`
- Focused Home, Activity, Channels, Search, theme, and footer widget
tests
- Full pre-push checks, including mobile tests, desktop checks, and
Tauri checks
- On-device iPhone review during the visual polish pass

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: npub1glqcqfjxdens59scl477pmejh8lht4hqkhx0y4w38jxr6e6w6y2sm29y4e <47c18026466e670a1618fd7de0ef32b9ff75d6e0b5ccf255d13c8c3d674ed115@buzz.block.builderlab.xyz>
Signed-off-by: Code Reviewer <037593536284cf40e221c96c931e9877d4166d54f6bb84e5341a86d7fd5d05a4@buzz.block.builderlab.xyz>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Co-authored-by: npub1glqcqfjxdens59scl477pmejh8lht4hqkhx0y4w38jxr6e6w6y2sm29y4e <47c18026466e670a1618fd7de0ef32b9ff75d6e0b5ccf255d13c8c3d674ed115@buzz.block.builderlab.xyz>
Co-authored-by: Code Reviewer <037593536284cf40e221c96c931e9877d4166d54f6bb84e5341a86d7fd5d05a4@buzz.block.builderlab.xyz>
## Summary

- admit relay-discovered agents to autocomplete when their response
policy authorizes the viewer
- require authorization in the exact active stream/forum channel for
mentions, while keeping community-wide discovery for member invitation
- fail closed for relay-only agents in DMs and unresolved composer
contexts
- re-authorize cached autocomplete rows after policy/channel changes so
stale agent suggestions cannot leak back in
- preserve managed-agent behavior and explicitly reject stale
agent-marked channel members absent from both live directories

## Validation

- `pnpm --dir desktop test` — 4,288 passed
- `pnpm --dir desktop typecheck`
- `pnpm --dir desktop check`
- `pnpm --dir desktop build:e2e`
- focused Playwright mention matrix — 12 passed
- focused Playwright member-invitation matrix — 2 passed
- pre-push hooks after rebase to current `origin/main` — desktop check
and 4,288 tests passed
- independent correctness/privacy re-review cleared with no remaining
blocker

## Related competing PRs

This supersedes or overlaps block#2333, block#3056, block#4242, block#4137, block#2314, block#4058,
and block#2605. This version adds exact-channel authorization, fail-closed
DM/context handling, cached-row reauthorization, forum coverage,
outbound mention-tag coverage, explicit stale-member coverage, and
add-member discovery coverage.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
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.

6 participants