Co-authored-by: Aaron D. Lee <himself@adlee.work> Co-committed-by: Aaron D. Lee <himself@adlee.work>
296 lines
18 KiB
Markdown
296 lines
18 KiB
Markdown
# 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.
|