slice-4 (dev-b): TapAudioPipe::barge_in_flush + advisory_tx + MockRealtimeBrain schedule #9

Merged
alee merged 9 commits from slice-4-dev-b-tap into main 2026-07-04 01:43:44 +00:00

9 Commits

Author SHA1 Message Date
3843b9d0ac feat(brain-realtime): MockRealtimeBrain advisory schedule (slice-4 §4.5)
All checks were successful
CI / fmt (pull_request) Successful in 1m38s
CI / clippy (pull_request) Successful in 2m26s
CI / test (1.85) (pull_request) Successful in 4m4s
CI / test (stable) (pull_request) Successful in 4m37s
CI / deny (pull_request) Successful in 1m26s
The mock can now emit speech_started/speech_stopped on a programmable
schedule keyed by input_audio_buffer.append count. Used by the slice-4
secondary-path e2e to exercise the brain advisory → reflex path. The
schedule is shared via an Arc<Mutex<_>> so set_advisory_schedule right
after start() is picked up by accepted connections.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-03 09:47:42 -04:00
a1021d6c5d feat(binary): spawn_tap_engine takes advisory_tx parameter (slice-4 §3.1)
The media thread will own the advisory channel (two senders: the engine +
the local VAD). spawn_tap_engine now takes advisory_tx as a parameter +
forwards brain speech_started/speech_stopped through it.

Temporary bridge: session_map.rs's legacy poll-task call site creates a
throwaway advisory channel until dev-a Task 7 (MediaThread) owns the real
channel.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-03 09:36:14 -04:00
1cb7260f66 feat(tap): forward speech_started/stopped to advisory_tx (slice-4 §3.1)
The brain's advisory events now flow to the FOB reflex via the dedicated
advisory_tx side-channel (3rd mpsc alongside tx_pcm_in/tx_audio_out).
handle_brain_frame + run_tap_client thread the sender through; the engine
loop constructs the channel internally until Task 5 moves ownership to the
caller.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-03 09:26:41 -04:00
58919b8bf7 feat(tap): TapAudioPipe::barge_in_flush + barge_drained_inflight (slice-4 §3.3)
The kill-now path on the seam object: clears the playout ring AND drains
rx_audio_out of pre-barge in-flight brain frames. The drain is what makes
the resume condition race-free — the first audio_out post-barge is
provably post-barge.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-03 00:01:38 -04:00
d3db7181b8 merge(main): integrate Task 1 + revised slice-4 spec
Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-02 23:47:28 -04:00
opencode controller
aa9b1be4f0 kickoff(slice-4): PM + dev-a + dev-b prompts for multi-agent execution
All checks were successful
CI / fmt (pull_request) Successful in 1m31s
CI / clippy (pull_request) Successful in 2m20s
CI / test (1.85) (pull_request) Successful in 5m15s
CI / test (stable) (pull_request) Successful in 5m50s
CI / deny (pull_request) Successful in 2m17s
One plan, two devs, critical-path partition:
- dev-a: Tasks 1 (foundation) → 2 (Reflex) → 2b (LocalVadReflex) → 6 (MediaThread) → 7 (rewire)
- dev-b: Tasks 3 (barge_in_flush) → 4 (advisory_tx) → 5 (spawn_tap_engine sig) → 8 (MockBrain)
- Shared: Tasks 9 (e2e) + 10 (CI seam gate), PM assigns

Relay on localhost:7110 (already running). Roles pm/dev-a/dev-b registered
in ~/Sources/relay/queue.ts. DCO baked into every commit instruction.
Wedge-#1 audit surfaced to PM (Task 9 step 1 must kill WITHOUT brain advisory).

Signed-off-by: opencode controller <controller@local>
2026-07-02 10:00:43 -04:00
opencode controller
9600839bf7 spec+plan(slice-4): revise trigger source — local VAD primary, advisory secondary
All checks were successful
CI / fmt (pull_request) Successful in 1m40s
CI / clippy (pull_request) Successful in 2m31s
CI / test (1.85) (pull_request) Successful in 5m28s
CI / test (stable) (pull_request) Successful in 6m34s
CI / deny (pull_request) Successful in 2m9s
Responds to the 2026-07-01 adversarial review's load-bearing finding:
advisory-only puts the brain round-trip in the barge-in trigger path,
contradicting wedge #1 (README:98-100, ARCHITECTURE.md:79-81).

