Files
rutster/docs/superpowers/kickoffs/2026-07-04-slice-4-finisher-prompt.md
Aaron D. Lee e1bcc5f158
All checks were successful
CI / fmt (push) Successful in 1m40s
CI / clippy (push) Successful in 2m18s
CI / test (1.85) (push) Successful in 5m47s
CI / test (stable) (push) Successful in 5m44s
CI / deny (push) Successful in 2m1s
kickoff(slice-4): finisher prompt — solo agent for Tasks 9.2 + 10
Single-agent (no PM/relay) kickoff to close out slice-4: the
secondary-path advisory e2e and the CI seam gate. API facts verified
against main @ 60b65ab (mock schedule API, ReflexMetrics fields,
lib.rs exports); seam gate specced as pinned blob hashes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012QndwfhjyTiZcUYp87dwW8
Signed-off-by: Aaron D. Lee <himself@adlee.work>
2026-07-04 11:38:11 -04:00

158 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Finisher Kickoff Prompt — slice-4 Tasks 9 (Step 2) + 10 (solo agent)
Paste everything below the `---` line into a fresh opencode session as the first user message.
---
You are a **senior developer** finishing the slice-4 "barge-in / VAD-driven playout kill" release, solo. Eight of the plan's ten tasks are merged (PRs #7#12). You own the last two:
- **Task 9 Step 2** — the SECONDARY-path barge-in e2e test (advisory-driven kill via the brain)
- **Task 10** — CI seam gate + final verification sweep
There is no PM and no relay this run. Your human is the reviewer and merger. You communicate by printing `## STATUS UPDATE` blocks in this terminal (format below) and stopping when you need a decision.
Today: 2026-07-04.
## Setup (do this first)
```bash
cd /home/alee/Sources/rutster
git fetch && git checkout main && git pull
git worktree add /home/alee/Sources/rutster.slice-4-finisher -b slice-4-finisher
cd /home/alee/Sources/rutster.slice-4-finisher
pwd # must print /home/alee/Sources/rutster.slice-4-finisher
```
**ALL work happens in `/home/alee/Sources/rutster.slice-4-finisher`.** If you dispatch subagents, every subagent prompt must begin with `cd /home/alee/Sources/rutster.slice-4-finisher`.
## Required reading (in order — do not skip)
1. `AGENTS.md` — in full. Especially: "Code style (Rust)" (learner-facing comments are REQUIRED — this project overrides any no-comments default), "Git workflow" (squash-merge + DCO signoff on EVERY commit via `git commit -s`), "Multi-dev parallelism".
2. `docs/superpowers/specs/2026-07-01-slice-4-barge-in-design.md` — §3 (advisory chain), §6 (e2e), §7 (done-criteria — your PR must check these off).
3. `docs/superpowers/plans/2026-07-01-slice-4-barge-in.md` — Task 9 + Task 10 sections only (the rest is merged).
4. `crates/rutster/tests/barge_in_integration.rs` — the merged PRIMARY-path test. Your Step-2 test lives in this file and follows its shape.
5. `crates/rutster/tests/realtime_integration.rs` — the in-process wiring template: `MockRealtimeBrain` + inline brain-pump task (`run_openai_pump`) + `spawn_tap_engine`. Your secondary-path test reuses this exact pattern.
6. `crates/rutster-media/src/reflex.rs``Reflex<P>`, `LocalVadReflex<P>`, `ReflexMetrics`, `VAD_RMS_THRESHOLD` (500.0), `VAD_DEBOUNCE_FRAMES` (3).
7. `crates/rutster-brain-realtime/src/mock.rs` — the Task-8 API you consume: `MockRealtimeBrain::start()`, `.url()`, `.set_advisory_schedule(Vec<AdvisoryTrigger>)` (all async), `AdvisoryTrigger { after_audio_in_frames, event }`, `AdvisoryKind::{SpeechStarted, SpeechStopped}`.
8. `crates/rutster/src/tap_engine.rs` — read `spawn_tap_engine`'s exact current signature (it takes `advisory_tx`; do not guess argument order).
## Task 9 Step 2 — SECONDARY-path e2e (do this first)
**File:** `crates/rutster/tests/barge_in_integration.rs` (append a second `#[tokio::test]`; do not modify the primary-path test).
**What it proves:** when the caller is too quiet for the local VAD (the primary trigger), the brain's `speech_started` advisory — flowing through slice-3's real plumbing (mock brain → translator → tap protocol → `tap_client` decode → `advisory_tx``Reflex`) — is the backstop trigger that kills playout.
**Wiring recipe (the realtime_integration.rs pattern, plus the reflex stack):**
1. `MockRealtimeBrain::start()`, then `.set_advisory_schedule(vec![AdvisoryTrigger { after_audio_in_frames: 2, event: AdvisoryKind::SpeechStarted }])`.
2. Stand up the inline brain-pump task exactly as `realtime_integration.rs` does (WS accept loop + `run_openai_pump` dialed at `mock.url()`).
3. `spawn_tap_engine(...)` against the brain pump's WS URL, passing your own `advisory_tx` end; keep `advisory_rx`.
4. Wrap the returned `TapAudioPipe` in `Reflex::new(pipe, advisory_rx, metrics)` then `LocalVadReflex::new(reflex, advisory_tx_clone)` — same stack as the primary test.
5. Push **quiet** caller frames (`PcmFrame::zeroed()`, RMS 0 < `VAD_RMS_THRESHOLD`) through the sink path so the frames reach the brain as `input_audio_buffer.append` events. By construction the local VAD cannot trip — any kill that fires is advisory-driven.
6. After the schedule fires, poll `next_pcm_frame()` (bounded retry loop with a short sleep and a ~2 s deadline, like realtime_integration.rs's bounded waits — the advisory crosses real async channels; do NOT assert on the very first tick).
**Assert:**
- Playout is killed: `next_pcm_frame()` returns `None` while a frame sits in the ring, within the bounded window after the advisory.
- `ReflexMetrics.barge_in_count == 1`.
- Resume: send a fresh `audio_out` frame → `next_pcm_frame()` returns `Some`.
**Plan deviation license:** the plan sketch mentions `MediaThread` in this test. The merged primary-path test drives ticks manually instead, which is deterministic. Prefer manual tick-driving for consistency; if you do so, say it in the PR description under "Plan deviations". If the full tap-engine wiring proves genuinely infeasible in-test, STOP and print a `## QUESTION` block — do not quietly downgrade the test to injecting advisories directly into `advisory_tx` (that would bypass the slice-3 plumbing the test exists to exercise).
**Commit** (message template from the plan, adjusted to the step):
```bash
cargo fmt --all --check && cargo clippy --all --all-targets -- -D warnings && cargo test --all
git add crates/rutster/tests/barge_in_integration.rs
git commit -s -m "test(slice-4): secondary-path barge-in e2e — brain advisory as backstop trigger
Quiet caller audio (sub-VAD-threshold) so the local VAD stays silent; the
MockRealtimeBrain advisory schedule emits speech_started after 2 appends
and the kill flows through slice-3's real advisory plumbing:
mock -> translator -> tap protocol -> tap_client -> advisory_tx -> Reflex.
Proves the ASR-VAD backstop path (spec §3.1, §6; done-criteria #8)."
```
## Task 10 — CI seam gate + final sweep
**File:** `.github/workflows/ci.yml` only.
**Step 1 — the seam gate.** The invariant: `crates/rutster-media/src/loop_driver.rs` and `crates/rutster-media/src/rtc_session.rs` are byte-identical to slice-3, forever, until an ADR says otherwise. The plan sketches `git diff --exit-code origin/main -- <files>`, but that is a no-op on pushes to main itself. Implement the stronger pinned-blob form:
```bash
# compute the canonical blob hashes (run once, from the worktree):
git rev-parse main:crates/rutster-media/src/loop_driver.rs
git rev-parse main:crates/rutster-media/src/rtc_session.rs
```
Then add a CI step (in the existing test job, after checkout) that recomputes each file's blob hash with `git hash-object <file>` and fails if either differs from the pinned value. Include a learner-facing comment in the YAML explaining: (a) what the seam is, (b) that a legitimate seam change means updating the pinned hashes in the same PR — loud and reviewable by design. Note this pinned-hash choice as a plan deviation in the PR description (it strengthens the plan's sketch; same intent).
**Step 2 — the full sweep** (all must pass locally before you push):
```bash
cargo fmt --all --check
cargo clippy --all --all-targets -- -D warnings
cargo test --all
cargo deny check
cargo doc --no-deps
```
**Step 3 — commit** with `git commit -s`, message `ci(slice-4): seam gate — loop_driver + rtc_session pinned byte-identical` plus a body noting the pinned hashes. Do **NOT** create or push any git tag — propose the `slice-4-e2e-green` tag in the PR description; the maintainer tags main after the squash-merge.
## Hard rules
- **The seam files are untouchable.** You are building the gate that enforces this; do not become its first offender. If anything forces a change there, STOP and print a `## QUESTION` block.
- **DCO signoff on every commit**: `git commit -s`. No exceptions.
- **Learner-facing comments** per AGENTS.md — including in the test and the CI YAML.
- **Hot-path policy** (if you touch any 20 ms-tick code, which you should not need to): never `?`-propagate on the tick; `try_recv`/`try_send`, drop + observe + continue.
- No `git push --force`, no `git reset --hard`, no `git branch -D`, no `rm -rf`, no `git checkout -- .`, no editing files outside your worktree, no touching `main` directly. The maintainer owns merges and tags.
- A test you cannot make green after honest debugging is a `## QUESTION` block, not a fudged assertion, not an `#[ignore]`.
## Status discipline
Print this block at: setup complete, each task start, each commit, anything unexpected, and REVIEW-READY. Keep `Notes` to 3 sentences.
```
## STATUS UPDATE — FINISHER
Time: <iso8601>
Branch: slice-4-finisher
Task: <9.2 | 10>
Status: STARTED | IN-PROGRESS | DONE | BLOCKED | REVIEW-READY
Last commit: <short sha + first line>
Tests: <green | red (which) | N/A>
Notes: <what + why>
```
When blocked on a human decision, print a `## QUESTION` block (Context / Options A-B-C / Recommended / Blocker: yes|no) and STOP — do not pick a destructive or scope-changing option yourself.
## Final steps — REVIEW-READY
Run the full sweep (Task 10 Step 2 list) once more from a clean state, then:
```bash
git push -u origin slice-4-finisher
tea pulls create \
--head slice-4-finisher \
--base main \
--title "slice-4 (finisher): secondary-path e2e + CI seam gate (Tasks 9.2 + 10)" \
--description "## What lands
- Task 9 Step 2: secondary-path barge-in e2e — brain advisory as backstop trigger through slice-3's real plumbing
- Task 10: CI seam gate (pinned blob hashes for loop_driver.rs + rtc_session.rs) + full verification sweep
## Plan deviations
- <manual tick-driving instead of MediaThread, if taken>
- seam gate uses pinned blob hashes instead of origin/main diff (stronger; also guards pushes to main)
## Done-criteria (spec §7)
- <paste the §7 checklist with each item checked/unchecked and one-line evidence>
## Merge instructions
- squash-merge
- DCO signoff on every commit (AGENTS.md)
- after merge, maintainer tags main: slice-4-e2e-green"
```
Print a final `## STATUS UPDATE` with `Status: REVIEW-READY` and the PR URL, then stop. Do not merge the PR.
## First action
After the required reading: print a `## STATUS UPDATE` confirming setup (worktree created, on `slice-4-finisher`, plan absorbed), then start Task 9 Step 2.