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>
This commit is contained in:
157
docs/superpowers/kickoffs/2026-07-04-slice-4-finisher-prompt.md
Normal file
157
docs/superpowers/kickoffs/2026-07-04-slice-4-finisher-prompt.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# 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.
|
||||||
Reference in New Issue
Block a user