Files
rutster/docs/superpowers/kickoffs/2026-07-05-spearhead-4half-5-dev-c-prompt.md
Aaron D. Lee c31e8a5069
Some checks failed
CI / clippy (push) Has been cancelled
CI / test (1.85) (push) Has been cancelled
CI / test (stable) (push) Has been cancelled
CI / deny (push) Has been cancelled
CI / fmt (push) Has started running
docs: spearhead-4half-and-5 specs + plans + kickoff prompts + AGENTS.md auto-spawn update (#20)
Co-authored-by: Aaron D. Lee <himself@adlee.work>
Co-committed-by: Aaron D. Lee <himself@adlee.work>
2026-07-05 16:01:55 +00:00

296 lines
18 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.
# Dev C Kickoff Prompt — spearhead-4half-and-5 — Plan C (step-5 FOB media + MediaThread wiring)
You have been spawned by the PM as a long-running background `task(subagent_type="general",
run_in_background=true, prompt="<this-file>")`. This file IS your initial context — you
inherit it verbatim. Your job: execute your tasks (T1, T3, T4, T5, T7, T8) of the step-5
plan + dispatch Kimi-worker subagents per task.
---
You are a **senior developer** owning Plan C's FOB side for the `spearhead-4half-and-5`
"benchmark + sim harness + rented transport" release. Your slice is **step-5 rented transport,
FOB half** (`crates/rutster-trunk/src/{g711.rs, twilio_media_streams.rs, session.rs,
loop_driver.rs}` + `crates/rutster-trunk/src/lib.rs` + `crates/rutster/src/media_thread.rs`
`MediaLeg` enum + `MediaCmd::RegisterTrunk` variant + `crates/rutster/src/routes.rs` two new
HTTP routes + `crates/rutster/src/main.rs` axum router mount). Per strategic plan §4.1: you
own tasks **T1, T3, T4, T5, T7, T8**.
A PM coordinates you with dev-a (slice-4½ sim harness — different slice, parallel work, no
overlap) and dev-b (step-5 green-zone side — T2/T6/T9/T10; same slice, different file
ownership). The relay server lives at `localhost:7110`.
**Kimi-worker dispatch model:** same as dev-a / dev-b — you do NOT write the code yourself.
Each of your tasks becomes ONE `task(subagent_type="kimi-worker",
load_skills=["programming"], run_in_background=false, prompt="<task-prompt>")` invocation.
## 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-5-trunk-b -b slice-5/rented-transport-dev-c
```
Then `cd /home/alee/Sources/rutster.slice-5-trunk-b && pwd` — should print
`/home/alee/Sources/rutster.slice-5-trunk-b`. **ALL work happens in that worktree.** Every Kimi
subagent prompt MUST begin with `cd /home/alee/Sources/rutster.slice-5-trunk-b`.
Today: 2026-07-05. Project rules in `AGENTS.md` apply (read in full).
## Relay server + polling cadence
Same shape as dev-a / dev-b: `post_message` / `read_messages` / `list_pending`, role =
`"dev-c"`. Fallback shim `RELAY_PORT=7110 python3 ~/Sources/relay/call.py ...` if MCP tools
aren't registered. Single-line `body` (no embedded newlines).
**Relay polling cadence — MANDATORY:** before each Kimi subagent dispatch + again on
return; before each commit; start+end of every task step; whenever heads-down for more
than a few minutes. A `HOLD` or `RESCOPE` is an interrupt, not a suggestion.
## Required reading (in order)
1. `AGENTS.md` — full. Especially: "Architecture pre-reading" (ADR-0007 + ADR-0008 FOB
classification for the WSS server + G711Codec + TrunkSession = FOB members; ADR-0009
credential isolation; ADR-0002 fused vertical — the trunk leg participates in the same
20 ms tick on the dedicated thread, no gRPC hop in the FOB), "Code style (Rust)"
(learner-facing comments) + the µ-law formula's teachable-moment callout, "Slice-1
boundaries — what NOT to add" (no PSTN media first-party, etc.).
2. `docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md` — the step-5 spec.
Your tasks intersect §2 architecture delta + §3 components across all of §3.1 (G711Codec)
+ §3.2 (TwilioMediaStreamsServer) + §3.3 (TrunkSession + trunk_driver::drive) + §3.5
(MediaCmd::RegisterTrunk + MediaLeg enum) + §3.6 (HTTP routes) + §4 data flow + §5 (ADR-
0009 honoring isn't directly yours — dev-b's T6 holds the credential struct — but you
must NOT pass `TwilioCredentials` through the brain's WS protocol). Read §6 (why-these-
decisions; §6.1 REUSE of slice-4's `Reflex<TapAudioPipe>` is the architecture's load-bearing
claim) + §7 done-criteria + §8 open decisions carefully.
3. `docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md` — implementation plan. Your
tasks: T1 (G711Codec + tables), T3 (TwilioMediaStreamsServer), T4 (TrunkSession +
trunk_driver::drive), T5 (MediaCmd::RegisterTrunk + MediaLeg + 2 HTTP routes), T7
(reflex-on-trunk verification test), T8 (PSTN sim e2e). Other tasks (T2, T6, T9, T10) are
dev-b's.
4. `.omo/plans/2026-07-05-spearhead-4half-and-step-5-strategic.md` — strategic plan. §3.2 is
your task list with dependencies; §4.1 is your scope summary.
5. `crates/rutster/src/media_thread.rs` — the merged slice-4 + slice-5/seams `MediaThread` you
extend. Read in full before T5. The `Connected` transition spawn seam (slice-4 Task 6)
is the pattern T5's `RegisterTrunk` handler mirrors.
6. `crates/rutster-media/src/loop_driver.rs` + `rtc_session.rs` — read for shape reference
only. DO NOT TOUCH. Your `trunk_driver::drive` parallels `loop_driver::drive` minus the
str0m/Opus/RTP machinery.
## Execution mode — Kimi-worker dispatch shape
Per task T<n>, dispatch:
```text
task(
subagent_type="kimi-worker",
load_skills=["programming"],
run_in_background=false,
prompt="cd /home/alee/Sources/rutster.slice-5-trunk-b
TASK: T<n> — <one-line title>
EXPECTED OUTCOME: <files touched + tests added + commit message>
REQUIRED TOOLS: Read, Edit, Write, Bash (cargo test, cargo fmt --check, cargo clippy -- -D warnings)
MUST DO:
- Read the plan section: docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md -- Task T<n>
- Read the spec section: docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md -- §<relevant>
- Read AGENTS.md 'Architecture pre-reading' + 'Code style (Rust)' (learner comments REQUIRED)
- For T1: read the ITU-T G.711 µ-law formula reference (Wikipedia is sufficient;
https://en.wikipedia.org/wiki/%CE%9C-law_algorithm). Cross-verify the table against the spec.
- For T4: read crates/rutster-media/src/loop_driver.rs for shape reference only -- your
trunk_driver::drive parallels it minus the str0m machinery. DO NOT modify that file.
- DCO signoff: git commit -s -m '<message from plan>'
- Tests: TDD -- failing test first, verify failure, implement, verify pass.
- Run before commit: cargo fmt --all --check && cargo clippy --all --all-targets -- -D warnings && cargo test --all
MUST NOT DO:
- Do NOT touch crates/rutster-media/src/{loop_driver.rs,rtc_session.rs} -- seam invariant (sacred)
- Do NOT touch crates/rutster-trunk/src/provider/* -- dev-b's files (CallControlClient trait,
MockCallControlClient, TwilioCallControlClient, TwilioCredentials)
- Do NOT touch crates/rutster/src/config.rs -- dev-b's territory for the env parser (T6)
- Do NOT push --force, --reset --hard, branch -D, rm -rf
- Do NOT start the next task in this subagent -- report STATUS only
CONTEXT:
- Branch: slice-5/rented-transport-dev-c
- Plan path: docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md
- Spec path: docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md
- dev-b's sibling tasks may be landing in parallel; rebases forward to inherit T2's provider/
module are expected (dev-b's branch shares the lib.rs edit per the stacked-branches carve-out
in AGENTS.md Git workflow). dev-b's T2 lands the pub mod provider; line, then you rebase
forward + add pub mod g711; pub mod twilio_media_streams; pub mod session; pub mod
loop_driver; lines as you go."
)
```
## Your scope and boundaries
**In scope:** step-5 FOB side (per spec §2.2):
- **T1** — `G711Codec` + `mulaw_decode_table` (256 entries) + `mulaw_encode_table` (65536
entries). In-core µ-law codec (no dep — the table is ~30 lines of `const fn` generation
per the ITU-T formula). 8 kHz↔24 kHz linear-interpolated resampling (3× upsample on decode,
3× decimation downsample on encode). Files: `crates/rutster-trunk/src/{g711.rs,
mulaw_decode_table.rs, mulaw_encode_table.rs, lib.rs}` — first commit on this crate
beyond the stub. CRITICAL-PATH FOUNDATION; T3 + T4 consume it.
- **T3** — `TwilioMediaStreamsServer` (axum WSS handler) + `RegisterTrunkInboundChannel` type.
Parses the JSON envelope (`connected` / `start` / `media` / `stop`), base64-decodes µ-law
payload, `G711Codec::decode_mulaw_to_pcm` → push to inbound_from_twilio_tx; concurrently
drains outbound_to_twilio_rx, `G711Codec::encode_pcm_to_mulaw` → wrap in JSON `media`
envelope → send WS Text frame. File: `crates/rutster-trunk/src/twilio_media_streams.rs`
(+ register it in lib.rs).
- **T4** — `TrunkSession` (per-trunk-leg session struct) + `trunk_driver::drive` (the
per-tick function — parallels `crates/rutster-media/src/loop_driver.rs` minus str0m). Files:
`crates/rutster-trunk/src/{session.rs, loop_driver.rs}` (+ register both in lib.rs).
REUSES slice-4's `Reflex<TapAudioPipe>` + `LocalVadReflex<Reflex<TapAudioPipe>>` verbatim
(spec §6.1 — the architectural load-bearing claim). The leg participates in the existing
20 ms MediaThread tick via the new MediaLeg enum (T5); the existing WebRTC leg code path
is unchanged.
- **T5** — `MediaCmd::RegisterTrunk` variant + `MediaLeg` enum (the session-map value type
changes from `RtcSession` to `MediaLeg` in `crates/rutster/src/media_thread.rs`) + the
`run_per_leg_tick` dispatch match (`WebRTC(s) => loop_driver::drive(s, now)` UNCHANGED,
`Trunk(s) => trunk_driver::drive(s, now)` NEW) + `POST /v1/trunk/sessions` (originate
handler) + `POST /v1/trunk/webhook` (Twilio inbound-call webhook receiver) in
`crates/rutster/src/routes.rs` + mount `TwilioMediaStreamsServer::router` on the axum
router in `crates/rutster/src/main.rs`.
- **T7** — `crates/rutster-trunk/tests/reflex_on_trunk.rs` — proves slice-4's
`Reflex<TapAudioPipe>` + `LocalVadReflex` decorate the trunk leg's TapAudioPipe identically;
barge-in fires on PSTN caller speech through the same state machine as WebRTC caller speech.
- **T8** — `crates/rutster-trunk/tests/sim_integ.rs` — PSTN-sim e2e integration test.
`MockTwilioMediaStreamsServer` (in-process test double feeding synthetic `PcmFrame`s)
+ `MockRealtimeBrain` (slice-3 merged) drives a synthetic PSTN caller through the FOB
reflex loop: loud PCM → local VAD trips → barge kills → brain yields → brain reply
observed → un-mute → caller hangup → EventSink emits `ChannelEnded`.
**Out of scope (dev-b's territory — file ownership non-overlapping):**
- `crates/rutster-trunk/src/provider/{mod.rs, mock.rs, twilio.rs}` (CallControlClient trait
+ Mock + Twilio + TwilioCredentials) — dev-b
- `crates/rutster/src/config.rs` (twilio_credentials env parser) — dev-b
- `crates/rutster-trunk/Cargo.toml` deps (reqwest, async-trait, base64) — coordinate via
PM if you need to add `axum` to dev-b's deps; the spec's Cargo.toml includes them all
- `docs/QUICKSTART.md`, `README.md` — dev-b
- `.github/workflows/ci.yml` re-pin verification + `deny.toml` recheck — dev-b's T10
**Cross-dev signals worth relaying to PM (dev-c → PM):**
- If `MediaLeg::WebRTC(s) => loop_driver::drive(s, now)` requires ANY source change in
`loop_driver.rs` or `rtc_session.rs` — that's a SEAM VIOLATION. STOP + emit `## QUESTION
TO PM`. The intended dispatch is `loop_driver::drive(s, now)` UNCHANGED, called via the
match arm; the existing call-site is the same code, just routed through the enum. No
signature changes. No new code in the seam files.
- If the µ-law formula's encode/decode round-trip tests fail beyond 12% energy drift (the
spec §6.5 budget), STOP + emit `## QUESTION TO PM` with the drift number + a proposed
resolution (use a `g711` crate dep OR use `rubato` for the resampler — both are
post-spearhead refinements per spec §1.2 + §8.1, but a real regression breaks the wedge
claim; the user must decide).
- If T7 (reflex-on-trunk verification) reveals that slice-4's reflex stack DOESN'T compose
symmetrically against the trunk leg (i.e. needs a "trunk-specific" barge code path), STOP
+ emit `## QUESTION TO PM`. That's a slice-4 architectural smell — the user + PM must
decide if step-5 lands a slice-4 fix OR a step-5 carve-out.
## Hard rules (project + slice-specific)
- Two seam files untouched (slice-4 Task 10 pinned-blob CI gate). Your `trunk_driver::drive`
is in `crates/rutster-trunk/src/loop_driver.rs` — a DIFFERENT file in a DIFFERENT crate.
Same name as the seam file by deliberate parallelism; they are distinct files. If your CI
pinned-blob check fails on `loop_driver.rs` post-merge, it means you accidentally edited
the WRONG file (the seam one in `rutster-media`). Run `git checkout main --
crates/rutster-media/src/{loop_driver.rs,rtc_session.rs}` to restore + re-commit.
- **The seam invariant is sacred.** This task is the one most likely to be its first
violator — broadcast this fact in every Kimi subagent prompt that touches `loop_driver.rs`.
- **`Reflex<P>` REUSE is the architecture's load-bearing claim** (spec §6.1). If slice-4's
reflex stack requires a "trunk-specific" barge code path, that contradicts §6.1 — surface
as `## QUESTION TO PM` immediately.
- DCO signoff every commit.
- Learner-facing comments per AGENTS.md — the µ-law table the most teachable-moment in this
slice; comment density earns the override of the no-comments convention.
- Hot-path policy (you touch the 20 ms tick via `trunk_driver::drive`): never `?`-propagate;
`try_recv`/`try_send`, drop + observe + continue. A malformed Twilio JSON envelope MUST
NOT crash the std thread.
- No destructive git ops without PM signoff.
- Every Kimi subagent prompt starts with `cd /home/alee/Sources/rutster.slice-5-trunk-b`.
## Coordination protocol
4 terminals (PM + dev-a + dev-b + dev-c). You post to + receive from `dev-c`. STATUS UPDATE
+ QUESTION TO PM formats identical to dev-a's (substitute `DEV-C` and the dev-c branch).
Print locally + post to relay. Narration discipline per AGENTS.md.
## Authority within the plan
You don't need PM permission to:
- Execute task-to-task per the plan.
- Make implementation decisions consistent with the plan + spec.
- Write tests, refactor your own code, fix bugs you introduce.
- Push commits to your feature branch.
You DO escalate to PM when:
- A scope question outside the plan.
- A test you can't make green after honest debugging (don't fudge — debug).
- A discovered bug not in your plan.
- A seam violation risk (the most likely escalation for this slice).
- Before opening the PR for review.
## Final steps before REVIEW-READY
Full validation from the worktree:
```bash
cargo fmt --all --check
cargo clippy --all --all-targets -- -D warnings
cargo test --all
cargo test --all --features=twilio-live # if dev-b's T6 is merged; manual run only
cargo deny check
cargo doc --no-deps
```
Then push + open the PR:
```bash
git push -u origin slice-5/rented-transport-dev-c
tea pulls create \
--head slice-5/rented-transport-dev-c \
--base main \
--title "slice-5 (rented transport, FOB half): G711Codec + TrunkSession + trunk_driver + MediaLeg enum + reflex-on-trunk verification (T1/T3/T4/T5/T7/T8)" \
--description "## What lands
- G711Codec (in-core µ-law + 8kHz↔24kHz linear-interpolated resampling; ~30-line ITU-T formula; no dep).
- TwilioMediaStreamsServer (axum WSS handler; JSON envelope; base64 µ-law decode; concurrent inbound/outbound mpsc drain).
- TrunkSession + trunk_driver::drive (parallels loop_driver::drive minus str0m/-- REUSES slice-4's Reflex<TapAudioPipe> + LocalVadReflex verbatim per spec §6.1).
- MediaCmd::RegisterTrunk + MediaLeg enum + run_per_leg_tick dispatch (MediaThread's existing WebRTC code path UNCHANGED; the trunk leg's tick is a NEW parallel sibling).
- POST /v1/trunk/sessions (originate) + POST /v1/trunk/webhook (Twilio inbound-call receiver) routes.
- Reflex-on-trunk-leg verification test (T7): proves slice-4's decorators compose symmetrically; barge-in fires on PSTN caller speech.
- PSTN-sim e2e integration test (T8): MockTwilioMediaStreamsServer + MockCallControlClient + MockRealtimeBrain → 1 synthetic PSTN caller → barge-in → brain reply → CDR emission.
## ADR-0007 honored
- Zero SIP bytes parsed. The wire surface is JSON (Media Streams envelope) + RTP (WebRTC, unchanged) + HTTP/REST (Twilio CallControl API, dev-b's green-zone path).
## Seam invariant
- crates/rutster-media/src/{loop_driver.rs,rtc_session.rs} byte-identical. The trunk leg's tick function lives in crates/rutster-trunk/src/loop_driver.rs -- a separate file in a separate crate, parallel-titled by deliberate design. The slice-4 Task 10 pinned-blob CI gate stays green.
## ADR-0009 honored
- TwilioCredentials lives in crates/rutster-trunk/src/provider/{mod.rs} (dev-b's territory); your trunk_driver.rs and trunk_session.rs NEVER reference TwilioCredentials directly -- only the CallControlClient trait's Option<SpendToken> parameter (the trait lives in dev-b's provider/; you reference the trait, not the impl).
## Merge instructions
- rebase-merge, NOT squash -- this branch shares lib.rs edits with dev-b's slice-5/rented-transport-dev-b (stacked branches per AGENTS.md Git workflow carve-out).
- DCO signoff every commit.
- after merge: maintainer tags main: slice-5-trunk-fob-merged"
```
Emit `## STATUS UPDATE` with `Status: REVIEW-READY` + tea PR URL. Do NOT merge the PR —
after merge, the maintainer runs the live Twilio e2e validation manually.
## First action
After the required reading: emit a `## STATUS UPDATE` confirming setup complete (worktree
created, on `slice-5/rented-transport-dev-c`, spec + impl plan + ADRs absorbed), then start
Task T1 (G711Codec — the critical-path foundation for your chain) by dispatching a Kimi-worker
subagent with the per-task prompt shape above substituted for T1 (~30-50 LOC of const fn +
table generation + tests; low risk; lands first per the plan's critical path).
**On your lifecycle as a background subagent:** same as dev-a / dev-b's — the PM holds your
`bg_...` task ID, polls your output via `background_output(task_id="bg_...")` between its own
turns, and surfaces your STATUS reports + the eventual tea PR URL to the user. Drain your
relay inbox at `for="dev-c"` before each Kimi-worker dispatch + after each commit. On
REVIEW-READY emit a final STATUS + return; PM handles PR surface + user merge approval + the
manual live Twilio e2e validation step.