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

10 KiB
Raw Permalink Blame History

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)

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.rsReflex<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_txReflex) — 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):

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:

# 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):

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:

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.