mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
312cf674fad5563c24a66ec5350d306d192ed64a
136 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7e96f91229 |
feat(mobile-infra): support development App Attest (#7744)
Development-signed iOS apps cannot enroll with the current gateway because their Apple App Attest AAGUID is rejected. Add an explicit personal development build feature and environment setting so a development gateway can use a developer's own application identity and sandbox APNs credentials. Ordinary gateway builds remain production-only. Special builds also default to production, enforce exactly the selected signed AAGUID, and retain certificate-chain, pinned-root, nonce, app-ID, key, credential-ID, and counter verification. Document the matching mobile signing configuration and expose the feature through an optional Docker build argument. ### Validation The development image deployed successfully to a personal Railway stack; private readiness, enrollment challenges, authenticated relay access, and APNs sandbox TLS/HTTP2 connectivity passed. Signed-off-by: Tom Brow <tomb@block.xyz> |
||
|
|
7881447c19 |
fix(audit): frame hash inputs with TLV (#7492)
Hash new audit entries from a TLV buffer built with one-byte field tags, big-endian u64 byte lengths, and raw values. Absent optional fields are omitted; present empty values retain their tag and zero length. This prevents bytes from moving between fields without restricting object IDs or inferring boundaries from field contents. Store an explicit `hash_version`. Migration 0048 labels existing rows as version 1, and new writers use version 2. Historical hashes are unchanged and mixed-version chains verify. The legacy encoding retains its original ambiguity; TLV protects new entries. Apply the migration before deploying the updated writers and verifiers. Tests cover both boundary collisions, absent versus empty fields, stable digests, unknown versions, mixed-version chains, and stored-row tampering. All 16 audit and 128 database unit tests passed. The six PostgreSQL audit tests passed against both migrated and fresh schemas, and a populated-row migration check preserved the historical hash. Full `just ci` passed. Related audit fixes: #4216 and #4249; issue #4173. Signed-off-by: Jordan Mecom <jm@squareup.com> |
||
|
|
a929532a04 |
fix(admin): allow cold storage worker DB startup (#7770)
## Summary The standalone S3 accounting worker can exit before its scan begins because database startup inherits the relay’s three-second connection budget. A cold DNS probe took about five seconds. Give `buzz-admin storage-snapshot` its own pool: one connection, no minimum idle connections, and a 30-second acquisition budget. Retry startup timeouts and transport failures at most twice, after two and five seconds. Total startup wait is bounded to 97 seconds. Configuration, authentication, TLS, and protocol errors fail immediately. Log each startup attempt’s elapsed time and error category without connection credentials. Relay defaults stay unchanged. Retries stop before lock acquisition; the same lock-owning database session still publishes the completed snapshot. ### Related issue Follow-up to #7543. No duplicate startup fix found. ### Testing Archived-command check: built a nextest archive, temporarily moved `target/debug/buzz-admin` out of the checkout, and ran `scripts/postgres-test-run.sh --archive-file <archive>`. Both tests failed before the path fix and passed afterward. The tests use nextest’s relocated executable path, with the original Cargo path retained for local runs. Manually restored the old startup call and ran `scripts/postgres-test-run.sh -p buzz-admin --test postgres_storage_snapshot -E 'test(storage_snapshot_retries_then)'`. It failed before reaching S3; restoring the fix passed. This confirms the test exercises the actual worker command. Local `just ci` passed all stages before mobile tests, which stopped at SDK discovery in the `objective_c` native hook. The default Xcode tools report an unaccepted license. Two existing PostgreSQL tests hit connection timeouts in the parallel run and passed individually. After merge, build a worker image and repeat the cold-pod staging smoke test through snapshot publication before changing relay metrics mode. Generated with Codex --------- Signed-off-by: Ravneet Arora <rarora@squareup.com> |
||
|
|
01b6174a1c |
fix(ci): don't run desktop tests for purely mobile client changes (#7709)
Mobile-only PRs currently trigger desktop CI because the desktop test filter's glob inadvertently matches every path outside Tauri. Fix that filter so that pure mobile changes skip desktop builds, tests, and their relay artifact producer. ### Verification - 12 regression tests exercise the exact pinned paths-filter action on mobile, desktop, Tauri, backend, mixed, workflow, and documentation changes. - Restoring the bad glob makes the mobile-only regression test fail. - The filter tests, existing required-context isolation contract, workflow syntax validation, and Biome pass locally. --------- Signed-off-by: Tom Brow <tomb@block.xyz> |
||
|
|
6b1e45d2f6 |
Isolate S3 storage metrics from the relay (#7543)
## Why **This PR moves the S3 storage scan out of the serving relay and into a separate batch job.** The job saves a complete result in PostgreSQL. The relay reads that result, exports the existing storage totals, and reports the snapshot's freshness and database-read health. ```text Today: relay -> scan S3 -> calculate totals -> Datadog metrics After rollout: CronJob -> scan S3 -> PostgreSQL snapshot -> relay -> Datadog metrics ``` The code in this PR is the new pipeline. It adds the worker, database snapshot, relay read mode, and Helm CronJob template. It does **not** enable the pipeline in production. The chart keeps the CronJob disabled, and the relay keeps its current inline mode by default. [squareup/builderbot-platform-core-infrastructure#244](https://github.com/squareup/builderbot-platform-core-infrastructure/pull/244) will set the production limits, enable the job, and switch the relay to the saved snapshot after this PR merges. The relay currently lists the media bucket once an hour and calculates storage totals inside the serving process. The production bucket now exceeds the relay's one million object cap, so each sweep fails and the last good per-community values remain stale. The Datadog dashboard can no longer show current storage use by community. Raising that cap inside the serving relay would move a larger, memory-heavy scan into the process that owns live WebSocket connections. The scan retains state for unique blob hashes and community bindings, so its memory use grows with the bucket. A large scan could raise relay memory use, trigger restarts, and drop user connections. The goal is to restore current metrics without putting a production-scale bucket scan in the relay's failure domain. No media objects move or change. Only the process that calculates the totals and the handoff to the relay change. ## What - Add `buzz-admin storage-snapshot`, a run-once worker that scans S3 and saves one complete accounting snapshot in PostgreSQL. - Add `external` relay mode to read the saved snapshot. Keep the current `inline` mode as the default, and add `off` as a fail-closed option. - Add an opt-in Helm CronJob for the worker. The 10 million object cap exists only on this Job. - Keep the current fleet and per-community gauges, and add snapshot age, generation duration, configured cap, cap utilization, and database-load health gauges. - Add an additive migration for the latest complete snapshot and its run metadata. ## Overall plan 1. Merge this PR to add the worker, database handoff, relay modes, and disabled-by-default chart support. This step does not change production behavior. 2. Publish the relay image and Helm chart `0.1.9` from `main`. 3. Update [squareup/builderbot-platform-core-infrastructure#244](https://github.com/squareup/builderbot-platform-core-infrastructure/pull/244) to pin those final artifacts and rerender its manifests. 4. Use the infrastructure PR to deploy the CronJob with a 10 million object cap, a one-hour deadline, and a 20 GiB memory limit. 5. Start one manual Job during a staffed window and verify its snapshot, duration, memory use, relay stability, and Datadog output. 6. Keep the daily schedule and `external` relay mode only after that gate passes, then add alerts for stale snapshots, snapshot-load failure, failed jobs, cap pressure, duration, and worker memory. The code and infrastructure remain separate so this PR can ship the mechanism without silently enabling a production-scale scan. The infrastructure PR owns the production settings and rollout gate. ## How ### Complete snapshot handoff The worker takes a deployment-wide PostgreSQL advisory lock before it lists S3. This prevents scheduled and manual workers from overlapping, even if Kubernetes starts both. The final database replacement runs through that same lock-owning session. If the session dies during the scan, publication fails instead of letting the stale worker overwrite its successor. A worker that no longer owns the lock cannot publish through another pooled connection. The worker reads S3 in pages of 1,000 objects and folds each page into physical totals, logical per-community usage, and anomaly counts. It stops before folding a page that would exceed `--max-objects` and emits structured progress every 100,000 objects. The worker replaces the singleton database row only after the full scan succeeds. A listing error, malformed page, cap breach, serialization error, lost lock session, or database error cannot publish a partial snapshot. The last completed snapshot stays available. Each stored result includes its completion time, duration, cap, and image or source revision. PostgreSQL is the handoff between the batch worker and the relay. The worker writes one complete deployment-wide snapshot, and the relay reads that snapshot on its normal leader metrics tick. No new network service or worker endpoint is required. ### Relay behavior `BUZZ_STORAGE_METRICS=inline` keeps the existing in-process sweep and its one million object default. `external` loads the newest completed worker snapshot on each leader metrics tick. `off` emits no storage-family metrics. An unknown value fails closed to `off`. External mode republishes the existing fleet, per-community, and anomaly metric names, so those current queries remain valid. Snapshot handoff health uses a separate family: `buzz_storage_snapshot_age_seconds`, `buzz_storage_snapshot_duration_seconds`, `buzz_storage_snapshot_max_objects`, `buzz_storage_snapshot_cap_utilization`, and `buzz_storage_snapshot_load_ok`. The `buzz_storage_sweep_*` gauges remain inline-only because they describe a scan attempted by the relay process. External mode does not synthesize `sweep_ok=1` from the last successful database row: an old row proves only that an earlier worker completed. Kubernetes CronJob/Job status is authoritative for the latest worker result, including non-zero exit, deadline expiry, and OOM termination. The relay keeps the last complete snapshot available when a worker run fails. Snapshot age shows that no replacement arrived on schedule, while `buzz_storage_snapshot_load_ok` distinguishes staleness from a missing row, database read failure, or invalid payload. If a community disappears, changes host, or leaves the configured emission scope, the relay zeroes the old labeled series instead of leaving stale values behind. Per-community bytes are logical referenced media usage. If two communities reference the same blob, each community receives the blob's bytes. Fleet physical totals still count each S3 object once. This PR preserves those existing metric semantics. ### Deployment boundary The CronJob is disabled by default. When enabled, it uses `concurrencyPolicy: Forbid`, no retry, a configurable active deadline, bounded history, explicit CPU and memory resources, a read-only root filesystem, and no Istio sidecar by default. The worker receives only `DATABASE_URL`, S3 settings, optional S3 credential references, and the code revision. It does not receive the relay private key, Git hook HMAC secret, Redis URL, or the full relay secret as environment variables. Operators may reuse the Buzz service account or select a dedicated one. ### Non-goals - This PR does not enable the worker or `external` mode in production. - This PR does not change media uploads, object ownership, retention, or deletion. - This PR does not change the names or meaning of the existing fleet, per-community, or anomaly storage gauges. - This PR does not add a lease service or allow multiple workers to publish concurrently. ## Risk The application and chart defaults do not enable the new worker or raise the serving relay's cap. The database change is an additive deployment-global singleton table. The relay's default remains `inline`, so merging this PR alone does not change the active metrics path. The main rollout risk is worker memory use because the fold retains state for distinct blob hashes and community bindings. The first production-sized run must confirm peak memory and duration before the schedule is trusted. The 10 million cap and one-hour deadline bound the first deployment, but they do not replace measurement. External mode also needs stale-snapshot, snapshot-load, and job-failure monitors because the relay intentionally keeps publishing the last complete result after a failed job or read error. This behavior avoids gaps and partial data, while snapshot age and load health tell operators when the result or PostgreSQL handoff needs attention. Job status remains necessary for immediate failures and termination reasons that a killed process cannot record itself. ## Testing No production S3 scan was run from this PR. Automated regressions verify that external mode keeps stale last-good totals visible without emitting inline attempt-health gauges, reports database-load failure while retaining the cache, and leaves inline telemetry unchanged. Mutation checks also prove those tests fail if external mode is routed through inline emission or a failed load is reported as healthy. After deployment, create one manual Job from the CronJob during a staffed window. Require a completed Job, exactly one new snapshot, fewer objects than the configured cap, acceptable duration and peak memory, no relay restart regression, restored Datadog points, and no OpenMetrics sample truncation. ## Next steps 1. Complete review and merge this PR. 2. Publish chart `0.1.9` and the final main-branch relay image. 3. Replace the provisional pins in [squareup/builderbot-platform-core-infrastructure#244](https://github.com/squareup/builderbot-platform-core-infrastructure/pull/244), rerender, and require clean CI. 4. Run the staffed manual Job gate and record object count, peak memory, duration, snapshot revision, and relay stability. 5. Confirm the relay reads the new snapshot in `external` mode and the existing `block.buzz_relay.*` storage series update again. 6. Enable the daily 03:17 UTC schedule and add dashboard panels and monitors for snapshot age, snapshot-load health, Job failures, cap pressure, duration, and worker memory. If production must roll back to an older relay image, set `BUZZ_STORAGE_METRICS=off` first. Older images do not understand `external` and would resume the failing inline scan. ## Bigger picture This is the application half of the storage-metrics repair. The paired infrastructure PR owns the production resource limits, schedule, artifact pins, secret boundary, and monitored rollout. Keeping those changes separate lets this PR remain safe by default while still providing a complete path to current per-community S3 totals. Related issue: N/A. No matching issue or pull request exists in `block/buzz`. Generated with Codex --------- Signed-off-by: Ravneet Arora <rarora@squareup.com> Co-authored-by: Codex <noreply@openai.com> |
||
|
|
76f7e5ef0c |
feat(push): make gateway origin configurable (#7261)
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> |
||
|
|
2226b6f95b |
fix(desktop): npub identity controls across profile, agents, and workflows (#7489)
🤖 ## Summary Building on #7488's npub foundation, this PR finishes the identity display change for the controls where you actually manage people and keys: profile, settings, agent access, and workflows. Everywhere in these surfaces, an identity key shows — and copies — as its canonical npub (npub is the human-readable encoding of a Nostr public key: the compact `npub1j57...fjmv` form where space is tight, the full npub where the whole key matters), and accepts npub as input. After this change: - Profile panel: the public-key row and the managed-by / declared-owner copies show the full npub. If a key can't be encoded, you see "Unavailable" with no copy button — never a raw or partial key. - Settings: the identity card shows and copies the npub. The hosted-communities account identity derives from the bound key (`pubkey_hex`) — the same authority as the mismatch gate and hosted operations — so the display can never disagree with what the app acts on; an unusable hex falls back to a neutral label instead of rendering the unverified server npub. The connected claim and a community's Connect action require that same usable bound key to match the local one — with no usable binding the card cannot claim connected or start Connect, while the community list, linking, and delete/rebind recovery stay available. - Hosted create/onboarding: the account and device identity rows in the create flow and owner onboarding derive from the same authoritative fields (bound key / local key), with the same neutral fallback; readiness requires a usable bound key that matches the local one. - Respond-to allowlist (controls who may respond to an agent): entries can be typed or pasted as hex or npub; both spellings of the same key are recognized as one entry and dedupe. Search results, chips, and remove buttons use the compact npub. - Workflow key fields: to/from keys display as npubs in the form and save back as canonical hex. Templates like `{{trigger.author}}`, roles, and free text pass through untouched; placeholders accept both spellings. - Recipient and agent dialogs: the verify popover is npub-only (the raw-hex line is gone); denied-membership screens never show a raw key. - The Rust-side truncated display name (used for native surfaces) shows the same compact npub, so those surfaces match the web UI. Internal representation is unchanged: keys are still stored, sent, and matched as canonical 64-character hex — npub is a display and input spelling, normalized to hex at the boundary, so existing data and integrations keep working. Bound-key usability and comparison use one normalized form (trimmed, lowercased, 64 hex characters; npub rejected), so padded or mixed-case spellings of the same key match. Display names, private keys, and event IDs are untouched. ## Details - `respondToAllowlist` / `RespondToField`: npub entries normalize to canonical hex; cross-form dedupe; compact npub in rows and chips; direct-add accepts npub and stores canonical hex. - `workflowFormTypes` / `WorkflowStepCard`: hex → npub for display, npub → canonical hex on save; templates, roles, and free text pass through in both directions (roundtrip-tested). - `UserProfilePanelFields`, `ProfileSettingsCard`, `HostedCommunitiesSettingsCard`, `MembershipDenied`, `SelectedRecipientChip`, `AddAgentToChannelDialog`: npub display and copy; invalid keys → "Unavailable" with no copy; hosted identity rows derive from the bound `pubkey_hex` (create/onboarding rows from the bound and local keys), never the unverified server npub; connected/readiness/Connect gates use the same usable-bound-key predicate, and the settings Connect invocation callback re-checks it before starting. - `src-tauri/src/commands/identity.rs`: `truncated_display_name` compacts to the first 8 + last 4 characters of the npub (above a 12-char threshold), mirroring `truncateNpub`. - e2e: profile key rows and clipboard polls assert npub forms and raw-hex suppression; the display-screenshots spec pins the npub-only popover; hosted specs drive the real settings card, create flow, and onboarding rows through their real providers, and the unlinked/npub-only identity cases assert no connected claim and no Connect action. ### Related issue - Fixes: N/A. No separate issue; the related work is the stack below. - Stack: builds on #7488 (shared npub foundation), now merged; this PR is rebased onto main and stands on its own. ### Testing At head `303c90ffa` (base: main `bfc38485`; 24 files, +1125/−146): - Focused unit suites (respondToAllowlist, workflowFormTypes, hostedCommunityApi bound-key helpers) green; mutation-checked — dropping allowlist canonicalization fails the dedupe case, and dropping bound-key normalization fails the npub-in-hex and padded same-key cases. - Full desktop unit suite 6,477/6,477, `desktop-typecheck`, `desktop-check` (formatting fixed narrowly with `biome check --write` on the touched files only), and a fresh E2E build at the current head; the add-community + hosted-communities-settings specs 18/18 and onboarding integration 69/69 on a fresh dedicated port, with focused new-case runs 4+4 covering padded same-key (ready, Connect kept — no false rebind) and npub-in-hex (neutral label, recovery, no Connect) across the settings card, create flow, and first-community onboarding, plus the unlinked-account settings regression asserting Connect cannot occur. - `cargo fmt`/clippy (both feature sets) and `cargo test identity` (71 pass) passed at the earlier full-change head; since then, the only production changes in this PR's delta are the hosted identity display authority and its fail-closed bound-key gating/normalization above (base-side fixes carry #7488's receipts) — every other change is test-only. ### Task provenance Buzz channel: `1f0e4a3d-7e01-4efe-bb16-843b357f85c9` Task: buzz://message?channel=1f0e4a3d-7e01-4efe-bb16-843b357f85c9&id=86b34eb4bd84a1472419e9af22636c011c0fe273e3c196f967d7a36996e149b6 --------- Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> |
||
|
|
cd54e26823 |
fix(agent): route GPT-5+ model-service FQNs to Responses (#7358)
## Summary Route Databricks Unity Catalog model services to OpenAI Responses when their service name matches GPT-5 or newer. These models can reject tools plus reasoning on Chat Completions. Match only the service component, using the existing family-token boundaries and a numeric major version. Catalog and schema names cannot select the protocol. Keep neutral effort capabilities and the full model ID unchanged; other services still use MLflow Chat Completions. Keep the Rust and desktop resolvers in sync, add shared boundary cases and a captured-HTTP regression for completion and summarization, and update the documented FQN rule. ### Related issue No duplicate found in searches for “FQN responses” PRs or “astra” issues. Related: #6918 introduced Unity Catalog discovery. Originating conversation: buzz://message?channel=0b881928-a3a6-4c01-b981-8e64268f01ce&id=770949343bc96a9ed88acd90a1b37d358a0efc52c79237d0fdb491ce02b8d4ed ### Testing No live Databricks inference test. The gateway must accept the full model-service ID on its OpenAI Responses route; this remains the integration risk. The local `just ci` attempt exceeded its five-minute deadline during `mobile-check`, so the full repository gate was not completed. All push-hook checks passed. Generated with Codex Signed-off-by: Fizz <400e8babadcee6a7f420103f10a2849d84c4a9c71d5bd04f3948c814216648a3@buzz.block.builderlab.xyz> Co-authored-by: Fizz <400e8babadcee6a7f420103f10a2849d84c4a9c71d5bd04f3948c814216648a3@buzz.block.builderlab.xyz> |
||
|
|
e09f715c9d |
Verify ACP relay events before prompt routing (#7010)
## What changed Verify every Nostr EVENT received by buzz-acp immediately after deserialization. Events with an invalid NIP-01 ID or Schnorr signature are dropped before subscription routing, deduplication, replay-watermark updates, membership handling, or either harness queue. ## Safety Signature verification runs on the blocking pool so cryptographic work does not block the relay task. A verification failure drops only that event and keeps the connection available for subsequent valid traffic. The existing observer-control verification remains as defense in depth. Regression tests cover valid delivery; changed content, ID, signature, pubkey, tags, and timestamp; a forged owner shutdown command with a recomputed ID; forged membership notifications; and forged observer-control events. ## Testing cargo test -p buzz-acp cargo clippy -p buzz-acp --all-targets -- -D warnings just ci --------- Signed-off-by: Jordan Mecom <jm@squareup.com> |
||
|
|
cd02b693aa |
refactor(relay): extract NIP-29 membership authorization (#7285)
## Why NIP-29 membership authorization for kinds 9000, 9001, and 9022 was embedded in a large async handler, requiring Postgres and Redis to test and repeating the last-owner rule across five call sites. This addresses [TheSentinel454/buzz#24](https://github.com/TheSentinel454/buzz/issues/24) without adding the broader state/repository abstraction suggested there because HTTP and WebSocket writes already share ingestion. ## What - Extract pure, typed membership authorization decisions while leaving database reads and mutations in `validate_admin_event`. - Preserve existing client-visible errors and independent database last-owner safeguards. - Collapse five last-owner policy restatements into one predicate and share the identical self-departure policy. - Include the relay decision modules in `just test-unit`, so these tests execute in CI. ## Risk Assessment Medium-low. This touches production relay authorization, but intentionally preserves wire behavior and database defense in depth; exhaustive decision tables and relay-backed tests cover the affected paths. ## Simplification This removes repeated policy from the orchestration path and makes the rule set directly testable without introducing a repository trait or second transport path. ## Verification Verified at `15255a090797f85874921120003c645962fefaed`: - `just test-unit` — all 10 package summaries passed. An initial run hit two unrelated timing-sensitive `buzz-acp` failures; the complete retry passed 905/905 in that package. - `cargo fmt --all -- --check` - `cargo clippy --workspace --all-targets -- -D warnings` - `just file-size-check` — 10/10 policy tests passed. - `just security-review-check` — 13/13 tests passed. - Push preflight — `push-head-scope`, `branch-skew`, `file-size-check`, `rust-tests`, and `desktop-tauri-checks` passed. - Blox Postgres relay lane — 84/84 at the byte-identical source patch; full live `e2e_relay` behavior matched the clean base (45 pass and the same pre-existing kind:9002 failure on each). Generated with Claude Code --------- Signed-off-by: tornquist <tornquist@squareup.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Codex <noreply@openai.com> |
||
|
|
8e7b275cb0 |
fix(scripts): copy global-agent-config.json in buzz-adopt-prod-agents (#7303)
## What Extend `scripts/buzz-adopt-prod-agents.sh` to copy `agents/global-agent-config.json` from the prod app-data store to dev as part of the existing atomic bundle commit, and document what the script cannot copy (baked build-time defaults). ## Why `global-agent-config.json` holds the owner's global agent defaults (`env_vars`, `provider`, `model`, `preferred_runtime`). Previously the script carried the dev copy across verbatim — it was absent from the bundle drop list and not in `RECORD_FILES`. After a `just reset`, the dev build inherited stale global defaults (or none at all) instead of mirroring prod, inconsistent with how all other bundle files are handled. The "WHAT THIS DOES NOT DO" header lacked any mention of baked build-time defaults, which are a separate (and common) source of prod/dev parity confusion. ## Changes - **`RECORD_FILES`** — add `global-agent-config.json`. The file has no volatile fields (`GlobalAgentConfig` struct = `env_vars`/`provider`/`model`/`preferred_runtime`), so it joins the verbatim-copy path already used by `teams.json` — no new transform. - **Stage-seed block** — add `global-agent-config.json` to the `rm -rf` drop list so the prod overlay replaces it cleanly; remove its stale mention in the "carried verbatim" comment. - **Docs/comments** — update "4-file bundle" → "5-file bundle" in the DMG concurrent-run warning and the step 2 comment; list the file explicitly in the step 2 header comment. - **"WHAT THIS DOES NOT DO" header** — add a bullet explaining that baked build-time agent defaults (`BUZZ_BUILD_BUZZ_AGENT_PROVIDER` / `BUZZ_BUILD_AGENT_ENV` via `option_env!` in `build.rs`) are compiled into the binary, not stored in app-data. Includes the correct `just production` invocation pattern and a `.env` warning. - **Preflight symlink checks and dry-run output** iterate `RECORD_FILES` and pick up the new entry automatically — no other changes needed. Verified: `bash -n` clean, `shellcheck` clean, `--dry-run --force` shows `[dry-run] stage global-agent-config.json (0600)` in the expected position. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> |
||
|
|
0e878664b0 |
ci: split CI into reusable workflows (#7168)
## Why The monolithic CI workflow is a frequent merge-conflict hotspot. Splitting cohesive domains into same-repository reusable workflows keeps one centrally filtered entry point while letting Rust, desktop, relay/PostgreSQL, client, and security CI evolve independently. ## What - Keep `ci.yml` as the only push/pull-request orchestrator with unchanged concurrency and path detection. - Move 18 execution jobs into five `workflow_call`-only domain workflows without changing their runners, steps, matrices, caches, artifacts, permissions, or timeouts. - Keep the relay artifact producer with desktop integration, the complete PostgreSQL lane, and relay E2E consumers. - Preserve all 12 existing required GitHub Actions contexts through lightweight top-level compatibility gates, so the repository ruleset does not need to change. - Update the Rust-cache contract to follow Unit Tests into `_ci-rust.yml`. ## Risk Assessment CI-only change with moderate workflow-orchestration risk. The main risks are reusable-workflow output propagation, skip behavior, and visible check naming; the old required names remain explicit top-level jobs, and the draft will stay open until an exact-head GitHub Actions run and independent review are complete. Generated with Codex --------- Signed-off-by: Luke Tornquist <tornquist@squareup.com> Signed-off-by: tornquist <tornquist@squareup.com> |
||
|
|
560fea7b4f |
feat: add databricks fable 5.1 model capabilities (#7213)
## 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> |
||
|
|
4794a5cecf |
ci: relax file-size ceilings by surface (#6485)
## 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> |
||
|
|
e17a0d44c3 |
fix(dev): keep the canonical profile when launching from desktop/ (#7143)
## Summary Carl, an automated agent, implementing on Wes's request. Fix ordinary Desktop dev checkouts being misclassified as linked worktrees when launched through `just production`, `staging`, or other recipes that source `instance-env.sh` from `desktop/`. From the repository root, Git reports both directories as `.git`. From `desktop/`, it can report an absolute `--git-dir` and `../.git` for `--git-common-dir`. The textual comparison treats them as different and chooses a branch-suffixed app profile (for example `.dev.main`) instead of the canonical `.dev` profile populated by the agent-adoption script. - Request `--path-format=absolute` for both paths. Actual linked worktrees still have distinct Git/common directories and retain their existing isolated app identities. - Add eight isolated fixture cases executing the real environment script with real Git: ordinary root/subdirectory on main and feature branches, linked root/subdirectory, detached linked subdirectory, and symlinked ordinary subdirectory. Paths contain spaces. Only native icon generation is stubbed; no user profile, keychain, app, or relay is accessed. - Run the regression in the existing always-run CI contract job. No agent migration, global-settings copy, keychain changes, profile merging, branch-label redesign, or packaged-release behavior changes. Existing Git `--path-format` support is required (Git 2.31+). ### Related issue Searched open PRs for `instance-env` and worktree titles, and open issues for dev-profile/adoption reports. No matching path-normalization fix found. - #7142 touches `instance-env.sh` for descriptive labels. This fix is independent; it uses a distinct test filename to avoid colliding with that PR's new `test-instance-env.sh`. - #6915 proposes a separate release-profile launch recipe; this fix preserves the current dev-profile contract instead. ### Testing At exact head `0a09a2f3716b0378546b66be2302b750ed4330b9`: - `scripts/test-desktop-instance-detection.sh`: **8/8 passed**. - Before the production change, the same regression failed on the ordinary checkout's `desktop/` case: actual `xyz.block.buzz.app.dev.main`, expected `xyz.block.buzz.app.dev`. - `bash -n scripts/instance-env.sh scripts/test-desktop-instance-detection.sh`: passed. - `git diff --check`: passed before commit; pre-commit and commit-msg hooks completed. - Applicable pre-push gates passed: branch-skew, push-head-scope, and file-size policy (6 tests plus all three entrypoints). Rust/Desktop/Mobile package lanes were correctly inapplicable to this shell/CI-only diff. No native app launch or first-boot key import was performed. The validated boundary is the generated launch environment/profile identity, not successful agent startup. Hosted CI has not been checked or represented as green. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> |
||
|
|
bd73490418 |
ci: run PostgreSQL tests in isolated lane (#6730)
## Why PR #6660 introduced four PostgreSQL-backed persistence tests and a focused CI selector, but an exact test-name list does not automatically cover future database tests. Broad ignored-test execution also exposed shared-schema races and ambiguity between desired-state and migration-applied schema expectations. ## What - Establish a discoverable convention: PostgreSQL unit modules use `postgres_tests`, PostgreSQL integration binaries use a `postgres_` prefix, and unrelated external-infrastructure tests use an `external_infra_` prefix. - Add a dedicated nextest PostgreSQL profile and archive-backed CI job covering the relevant crates without enumerating test names. - Create a run-scoped desired-state source database and a unique PostgreSQL database per test process for parallel-safe isolation, with cleanup on success, failure, or interruption. - Route destructive migration and migration-parity tests to clean `template0` databases while desired-state tests clone the desired-state database. - Document discovery, schema modes, required role privileges, and a bounded portable local runner. - Keep the existing infrastructure-free unit-test jobs unchanged. This is intentionally limited to test and CI harness behavior. It does not move production database code, change persistence semantics, or implement issue #20's broader shared test-utility refactor. ## Risk Low production risk because all changes are confined to tests, CI configuration, documentation, and test harness scripts. Remaining operational risks: - Cleanup retries `dropdb --force` five times across roughly four seconds. Exhaustion warns with the database name but deliberately does not mask the test result; individual PostgreSQL diagnostics are suppressed. - The seven-package boundary is duplicated between the runner and CI archive and must remain synchronized if PostgreSQL tests move to a new crate. - Portable SHA fallback branches were exercised on Linux; no macOS Blox workstation was needed for this Linux CI artifact. - GitHub's unchanged generic Unit Tests job currently fails while cold-linking `buzz-voice` because `sherpa-onnx-c-api` is absent. The branch changes no voice/build/toolchain inputs; the exact parent previously passed that job, and Blox passes the same infrastructure-free suite (1,450/1,450). A prior-head one-job retry and the final-head run both reproduced the hosted-runner failure. ## Verification Author Blox workstation `2020088`: - `cargo fmt --all -- --check` - `just clippy` - `just test-unit`: 1,450 passed; PostgreSQL tests remain skipped in fast jobs - PR #6660 focused tests: 4/4 passed through the final runner - Full lane: 282/282 passed in 10.087s with a non-superuser role limited to `CREATEDB`, `CREATEROLE`, and `pg_read_all_stats` - 272 desired-state tests - 10 migration-applied tests - 6 explicitly filtered external-infrastructure tests - Cleanup fault injection: a deliberately underprivileged 282-test run produced the expected 277 passes and 5 failures, and the post-run catalog audit found zero lane databases after retry cleanup. The restored successful run also left zero lane databases. GitHub exact final head `92c231e48f299ea2af23817763f5ae80ac013d68`: - [PostgreSQL Tests](https://github.com/block/buzz/actions/runs/32789030203/job/97630827823): 282/282 passed across 10 binaries in 98.886s; 1,240 skipped, including 6 via the profile filter - The shared relay/PostgreSQL archive predecessor completed successfully - [Unit Tests](https://github.com/block/buzz/actions/runs/32789030203/job/97626930420): unrelated `sherpa-onnx-c-api` native-link failure described above - Independent exact-head review on separate Blox workstation `2022762`: no substantive findings after all initial findings were addressed. The reviewer independently verified cleanup retry behavior, exit-status preservation, shell portability, syntax, and a clean exact-head worktree. ## References - Stacked on #6660 at exact head `561de54be4d9c2b622b7c2aa5b61bc3068f47e2a` - https://github.com/TheSentinel454/buzz/issues/20 - https://github.com/TheSentinel454/buzz/issues/20#issuecomment-5398526792 Generated with Codex. ## Update — August 24, 2026 review follow-up - Centralized the repeated PostgreSQL test URL resolution in crate-local, test-only helpers without introducing the broader shared utility refactor from issue #20. - Restored descriptive hybrid/Redis test function names. Structural `external_infra_*_tests` modules now own exclusion, and the nextest filter only recognizes module path segments. - Added a three-second source guard that scans every Rust file and fails CI when an ignored PostgreSQL test would be omitted or an external-infrastructure test would be included. Fixture tests cover accepted modules/binaries and both failure modes. - Removed the two implementation-plan documents. Performance profiling on Blox workstation `2027352` (same prebuilt archive and cargo-nextest 0.9.143 for every comparison): - Current per-test database model, 8 workers: 10.15–10.40s across three runs. The 283 `createdb` calls and 284 `dropdb` calls consumed 28.85–29.46 aggregate seconds, about 39–40% of aggregate test-process duration. - Reusing one database per worker without cleanup: 6.55–6.84s, about 35% faster, but all three runs failed because global matcher-queue tests inherited a quiesced community from an earlier test; the failing test varied with scheduling. - Reusing workers with `TRUNCATE … RESTART IDENTITY CASCADE`: all 282 tests passed, but total time regressed to 10.47–10.67s. The 265 truncate calls consumed 24.34–25.45 aggregate seconds, so truncation merely replaced most clone/drop cost. - Raising concurrency to 16 workers reduced one isolated-database run to 8.79s, but 24 workers exposed a cluster-global `pg_stat_activity` race. The profile remains at the proven-safe 8 workers. Decision: retain unique per-test databases. Harness cleanup uses `dropdb --if-exists --force`; it drops the database rather than truncating tables or deleting rows. Verification at local branch head `60086c1f6ee34a193c342255a5e8e6293b60e988`: - Discovery inventory: exactly 282 intended tests; all 6 hybrid/Redis tests present and structurally excluded. - PR #6660 focused persistence tests: 4/4 passed. - Full PostgreSQL lane: 282/282 passed three times; 1,240 skipped each run; wall time 9.72–9.96s without profiling shims. - Non-ignored tests with a desired-state database: 1,234/1,234 passed; one mesh-demo timeout from the first run passed immediately in isolation. - `cargo fmt --all -- --check` and all-target/all-feature clippy for `buzz-db`, `buzz-deletion`, and `buzz-relay` passed. Final independent re-review at exact head `42097c0136ab3fa8f0efe5720ae829c04575b9b6` on separate Blox workstation `2028455`: no substantive residual findings. The reviewer independently exercised ordinary strings, zero/one/three-hash raw strings, line/block comments, and string-contained lookalikes, then reran the full 353-file scan, shell syntax, Python AST parsing, and diff check. Independent review found that the source guard's initial regular expression could miss raw-string ignore reasons and treat a commented attribute as real. Final head `42097c0136ab3fa8f0efe5720ae829c04575b9b6` parses valid ordinary/raw Rust string literals only at attributes found in comment-sanitized source; regression fixtures cover both cases. The fixture suite, Python compilation, shell syntax, diff check, and full 353-file repository scan pass on Blox. ## Update — August 25, 2026 restack PR #6660 merged, so this follow-up was rebased from its former exact parent onto current `origin/main` (`8d2d0ff5ad42733e9949442c4b6358d0ba87f9a8`). The final candidate head is `05dcc2ab28948e3ab79bb44839a69f2ba44648a2`; the PR no longer carries #6660's pre-squash history. Fresh exact-head verification on Blox workstation `2028572`: - Discovery guard passed across 353 Rust files; inventory remained exactly 282 intended PostgreSQL tests. - PR #6660 focused persistence tests: 4/4 passed. - Full PostgreSQL lane: 282/282 passed three times; 1,243 skipped each run; wall time 9.70–9.87s. - `cargo fmt --all -- --check` and all-target/all-feature clippy for `buzz-db`, `buzz-deletion`, and `buzz-relay` passed. ## Update — August 25, 2026 final hosted verification - [GitHub PostgreSQL Tests](https://github.com/block/buzz/actions/runs/32801679226/job/97667835080): 282/282 passed in 53.787s; 1,243 skipped. - The final guard scanned all 353 Rust files successfully before the hosted lane ran. - The shared relay/archive prerequisite and infrastructure-free Unit Tests job both passed at exact final head `42097c0136ab3fa8f0efe5720ae829c04575b9b6`. --------- Signed-off-by: Luke Tornquist <tornquist@squareup.com> Signed-off-by: tornquist <tornquist@squareup.com> |
||
|
|
0affe527e8 |
fix(model-capabilities): humanize databricks goose model names (#7135)
🤖 ## Summary - add curated human-readable labels for Databricks Goose models that otherwise render as fully qualified identifiers - render `data_workflow_tools.goose.goose-glm-5-3` as `GLM-5.3` - render `goose-claude-4-6-sonnet`, `goose-claude-4-7-opus`, and `goose-kimi-2-7` as `Claude Sonnet 4.6`, `Claude Opus 4.7`, and `Kimi 2.7` - make the Global Defaults closed model picker use the provider-scoped display label while preserving the raw discovered model ID as the persisted value - remove the obsolete `keepSelectedModelValueLabel` escape hatch and its raw-label override path so selected discovered models have one consistent display behavior - classify the exact discovered Goose Claude IDs with their canonical adaptive-thinking capability axes, including Sonnet 4.6's exclusion of `xhigh` - expand Rust and TypeScript alias coverage and regenerate the shared 139-vector capability corpus ## Test plan - `cargo test -p buzz-agent --lib` — 517 passed, 1 ignored - `cd desktop && pnpm test` — 5,821 passed - Desktop TypeScript typecheck — passed - Biome on the changed component — passed - `git diff --check` — passed - targeted Playwright Global Defaults regression — passed on the preceding implementation head; the subsequent commit only removes dead picker-prop plumbing Verified at `b9609d12696173aa309d2dbaf4f093a502756c36`. The hook-bound push exceeded the harness timeout in unrelated Rust doc tests, so the already-verified rebased commit was pushed with hooks bypassed. Follow-up to #6955. --------- Signed-off-by: Kalvin Chau <kalvin@block.xyz> Co-authored-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> |
||
|
|
93237b4a74 |
fix(acp): wake agents from workflow messages (#6953)
> Pinky, an AI agent, is opening this PR on Wes's behalf.
## Summary
Workflow-generated messages can contain a valid agent mention but still
fail the ACP inbound author gate because the relay signs the event. This
keeps the existing wake policy and gives ACP a narrowly verified
effective author:
- preserve the workflow owner's existing `p` tag and all
rendered-mention `p` tags
- add explicit `["buzz:workflow-owner", <owner hex>]` provenance to
relay-generated workflow messages
- add `["buzz:workflow-mention", <agent hex>]` authority only for
mentions resolved from the stored, unrendered workflow step template
- accept that owner only for a verified kind-9 event signed by the
relay's current NIP-11 `self` key, with unique canonical workflow
metadata and an explicit workflow mention for the receiving agent
- route the verified owner through the existing author and in-flight
mode policies in both normal and setup listeners
- refresh relay identity after reconnects, retaining the last verified
key on transient fetch errors while treating a successful response
without `self` as definitive removal
Malformed, duplicate, forged, tampered, wrong-kind, and wrong-relay
attribution all fail closed to the raw event signer. `respond-to=nobody`
remains absolute. Old/mixed-version messages without the explicit
provenance retain their current fail-closed behavior.
## Trust boundary
The workflow owner means **“scheduled by,” not “authored every rendered
word.”** Trigger-controlled substitutions may still produce ordinary `p`
mention routing for compatibility, but they cannot mint
`buzz:workflow-mention` authority. Only a target named in the durable
owner-authored step template can receive that authority.
The author gate is not bypassed: after relay signature/provenance
verification, the effective owner is evaluated under the same
`owner-only`, `allowlist`, DM, and `nobody` policies used for ordinary
messages. Owner control commands continue to use the raw event signer.
## Why this PR
This is the focused immediate fix for waking an **online** agent from a
stored workflow mention. Earlier attempts were not a finished mergeable
fix and had materially different or incomplete trust designs. Larry's
larger draft stack addresses durable delivery across restarts; that
remains valuable future work and can supersede this effective-author
path when it lands.
## Validation
At exact clean commit `fe5b55619fe44176343eefb4cb7fe180df45a7d8`:
- `buzz-relay workflow_sink`: 25/25 passed, including all four ignored
PostgreSQL cases
- `buzz-acp --lib`: 845/845 passed
- `buzz-workflow --lib`: 169/169 passed (2 unrelated PostgreSQL tests
ignored)
- warnings-denied Clippy passed for the changed Rust packages
- `cargo fmt --all -- --check` passed
- `git diff --check` passed
- repository pre-push gates passed, including branch-scoped Rust tests
- CI now selects the ACP library tests and the relay's pure + PostgreSQL
workflow-sink tests so these guards cannot silently remain unexecuted
The production event-to-author gate is shared by normal and setup
listeners and has biting regression tests for accepted explicit
attribution, legacy owner-`p` rejection, and forged-attribution
rejection.
## Exact-head local relay + ACP proof
Following the release-binary/local-relay shape in `TESTING.md`, the
exact commit above passed a fresh isolated real-process matrix using:
- a freshly recreated Postgres database with migrations
- isolated Redis
- exact-head release `buzz-relay`, `buzz`, `buzz-admin`, and `buzz-acp`
binaries
- newly provisioned owner, channel, and bot member through the CLI
- workflow creation and triggering through the running relay
- a deterministic ACP protocol subprocess capturing actual
`session/prompt` dispatches
- a NIP-11 `self` value verified against the running relay signer
Cases:
1. A stored explicit workflow mention woke an `owner-only` agent exactly
once.
2. A workflow message without an agent mention did not wake it.
3. A non-relay signer forging every workflow authority tag did not wake
it.
4. Trigger-controlled `{{trigger.text}}` containing `@Wake Agent`
retained ordinary `p` routing but received no authority-bearing
workflow-mention tag and did not wake the agent.
5. `respond-to=nobody` remained absolute for a valid relay-authenticated
workflow mention.
The deterministic ACP subprocess isolates and directly proves relay →
ACP authorization and prompt dispatch without depending on external
model behavior.
## Deployment and residual risk
Relay and ACP changes must be deployed together for the new wake
behavior; mixed versions fail closed. Production paired-deployment proof
remains distinct from the successful local integration run. Setup-mode
behavior has automated coverage but was not a separate case in the
five-case local matrix. Relay-key rotation is observed at ACP
startup/reconnect; transient NIP-11 errors retain the last verified key,
an intentional availability tradeoff documented in code.
---------
Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Co-authored-by: LioLionel <62820906+LioLionel@users.noreply.github.com>
Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
|
||
|
|
c432a111ca |
feat(mobile): push notifications MVP (#6269)
This PR implements MVP, iOS-only,
[NIP-PL](
|
||
|
|
ae0ecd9a67 |
feat(model-capabilities): humanize Databricks UC model families (#6955)
Chat-eligible Unity Catalog models from the Gemini, DeepSeek, GLM, Grok, Llama, Qwen, Gemma, and Inkling families were rendering as raw FQNs such as `system.ai.gemini-3-5-flash` in the agent model picker. #6918 surfaces these models, but the capability manifest carried no records for most of them and the registry-label path could not strip their Unity Catalog or `goose-` prefixes. I added a display-only `label_family_tokens` list and `databricks_v2` exact records for the sixteen previously unlabeled endpoint stems. All 26 target FQNs and their `goose-` aliases now resolve to curated labels through `databricks_registry_label`, while capability resolution continues to use only the existing `family_tokens` (`claude-`, `gpt-`, and `kimi-`). This keeps label discovery from changing capability profiles for unrelated model IDs. Each new record includes reconciliation metadata against the pinned [models.dev catalog](https://models.dev/api.json). Nine records adopt first-party effort evidence that the Databricks MLflow Chat transport can express: Gemini 3.5 Flash, Gemini 3.5 Flash Lite, Gemini 3.6 Flash, Gemini 3 Pro Image, DeepSeek V4 Flash, DeepSeek V4 Pro, GLM-5.3 Flash, Grok 4.6, and Inkling. The remaining seven deliberately retain the `databricks_v2/concrete_unknown` fallback because upstream evidence is absent, identifies a non-reasoning model, or provides only toggle/token-budget controls that `reasoning_effort` cannot represent. The normative corpus adds the sixteen exact records, four Unity Catalog alias probes, and two capability-isolation probes. Existing base vectors remain unchanged, and Rust and TypeScript consume the same strict manifest and corpus. Related: #6918 --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Thufir <7ebdb0b67dab08a570b9faf7bbada97535673b4ccaba2cbd546ad3ba84c87fa6@buzz.block.builderlab.xyz> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: Thufir <7ebdb0b67dab08a570b9faf7bbada97535673b4ccaba2cbd546ad3ba84c87fa6@buzz.block.builderlab.xyz> |
||
|
|
0ccf934b88 |
fix(db): disable heartbeat vacuum truncation (#6898)
## Why `replica_heartbeat` is updated continuously, but autovacuum heap truncation can take an `ACCESS EXCLUSIVE` lock whose replay cancels concurrent hot-standby reads. Truncating a fixed, single-row table provides no meaningful space benefit. ## What - Add migration 0034 to set `vacuum_truncate = false` on `replica_heartbeat` - Keep the desired-state schema aligned for fresh installations - Extend migration coverage so both paths retain the reloption ## Risk Assessment Low — this disables only autovacuum's heap-truncation phase for a single-row table; normal vacuum cleanup remains enabled. The tradeoff is retaining at most the table's otherwise-truncatable tail pages. ## References - [Investigation thread](https://sq-block.slack.com/archives/C0B2WT43BDH/p1787760831375989) - [PostgreSQL table storage parameters](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-STORAGE-PARAMETERS) Generated with Codex --- **Update Aug 27, 2026:** Hardened fresh `pgschema` bootstraps after review. - Renamed the shared post-apply script to `reconcile-schema-after-pgschema.sql` and made it restore the heartbeat reloption and singleton row idempotently. - Added live catalog and row assertions that stop bootstrap when the database does not match the required state. - Updated every repository `pgschema apply` caller, including the desktop release smoke path. - Added a regression test that requires future `pgschema apply` callers to run reconciliation. - Documented the `pgschema` DML and storage-parameter limitation in `AGENTS.md` and at the reconciliation entry point. - Merged current `main` and renumbered this migration to 0034 after `main` added migration 0033. --------- Signed-off-by: Luke Tornquist <tornquist@squareup.com> |
||
|
|
820a858997 |
fix(release): attribute desktop candidates to the operator (#6831)
The desktop release tooling hardcoded one contributor's personal identity into every release candidate commit. `scripts/prepare-desktop-release.sh` committed the candidate with a `git -c user.name='Wes' -c user.email='wesbillman@users.noreply.github.com'` override, and `scripts/desktop_release.py` `validate` required the candidate author to be exactly `Wes <wesbillman@users.noreply.github.com>` plus a matching `Signed-off-by` trailer. That leaked from Wes's working setup into the validation contract in #3568, so a release cut by any other operator was falsely attributed to and signed off by Wes (as happened on #6828). ## Change - `prepare-desktop-release.sh`: drop the `-c` identity overrides so `git commit -s` uses the operator's own configured identity to author and sign off the candidate. The automation `Co-authored-by` trailer is unchanged. - `desktop_release.py` `validate`: replace the exact-Wes checks with structural ones — the commit author must be non-empty, the body must contain a `Signed-off-by` trailer whose name and email match the commit author (honest DCO), and the existing automation `Co-authored-by` regex check stays. Failure messages remain specific. - `test-desktop-release-candidate.sh`: the fixture candidate now commits under the harness's own identity, and a new negative case rewrites the author to a mismatched identity and asserts the validator rejects it. Release authorization is bound to the merged PR via the GitHub API in `scripts/verify-desktop-release-merge.sh`, never the commit author field, so this does not weaken the trust model. `RELEASING.md` and `.github/workflows/desktop-release-candidate.yml` reference no author identity and need no change. Verified locally: `scripts/test-desktop-release-candidate.sh` passes, including the new sign-off/author-mismatch rejection. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> |
||
|
|
cae7f826b3 |
fix(ci): check out source in docker.yml merge job (#6833)
## Problem Every `docker.yml` run on `main` has failed since [#6781](https://github.com/block/buzz/pull/6781) merged. That PR added a "Create deployment eligibility predicate" step to the `merge` job, which runs `jq` against `$GITHUB_WORKSPACE/scripts/create-deployment-eligibility-predicate.jq`. But the `merge` job has no `actions/checkout` step — the workspace is empty, so `jq` can't open the file and exits `2` (`jq: Could not open ... No such file or directory`). The `build` and `qualify` jobs each check out the source; `merge` never needed one until this step was added. ## Fix - `.github/workflows/docker.yml`: add `actions/checkout` (same pinned SHA as the other jobs, `df4cb1c` / v6.0.3) as the first step of the `merge` job. - `scripts/test-relay-image-eligibility-workflow.sh`: guard the regression by asserting the `merge` job checks out the source before building the predicate. ## Verification CI cannot exercise the `merge` job on a pull request — the job is gated `if: github.event_name != 'pull_request'`, so it only runs on push to `main`. The proof is the root cause (missing checkout for a step that reads a repo file) plus the eligibility workflow test: `scripts/test-relay-image-eligibility-workflow.sh` passes with the fix and fails with the new guard's specific message (`merge job must check out the source before building the eligibility predicate`) when the checkout is removed. Signed-off-by: Will Pfleger <pfleger.will@gmail.com> |
||
|
|
ee6ca5fa28 |
Remove public relay signing key fallback (#6729)
Require `BUZZ_RELAY_PRIVATE_KEY` on every relay startup and remove the shared public fallback key completely. For local development, `just bootstrap` now generates a random key once in the gitignored `.env` file. Re-running bootstrap preserves that key, so relay-authored events retain the same identity across restarts. The local relay recipes reload `.env`, while isolated CI and E2E launchers pass explicit per-run keys. Startup fails immediately when the key is missing or invalid, before connecting to Postgres or Redis. Deployed relays continue to receive their stable key from the existing chart-managed secret. Validated with: - `./scripts/test-ensure-local-relay-key.sh` - `cargo test -p buzz-relay --bin buzz-relay` - `cargo clippy -p buzz-relay --bin buzz-relay -- -D warnings` - `cargo fmt --all -- --check` - `shellcheck scripts/ensure-local-relay-key.sh scripts/test-ensure-local-relay-key.sh` Signed-off-by: Jordan Mecom <jm@squareup.com> |
||
|
|
f249710331 |
Qualify canonical relay images for staged delivery (#6781)
## Why Phase 1 of progressive delivery needs an explicit eligibility boundary before deployment automation can safely consume relay artifacts. Today the canonical Docker workflow can publish independently of the same-SHA CI result, the relay does not expose its source/build identity, and the Helm chart only renders mutable tags. The existing `ghcr.io/block/buzz-staging-dev` workflow in #6709 remains a manual pre-merge preview lane. It is deliberately not a canonical promotion input. ## What changed - Compile the full source SHA and GitHub Actions build identity into canonical relay binaries and expose it at `/_status`. - Gate creation of tagged multi-architecture manifests on the latest exact-SHA `CI` push run succeeding on `main` or `release`. - Preserve the signed SLSA provenance and add a signed, release-only deployment-eligibility predicate with source, build run, qualifying CI run, and exact compatible Buzz chart version. - Keep failed or pending builds untagged and without an eligibility predicate; preview-package artifacts are excluded by package and signer contract. - Add optional `image.digest` support to Buzz chart `0.1.8`, retaining the existing tag fallback. - Document verification and the intentional boundary between image/chart compatibility and backwards-compatible database migrations. ## Risk and rollout Canonical tag publication now waits for same-SHA CI and fails closed when the newest matching run fails. Per-architecture blobs may remain untagged after a failed qualification; they are not promotion inputs. Debug manifests are also CI-gated but do not receive the release eligibility predicate. There are no migration or schema-orchestration changes. The companion BuilderBot infrastructure PR will pin a separately verified canonical main digest and expose a read-only running-deployment inspection command. Signed eligibility is available only for artifacts published after this workflow lands. ## Verification - Blox: workflow contract fixtures, including stale-green rejection and predicate structure - Blox: `actionlint` for `ci.yml` and `docker.yml` - Blox: 46 Helm unit tests, chart lint, and production/quickstart render fixtures - Blox: relay status unit test, workspace Rust formatting, and workspace all-target clippy - Live evidence: exact-SHA CI selector chose successful run `32857345153` for source `9d1e4b257657f382d3111ce748f3da8d063b7671` - Existing canonical digest provenance verified with `gh attestation verify` ## References - #6709 — developer-preview precursor; intentionally separate from canonical eligibility - `docs/deployment-identity.md` *Generated with Codex* --------- Signed-off-by: Luke Tornquist <tornquist@squareup.com> |
||
|
|
69b1225923 |
fix(ci): prevent poisoned Rust caches (#6618)
## Summary - roll every `Swatinem/rust-cache` use back from v2.9.2 to the last known-good v2.9.1 digest - give Unit Tests a new `sherpa-cache-v1` key so it cannot restore the existing poisoned artifact - pin Renovate to v2.9.1 and add CI contracts that reject unsafe cache actions or a misplaced generation key ## Why After #5441 upgraded rust-cache to v2.9.2, warm-cache `main` Unit Tests runs began failing while linking `buzz-voice` with `could not find native static library sherpa-onnx-c-api`. The failed run at `db5617dd1` restored the same 1.4 KB cache generation that had already failed at `01091c15a`; the preceding cold run at `26f4c3ed3` downloaded sherpa 1.13.4 and passed. v2.9.2 changed target cleanup, while `sherpa-onnx-sys` treats its prebuilt `lib/` directory as proof that the native archive exists. Rolling back the action and invalidating the affected key removes both sides of that failure state without disabling target caching. ## Validation At `6da0037a0407fc498cd482fcbbb74c7a15907e9f`: - `scripts/test-rust-cache-contract.sh` - `scripts/test-rust-cache-contract-regressions.sh` - negative fixtures reject a bad digest in a newly named `.yaml` workflow and a generation key moved outside the cache action's `with` block - YAML parse for all workflows - release, desktop candidate, mobile release, mobile candidate, and mobile worktree source contracts - `just file-size-check` - pre-commit and pre-push hooks The PR Unit Tests run proves the cold-cache path because pull requests restore but do not save Rust caches. The first successful `main` run after merge will save the new Unit Tests key; the following `main` run will exercise the warm restore. ## Related issue None found. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> |
||
|
|
8c0f42e187 |
Add mobile Huddles voice MVP (#6056)
## 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> |
||
|
|
24ec6a468e |
Repair stale large channel roster snapshots (#6251)
## Summary - detect relay-authored NIP-29 kind 39002 roster snapshots truncated by the former 1,000-member query cap and repair stale large rosters during relay startup - serialize canonical roster capture and replacement with membership writes, preserving tenant, channel, signer, pubkey, and role boundaries through mixed-version deployments - install migration 0032's fail-closed roster fence on the partitioned events table and verify its catalog shape plus behavior before opening relay listeners ## Rollout Migration 0032 is a hard schema-before-code compatibility boundary. Apply migrations before rolling this relay version. Startup refuses to open listeners when the parent/partition triggers are missing, disabled, mis-shaped, or behaviorally inert. For large installations, prefer `buzz-admin migrate` and monitor lock acquisition as documented in the chart README. ## Validation Exact head: `bcbba271f54bc0046a6683007e5a2b70403a11d5` - rebased onto `569308c23c9c2bf620dd3a9a5e4baecbcfa22e16`; the nine-file feature patch is byte-identical to pre-rebase head `be8ea0084f4d4c78c7c2550baad4399e4df8ce73` - pre-push hook passed at exact head: branch-skew, file-size, full Rust unit suite, Desktop Tauri clippy, and Desktop Tauri tests - `cargo fmt --all -- --check` - `cargo test -p buzz-relay group_members_snapshot_keeps_members_past_one_thousand -- --nocapture` - focused CI-mode Playwright regression: `selected relay agents revoked after the invite prompt cause no side effects` passed at exact head - prior exact-patch validation: `large_roster_reconciliation_candidates_respect_snapshot_count_and_signer`, mixed-writer locking/rollback, migration admission, partition trigger coverage, and desired-schema parity regressions ## Review Independent DB/relay review found no blocking issues in the exact feature patch. The concurrency fence holds the established replacement and membership locks on one transaction/connection through replacement; failures roll back both soft-delete and insert. Reconciliation remains tenant/channel/signer scoped and validates exact normalized pubkey-plus-role membership. The prior red Desktop shard was unrelated to this backend-only diff: its mocked mention test exercises no relay, database, or migration path. It reproduced as a timing flake on the old head, passed on retry/base, and now passes locally after rebasing onto current main. --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> |
||
|
|
cd0d33f085 |
fix(hooks): scope pre-push lanes to branch merge-base diff (#6423)
Lefthook selected pre-push lanes from the file set `git diff --name-only
HEAD @{push}` returns, which is overinclusive two different ways:
- **Rebase/merge poisoning.** `@{push}` is a two-dot diff against the
branch's last-pushed tip. After a rebase onto newer main — or the `git
merge origin/main` that `check-branch-skew.sh` itself instructs agents
to run — that diff includes everything `main` changed since the last
push, so `mobile-checks`, the `desktop-*` lanes, and `rust-tests` fire
on branches that never touched those trees (a recent relay-only push
discovered 266 files, 26 of them `mobile/`).
- **Brand-new branch in a worktree.** When `@{push}` doesn't resolve,
lefthook reads `$GIT_DIR/refs/remotes/origin/HEAD` — which doesn't exist
in a linked worktree's git-dir — then falls back to the
alphabetically-first `HEAD ->` remote. In a clone with a stale
third-party remote sorted before `origin`, that diffs against a frozen
tip and runs the full suite. All agent work happens in worktrees.
## Fix
Add `files: git diff --name-only origin/main...HEAD` to the six globbed
pre-push lanes (`rust-tests`, `desktop-check`, `desktop-typecheck`,
`desktop-test`, `desktop-tauri-checks`, `mobile-checks`). The three-dot
form is the branch's merge-base diff against `origin/main` — the same
base resolution `scripts/check-file-sizes-core.mjs` (`resolveBaseRef`)
and CI's dorny/paths-filter already use. A lane now fires only when this
branch actually changed a file it covers; `main`-side changes never
re-trigger it, and a new branch diffs against `origin/main` (empty diff
→ all globbed lanes skip) rather than a stale remote. `branch-skew` and
`file-size-check` stay unfiltered by design.
Also pin hook dispatch to the Hermit-managed lefthook. The generated
`.git/hooks/*` dispatchers prefer `$LEFTHOOK_BIN`, then a `lefthook` on
`PATH` — so a Homebrew lefthook shadowed the pinned 2.1.3. A `rc:
bin/.lefthookrc` (a lefthook config key `lefthook install` bakes into
every dispatcher) exports `LEFTHOOK_BIN` to `bin/lefthook`, so a push
runs the pinned version regardless of `PATH`. `just hooks` already runs
`lefthook install`, so re-running it picks up the `rc` line — no recipe
change needed.
`AGENTS.md` documents that lanes are scoped by merge-base diff and that
agent shells should lead `PATH` with `./bin` so pinned tools win.
## Verification
Reproduced both bugs in a scratch repo mirroring the worktree +
stale-remote topology, with lanes stubbed to echo on selection:
- **Bug 1:** relay-only branch, `git merge origin/main` (main carried
`mobile/` + `desktop/` changes). Without the fix, `desktop-check` and
`mobile-checks` fired; with it, three-dot diff = only the relay file,
all globbed lanes skip.
- **Bug 2:** brand-new branch, no upstream, in a linked worktree with an
alphabetically-first stale remote. Confirmed `@{push}` is `fatal`,
`refs/remotes/origin/HEAD` is absent from the worktree git-dir, and the
stale remote's `HEAD ->` sorts first. Without the fix it fired lanes off
the stale tip; with it, lanes scope to `origin/main` merge-base and
skip.
- **Positive controls:** a `mobile/**` commit still fires
`mobile-checks`; a `crates/**` commit still fires `rust-tests` +
`desktop-tauri-checks`.
- **Dispatch:** with Homebrew lefthook 2.1.10 on `PATH`, running the
real generated `.git/hooks/pre-push` under `LEFTHOOK_VERBOSE=1` shows it
sourcing `bin/.lefthookrc`, exporting `LEFTHOOK_BIN`, and running
`lefthook v2.1.3`.
- This PR's own push (a brand-new branch in a linked worktree — the bug
2 case) ran only `branch-skew` and `file-size-check`; no
mobile/desktop/rust lanes fired, since the branch touches only
`lefthook.yml`, `AGENTS.md`, and `bin/.lefthookrc`.
---------
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>
|
||
|
|
2ce8df8533 |
fix(models): curate Databricks alias-aware labels for 5 missing endpoints (#6360)
Curates Databricks model labels through prefix-stripping aliasing and materializes exact records for five endpoints missing from the Databricks catalog. **Alias-aware label resolution** (Databricks v2) - Strip workspace-specific prefixes (`goose-`, `team-x-`, etc.) before exact-record lookup so any prefixed alias resolves to its canonical label without enumerating every alias variant. - Return `None` for uncurated ids instead of falling back to a raw string; callers control the fallback display. **New exact records — label-only (Anthropic Messages route, axes from family rules)** - `databricks-claude-fable-5` → "Claude Fable 5" (materialized from `anthropic-adaptive-xhigh-fable-5`) - `databricks-claude-opus-4-8` → "Claude Opus 4.8" (materialized from `anthropic-adaptive-xhigh-opus-4-8`) - `databricks-claude-opus-5` → "Claude Opus 5" (materialized from `anthropic-adaptive-xhigh-opus-5`) - `databricks-claude-sonnet-5` → "Claude Sonnet 5" (materialized from `anthropic-adaptive-xhigh-sonnet-5`) **New capability-bearing record — Kimi K3 (MLflow Chat route)** - `databricks-kimi-k3` → "Kimi K3" with axes from models.dev Moonshot catalog: reasoning toggle + effort `[low, high, max]`, no default; `_reconciliation_doc` records the source and reconciliation policy. **Corpus and tests** - 6 new normative-corpus vectors (canonical + one `goose-*` alias per new id); executable vector count updated to 113 in both Rust and TS gates. - Rust and TS label tests extended to cover all 3 new canonical ids and their aliases via the prefix stripper. - Sentinel variable fix in discovery-provider test to prevent false failure in Databricks dev environments where `BUZZ_AGENT_PROVIDER` is set. --------- 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> |
||
|
|
40f1dac691 |
Refine mobile pairing confirmation (#6018)
## Summary - align the mobile security-code confirmation screen with the Add Community visual system while keeping the SAS verification flow unchanged - use “Confirm desktop code” and a 15% primary-color outline on each digit box - support a gitignored, debug-only Android app name and application ID override for side-by-side device testing; release and profile identities remain unchanged ## Validation - `flutter test test/features/pairing/pairing_page_test.dart` (21 tests) - full mobile pre-push suite (1,469 tests) - focused Flutter analysis and formatting - mobile worktree identity contract checks --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
4f9727a4b3 |
chore(scripts): add buzz-adopt-prod-agents.sh (#6250)
Adds `scripts/buzz-adopt-prod-agents.sh`, which copies the installed-DMG (production) agent records and owner identity into the dev app-data store so a dev build boots as the **same agents and same owner npub** as the installed app — surviving `just reset`. ## What it restores `just reset` wipes the two things Buzz cannot re-derive: - The agent **records** — `managed-agents.json`, `personas.json`, `teams.json`, and `agents/teams/`. - The **owner identity** nsec, written as `identity.key` (0600, atomic). Agent private keys and identity-key adoption then happen automatically on the next dev boot via the shipped in-app migrations. ## When to run it 1. Quit any running **dev** build. A running installed DMG is fine — the script treats it as a read-only source and only warns against creating/archiving agents or editing teams while it runs. It never kills processes. 2. Run `just reset`. 3. Before the first dev boot, run `bash scripts/buzz-adopt-prod-agents.sh`. - `--dry-run` prints every action with zero writes. - `--force` overwrites an already-populated dev store. - One keychain prompt is expected (reading the prod owner identity). 4. Start the dev build. First boot copies the agent keys prod→dev and adopts `identity.key`, then deletes it. For worktree launches, export `BUZZ_SHARE_IDENTITY=1` (and `BUZZ_PRIVATE_KEY`) or the worktree mints its own duplicate agents. ## Running-process check Only a running **dev** build blocks the run: the script atomically swaps the entire dev `agents/` directory and stages `identity.key` for the next dev boot to consume, so doing that under a live dev process is the corruption the check must prevent. A running installed DMG is allowed — the app writes `managed-agents.json` via tmp+atomic-rename, so it can never hand the script a torn file. Each matching `buzz-desktop` PID is classified by its true post-exec executable path (via `lsof -d txt`, which reports the running vnode with symlinks already resolved); the installed `/Applications/Buzz.app/Contents/MacOS/buzz-desktop` path is the only allow. Anything else still alive blocks fail-closed; a PID that exits before its path can be resolved is ignored. ## Requirements Requires `python3` when a dev `agents/` already exists — it drives the `renamex_np(RENAME_SWAP)` syscall bash cannot call. The script fails in preflight with a clear message if `python3` is absent, never mid-commit. ## Safety Prod is strictly read-only; symlinked or aliased prod/dev roots are refused before any write. The records/identity restore commits in one atomic operation (`renamex_np(RENAME_SWAP)` when a dev store exists, a single `mv` when absent) that fails closed — a crash or I/O error leaves `agents/` either fully old or fully new, and unrelated live dev state (`logs/`, `agent-pids/`, `global-agent-config.json`, retention stores) is preserved verbatim across the swap. This is a temporary measure while we trial it and decide whether to port the logic into the dev-build startup path. Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> |
||
|
|
6d45f98665 |
ci: make file-size policy a first-class gate (#6187)
## Summary - make the differential file-size ratchet a first-class repository gate - run the same unfiltered gate from pre-push, `just check`, and CI - remove hidden file-size coupling from Desktop, Web, and Mobile lint commands - isolate ratchet Git subprocesses from hook-exported repository state ## Why The Desktop ratchet grew to govern `desktop/src-tauri/crates/**`, but the pre-push `desktop-check` command remained path-filtered to non-Tauri files. That contract drift allowed a Tauri Rust file-size regression through local validation. The ratchet already computes its own merge-base diff, so duplicating governed paths in Lefthook and CI adds drift risk without meaningful runtime savings. One root gate owns the policy now. ## Testing - `just file-size-check` - oversized untracked probe under `desktop/src-tauri/crates/**` fails with the 1,000-line ceiling - file-size core tests with hook-style `GIT_DIR` / `GIT_WORK_TREE` environment - `lefthook dump` confirms the unfiltered pre-push command - mandatory pre-push suite passed on `3217003db10c84d8a0c5f636ec4c92936777a002` - `git diff --check` Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
1b7e5ac1be |
feat(model-capabilities): drive model capabilities and labels from one manifest (#5597)
## Summary Centralizes model capability knowledge — thinking mode, supported effort levels, wire routes, and human-readable labels — into a single manifest, `scripts/model-capabilities.json`. Rust and TypeScript each get a small interpreter that reads the same manifest, replacing hand-maintained tables scattered across both languages that had already drifted apart. A capability change is now a data edit, not parallel edits to two code paths. Supersedes the codegen approach explored in #3603. A cross-language contract keeps the two interpreters honest: `scripts/normative-corpus.json` is a golden snapshot generated from the Rust resolver (103 vectors covering all six capability axes) and replayed natively in TS. CI fails if either language disagrees with the corpus or the corpus drifts from the resolver. Regenerate with `just regen-model-corpus`. ## Behavior changes - **Effort dropdown for `openai-compat` providers** no longer offers `max`. The request path always clamped `max` to `xhigh` on the wire, so the UI stops offering a value that was silently rewritten. UI-only, wire-identical. - **Databricks v2 routing (wire-visible):** uncurated endpoint names carrying a bare Claude code-name segment (e.g. `goose-opus-5`) now route to the MLflow chat wire instead of Anthropic Messages — they lose Anthropic prompt caching but still succeed on a valid OpenAI-compatible wire. Curated `databricks-claude-*` records and any name starting with `claude` are unchanged. A handful of other uncurated/adversarial name shapes similarly fall back to MLflow chat instead of pattern-matched routes; every curated model resolves identically to before, all axes. - **Curated model labels on the real discovery path.** The Databricks API returns no display name, so discovery emits the raw endpoint id as the model `name` (`{id, name: id}`) on every path. `ModelEntry.name` is now curated at all four construction seams in `buzz-agent` — v2 discovery, v1 parse, the auth-empty default catalog, and the configured-model fallback — via a read-only `databricks_registry_label` lookup over the manifest's `databricks_v2` exact records; `id` stays the raw wire/config value. A known id renders its curated label (`databricks-gpt-5-5` → `GPT-5.5`), an unknown id passes through unchanged, and the default-catalog row reads `GPT-5.5 (default catalog)`. As a defense against older `buzz-agent` binaries and any harness that echoes ids, `resolveModelLabel` treats a discovered name equal to the trimmed id as absent and falls through to the registry tier; a genuinely distinct name (including the suffixed default-catalog label) still wins. ## Cleanup Deletes the duplicated capability tables and their tests: the `config.rs` gpt5 matchers, effort tables, and clamp logic; the legacy segment-based Databricks v2 route classifier in `llm.rs`; and the TS hand tables plus `effortTable.fixture.json`. All are replaced by manifest lookups through the shared resolver — no line of capability data exists in two places. --------- 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> |
||
|
|
122a8b8988 |
Projects v3: unify sharing, discussions, and issue ownership (#5792)
## Summary Projects v3 makes repository work shareable, discussion-aware, and easier to scan in one coherent workspace. People can copy canonical links, reopen the exact workspace tab, understand issue and pull-request context at a glance, find related channel conversations, and assign or unassign issues across Desktop and CLI. - **Unified workspace** — top-level sections sit above repository controls in one rounded workspace, with navigation positioned close to the page heading. README and Files retain branch selection; every section has a labeled icon header, and Issues and Pull Requests expose creation from a consistent right-aligned action. - **Repository management** — the repository selector is always available, including single-repository projects. Its integrated add flow lets project owners create a repository manually or select an existing repository without a separate toolbar button. - **Readable work-item lists** — issue and pull-request rows use plain-language context instead of opaque metadata. Files, commits, issues, pull requests, channels, and contributors share consistent row density and right-aligned timestamps, while deterministic fallback-avatar colors keep participants distinct on light backgrounds. Inbox pull-request metadata wraps between complete phrases and truncates long channel names instead of compressing copy into narrow columns. - **Reliable entity links** — projects, repositories, issues, pull requests, and commits have canonical `buzz://` links, preview cards, OS deep-link routing, and tab-aware navigation. Reopening the same link re-applies its destination instead of leaving the user on a locally selected tab. - **Related conversations** — repository and work-item views surface channels discussing the current entity, including participants, channel navigation, message context, and an explicit notice when discovery reaches its 500-result cap. - **Reversible issue ownership** — trusted assignment and unassignment events work across Desktop, Tauri, `buzz-sdk`, and `buzz issues`. Assignees appear in project views and the assigned inbox, while authorized users can remove assignments directly from the assignee row. Assignment state is derived chronologically from labeled Nostr notes. Issue authors and repository owners may change any assignee; other users may only assign or unassign themselves. Shared golden fixtures keep entity-link grammar and validation aligned across TypeScript and Rust. The branch also updates `webbrowser` to the patched release for RUSTSEC-2026-0257. ### Related issue N/A. ### Testing - [x] `just ci` — formatting, lint, typechecking, unit tests, and builds passed - [x] Full pre-push suite — organization, branch-skew, Desktop checks, typechecking, and tests passed on the latest push - [x] `cargo test -p buzz-cli` and focused `buzz-sdk` assignment tests passed - [x] Focused Tauri recipient-note and 500-result search-limit tests passed - [x] Desktop entity-link and issue-assignment unit tests passed - [x] Playwright smoke coverage passed for assignment, repeated entity-link navigation, repository create/select flows, section headers and actions, timestamp alignment, timeline icons, sentence-style issue/PR metadata, header spacing, avatar contrast, and Inbox metadata at stacked and side-rail breakpoints - [ ] Manual staging pass: link round-trips, Channels tab, assignment flows, and inbox routing ### Screenshots Pull requests explain who opened the request, where it lives, and which branch it comes from; fallback avatars remain visually distinct.  Issues use the same sentence-style hierarchy while keeping status and recency easy to scan.  The wide Inbox detail keeps author, timestamp, and origin context readable beside its metadata rail.  [View the complete six-state Projects v3 screenshot set](https://github.com/block/buzz/pull/5624#issuecomment-5268039672) and [the compact/wide Inbox comparison](https://github.com/block/buzz/pull/5624#issuecomment-5268614585). --- > Supersedes #5624, whose head commit accumulated permanently-queued required check suites (block-dco-check et al.) that GitHub never dispatched. History flattened into a single signed-off commit on latest main; tree verified byte-identical (`git merge-tree`) to merging the original branch into main. --------- Signed-off-by: Thomas Petersen <thomasp@squareup.com> Co-authored-by: Wintermute <3f1797424fd9ad6653a83665c660517777cd7f8c228c0d5907f49e01537f3ca5@buzz.block.builderlab.xyz> |
||
|
|
76f114a252 |
test: add deterministic desktop release smoke (#5699)
## Summary - add `just desktop-release-smoke`, a deterministic desktop correctness/reachability smoke against an ephemeral real local relay - preserve existing DM history when the first live DM enters a pageless query window, the desktop-v0.5.10 disappearing-DM regression - enforce foreground JS ordering: a frame and actionable sidebar input must dispatch before mounted stale queries begin resume refetches, while separately requiring the navigation to commit promptly - seed a 10,000-event dense-second fixture and verify exact event-ID reachability, SHA-256 identity, ordering, duplicate absence, bounded mounted rows, and drained render work - isolate Postgres per run, serialize the shared Redis DB, retain phase/relay/Playwright diagnostics, and gate desktop release manifest assembly on the smoke This is deliberately **not a performance-regression gate**. CDP and action timing fields are informational only. There is no candidate/baseline comparison or threshold. A future performance lane needs repeated equivalent fixtures, discrete interaction samples, and an explicit comparator/noise policy. The diagnostics record the fixture version, row count, wall-clock base timestamp (`fixtureSecond`), expected event-ID hash, observed state, and measurements. Because the created-at floor requires a current timestamp, paired comparison remains disabled. The release job runs on an isolated GitHub-hosted runner. The script also guards automatic local runs with a Redis allocation lock. Its remaining direct-PID cleanup and free-port selection race mean it should not be repurposed onto a persistent concurrent shared runner without first hardening process-group cleanup and port reservation. ### Related issue N/A ### Testing - `pnpm --dir desktop typecheck` - focused real-local-relay release smoke passed after adversarial review fixes - identical DM witness passed current and failed `desktop-v0.5.10` with the history-loss signature - identical foreground witness bytes (`2c1e97df04c9b8ca0304b66bbbe9bdb4d08924ad8ce0f68a9c490458fcc3aca8`) failed `desktop-v0.5.10` structurally: the first resume fetch was marker 1, before first frame/sidebar dispatch at marker 8 - with PR #5696 (`59f613c40`) merged, the witness showed focus at 951.3 ms, first frame at 951.6 ms, click dispatch at 952.1 ms, first resume fetch at 968.9 ms, and route commit at 992.4 ms - the gate therefore protects first paint and actionable input dispatch; route commit is a bounded responsiveness witness, not a prerequisite for resume work - the corrected focused foreground scenario passed at `6d9b5be40da58bbee92a856b04c3558946d0a950`; the prior merged-tree full run passed DM retention and 10k reachability before exposing this contract mismatch - pre-push passed on exact pushed head `6d9b5be40da58bbee92a856b04c3558946d0a950`, including desktop checks, typecheck, desktop tests, Rust tests, mobile tests, and Tauri checks - full 10,000-event scenario reached 10,000/10,000 exact IDs with matching SHA-256, 199 continuation requests, and 95 mounted rows in about 4.4 minutes - reduced-row review run passed in 18.4 seconds ### Foreground witness boundary The Chromium test is a deterministic JS policy gate. Headless Chromium does not expose an honest blur/focus transition in this fixture, so the test drives the production focus listener and `document.hasFocus()` predicate together and records that simulation explicitly. It proves refetch fan-out ordering, not AppKit activation, WKWebView paint, or an activating physical click. A packaged macOS native lane is still required before claiming the actual desktop activation experience is certified. --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
e0940927ff |
fix(channels): return complete member rosters (#5765)
## Summary - return complete channel rosters instead of truncating at 1,000 members - chunk `event_mentions` inserts inside one transaction so large kind `39002` snapshots remain discoverable by every `p` tag - add a targeted `buzz-admin reconcile-channels --channel <uuid>` force-republish path for stale discovery snapshots - cover a 1,501-member roster, 11,000-tag mention index, and kind `39002` tag construction past member 1,000 ## Why The relay builds NIP-29 discovery and several authorization decisions from `get_members()`, but that helper silently returned only the first 1,000 active members. Desktop then counted the truncated kind `39002` event, while late members could be rejected by roster-scanning member actions. Removing the roster cap exposes PostgreSQL's 65,535 bind-parameter ceiling in mention indexing, so the insert is chunked transactionally to preserve all-or-nothing indexing. The existing reconcilers only fill missing discovery events. The targeted admin option bypasses the separately known 1,000-channel reconciliation-list ceiling and replaces an existing channel snapshot using the configured production relay key. ## Attribution This supersedes and builds on #3166 by @LordMelkor. Thank you for identifying the roster boundary and contributing the original complete-roster and mention-index patch. The production roster/query changes and the two PostgreSQL regressions retain that work's shape; this PR rebases it onto current `main`, adds relay coverage, and adds the targeted repair operation requested for rollout. ## Validation Exact pushed head: `24d02e4f3824150ed84913c9d230e675502e5b12` - `cargo check -p buzz-db -p buzz-admin` - `cargo test -p buzz-db channel::tests::get_members_returns_full_roster_beyond_1000 -- --ignored --exact --nocapture` - `cargo test -p buzz-db feed::tests::insert_mentions_indexes_rosters_past_bind_parameter_cap -- --ignored --exact --nocapture` - `cargo test -p buzz-relay --lib handlers::side_effects::tests::group_members_snapshot_keeps_members_past_one_thousand -- --exact` - `cargo run -q -p buzz-admin -- reconcile-channels --help` - mandatory pre-push hook: branch-skew, desktop checks/typecheck/tests, mobile tests, Rust tests, and desktop Tauri checks all passed on the pushed head ## Rollout 1. Deploy the relay/backend build. 2. Run `buzz-admin reconcile-channels --channel <general-channel-uuid>` with `BUZZ_RELAY_PRIVATE_KEY` configured. 3. Verify the replacement kind `39002` roster count matches the active database membership count. No schema migration or desktop release is required. Fixes #3156 Supersedes #3166 --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
8a2c9af2db |
feat(deletion): add durable whole-community deletion (#4425)
## Summary Adds a durable, operator-controlled V1 for deleting an entire Buzz community without deleting another tenant's data. The workflow is exposed through `buzz-admin deletions`: - `sweep` records independent fleet storage-taxonomy observations - `submit`, `list`, `inspect`, and `approve` manage a deletion request - `unblock` resumes a fail-closed request after an operator records remediation identity and reason - `run` and `drain` execute bounded work Requests advance through a PostgreSQL-backed state machine and stop at `retention_pending` after logical deletion has been independently verified across PostgreSQL, object storage, and Redis. This PR ships the engine and CLI, not a continuously running worker or Kubernetes packaging. For V1, a cluster/VM administrator invokes `/usr/local/bin/buzz-admin` from the existing relay image, for example with `kubectl exec` or an equivalent container/VM exec path. ## What whole-community V1 removes For the target community, V1 removes: - rows from the allowlisted community-scoped PostgreSQL catalog, including members, profiles, authored events and bodies, DMs, reactions, mentions, memberships, tokens, workflows, moderation, audit, feedback, and rate-limit state - media sidecars and upload-attribution records under `_meta/<community>/` and `_uploads/<community>/` - Git repository pointers under `repos/<community>/` - Redis keys under `buzz:<community>:*` The community row survives as a permanent tombstone, and deletion control-plane records remain as evidence of the request, approval, execution, and result. ## Safety model Deletion is not a broad `DELETE CASCADE` followed by optimistic cleanup. The destructive boundaries are durable and fail closed. ### 1. Inventory and approval - `submit` resolves the target and freezes the schema plus summary-only storage inventory. - Approval is bound to the exact request, community, and frozen inventory digest. - Unsupported manifest versions, malformed keys inside the target's owned prefixes, live scoped-table/write-fence coverage drift, frozen-inventory mismatch, and approval mismatch block execution rather than guessing. Migration and catalog revision numbers are not authorization gates; the executor validates the live safety shape instead. - Storage inventory is server-side prefix scoped to exactly: - `_meta/<community>/` - `_uploads/<community>/` - `repos/<community>/` - The deletion path never lists the whole shared bucket and has no arbitrary per-community object cap. Its listing work is proportional to the target community's bindings, not total fleet storage. - Fleet-wide taxonomy sweeps remain independent observability. They report unknown writer shapes but do not gate deletion submission, fencing, or destructive progress. Maintainers must add deletion taxonomy coverage whenever a new community-owned object-key class is introduced; writer-coverage tests bind the current media and Git writers to that contract. ### 2. Quiesce, fence, and destructive freeze - Writes continue through submission, inventory, and approval. They stop when execution moves the target into `quiescing` and then establishes the durable fence. - Already-admitted external effects finish under heartbeated serving-write leases; the exact admitted lease may renew while the community is quiescing, but new lease acquisition is rejected. The executor drains admitted leases before destructive work. - Invite minting after quiescing begins fails as typed `AccessDenied` (HTTP 503 at the relay boundary) before an invite can be persisted. - Database triggers enforce the community write fence across the complete catalog of community-scoped tables. Startup/readiness and destructive execution validate that catalog so a newly added but unfenced table cannot silently escape. - **Named isolation assumption — fresh write snapshot.** Every writer transaction that can reach a community-fenced relation must use PostgreSQL `READ COMMITTED`; each guarded write therefore observes a statement snapshot no older than acquisition of the community deletion lock. `REPEATABLE READ` and `SERIALIZABLE` can retain a pre-fence snapshot and are unsupported for writers. The writer pool refuses non-`READ COMMITTED` sessions at connection setup, and both SQL fence functions reject an explicit per-transaction isolation override with SQLSTATE `25000`. Configuration-delivered bad isolation can surface through SQLx as a pool-acquire timeout because every `after_connect` attempt is rejected; the precise `community writes require READ COMMITTED isolation` reason remains observable when the SQL guard is reached. Read-only replica transactions are outside this assumption. - Holding the shared advisory lock until the guarded write executes is a separate liveness condition: under `READ COMMITTED`, releasing it early does not permit resurrection because the trigger rechecks the fence, but it can turn a fleet sweep into a statement-wide SQLSTATE `55000` abort. - After the fence closes writers, storage is re-enumerated into chunked side-table rows. Per-prefix counts and digests bind those concrete keys to the destructive manifest. - Manifest chunk insertion, update, and deletion are protected after freeze. This closes the race where an unbound key could otherwise appear after the manifest was committed. ### 3. Checkpointed destruction - Target-owned object bindings are deleted from the frozen destructive manifest in bounded batches with durable progress. - The concrete key list lives in chunked side-table rows rather than one request-row JSON value. It supports large communities, resumable execution, and terminal cleanup. - Missing objects are accepted as idempotent crash-window outcomes; malformed ownership, changed evidence, and unexplained target-prefix drift fail closed. - PostgreSQL purging remains scoped by `community_id`, including the guarded NIP-RS hard-delete path discovered with real Desktop kind `30078` read-state data. - Redis cleanup explicitly scans and `UNLINK`s only `buzz:<community_id>:*`. Natural expiry is insufficient because some keys, including tunnel generation counters used as fencing state, are deliberately persistent. ### 4. Independent verification - PostgreSQL logical absence is checked after purge. - The three target-owned storage prefixes are freshly inventoried again and must be empty. - Redis requires two complete empty namespace scans. - Only after all three stores pass does the request advance through `logically_verified` to `retention_pending`. ## What V1 deliberately does not erase ### Shared content-addressed storage Per-community deletion removes bindings, metadata, attribution records, and Git pointers. It does **not** physically delete fleet-shared CAS bytes that another community may still reference: - media blobs and thumbnails - Git manifests, packs, and indexes (`manifests/`, `packs/`, and `idx/`) Safe reclamation requires a separate fleet-wide reachability and retention GC. Unknown keys elsewhere in the shared bucket do not block one community's deletion; malformed or unrecognized keys inside that community's three owned prefixes still fail closed. ### External retained copies The online logical-deletion proof does not erase object versions/replicas, database backups/WAL, CDN copies, provider retention copies, or observability exports. Those require their own retention and purge controls. ### Member-only erasure This PR erases a whole community. It does not implement the different operation "erase one npub while preserving the community." Removing membership or accepting NIP-09 is not member erasure. A member-only workflow would need to find and selectively remove or redact authored event content and pubkeys, profile data, DMs, reactions, mentions, memberships/roles, tokens, workflows/subscriptions, upload attribution, moderation/audit history, repository attribution, and identity embedded in tags or JSON. It would also need explicit rules for ownership transfer, surviving replies and thread metadata, audit-chain integrity, immutable Git history, and shared-CAS reachability. That requires a pubkey-level fence and selective graph rewrite; it is a separate deletion product, not a safe extension of this whole-tenant worker. ## In scope - migration `0029_community_deletion.sql`: requests, approvals, leases, manifest chunks, checkpoints, tombstones, and the universal write-fence catalog - durable executor leases, generations, heartbeats, retry/block state, and resumable stage transitions - operator-driven `sweep`, `submit`, `list`, `inspect`, `approve`, `unblock`, `run`, and `drain` commands - serving-path fences for database writes and external effects across event ingest, media, Git, workflow, push, invites, mesh/tunnel, and related paths - target-prefix-only storage inventory, summary manifests, post-fence destructive chunks, and bounded batch deletion - exact community Redis namespace purge and two-pass absence verification - cross-community isolation, crash/resume, manifest-integrity, writer-taxonomy, and schema/migration regressions - desired-state `schema/schema.sql` support without requiring a SQLx migration ledger ## Deferred / not covered - dedicated Helm/chart worker Deployment, service account, secrets, probes, resources, and network policy - autonomous `buzz-admin deletions worker` poll loop and worker-only health server - least-privilege separation among migration, relay-serving, and destructive execution roles - fleet-wide shared-CAS physical GC - backup/provider/CDN/observability retention completion - member-only erasure - provider-native conditional-delete improvements - a general force-continue escape hatch; permanent safety failures remain fail closed unless an operator remediates the cause and records an audited `unblock` The removed continuous-worker implementation remains deferred; no remote follow-up branch is claimed by this PR. ## Validation ### Current PR head and repository state Current pushed head: `359d8402ee15f049768f54156f67b953c7a7e2ed`, rebased onto `cc9a2f783375e51a6e8d1f2f9d01d5f7e22813d1` (`origin/main` at push time). The complete PR diff is now 47 files, 9,834 additions, and 517 deletions. The bespoke source-scanner stack was removed to keep this PR scoped to community deletion. Tyler/team requested the underlying fenced-write safety behavior, not `ast-grep`, `crates/buzz-db/tests/community_fenced_writes.rs`, its 27 fixtures, or the new `scripts/lints/community_*.yml` rules. Those scanner-specific files, dependencies, Hermit links, and runner wiring are absent from the current tree. The production database write fence, startup/destructive live-catalog validation, and deletion behavior remain. Source validation on this exact SHA passed: - `cargo fmt --all -- --check` - `bash -n scripts/run-tests.sh` - `cargo nextest run -p buzz-db --all-targets`: 102 passed, 173 skipped, 0 failed - `cargo nextest run -p buzz-deletion --all-targets`: 10 passed, 9 skipped, 0 failed - `cargo nextest run -p buzz-admin --all-targets`: 1 passed, 0 failed - affected-package/all-target Clippy with warnings denied - lockfile consistency - Helm 3.16.4 lint and all 44 chart unit tests - Helm region controls using that fixture: default `BUZZ_S3_REGION=us-east-1`, explicit `eu-west-2` override, and blank-region schema rejection The prior Kubernetes battery below was run against `928992237358a3294621ac0280830b77155abc04`. It remains useful evidence for the patch-equivalent production deletion implementation, but it is **not** claimed as exact-SHA evidence for current head `359d8402ee15f049768f54156f67b953c7a7e2ed`; the current cleanup removes only scanner/test/tooling infrastructure. CI restarted for the new head after the rebase and is pending. Human review remains `CHANGES_REQUESTED`. ### Prior-head live Kubernetes deletion and safety gates The full program used one immutable image, real PostgreSQL, Redis, MinIO, and a three-relay Kubernetes release: - source: `928992237358a3294621ac0280830b77155abc04` (**prior head**) - image: `buzz-e2e:sha-928992237358` - immutable image digest: `sha256:a1a204f4618ac22d9e210be5e5290645a15d79831ae30b0e44379357c8e4a895` - evidence root: `/tmp/buzz-e2e/20260807T033025Z-928992237358-full-gates/` - evidence-manifest digest: `82875c5bc9bea7370b796a7aef3457b3a1c8306c84c59e0f7388bbb5ad30e865` Passed gates at that prior head: - **Chart/operator region:** default `us-east-1`, explicit nondefault propagation, blank-region schema rejection, live in-pod environment, and an in-pod taxonomy sweep over 18 objects with zero unknown. - **Fenced writers and lifecycle:** open-write/fence ordering; 100-attempt anti-starvation; invite, push matcher, and exhausted-reaper bystander isolation; non-`READ-COMMITTED` rejection; manifest/tombstone contracts; eight-failure stage block and audited `unblock`. - **Destructive lifecycle:** submit → approve → run → `retention_pending`; PostgreSQL tombstone and Redis/S3 verification true; zero retries/errors; terminal reruns rejected with exit 5. - **Fresh 10,001-object crash boundary:** exactly two chunks (10,000 + 1). The executor deleted chunk 0 from MinIO while its PostgreSQL stamp was row-lock-blocked, was killed with `SIGKILL`, left one object and both stamps absent, then resumed the same request under generation 2 to zero objects and terminal state. - **Independent dead-owner recovery:** a dedicated executor claimed generation 1, blocked before effects, and was killed through containerd with `SIGKILL` (no TERM cleanup). The request remained owned and unreclaimable before lease expiry; a successor claimed generation 2 after 60 seconds and completed with two attempts and zero retries. - **Three-pod socket isolation:** ordinary NIP-42 and joined huddle-audio target witnesses on every replica received exact `1008 / community deleted`; healthy-tenant witnesses on those pods remained live; deleted-host reconnect returned HTTP 404. - **Health/provenance:** all replicas independently returned ready and retained the exact image digest before/after destructive runs and an audio-enabled rolling restart; PostgreSQL, Redis, and MinIO were healthy at close. Instrument corrections were retained as evidence rather than counted as product failures: a foreground PostgreSQL forward caused an initial `PoolTimedOut`; Kubernetes pod deletion exercised graceful TERM rather than dead-owner recovery; shell-background socket witnesses died with their parent; and the first image build hit the corporate TLS proxy. Detached forwarding/witnesses, containerd `SIGKILL`, and the configured internal CA/Artifactory mirror produced the discriminating runs without weakening product security. ### Prior-head cleanup For the prior-head Kubernetes run, the Helm release was removed, namespace absence was verified, run-owned Screen sessions were absent, and that source worktree remained clean. The evidence manifest was independently recomputed and every indexed artifact passed `shasum -a 256 -c`. The current `359d8402` source worktree is also clean after the scanner-only cleanup and push. --------- Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: Kalvin Chau <kalvin@block.xyz> Signed-off-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: cid <d9f92a72922bf45c17379a47d64dae84b6020397c2d5a52b5317d512068cd9d3@buzz.block.builderlab.xyz> Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Co-authored-by: cid <d9f92a72922bf45c17379a47d64dae84b6020397c2d5a52b5317d512068cd9d3@buzz.block.builderlab.xyz> |
||
|
|
240cdd3ea1 |
chore: mesh upgrade, clean up legacy special case code, simplify model selection for mesh (#5289)
Shared compute now has exactly two model choices: MeshLLM's virtual `mesh` model, or a model you name. Buzz picks between them in one place, and buzz-agent no longer knows meshes exist. ## What changed - **MeshLLM v0.74.0 → v0.75.1.** v0.75.0 added `degrade_to_single_model`, so a `model=mesh` request is answered by one served model when there is no committee to form, instead of failing. v0.75.1 adds Mesh-LLM#1196, which skips stale pre-0.75 runtime cache entries rather than aborting startup on them — without it, anyone who had run mesh on 0.73/0.74 could not start. - **Deleted the client-side mesh catalog probe.** buzz-agent used to poll `/v1/models` (5s TTL, 30s cooldown, two-observation debounce) to decide whether `mesh` was safe to send. MeshLLM now decides per request, so the polling, its hysteresis, and its 503 fallback are gone. - **One mapping point.** `relay_mesh_wire_model()` turns the stored value into a wire name: `auto` becomes `mesh`, a named model passes through. The spawn env, the ACP harness, and the readiness probe all use it, so they cannot disagree — previously `BUZZ_ACP_MODEL` and the probe both said `auto`, a name the mesh does not advertise. - **Removed the `nostr-relay-pool` advisory exception.** #5404 allowed RUSTSEC-2026-0243 "after mesh-llm migrates to nostr-sdk >= 0.45". v0.75.1 does, so the retired crate is gone from both lockfiles and the exception would only mask a future advisory for it. - **Deleted `scripts/ensure-mesh-native-runtime.sh`** and its six justfile call sites. It built llama.cpp from source into the runtime cache; the app already downloads the signed release runtime itself, and CI never called it. ## Why it is better **−639 lines of Rust.** Availability is decided by the node that knows the answer, per request, instead of by a client cache that could be stale for up to 30 seconds. A second worker joining now takes effect on the next request rather than after two confirming probes. ## Behaviour change A 503 on an explicit `mesh` request takes the ordinary transport retry under the same model instead of failing over to a second one — there is no second model to fail over to now. MoA repairs partial committee results internally before it reaches that point. ## Validation `crates/buzz-relay/examples/mesh_agent_e2e.rs` now sends `mesh` where it previously sent `auto` or the physical model id, so no leg was covering what Buzz actually puts on the wire. 4/4 on gemma-4-E4B, gemma-4-26B-A4B, and Qwen3-8B — including a real ACP tool call through `mesh` into buzz-dev-mcp, asserted by reading the written file back off disk. Hand-tested in the desktop app on both gemma-4 sizes: picked Auto, agent logged `model_id=mesh`, replied in channel. ## Not covered A committee that forms and then loses a worker returns 502, and that needs two workers to reproduce — not testable on one machine. --------- Signed-off-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Michael Neale <michael.neale@gmail.com> |
||
|
|
43573d114b |
ci(release): gate OSS desktop auto-update promotion (#5398)
## Summary Separate OSS desktop artifact publication from fleet-wide auto-update promotion. - retain the exact generated updater manifest as `updater-manifest.json` on each immutable `desktop-vX.Y.Z` release - stop the tag-triggered build from mutating `buzz-desktop-latest/latest.json` - add a `main`-only manual promotion workflow with one global concurrency group - validate stable semver, release/tag commit identity, draft/prerelease state, exact platform set, signatures, version-bound asset URLs, asset existence, monotonicity, idempotent retries, and a final stale-state check before writing - document the operator flow and pin the split with focused contract tests ## Safety behavior Publishing a versioned GitHub release no longer exposes it through the in-app updater. Operators can install and test those exact signed/notarized artifacts, then manually run **Promote OSS Desktop Auto-Update** with the stable version. Promotion rejects downgrades. A same-version retry succeeds only when the rolling and candidate manifests are byte-identical. The workflow re-reads the current rolling version immediately before its only write and records the actor, source tag commit, previous version, manifest digest, and run URL. ## Verification Verified at commit `39caf1603be06bb476905225ec55f7bbbe86b237`: ```text scripts/test-oss-desktop-promotion.sh OSS desktop promotion contract passed scripts/test-release-ref-contract.sh release ref contract passed git diff --check origin/main...HEAD (clean) ``` The repository pre-push hook also passed `branch-skew` for the exact pushed head; package suites were correctly skipped because this change only touches release workflows, scripts, and documentation. Originating conversation: Buzz channel `separate-publish-step-release`, thread `8857ce8bbe928e891165eddcf06c666cf6eae16181c3f02a6d8c396d8a536026`. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
c1e20a814b |
fix(release): pin desktop PR operations to block/buzz (#5212)
## Summary Pin every GitHub CLI PR operation in the Desktop release helper to `block/buzz`. Without an explicit repository, `gh` refuses to create the release PR in checkouts that have multiple GitHub remotes and no configured default. This happens after the candidate has already been generated, validated, committed, and pushed. Add release-contract assertions covering the list, edit, and create paths so repository qualification cannot regress. ## Validation - `bash -n scripts/prepare-desktop-release.sh scripts/test-release-ref-contract.sh` - `scripts/test-release-ref-contract.sh` - pre-push `branch-skew` Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
38bf642fcf |
ci: prove the relay-driven mesh lifecycle — discover, join, infer, deny — with real nodes (#3862)
## Summary
CI now proves the full Buzz shared-compute join story end to end: a
member can discover another member's served model **through the Buzz
relay alone** and run inference over the mesh, while a non-member gets
nothing — the relay rejects its auth, and the mesh refuses to route for
it even holding a leaked endpoint address.
This is deliberately different from mesh-llm's own CI smokes (which
bootstrap two nodes with a hand-carried invite token / mdns): here the
**relay is the control plane**, exactly like the desktop app:
1. **Membership** — identities A and B are added via `buzz-admin`
(kind:13534 NIP-43 roster); C is not.
2. **Advertise** — each member publishes a client-signed kind:30003
discovery note carrying its MeshLLM owner binding and (for the serve
node) `serveTargets[].endpointAddr`, covered by an endpoint-binding
signature — the exact payload shape the desktop coordinator publishes.
3. **Trust** — the serve node derives its admission allowlist from the
relay (statuses ∩ roster) and requires the **exact expected {A, B}
owner-id set** before starting with `TrustPolicy::Allowlist`.
4. **Join** — the client verifies owner + endpoint bindings and
membership, then dials the relay-discovered endpoint (the desktop
join-watcher's `dial_endpoint_addr` step). No out-of-band token.
5. **Infer** — a chat completion against the client's local OpenAI
endpoint routes over QUIC to the serve node's model (CPU, SmolLM2-135M,
~105MB).
6. **Deny (differential)** — the stranger's NIP-42 auth must fail with
the relay's own membership rejection (`restricted: not a relay member` —
successful auth or any unrelated connect error fails the run), and
dialing the leaked endpoint must not produce a routed inference —
**while the trusted client re-proves inference immediately afterwards**,
so a dead serve node can't masquerade as an admission denial.
## What's in the PR
- `crates/buzz-relay/examples/mesh_relay_lifecycle_smoke.rs` — the
harness. One process per node (mesh-llm keeps process-global state under
`~/.mesh-llm`), orchestrator + serve/client/stranger roles,
byte-identical binding payloads to
`desktop/src-tauri/src/mesh_llm/identity.rs` (called out with
keep-in-sync comments). Child stdout is pumped through a reader thread
so every wait has a hard deadline; timed-out children are killed; exit
statuses are checked.
- `scripts/ci-mesh-lifecycle-smoke.sh` — provisions a membership-gated
relay (throwaway owner + signing identities via `buzz-admin
generate-key`), runs the harness, cleans up. Fails fast if :3000 is
already occupied (a stale open relay would mask gating).
- `scripts/start-relay-for-tests.sh` — gains opt-in NIP-43 membership
env passthrough (`BUZZ_REQUIRE_RELAY_MEMBERSHIP` + `RELAY_OWNER_PUBKEY`
+ `BUZZ_RELAY_PRIVATE_KEY`). Default behavior unchanged.
- `.github/workflows/mesh-lifecycle.yml` — separate, path-filtered,
non-required workflow (mesh paths, the harness's dependency crates,
`Cargo.lock`, dispatch), pinned to `ubuntu-24.04`. Caches the mesh
native runtime + HF model keyed on the lockfile hash, so a mesh pin bump
rolls the runtime cache. Uploads relay + harness logs on failure.
## Scope
This is an **independent protocol harness**: it speaks the same wire
protocol and payload shapes as the desktop but re-implements the
binding/verification logic (the desktop crate is outside the workspace).
Regressions inside the desktop's own discovery filtering are the desktop
unit tests' job; what this smoke proves is that the relay + mesh-llm SDK
+ admission stack support the lifecycle end to end.
## Relationship to mesh-llm's CI
Follows the shape mesh-llm's own CI proved stable (tiny CPU model, one
runner, multiple real mesh-llm processes over real QUIC — cf. their
`ci-two-node-client-serving-smoke.sh`), but swaps the token bootstrap
for the relay-driven lifecycle, which is the part only Buzz can test.
## Validation
Green on GitHub Actions (ubuntu-24.04) across three runs, including
after rebases onto the mesh v0.74 upgrade (#3467) and latest main:
```
PASS 1/6: relay-derived allowlist is exactly {A, B}
PASS 2/6: serve member ready + advertised model: jc-builds/SmolLM2-135M-Instruct-Q4_K_M-GGUF:Q4_K_M
PASS 3/6: client member discovered + joined via relay
PASS 4/6: inference routed over the mesh: "PONG"
PASS 5/6: relay rejected the stranger's NIP-42 auth (membership gate)
PASS 6/6: stranger denied (gossip visible, inference rejected: 503 all tunnels failed) while trusted inference still routes
PASS: full relay-driven mesh lifecycle verified
```
Also validated locally on macOS. `cargo fmt --all --check` and `cargo
clippy -p buzz-relay --all-targets -- -D warnings` pass.
## Notes
- The harness follows the repo's mesh `[dev-dependencies]` pin
automatically, so it doubles as a canary for future mesh upgrades (it
already caught the v0.73.1 → v0.74.0 bump during development).
- The stranger "deny" accepts either shape mesh-llm exhibits: no model
visibility at all, or gossip visibility with inference refused —
mesh-llm applies the receiving node's owner policy after the gossip
handshake, so admission gates *routing*, not gossip. The differential
trusted-inference re-check (PASS 6/6) is what makes that a real denial
rather than a dead server.
- Model-visibility windows are tunable via `MESH_CLIENT_WINDOW_SECS` /
`MESH_STRANGER_WINDOW_SECS` if shared runners prove slow — pin a longer
window in the workflow env rather than re-running the job.
---------
Signed-off-by: Michael Neale <michael.neale@gmail.com>
|
||
|
|
4674750b7e |
fix(release): tag immutable desktop candidates (#4811)
## 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 #4788 and #4800 and the recovery revert in #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> |
||
|
|
383d9e1eaf |
fix(ci): make desktop cache test version agnostic (#4791)
## Summary - derive the current desktop package version in the release cache-key contract test - mutate that version in both `Cargo.toml` and `Cargo.lock` instead of assuming `0.5.4` - prevent desktop release version bumps from failing generic CI ## Context PR #4788 bumped Desktop to `0.5.5`, exposing the hard-coded fixture. The dedicated release candidate check passed, while generic CI failed with `desktop version changed cache key`. ## Verification - pre-commit hooks passed - pre-push hooks passed - CI will validate the full contract Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
e1f6da7c42 |
ci: add guarded desktop release cache prewarm (#4575)
## Summary Gate 1 only for desktop release caching: - replaces canary `rust-cache` use with explicit exact-key `actions/cache/restore` + `save` - computes keys after `cargo update --workspace`, including platform, target, Rust toolchain, Cargo manifests/locks, profile/features, and native-toolchain inputs - normalizes only the desktop package version so a trusted `main` canary can warm an otherwise identical release tag - excludes Tauri bundle directories, so installers and signed artifacts are never cached - adds a restore-only `cache-proof-*` tag workflow that fails unless tag scope sees the exact default-branch cache - adds contract tests that enforce no release-workflow cache change in Gate 1 `release.yml` is intentionally unchanged. A cache miss remains the current cold canary build; the release path cannot be affected by merging this PR. ## Validation - `scripts/test-desktop-release-cache-key.sh` - `scripts/test-desktop-release-cache-workflow.sh` - `scripts/test-release-ref-contract.sh` - Ruby YAML parse of all four changed workflows - `git diff --check` - pre-push `branch-skew` ## Post-merge proof plan 1. Run each canary cold on trusted `main`, recording cache size/save time and fresh artifact inventory. 2. Run each canary warm, requiring the exact-key hit and recording restore/build time. 3. Create a disposable `cache-proof-*` tag at that same trusted `main` SHA and dispatch **Desktop release cache tag-scope proof** from the tag. 4. Do not begin Gate 2 or modify `release.yml` unless the exact tag-scope restore succeeds and cache transfer economics are favorable. --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
6530b58a61 |
feat(k8s): Kubernetes backend plugin + desktop deploy path (#4289)
# Kubernetes backend plugin (crates/buzz-backend-kubernetes) + desktop deploy path Implements docs/remote-agents.md (merged @ |
||
|
|
e5e5bac2a9 |
fix(release): preserve main in desktop PR body (#3979)
## Summary - escape the Markdown backticks around `main` in the desktop release PR body - prevent the shell from executing `main` as command substitution - lock the heredoc contract into the release-ref test ## Verification - `scripts/test-release-ref-contract.sh` - `bash -n scripts/prepare-desktop-release.sh scripts/test-release-ref-contract.sh` - `git diff --check origin/main...HEAD` This is a follow-up to the cosmetic PR-body issue observed on #3972. It does not modify that frozen release candidate. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
54c8ef30a9 |
fix(release): require exact-head approval for desktop tags (#3973)
## Summary - require an exact-head trusted approval before desktop auto-tagging - remove rule-suite authorization that `GITHUB_TOKEN` cannot access - pin review pagination to `page=1` and test the deployed `gh` control flow ## Why The previous verifier unconditionally queried repository rule-suite endpoints with `github.token`. Those endpoints require Administration: read, which Actions `GITHUB_TOKEN` cannot receive. Its paginated list request also duplicated page one when no explicit page was supplied. This deliberately removes admin-bypass authorization rather than introducing a second credential during release recovery. Desktop release PRs must now have GitHub's overall `APPROVED` decision and a MEMBER/OWNER/COLLABORATOR approval attached to the exact candidate SHA. ## Validation - `scripts/test-desktop-release-authorization.sh` - `scripts/test-release-ref-contract.sh` - `bash -n scripts/verify-desktop-release-merge.sh scripts/verify-desktop-release-authorization.sh scripts/test-desktop-release-authorization.sh scripts/test-release-ref-contract.sh` - `git diff --check origin/main...HEAD` The new flow test uses a stub `gh` executable, asserts the exact `page=1` request, fails any rule-suite API call, and rejects stale-SHA, untrusted-author, changes-requested review, and non-approved aggregate-decision cases. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
db7e84d4f8 |
fix(release): make desktop tagging squash-safe (#3965)
## Summary - validate desktop release candidates before merge and keep the repository squash-only - tag the squash commit only after proving frozen-base parent and complete-tree identity with the validated PR head - accept either an exact-head approval or the durable Default-ruleset bypass record as release authorization - remove the unusable App-backed preparation workflow; retain `just release-desktop` ## Ruleset follow-up After this PR merges, update Default ruleset `13596885` to: - enable strict required status checks - dismiss stale reviews on push and require approval after the last push - require the integration-bound `Desktop Release Candidate` check The next desktop release should be cut only after that settings update. ## Verification At commit `d8c254db427eedbcffac1a6e078e90d1d0f5e151` with a clean worktree: - `scripts/test-release-ref-contract.sh` - `scripts/test-desktop-release-candidate.sh` - `bash -n scripts/verify-desktop-release-merge.sh scripts/prepare-desktop-release.sh scripts/test-release-ref-contract.sh` - `git diff --check` The bypass test fixture is the captured rule-suite shape from real squash merge PR #2864 / suite `3520068134`. --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |
||
|
|
052174a148 |
fix(release): make immutable desktop release operable (#3943)
## Summary - document `Prepare Desktop Release` as the canonical desktop release entry point - describe the frozen candidate, exact-head approval, and true merge-commit contract - document all platform outputs and complete release App/signing configuration - link the release runbook from the README - allow stable reruns to repair the rolling updater manifest after the versioned release has already published ## Release blocker The live repository cannot currently complete this flow: repository settings disable merge commits and the `main` ruleset allows only squash, while `scripts/verify-desktop-release-merge.sh` requires a two-parent merge whose second parent is the approved candidate. Those settings must allow merge commits before a desktop release PR is merged. ## Validation - `bash scripts/test-desktop-release-candidate.sh` - `bash scripts/test-release-ref-contract.sh` - `git diff --check` - verified live repository merge settings, `main` ruleset, release tag ruleset, Actions variable names, and secret names with GitHub API - independent review by Princess Donut; incorporated all findings, including the rolling-manifest retry gap and unsigned Windows labeling Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |