Skip to content

Sync upstream block/buzz main (42aeb1571) - #114

Merged
yjc801 merged 14 commits into
mainfrom
fork-sync/2026-09-01d
Sep 2, 2026
Merged

Sync upstream block/buzz main (42aeb1571)#114
yjc801 merged 14 commits into
mainfrom
fork-sync/2026-09-01d

Conversation

@yjc801

@yjc801 yjc801 commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Merges block/buzz main (42aeb1571) into fork main — the 8 upstream commits that landed while #111 was in review.

Upstream commits merged

Conflict resolved

Justfile, the test-unit recipe — the fork carries two extra stanzas (buzz-backend-sprites, buzz-waker) immediately above the buzz-agent step that upstream block#5545 rewrote (widened from -p buzz-agent --lib to the whole crate, so the new OAuth coordinator integration tests actually execute). Kept both fork stanzas, took upstream's widened buzz-agent step and its comment.

4794a5cec (surface-specific file-size ceilings: Desktop Rust 1500, Desktop frontend and Mobile 1200, Web unchanged at 1000) merged clean, including its AGENTS.md update — no fork-side adjustment needed, and the fork's existing extractions all still pass.

The xyz.block.buzz branding scan over all 111 touched files found only mobile/push-gateway bundle identifiers, which this fork does not rebrand.

