feat(memory): encrypt local store and preserve reviewed Markdown portability - #347
daveh-beep wants to merge 12 commits into
Conversation
…ability Signed-off-by: David Hamilton <daveh@squareup.com>
## Summary Adds low-distraction status cues to active Voice conversations. Voice settings offer Off, While working (the default), and While working and waiting. Working uses the macOS Pop cue; waiting uses Purr. There is no volume control in settings. Cues play at the beginning of each five-second window. Submitting a prompt silences the waiting cue without changing the saved preference. The chained client enters working on the first live tool call and stays working until the run ends. Every subsequent tool call signals working idempotently, without replaying the cue or resetting its cadence. Incoming speech and outgoing audio temporarily suppress playback without changing that state; the current cue resumes immediately when audio ends. Run completion restores waiting, and cues stop with the owning Voice session. ## Reviewer-reproducible examples In Voice settings, select While working and waiting and start a chained voice conversation. Submit a request that has the agent speak briefly before its first tool call, make two consecutive tool calls that keep one run active across multiple five-second intervals without speech between the calls, speak again, and then make a final tool call. Expect the waiting cue to stop when the prompt is submitted, no working cue before the first tool call, an immediate working cue when the first call starts (unless speech is active), and five-second cadence to continue across the second call. Speech suppresses playback; the working cue resumes immediately afterward. Run completion restores waiting. Select While working and repeat the multi-tool request. Working cues play during tool activity; no waiting cue plays after the run becomes idle. Select Off and repeat the task: speech remains audible, but neither working nor waiting cues play. End the voice conversation to stop all cues. Live verification covers chained voice with Apple TTS and speaker output. Other voice modes and output routes were not live-tested. --------- Signed-off-by: Sol <49aa1f65411fd096d2e2ec144f1e7aa36fdc76d1b907cfdf7be000c66f9d3b8e@buzz.block.builderlab.xyz> Co-authored-by: Sol <49aa1f65411fd096d2e2ec144f1e7aa36fdc76d1b907cfdf7be000c66f9d3b8e@buzz.block.builderlab.xyz>
update docs to warn about `bb-cli` migration Co-authored-by: Jarrod Sibbison <jsibbison@squareup.com>
## Summary Renames the reusable voice-call Cargo package, Rust library namespace, and standalone command from `berd-voice` to `berd-call`. Desktop Berd now imports the same runtime as `berd_call`, while the `berd-call` binary remains a separate client of that library. The rename updates workspace wiring, protocol documentation, tests, and scripts without adding a compatibility alias or standalone CLI telemetry. Existing desktop telemetry schema names and analytics values remain unchanged. The persisted asset-store lock filename also stays stable so overlapping app versions continue coordinating access to the same model store. ## Reviewer-reproducible examples From a fresh checkout of this branch: ```bash cd src-tauri cargo run -p berd-call -- --help ``` The command builds and runs the renamed package, then prints usage beginning with: ```text supported commands are session, synthesize, voices, models, benchmark tts, and benchmark stt usage: berd-call session --pcm-output-fd FD ... ```
**Category:** fix **User Impact:** Status sounds no longer accumulate behind speech or play immediately after a voice response. **Problem:** Status cues could overlap or queue when playback completion lagged, and Berd’s desktop host duplicated activity arbitration that belongs in the shared call runtime. **Solution:** Make status playback single-flight, centralize overlapping speech suppression in `berd-call` activity guards, cancel cues before speech proceeds, and restart the full cadence after speech without replaying missed cues. Depends on #338 <details> <summary>File changes</summary> **src-tauri/crates/berd-call/src/status_sounds.rs** Makes cue playback single-flight and adds acknowledged, reference-counted conversation activity guards with full-interval resume after speech. **src-tauri/crates/berd-call/src/lib.rs** Exports the shared status-sound activity guard. **src-tauri/src/commands/native_voice.rs** Replaces Berd’s local user/playback suppression counters with shared `berd-call` guards. **src-tauri/crates/berd-call/README.md** Documents shared activity ownership and cue coalescing. **src-tauri/crates/berd-call/PROTOCOL.md** Documents speech preemption and no-replay cadence behavior. </details>
## Context In OpenAI Realtime Expert-Spokesperson calls, the spokesperson can begin a spoken acknowledgement and invoke the handoff tool in the same response. Berd treated that handoff as a cancellation of the response that produced it, marking its own acknowledgement interrupted. OpenAI could then report that the already-finished response was no longer active and terminate the call. Normal hangup could also stop the native runtime before already-queued provider events reached it, surfacing `Spokesperson runtime is unavailable` during teardown. ## Summary A handoff starts Expert work without cancelling acknowledgement audio that has already begun. Once the acknowledgement finishes generating, the Expert response can start while its audio drains. Expert audio replaces any remaining acknowledgement without overlapping it. User speech still interrupts playback immediately. The provider's late `Cancellation failed: no active response found` race no longer ends the call. Hangup drains provider events that were already queued before stopping the native runtime, preventing a late teardown event from surfacing as a call failure. ## Reviewer-reproducible example 1. Run `just dev`, configure Voice for OpenAI Realtime Expert-Spokesperson, start a voice call, and mute the microphone. 2. Ask the Spokesperson to use the terminal to run `pwd` and report the printed path. The wording can vary; the request must require Expert tool use and produce a handoff. 3. Confirm the acknowledgement becomes **Spoken** and the `Spokesperson → Expert · Handoff` event appears without marking the acknowledgement **Interrupted**. 4. Let the Expert answer arrive. Confirm its audio replaces any remaining acknowledgement rather than overlapping it. 5. Start another acknowledgement, unmute the microphone, speak while it is playing, and confirm user speech interrupts it immediately. 6. Mute the microphone, repeat the `pwd` tool-use request, wait for the handoff event, then hang up. Confirm the call returns to its normal start state without either cancellation error or `Spokesperson runtime is unavailable`. --------- Signed-off-by: John Tennant <jtennant@block.xyz>
## Summary
Adds a public, self-describing command surface for the standalone
`berd-call` binary. Global help groups the supported runtime,
speech/model, synthesis, and benchmark commands; command-scoped help
documents their exact invocation; and version output is available
through both flag and command forms.
Help and version exit successfully before initializing audio, models,
credentials, or network clients. Host integration commands such as
`start`, `speak`, `status`, and `stop` are not part of the standalone
`berd-call` interface.
## Reviewer-reproducible examples
```bash
cd src-tauri
cargo run -q -p berd-call -- --help
cargo run -q -p berd-call -- help session
cargo run -q -p berd-call -- --version
cargo run -q -p berd-call -- version
cargo run -q -p berd-call -- start
```
Output excerpts:
```text
Berd Call
Voice-call runtime and speech tools for Berd and other hosts.
Usage:
berd-call <command> [options]
Call runtime:
session Run the host-facing framed voice-session protocol
Speech and models:
synthesize Render text to a WAV file
voices List or download Siri voices
models Inspect or install speech models
Diagnostics:
benchmark tts Benchmark a TTS backend
benchmark stt Benchmark an STT backend
```
```text
Run the host-facing framed voice-session protocol.
Usage:
berd-call session --pcm-output-fd FD --voice NAME --language BCP47
berd-call session --pcm-output-fd FD --tts-backend openai
berd-call session --pcm-output-fd FD --tts-backend pocket
--model-dir ABSOLUTE_PATH --voice ID
```
```text
berd-call 0.1.0
```
The host integration command `start` exits 2 and renders the global help
after:
```text
unrecognized command: start
```
…342) ## Summary Adds the native host needed to run the shared `berd-call session` runtime as a standalone macOS call. `berd-call start` owns default-device microphone capture, PCM playback, and the child session lifecycle; loopback-only `speak`, `status`, and `stop` commands control that foreground call. Direct mode streams authoritative user transcripts as TSV. Expert-Spokesperson mode waits for the shared runtime delivery boundary and preserves each delivered cursor and role. CoreAudio route metadata suppresses input for built-in speakers without relying on localized device names, while headphone-like output retains barge-in. The standalone boundary contains call hosting and control only. Updaters, menu-bar UI, persisted application settings, compatibility hooks, and duplicate speech engines remain outside it. ## Reviewer-reproducible examples From `src-tauri`, list the installed voices: ```bash cargo run -q -p berd-call -- voices list --language en-US ``` Choose one voice from that output, then replace `<installed-voice>` below: ```bash cargo run -q -p berd-call -- start \ --voice <installed-voice> --language en-US --port 5322 --stream ``` Speak aloud and note the resulting TSV cursor. In terminal A, use that cursor to start a longer reply: ```bash cargo run -q -p berd-call -- speak --port 5322 --re <cursor> "Here is a longer reply you can interrupt while it is playing." ``` While terminal A is still blocked on playback, interrupt it from terminal B: ```bash cargo run -q -p berd-call -- stop --port 5322 ``` Terminal A returns an interrupted speech result containing `"status": "interrupted"` and `spokenThroughUtf8`. Terminal B returns `"stopping": true` before the foreground process exits cleanly. Completed speech returns `"status": "completed"`. To verify Expert-Spokesperson delivery, provide `OPENAI_API_KEY` and start the same command with `--mode expert-spokesperson`. Say: "Please ask the expert to explain how the code in this project starts a voice session." The stream delivers the recognized user text followed by an Expert handoff. For example (cursor values and handoff wording vary): ```text cursor role text 1 user Please ask the expert to explain how the code in this project starts a voice session. 2 handoff Explain how the code in this project initiates a voice session... ``` Rows are tab-separated, with one numeric cursor, role, and text per line. Spokesperson speech uses `spokesperson` or `spokesperson_interrupted` roles. To verify route policy, select built-in speakers as the macOS default output, restart the call, and run: ```bash cargo run -q -p berd-call -- status --port 5322 ``` The session snapshot reports `"policy": "suppress_input"`. Repeat after selecting headphones or AirPods as the default output; the snapshot reports `"policy": "allow_barge_in"`, and speaking during playback interrupts it.
…ranch The memory review commit 5b894c9 overwrote the voice block in en and es settings.json with a divergent variant. That removed 62 voice keys and reworded 10 existing strings, which breaks 14 voice settings tests. Restore the voice block from the stack's base ce48ca5 and keep the one string the memory work genuinely added (voice.interruptionDescription). All 447 tests in src/features/voice-conversation pass; just check passes. Signed-off-by: David Hamilton <daveh@squareup.com> (cherry picked from commit 4bf3772) Signed-off-by: David Hamilton <daveh@squareup.com>
Integrate main at 2f93fb3 after the separately attributable #348 voice catalog repair. Resolve Cargo and locale conflicts to the locally validated integration baseline. This changes only the encryption follow-up branch; the foundation, reviewed-proposals and MCP owner branches are unchanged. Signed-off-by: David Hamilton <daveh@squareup.com>
… storage Keep pending credential calls off the policy lock and synchronous app dispatch. Revalidate store identity, preserve initialization serialization, bound key workers, and retain repeated off-state handoffs. Enforce the current desktop availability boundary across native, renderer, MCP and packaging paths. Add opt-in shared-store validation with Linux directory-sync and Windows lock-contention repairs, synthetic regressions, and explicit native-acceptance limits. Include the narrow tested Sherpa cache repair needed for native validation. The reconstructed source matches all 2,617 entries of the local just-ci snapshot: 7,962 frontend tests passed with one skipped, 214 release-script tests, and all configured Rust/check/clippy/build lanes passed. Signed app/sidecar key access and Windows runtime remain unverified; keep the PR draft. Signed-off-by: David Hamilton <daveh@squareup.com>
Signed-off-by: David Hamilton <daveh@squareup.com>
|
🤖 @delkc — Dave’s agent here. Updated this draft with the tested encryption follow-up, preserving the #288 → #289 → #290 stack. Your branches are unchanged. This branch includes #348’s voice-catalog repair as a separate signed cherry-pick and main at Full local The draft now includes the pending-key/memory-off correction, platform gating, and portable storage repairs. It is not ready to ship: real signed app/sidecar key authorization, native Windows execution, and legacy-data/downgrade/recovery decisions remain open. Added desktop-platform gates stay closed. When you have time, please advise on folding the catalog repair into the lower stack and the preferred restack/merge shape. Also, do any draft-build users have memory data we need to preserve through migration? The current implementation refuses legacy stores without deleting them. Acceptance details and limits are in |
Summary
Extend the encrypted-memory follow-up to the existing memory stack. Keep editing and explicit Markdown import/export in Berd, preserve review and consent boundaries, and fail closed when keys or platform support are unavailable.
This is the draft encryption follow-up to #290, not a replacement for #288–#290. It includes #348’s voice-catalog repair as an attributable cherry-pick and merges main at
2f93fb34to preserve the tested integration. Clay’s branches are unchanged. Cross-platform storage validation is included; this does not enable or claim Windows/Linux/Intel desktop support.portable-storevalidation for the shared store/MCP on Intel macOS, Linux, and Windows. Repair Linux directory synchronization and Windows lock-contention classification without enabling those desktop builds prematurely.Related issue
Depends on the existing draft stack:
No separate issue was found in the scoped
memory encryptionissue search. The existing PRs are the relevant work; do not create a duplicate memory implementation. Further restacking remains coordinated with the stack owner; this is not a claim of validation against newer main revisions.Testing
Completed on the integrated implementation snapshot (all executable source/config/test inputs match this PR; four subsequent documentation updates reconcile status):
just ciData tests use synthetic temporary stores and injected keys. Linux source tests ran with networking disabled, no host-home mounts, and no credential service. Windows cross-compilation is not Windows execution. Rosetta is not final Intel-hardware/package acceptance.
UI behavior was previously checked using synthetic fixtures for edit/save, unsaved Markdown import, export confirmation, and unavailable targets. Sanitized before/after screenshots still need to be selected and reviewed for the submitted candidate. No screenshots of real memory are required or appropriate.
Behavior and compatibility
LAWS/MEMORY.mdchanges the earlier direct-plaintext-file contract to in-app editing plus explicit Markdown portability. This is an intentional product-contract change requiring owner review.Why this remains draft
just cipassed, and branch reconstruction matched the tested source before the documentation-only update. Further stack/base changes need applicable revalidation.If encryption is required for launch, the lower memory layers and encryption must reach users together. Reviewable commits must not become independently releasable plaintext or partially encrypted states.
AI tools assisted with implementation and tests. The submitting contributor remains responsible for reviewing the code, evidence, and DCO certification.