Suggested model tier: Sonnet 4.6 low effort (pure logic over T1/T3 contracts; well-bounded)
Context
Traces are linear; cognition isn't. The Arc changes state at arbitrary moments, and a clip can't anticipate that. TraceStateMachine bridges the two: named states map to TraceSegments, and a transition policy decides how playback moves between them without visual pops.
Deliberately generic — this type knows nothing about Arc, Socket, or Lumos semantics. It maps strings to segments. Socket binds Arc Signal states to segment names in its own integration ticket. (Preserve optionality: the morphology renderer, future NPCs, anything emitting VoxelFrames gets state-driven playback for free.)
Objective
TraceStateMachine in :phosphor-trace that drives a TracePlayer through segment changes with deterministic, pop-free transition behavior.
Expected outcomes
TraceStateMachine(trace, initialState: String) with requestState(name: String).
- Transition resolution order, checked at request time:
- If a one-shot transition segment named
"$current→$target" exists in the trace → finish current loop iteration is NOT required; play the transition segment once, then enter the target's loop.
- Else →
FinishLoopThenSwitch: complete the current loop iteration, switch at the loop boundary (boundaries are visually continuous by construction since loops are recorded to wrap).
- Configurable override:
Crossfade(durationMs) — player exposes two concurrent read heads and a blend weight; the blending itself is performed downstream (the player emits BlendedFrameRequest or pre-blended frames — recon decides which is cheaper given the dynamic-channel layout from T1).
- Re-entrant requests collapse (requesting the current state is a no-op; rapid A→B→A settles correctly).
state: StateFlow<String> for observers.
Technical constraints
commonMain, :phosphor-trace; no Compose; deterministic given a deterministic clock (testable with virtual time); Result-typed error for unknown state/segment names.
Tasks
A — Recon (comment before code): Read T1's final channel layout and T3's player internals; decide where blending happens (player-side pre-blend vs downstream) with a one-paragraph cost rationale. STOP for approval.
B — State machine + transition policies.
C — Fuzz test: Seeded random sequence of requestState calls at random virtual-time offsets across a synthetic 3-state trace; assert: never an out-of-range frame index, never a discontinuity exceeding the crossfade envelope, terminal state always reached, same seed → same playback log.
Validation / DoD
Fuzz test green with 3 different seeds pinned in CI; unknown-state request returns typed failure without crashing playback; demo shows idle→thinking→idle driven by buttons with no visible pop.
Out of scope
Arc/Signal mapping (Socket integration ticket); authoring transition segments (Workbench usage, not code); easing curves beyond linear crossfade.
Human review gate
Miley approves the blend-placement recon before B; visually confirms the 3-state demo before close.
Agent handoff prompt
You are implementing PHO-39 in socket-link/phosphor. Depends on PHO-37 (merged).
1. RECON FIRST: read VoxelTrace channel layout + TracePlayer internals; comment
blend-placement decision (player pre-blend vs downstream) + rationale. STOP.
2. Implement TraceStateMachine: transition resolution order exactly as
specified (explicit "a→b" segment > FinishLoopThenSwitch > configured
Crossfade). StateFlow<String> for observers. Result-typed unknown-state error.
3. Generic only — no Arc/Socket/Lumos references in this module.
4. Fuzz test with seeded virtual time: no OOB index, no pop beyond crossfade
envelope, deterministic playback log per seed.
5. DoD: green JVM + iosSimulatorArm64; 3-state demo recording in PR.
If recon contradicts any assumption in this ticket, STOP and comment.
Suggested model tier: Sonnet 4.6 low effort (pure logic over T1/T3 contracts; well-bounded)
Context
Traces are linear; cognition isn't. The Arc changes state at arbitrary moments, and a clip can't anticipate that.
TraceStateMachinebridges the two: named states map toTraceSegments, and a transition policy decides how playback moves between them without visual pops.Deliberately generic — this type knows nothing about Arc, Socket, or Lumos semantics. It maps strings to segments. Socket binds Arc Signal states to segment names in its own integration ticket. (Preserve optionality: the morphology renderer, future NPCs, anything emitting VoxelFrames gets state-driven playback for free.)
Objective
TraceStateMachinein:phosphor-tracethat drives aTracePlayerthrough segment changes with deterministic, pop-free transition behavior.Expected outcomes
TraceStateMachine(trace, initialState: String)withrequestState(name: String)."$current→$target"exists in the trace → finish current loop iteration is NOT required; play the transition segment once, then enter the target's loop.FinishLoopThenSwitch: complete the current loop iteration, switch at the loop boundary (boundaries are visually continuous by construction since loops are recorded to wrap).Crossfade(durationMs)— player exposes two concurrent read heads and a blend weight; the blending itself is performed downstream (the player emitsBlendedFrameRequestor pre-blended frames — recon decides which is cheaper given the dynamic-channel layout from T1).state: StateFlow<String>for observers.Technical constraints
commonMain,
:phosphor-trace; no Compose; deterministic given a deterministic clock (testable with virtual time); Result-typed error for unknown state/segment names.Tasks
A — Recon (comment before code): Read T1's final channel layout and T3's player internals; decide where blending happens (player-side pre-blend vs downstream) with a one-paragraph cost rationale. STOP for approval.
B — State machine + transition policies.
C — Fuzz test: Seeded random sequence of
requestStatecalls at random virtual-time offsets across a synthetic 3-state trace; assert: never an out-of-range frame index, never a discontinuity exceeding the crossfade envelope, terminal state always reached, same seed → same playback log.Validation / DoD
Fuzz test green with 3 different seeds pinned in CI; unknown-state request returns typed failure without crashing playback; demo shows idle→thinking→idle driven by buttons with no visible pop.
Out of scope
Arc/Signal mapping (Socket integration ticket); authoring transition segments (Workbench usage, not code); easing curves beyond linear crossfade.
Human review gate
Miley approves the blend-placement recon before B; visually confirms the 3-state demo before close.
Agent handoff prompt