Description
The backend start handler at app/api/streams/[id]/start/route.ts unconditionally flips any stream to active without consulting the authoritative transition table in app/lib/state-machine.ts. A stream that is already ended, withdrawn, or paused-but-already-active can be illegally restarted, corrupting the lifecycle invariant draft → active → paused → ended → withdrawn. This is a server-side state-machine correctness bug, not a UI concern.
Requirements and Context
- Route
app/api/streams/[id]/start/route.ts must call transition(stream.status, "start") from app/lib/state-machine.ts and reject illegal transitions with 409 ILLEGAL_TRANSITION.
- Preserve idempotent
start on an already-active stream (the transition table already models this).
- Keep the existing rate-limit and org-policy checks intact.
- Must be secure, tested, and documented
- Should be efficient and easy to review
Suggested Execution
- Fork the repo and create a branch
git checkout -b bug/start-state-machine-enforcement
- Implement changes
app/api/streams/[id]/start/route.ts — replace the unconditional status mutation with a transition() call
app/lib/state-machine.ts — reuse, do not duplicate, the transition logic
- Map
ILLEGAL_TRANSITION to the shared { error: { code, message } } envelope with HTTP 409
- Test and commit
npm test -- app/api/streams
- Cover edge cases: start from
draft, paused, ended, withdrawn, and a missing stream
- Include test output and notes in the PR
Example commit message
fix: enforce state-machine transitions in stream start handler
Acceptance Criteria
Guidelines
- Minimum 90% test coverage; cover every illegal-transition branch
- Clear documentation and inline comments
- Timeframe: 96 hours
Description
The backend
starthandler atapp/api/streams/[id]/start/route.tsunconditionally flips any stream toactivewithout consulting the authoritative transition table inapp/lib/state-machine.ts. A stream that is alreadyended,withdrawn, orpaused-but-already-active can be illegally restarted, corrupting the lifecycle invariantdraft → active → paused → ended → withdrawn. This is a server-side state-machine correctness bug, not a UI concern.Requirements and Context
app/api/streams/[id]/start/route.tsmust calltransition(stream.status, "start")fromapp/lib/state-machine.tsand reject illegal transitions with409 ILLEGAL_TRANSITION.starton an already-activestream (the transition table already models this).Suggested Execution
app/api/streams/[id]/start/route.ts— replace the unconditional status mutation with atransition()callapp/lib/state-machine.ts— reuse, do not duplicate, the transition logicILLEGAL_TRANSITIONto the shared{ error: { code, message } }envelope with HTTP 409npm test -- app/api/streamsdraft,paused,ended,withdrawn, and a missing streamExample commit message
Acceptance Criteria
endedorwithdrawnstream returns409 ILLEGAL_TRANSITIONdraft/pausedstream still succeeds and setsactivestarthandler imports and usestransition()fromapp/lib/state-machine.tsGuidelines