Verification (local, on the merge commit)

  • cargo check --workspace --all-targets — clean
  • just test-unitnot meaningful locally: cargo-nextest is not installed here, so the recipe takes its scripts/run-tests.sh unit fallback, which does not cover buzz-agent's integration tests. CI's nextest path is the real gate.
  • just desktop-tauri-check — clean
  • just desktop-tauri-test — all suites ok
  • just fmt-check — clean
  • just file-size-check — clean (against the new ceilings)
  • bash scripts/test-desktop-instance-detection.sh — 8/8 cases pass (the fork's identifier carry from Sync upstream block/buzz main (e17a0d44c) #111 survives)
  • just mobile-check — no issues
  • just mobile-test — 2019 pass
  • desktop tsc --noEmit — clean
  • desktop pnpm test — 6018 pass, 0 fail
  • desktop pnpm check (biome + px-text + pubkey-truncation) — clean

Known flake surfaced (not introduced here)

CI's first Unit Tests run failed on buzz-agent::fake_llm::cancelled_turn_with_usage_emits_notification_before_response (stopReason came back Null, expected "cancelled"). A re-run passed, and 12 consecutive local runs passed.

This is upstream's test against upstream's code — git diff upstream/main HEAD -- crates/buzz-agent is empty, the fork carries no delta in that crate. It is newly reachable for us only because block#5545 widened the buzz-agent step from --lib to the whole crate. The test's comment asserts its gate rules out a race ("The gate guarantees stopReason: cancelled — not a race-driven error"), but the observed Null says otherwise under load. Worth reporting upstream rather than patching downstream.

🤖 Generated with Claude Code

wpfleger96 and others added 14 commits September 1, 2026 18:20
…budgets (block#7185)

Raise the `buzz-dev-mcp` shell timeout ceiling to 1,200,000 ms (20
minutes) while keeping the omitted-value default at 120,000 ms (2
minutes), and align the two outer timeout layers that bound every MCP
tool call.

## What changed

**`crates/buzz-dev-mcp`** — shell timeout cap raised to 1,200,000 ms;
tool and parameter descriptions updated to match.

**`crates/buzz-agent`** — `BUZZ_AGENT_TOOL_TIMEOUT_SECS` default raised
from 660 s to 1,260 s (20-min cap + 60 s cleanup headroom). The old 660
s default would have killed the MCP server at 11 min, before a 20-min
shell call could finish. README updated.

**`crates/buzz-acp`** — `DEFAULT_IDLE_TIMEOUT_SECS` raised from 900 s to
1,500 s and its doc comment updated (1,200 s max shell + 300 s breathing
room). The old value was documented as "600 s max shell + 300 s" — stale
arithmetic.

## Tests

- Existing boundary tests in `buzz-dev-mcp` (default, exact-cap,
over-cap, `u64::MAX`) all pass.
- `default_idle_timeout_is_1500_seconds` — pinned constant replaces old
900 s assertion.
- `default_tool_timeout_is_1260_seconds` — new pinned constant in
`buzz-agent`.
-
`budget_ordering_invariant_shell_cap_plus_headroom_fits_within_idle_timeout`
— new const assertion in `buzz-acp` that encodes the full three-layer
ordering: shell cap (1,200 s) ≤ agent tool timeout (1,260 s) < ACP idle
timeout (1,500 s) < max turn duration. A future edit that inverts any
tier fails to compile.

---------

Signed-off-by: Alia <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@buzz.block.builderlab.xyz>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Alia <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@buzz.block.builderlab.xyz>
Co-authored-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
Changes `CODEX_REASONING_EFFORT` from `max` to `high` in the
`security-review` job.

`max` increases both normal review latency and exposure to the upstream
PTY-shutdown hang
([openai/codex-action#169](openai/codex-action#169))
where Codex finishes writing its output file but holds stdio open. The
composite `uses:` action ignores the 30-minute step timeout and
continues running until the 40-minute job timeout fires; at that point
GitHub cancels the entire job and the `always()` salvage step never gets
to run. `high` retains a high reasoning setting while trading some depth
for speed, reducing typical completion time and shrinking the window
during which a hung process blocks the salvage path.

No other behavior changes. Action pin, CLI version, model, output
schema, prompt, and timeout values are unchanged.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…block#7187)

### What changed?

Clear inherited linker flags on the NotificationService target in Debug,
Release, and Profile. The extension continues to link BuzzPushKit
through its target framework phase, while Runner retains its CocoaPods
plugin flags.

Extend the macOS mobile CI lane to install Flutter dependencies and
build the complete unsigned iOS Release app. This exercises the
production Flutter, CocoaPods, Runner, BuzzPushKit, and
NotificationService build graph on every mobile change.

### Why?

The iOS 0.16 RC archive exposed that NotificationService inherits
Runner-only CocoaPods linker flags through the shared Flutter xcconfig.
That made the extension link Flutter plugins without the Flutter engine
and fail on unresolved Flutter symbols.

The previous CI coverage built only the standalone BuzzPushKit package,
so it could not detect an app or extension linker regression.

### How is it tested?

- A complete unsigned Release build of the Runner scheme succeeded with
Xcode and linked, embedded, and validated `NotificationService.appex`.
- The new GitHub Actions lane builds the full unsigned iOS Release app
with `flutter build ios --release --no-codesign --no-pub`.
- Pre-commit and pre-push hooks passed.

---------

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

- raise Desktop Rust's differential file-size ceiling from 1,000 to
1,500 lines
- raise Desktop frontend and Mobile ceilings from 1,000 to 1,200 lines
- keep Web at 1,000 lines and preserve the existing no-growth ratchet
above each ceiling

## Why

The flat 1,000-line limit is forcing mechanical trimming in Desktop and
Mobile even for small cohesive changes. Surface-specific ceilings
relieve that pressure without granting Web or every authored component a
blanket 2,000-line budget.

## Testing

- `just file-size-check`
- `cd desktop && pnpm exec biome check scripts/check-file-sizes.mjs`
- `node --check mobile/scripts/check-file-sizes.mjs`
- `git diff HEAD^ --check`

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
A few things to prepare for deploying the Buzz push gateway as
implemented in block#6269:
- Cut `buzz-push-gateway` chart `0.2.0` from the current config
(certificate auth, dogfood client)
- Datadog-compatible metrics
- Align the desired schema, metrics docs, and production ingress
guidance with the current dogfood deployment contract

## Links

- [BUZZ-17: Publish the MVP-compatible gateway
chart](https://linear.app/squareup/issue/BUZZ-17/publish-the-mvp-compatible-gateway-chart)
- [BUZZ-26: Add Datadog-compatible push-gateway metrics and correct
source
drift](https://linear.app/squareup/issue/BUZZ-26/add-datadog-compatible-push-gateway-metrics-and-correct-source-drift)

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Codex <noreply@openai.com>
Pinky is opening this PR on Wes's behalf.

## Summary

Carry forward the fix from block#7103 by **Taksh / @Chessing234**, with the
original author and DCO sign-off preserved in commit `99dd19191c`. A
separate Pinky-authored commit fixes and strengthens the regression
tests.

`recover_from_keyring` previously deleted an unreadable keyring identity
before checking for a valid leftover `identity.key`. A migrated
installation normally has a marker but no file, so that deletion could
destroy the only remaining key material.

- Attempt valid-file recovery before any explicit keyring deletion.
- If a migration marker exists but no valid file can be recovered, enter
`Lost` without deleting the unreadable keyring value.
- Retain the existing no-marker clear/generate policy.
- Correct the stale deletion expectation in
`corrupt_keyring_recovers_valid_file_without_rotating`, retaining its
identity and persistence checks.
- Add an explicit no-delete assertion to
`corrupt_keyring_with_valid_file_recovers_before_delete`.

Production recovery behavior matches the contributor's fix; follow-up
production-file edits only clarify comments and restore a doc comment.
The existing migration durability order remains **store → uncached
verification → marker → file removal**. Lost-state signing/startup gates
and explicit user re-import remain intact.

### Related issue

Fixes block#6218. Linked continuation/replacement of block#7103, not a competing
implementation. The original PR remains open for maintainer disposition.
Searched existing keyring PRs and identity/keyring issues; block#7103 is the
direct duplicate and source contribution.

### Testing

Validated head: `b6a5512ba85f9e76a039f69714ed04a98eabc710`, based on
`4365883151698cd30e31cf4091629543b61c2478`.

- **Focused baseline:** `cd desktop/src-tauri && cargo test --lib
app_state::` — 52 passed, 0 failed.
- **Mutation check:** in an isolated copy, restore the original
delete-before-file-probe ordering without changing the test file.
`corrupt_keyring_with_valid_file_recovers_before_delete` fails at the
new `store.deleted.borrow().is_empty()` assertion (0 passed, 1 failed;
expected exit 101). The candidate working tree was never mutated.
- **Actual pre-push hooks passed, without bypass:** `push-head-scope`,
`branch-skew`, `file-size-check`, and `desktop-tauri-checks`.
- `cargo clippy --manifest-path desktop/src-tauri/Cargo.toml --workspace
--all-targets -- -D warnings`
- `cd desktop/src-tauri && cargo test --workspace` — 3,156 passed, 0
failed, 20 ignored across test binaries.
- Pre-commit Tauri formatting and DCO hooks passed.
- Independent read-only review by Brain found no further defects in the
final range and verified the baseline/mutation artifacts and contributor
attribution. This is not a GitHub approval.

Local validation used the repository's sidecar stubs for compilation.
Full-repository `just ci`, a native-app recovery workflow, and
live-keyring fault injection were not run. GitHub CI and an actual
current-range Codex security review are still pending; local hooks do
not substitute for those results. No UI markup changed, so screenshots
are not applicable.

### Limits

This prevents destructive cleanup on the marker-backed recovery path; it
does not identify what originally made the keyring value unreadable or
guarantee recovery of already-corrupt material. Markerless last-copy
preservation remains a pre-existing limitation outside this change. Only
the two app-state Rust files change; no new dependency, workflow, or
secret-export surface is introduced.

---------

Signed-off-by: Taksh <takshkothari09@gmail.com>
Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Co-authored-by: Taksh <takshkothari09@gmail.com>
Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
…lock#5545)

## What

Consolidates all Databricks OAuth acquisition behind one coordinator on
`PkceOAuthTokenSource`. Every entry point — the four `TokenSource`
methods (`bearer`, `bearer_no_browser`, `refresh_now`,
`interactive_login`) plus the public `acquire_with_intent` — routes
through a single `acquire()`/`acquire_locked()` core that owns browser
and cooldown policy.

Before this, acquisition logic was scattered across those methods with
no coordination: concurrent callers (Desktop discovery, the saved-agent
model picker, managed-runtime inference) could each pop their own
browser, and a just-denied attempt would immediately re-prompt on the
next passive read.

## How

- **Intent policy.** `AuthIntent::{Auto, UserInitiated, Headless}`
decides whether a caller may open a browser and whether it honors the
cooldown. `Headless` never browses; `Auto` browses but honors an
unexpired cooldown; `UserInitiated` browses and bypasses+clears the
cooldown.
- **Two-layer single-flight per cache key.** An in-process registry
(`INFLIGHT`) coalesces same-key, same-intent callers onto one leader's
attempt before the file lock. The slot key is `(lock_path, AuthIntent)`,
so a `UserInitiated` sign-in never inherits an `Auto` leader's result. A
joined result is revalidated against the waiter's own contract. Across
processes, callers serialize on a `flock`-based advisory lock and share
success through the on-disk cache. RAII `Drop` releases both lock and
leader slot.
- **Joiner credential-state reconciliation.** `SlotPublish` carries the
full `CachedToken` on success. Each joiner reconciles its own
independent `state` cell under `state.lock().await` before returning:
adopt when absent, expired, or matching the joiner's rejected
credential; preserve any distinct newer usable credential. On a matching
shared failure, neutralize the joiner's in-memory rejected entry under
lock via `expire_rejected_memory` — durable disk mutation is reserved
for `acquire_locked` under the cross-process file lock. Without this, a
joining source's state remains stale or empty and subsequent plain
`bearer()` calls resurface the rejected or absent credential.
- **Validate-before-persist boundary.** `finish()` is the
candidate-token persistence boundary for refresh and browser results.
Before a token is written to cache or the cooldown is cleared, a bearer
equal to the caller's rejected bytes yields a typed failure.
- **Token neutralization.** When `acquire_locked` enters with `rejected
= Some(bytes)`, it calls `expire_rejected()` under the state lock before
any cache check.
- **Cross-process failure single-flight.** An `AttemptRecord` sidecar
records a monotonically-increasing generation, intent, result code, and
SHA-256 digest of the completing caller's rejected token. Adoption is
temporal (pre-queue snapshot predates current generation) and
digest-matched.
- **Typed outcomes.** `AuthError` with stable `code()`/`from_code()`
replaces display-text matching.
- **Durable cooldown sidecar.** Every failed browser attempt is recorded
next to the cache key. 5-minute expiry.
- **Windows disk persistence disabled.** On non-Unix platforms,
`persist()` is a no-op. Lock, cooldown, and attempt sidecars are active
on all platforms. Tests that seed or assert on the on-disk token cache
are `#[cfg(unix)]`-gated.
- **Injected browser opener** invoked while the localhost callback
listener is live.

## Tests

- `crates/buzz-agent/tests/databricks_auth_coordinator.rs`:
browser/cooldown/classification acceptance matrix with a scripted
`BrowserOpener` and stub OIDC provider. P1 regressions exercise the full
`finish()` → `acquire_locked()` → `acquire_leader()` →
`LeaderGuard::complete()` → joiner wiring:
- `test_inprocess_joiner_reconciles_stale_state_after_shared_success`
(Unix): two real sources both loaded locally-fresh-but-rejected X; after
shared success Y, subsequent plain `bearer()` on both returns Y, not X.
-
`test_inprocess_joiner_neutralizes_rejected_on_matching_shared_failure`
(Unix): B's matching rejected X is force-expired in memory after shared
`RefreshRejected`; subsequent read cannot return X.
- `test_inprocess_joiner_populates_empty_state_no_second_acquisition`
(non-Unix): empty A/B join a browser success; B's subsequent headless
read returns Y without a second browser (no disk fallback on non-Unix
exposes the regression).
- `test_crossprocess_userinitiated_waiter_adopts_predecessor_denial`
(snapshot-marker barrier replacing an earlier sleep for deterministic
generation ordering).
- `auth.rs` in-crate tests: lock-primitive edges, disk-recheck on shared
failure (`#[cfg(unix)]`), and:
- `test_joiner_reconciliation_blocked_until_state_lock_released`:
deterministic direct-poll proof that awaited reconciliation requires
`state.lock().await`. The test task holds B's state mutex and manually
polls a pinned real `acquire()` future — Poll 2 (slot published, mutex
still held) must return `Pending` because `lock().await` blocks; with
`try_lock` instead, Poll 2 returns `Ready`, failing the assertion.
- `test_joiner_preserve_distinct_newer_credential`: deterministic direct
polling parks B at `slot.wait()`, then writes Z directly into B's state
in the same task, then publishes Y and awaits completion. B must return
Y but leave state == Z. Mutation check: unconditional adoption
overwrites Z with Y, failing the state assertion.
- `test_joiner_shared_failure_recovers_disk_replacement` (Unix): the
matching-failure joiner enters the recovery branch — after
`expire_rejected_memory` (in-memory, empty state no-op) it reads a
sibling-written disk replacement via `usable_from_disk` and returns it.
Mutation check: removing the `usable_from_disk` recovery branch returns
`Err(RefreshRejected)`.
- `test_joiner_failure_does_not_write_disk` (Unix): byte-for-byte
disk-invariance regression — a matching-failure joiner calls
`expire_rejected_memory` and must not touch the on-disk cache. An
independent process C may write a valid replacement between A's failure
and B's reconciliation; this guard ensures B's unfenced in-memory
neutralization cannot overwrite C's concurrent disk write. Mutation
check: reverting to `expire_rejected` rewrites the file (`expires_at =
0`), changing the bytes and failing the assertion.
- `test_lock_timeout_leaves_cooldown_sidecar_byte_for_byte_untouched`: a
waiter past its deadline returns `LockTimeout` before entering
`acquire_locked`; the cooldown sidecar bytes are unchanged. Documents a
pre-lock limitation: `LockTimeout` callers do not neutralize state or
sidecars.

## Scope / follow-ups

- **Runtime 401 handling is deferred.** This PR owns acquisition
single-flight and policy.
- **Desktop wiring is Phase 2** (not in this PR's boundary). Confined to
`crates/buzz-agent/`.
- **Windows DACL** is a follow-up once the `windows-sys` binding is
available.

## Stack

Built on [block#5534](block#5534)
(`hayt/databricks-oauth-cache-hardening`), now merged. Retargeted to
`main`.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Summary

Add Pi as a selectable desktop ACP runtime via `pi-acp`, including
discovery guidance and its official logo.

### Related issue

Follow-up to closed block#6546.

### Testing

- Focused Tauri preset and desktop logo tests
- TypeScript typecheck

Generated with Codex

---------

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

This PR makes relay readiness failures diagnosable without weakening the
existing fail-closed readiness contract. It distinguishes Postgres pool
acquisition from query execution, Redis pool acquisition,
deletion-catalog validation, and the overall two-second deadline;
exports a bounded Prometheus contract for rollout dashboards; and fixes
the concurrency, shutdown, and listener-boundary semantics needed for
those signals to be trustworthy.

## Why

The previous `/_readiness` implementation exposed only an aggregate
ready/not-ready result. During a rollout, operators could not tell
whether a pod was blocked on:

- acquiring a Postgres connection;
- executing the Postgres readiness query;
- acquiring a Redis connection;
- validating the deletion catalog; or
- the shared readiness deadline.

Adding metrics to the existing handler also exposed three correctness
hazards that this PR resolves:

1. the same handler is mounted on both the public application listener
and the private Kubernetes health listener, so public requests could
otherwise distort rollout telemetry;
2. concurrent probes can finish out of order, allowing an older result
to overwrite newer current-state gauges; and
3. a probe started before SIGTERM can finish afterward, incorrectly
return `200 ready`, and resurrect ready gauges while the process is
draining.

## Behavior

### Readiness evaluation

- Postgres, Redis, and deletion-catalog checks still run under one
shared two-second deadline.
- Postgres distinguishes pool acquisition timeout/error from query
timeout/error.
- Redis distinguishes pool acquisition timeout/error. This does not
claim a Redis command round trip.
- The deletion catalog distinguishes operation timeout/error.
- Multiple failures are reported as `multiple_dependencies_failed`;
exhaustion of the shared deadline is reported as `overall_timeout` when
no more specific completed outcome wins.
- Readiness remains fail-closed: every dependency must succeed for `200
{"status":"ready"}`.

### Ordered publication and shutdown

`ReadinessCoordinator` is process-owned and uses one mutex as the
linearization point for probe generations, current-state publication,
and terminal shutdown.

- Every completed dependency attempt may contribute its truthful counter
and duration observation.
- Only the newest admissible probe generation may publish current-state
gauges.
- An older, slower probe cannot overwrite a newer probe's gauges.
- `begin_shutdown()` and probe commit serialize through the same
coordinator.
- Once shutdown commits, an in-flight probe cannot return ready or
publish ready/current dependency gauges, even if its dependency work
later succeeds.

Shutdown without dependency evaluation records only:

- `buzz_readiness_checks_total{reason="shutting_down"}`; and
- `buzz_readiness_state{check="overall"} = 0`.

It does **not** fabricate dependency failures, dependency state changes,
or zero-duration latency samples. If shutdown wins after an in-flight
evaluation actually ran, those completed dependency attempts may remain
as attempt telemetry, but they cannot overwrite shutdown-dominant
current state.

### Listener and response contract

- The private health listener's `/_readiness` route is the sole
authority for rollout readiness telemetry.
- The public application listener retains `/_readiness` for
compatibility, evaluates the same dependencies, and preserves the
existing response shape, but it emits no `buzz_readiness_*` metrics.
- Ready responses remain `200 {"status":"ready"}`.
- Shutdown responses remain `503 {"status":"shutting_down"}`.
- Failed private-health responses include the bounded `reason` plus
`postgres`, `redis`, and `deletion_catalog` booleans.
- Failed public compatibility responses retain the dependency booleans
but omit the new detailed reason.
- No header, query parameter, path value, or other request-controlled
value becomes a metric label.

## Prometheus contract

The final schema is intentionally capped at **99 raw Prometheus series
per pod**.

| Metric | Type | Labels | Raw series/pod |
|---|---|---|---:|
| `buzz_readiness_checks_total` | counter | `reason` | 12 |
| `buzz_readiness_dependency_checks_total` | counter | `dependency`,
typed `outcome` | 11 |
| `buzz_readiness_check_duration_seconds` | histogram | `check` | 72 |
| `buzz_readiness_state` | gauge | `check` | 4 |
| **Total** |  |  | **99** |

### Closed label sets

`reason`:

```text
ready
shutting_down
postgres_pool_timeout
postgres_pool_error
postgres_query_timeout
postgres_query_error
redis_pool_timeout
redis_pool_error
deletion_catalog_timeout
deletion_catalog_error
overall_timeout
multiple_dependencies_failed
```

Valid `dependency` / `outcome` pairs are enforced by typed enums:

- `postgres`: `success | pool_timeout | pool_error | operation_timeout |
operation_error`
- `redis`: `success | pool_timeout | pool_error`
- `deletion_catalog`: `success | operation_timeout | operation_error`

`check` is `overall | postgres | redis | deletion_catalog`.

The readiness histogram has 15 configured buckets concentrated around
the two-second deadline:

```text
0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5,
0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.5, +Inf
```

The contract deliberately removes the redundant overall `result` label
and the histogram `outcome` label. Pod, ReplicaSet, version, rollout,
raw error, SQL, URL, tenant, user, community, pubkey, and
request-controlled values are prohibited application labels;
infrastructure enrichment can supply deployment identity outside the
application metric.

## Postgres production seam and CI

The real `Db::readiness_check` path now supports deterministic
production-seam testing while preserving the same acquisition/query
implementation used by the relay. The isolated PostgreSQL lane
automatically discovers and executes three ignored integration tests
covering:

- a held sole connection causing pool timeout, followed by recovery
after release;
- closed-pool acquisition error;
- acquisition success followed by query timeout;
- classified query error;
- cancellation while waiting for a connection;
- cancellation during an in-flight query; and
- eventual pool recovery with waiter/in-flight state balanced.

This prevents the central SQLx/Postgres behavior from being merely
compiled but never executed in CI.

## Tests and verification

- `cargo fmt --all -- --check`
- `./scripts/test-postgres-test-discovery.sh`
- complete `cargo test -p buzz-db`
- focused `cargo test -p buzz-relay readiness`
- real-router `cargo test -p buzz-relay real_health_route_`
- controlled PostgreSQL execution of all three ignored readiness tests
- production health router -> real `GET /_readiness` -> Prometheus
render assertions
- public-router requests proving zero rollout telemetry
- deterministic out-of-order A/B probe tests
- SIGTERM-during-probe tests proving shutdown dominance
- exported metric name/type/exact-label/bucket assertions
- exported raw-series allowlist and 99-series ceiling assertion

The route-to-scrape regression test uses the production Prometheus
builder and verifies the `2`, `2.5`, and `+Inf` readiness buckets. It
fails if the health recording call, health route, public/health
boundary, generation fence, shutdown fence, or bucket override is
removed.

## Risk assessment

**Medium.** This changes the live readiness publication path and adds
synchronization around probe commit/shutdown. The risk is bounded by:

- preserving the existing dependencies and shared two-second deadline;
- keeping readiness fail-closed;
- using a short, process-local mutex only at begin/commit linearization
points, not across dependency awaits;
- retaining the public compatibility endpoint while isolating its
telemetry;
- enforcing typed, low-cardinality labels and an exported series
ceiling; and
- covering the production router, Prometheus exposition, real PostgreSQL
seam, concurrency ordering, and shutdown races.

## Operational notes

- Dashboards should treat `buzz_readiness_state` as the latest sampled
current state, not as an event stream.
- `shutting_down` should be excluded from dependency-failure alerts
because no dependency failure is implied.
- Do not use `default_zero()` for missing current-state data;
missing/stale is unknown, not healthy.
- Use histogram buckets, heatmaps, max, or average until the Datadog
distribution metadata confirms percentiles are enabled; do not title a
widget p95 before that live readback.

## Non-goals

This PR does not add the broader process-startup lifecycle,
worker/listener supervision, shutdown coordinator, WebSocket/huddle
handoff, client recovery telemetry, dashboard mutations, Datadog
configuration changes, or deployment changes. Those remain separate
follow-up work.

## References

- [Staging dev relay image
runbook](https://github.com/block/buzz/blob/main/docs/staging-dev-relay-images.md)
- Readiness telemetry contract: `deploy/charts/buzz/README.md`

---------

Signed-off-by: Ravneet Arora <rarora@squareup.com>
Rewrites `docs/nips/NIP-FI.md` as a stateless spec and deletes the five
companion profiles (NIP-FI-CONF, NIP-FI-DELEG, NIP-FI-EDGE,
NIP-FI-LIFECYCLE, NIP-FI-MODEL) that presuppose relay-side state.

## What changes

### `docs/nips/NIP-FI.md` — full rewrite

The relay-side authority engine (bindings, receipts, lifecycle,
invalidation, leases, delegation, enrollment modes, TOFU) is removed.
The spec settles exactly five things:

1. **Assertion contract**: JWT claims (`iss`, `sub`, `nostr_pubkey`,
`aud` (required), `iat`/`exp`, finite TTL bounds), npub binding
semantics, required NIP-42 proof-of-key pairing. Evidence rules
(assertion-key-mismatch → `authorization_denied`, freshness) preserved
from v1.

2. **Verification**: offline against configured per-issuer JWKS
snapshots; multi-issuer; fail-closed on missing/expired/unverifiable.
Cites `crates/buzz-auth/src/nip_fi/` (PR 3 / `70895b355`) as
implementing the assertion-verification procedure. The
`require_attested_key` flag in `IssuerPolicy` is the enforcement
primitive for the unconditional `nostr_pubkey` requirement; conformance
requires forcing it true for every issuer — follow-on code outside this
PR.

3. **Session policy**: required finite `max_connection_lifetime_seconds`
knob with no permissive default; re-auth on every reconnect; no in-band
renewal.

4. **Admin disconnect API**: session-only normative text with a
dedicated `VerifyCommandJwt` procedure — distinct `typ:
nip-fi-command+jwt`, signed `method`/`path` binding, normative
`maximum_command_age` bound (0 < value ≤ 60 s), atomic `(iss, jti)`
reservation as the final admission step after all pure checks.
Non-normative note documents cumulative residual access: `max(0,
min(exp, iat + maximum_assertion_age) - now)` assuming issuance stops;
states that previously issued assertions remain valid for reconnection
until their authority expires; states that continued issuance extends
access with no protocol-level bound. Non-normative note documents the
session-only vs deny-until-TTL trade-off. This verifier and endpoint are
follow-on code.

5. **Deletions**: bindings, enrollment, lifecycle, receipts, leases,
invalidation, delegation gone. "Out of scope" section names every issuer
and deployment concern explicitly.

### Companion profiles deleted

NIP-FI-CONF, NIP-FI-DELEG, NIP-FI-EDGE, NIP-FI-LIFECYCLE, NIP-FI-MODEL —
all presuppose relay-side binding/lifecycle state.

## What does NOT change

The entire `crates/buzz-auth/src/nip_fi/` Rust crate (PR 3 /
`70895b355`) implements the assertion-verification procedure described
in this spec. No Rust code changes in this PR. The
`require_attested_key` enforcement integration and the
`VerifyCommandJwt` / disconnect endpoint implementation are explicit
follow-on code work.

## Follow-on work (separate PRs after spec merges)

- `require_attested_key` forced-true startup enforcement
- `VerifyCommandJwt` implementation and disconnect endpoint
- Down-migration dropping migrations 0041/0042 (0042 before 0041 per FK
order)
- `schema.sql` NIP-FI sections removed
- `buzz-db` migration test blocks cleaned up

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Summary
- add the canonical public Databricks `Claude Fable 5.1` model record
- match the existing Fable family contract: adaptive thinking,
`low|medium|high|xhigh|max`, default `high`, Anthropic Messages, and no
normalization
- add generated Rust/TypeScript corpus coverage and canonical Global
Defaults label/persistence coverage
- remove deployment-specific catalog references from the repository

## Scope
This is metadata and regression coverage only. It does not change
model-capability resolution or production frontend logic.

## Validation
- `cargo fmt --check`
- `node --test
desktop/src/features/agents/ui/modelCapabilitiesCorpus.test.mjs`
- `cargo test -p buzz-agent`
- `pnpm build:e2e`
- `pnpm exec playwright test --project=smoke --grep 'defaults render the
Fable 5.1 label without changing the persisted id'` — 1 passed
- repository search for the removed catalog prefix — no matches

Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Co-authored-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
**Category:** fix
**User Impact:** Top-level channel messages now notify only agents
explicitly selected for that message, while thread replies visibly
retain their addressed agents.

**Problem:** Channel-root and thread composers presented the same
automatic-mention model even though retained recipients are only
predictable within an ongoing thread. That could make a new top-level
message notify an agent the sender did not deliberately choose for that
message.

**Solution:** Make retained audiences a thread-only capability. Root
messages remain explicit and one-shot; threads retain visible, removable
agent recipients, with the automatic-mention setting exposed directly in
the mention picker.

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

**desktop/src/features/channels/ui/ChannelPane.tsx**
Removes persistent audience state from the channel-root composer.

**desktop/src/features/messages/ui/ComposerAddressControls.tsx**
Uses the broader **Manage mentions** label because the picker includes
people as well as automatic agent controls.

**desktop/src/features/messages/ui/ComposerAddressControls.test.mjs**
Locks the updated accessible label and active treatment.

**desktop/src/features/messages/ui/MentionAutocomplete.tsx**
Shows the right-aligned automatic-mention setting directly, uses
thread-specific copy, preserves keyboard/focus behavior, and keeps the
current mention when retention is unchecked.

**desktop/src/features/messages/ui/MentionAutocomplete.test.mjs**
Covers the always-visible setting, compact layout, copy, and
thread-scoped agent actions.

**desktop/src/features/messages/ui/MessageComposer.tsx**
Separates unpinning an agent for future replies from removing its
current draft mention.

**desktop/src/features/messages/ui/MessageComposer.types.ts**
Narrows retained audience contexts to threads.


**desktop/src/features/messages/ui/persistentAgentAudienceHosts.test.mjs**
Prevents channel-root and new-message hosts from opting back into
retained audiences.

**desktop/src/features/messages/ui/useAgentAddressLockPicker.ts**
Splits unpin and current-mention removal semantics.

**desktop/src/features/messages/ui/useAgentAddressLockPicker.test.mjs**
Verifies unpinning retains the current draft mention.

**desktop/src/features/settings/ui/AgentsSettingsPanel.tsx**
Describes the preference as addressing selected agents in thread
replies.

**desktop/tests/e2e/persistent-agent-audience.spec.ts**
Moves retained-audience lifecycle coverage to thread composers and adds
root, settings, layout, focus, keyboard, unpin, and draft regressions.

**desktop/src/features/messages/ui/MessageComposerAutocompletes.tsx**
Preserves composer focus ownership while routing the thread-only
controls.

**desktop/src/features/messages/ui/useComposerFocusOwnership.ts**
Keeps focus within the composer while interacting with its mention
overlay controls.

</details>

### Reproduction steps

1. Enable **Automatically mention agents** under agent settings.
2. In a channel root, select an agent and send a message. Confirm the
agent is addressed once, no retained-recipient control appears, and the
next root message has no agent recipient.
3. Open a thread and select an agent. Confirm the visible recipient
persists into later replies.
4. Open **Manage mentions** in the thread composer. Confirm the
automatic-mention setting is immediately visible, right-aligned, and
labeled **Address selected agents in thread replies**.
5. Uncheck a selected agent. Confirm its current draft mention remains,
while later replies no longer retain it automatically.

---------

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>
Resolved Justfile test-unit stanza: keep the fork-only buzz-backend-sprites
and buzz-waker steps, take upstream's widened buzz-agent step (whole crate
instead of --lib, for the new DatabricksAuthCoordinator integration tests).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Junchao Yan <yjc801@gmail.com>
@yjc801
yjc801 merged commit 34689ab into main Sep 2, 2026
46 of 47 checks passed
@yjc801
yjc801 deleted the fork-sync/2026-09-01d branch September 2, 2026 02:46
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.

8 participants