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

18 KiB
Raw Blame History

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)

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, dispatch:

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

  • T1G711Codec + 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.
  • T3TwilioMediaStreamsServer (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).
  • T4TrunkSession (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.
  • T5MediaCmd::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.
  • T7crates/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.
  • T8crates/rutster-trunk/tests/sim_integ.rs — PSTN-sim e2e integration test. MockTwilioMediaStreamsServer (in-process test double feeding synthetic PcmFrames)
    • 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:

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:

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.