Spec changes:
- §1.1: LocalVadReflex<P> added to scope as primary trigger
- §1.2: local VAD tuning framework deferred (the VAD itself in scope)
- §3.4: new — LocalVadReflex design (RMS, debounce, observe-then-delegate)
- §5.1: data flow shows local VAD as primary (≤80ms, zero brain round-trip);
  brain advisory as secondary (confirms ~300ms later)
- §6.1: 'Why advisory-only' → 'Why both, local VAD primary' (revised rationale)
- §7: done-criteria 5-12 (added LocalVadReflex unit tests + two e2e paths)

Plan changes:
- Task 2b: new — LocalVadReflex<P> + 6 unit tests
- Task 5: spawn_tap_engine signature revised (takes advisory_tx parameter;
  media thread owns the channel; two senders via tokio mpsc Sender Clone)
- Task 6: Connected spawn site wires LocalVadReflex<Reflex<TapAudioPipe>>
- Task 9: two e2e cases — PRIMARY (kill WITHOUT brain, wedge #1 proof) +
  SECONDARY (advisory backstop)
- Self-review: wedge-#1 audit line added — Task 9 step 1 is the proof

DCO signoff added per AGENTS.md (commit -s).

Signed-off-by: opencode controller <controller@local>
2026-07-01 20:21:38 -04:00
opencode controller
69d5feef59 plan(slice-4): barge-in implementation plan (10 tasks, TDD-stepped)
All checks were successful
CI / fmt (pull_request) Successful in 1m38s
CI / clippy (pull_request) Successful in 2m30s
CI / test (1.85) (pull_request) Successful in 5m28s
CI / test (stable) (pull_request) Successful in 6m7s
CI / deny (pull_request) Successful in 2m6s
Structured for multi-agent dispatch per AGENTS.md 5-rule parallelism:
Task 1 = critical-path foundation (AdvisoryEvent + ReflexMetrics +
barge_in_flush trait) — nothing else parallelizes until it lands.
Tasks 2-5 depend on Task 1 (Reflex state machine, barge_in_flush
override, advisory_tx threading, spawn_tap_engine return). Task 6 =
MediaThread (depends on 2+5). Task 7 = session_map rewire (depends on
6). Task 8 = MockRealtimeBrain schedule (parallelizable after 5).
Task 9 = barge e2e (depends on 6+7+8). Task 10 = CI seam gate.
2026-07-01 20:07:42 -04:00
opencode controller
3be1756b34 spec(slice-4): barge-in / VAD-driven playout kill on dedicated media thread
Spearhead step 4 of 6. The FOB reflex loop: on brain speech_started
advisory, kill playout from the core-authoritative buffer; resume on
first fresh audio_out post-barge. Graduates the 20ms media loop off
the tokio pool onto a dedicated std::thread (ARCHITECTURE.md mandate,
deferred from slice-1 loop_driver.rs:18-23). Reflex<P: AudioPipe>
wrapper in rutster-media (FOB) decorates the pipe — loop_driver.rs +
rtc_session.rs stay byte-identical (the §8.5 #6 seam gate, restated).

Decisions (brainstorming 2026-07-01):
- Trigger: advisory-only (brain speech_started/stopped); local VAD deferred
- Resume: first fresh audio_out; SpeechStopped observational only
- Thread: single dedicated std::thread; per-session/threadpool deferred
- Approach C: B's thread model + reflex.rs module (per user selection)

Out-of-scope (§1.2): local VAD, per-session threads, min-mute floor,
brain-side input_audio_buffer.interrupt, TLS, authn, spend cap.

Depends on: slice-1 (media loop + seam), slice-2 (tap + playout buffer),
slice-3 (brain + speech_started/stopped advisory, S4 turn-ownership lock).
2026-07-01 20:04:05 -04:00