# Validation Matrix: Streaming Simplification (WebRTC-only)

| Row ID | Checklist Item | Status | Code Evidence | Test Evidence | Runtime Evidence |
|---|---|---|---|---|---|
| B1 | Add/confirm `SIMPLE_STREAMING` environment/config switch | done | `Backend/media/config.ts:28,44-50` (`parseFeatureFlag`, `simpleStreamingEnabled`, `streamRecordingEnabled`) | `bun test` -> `tests/media-config.test.ts` passed (3 cases) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B2 | Update stream request endpoint with simplified flow and role/link checks | done | `Backend/routes/streams.ts:168-184` (`createStreamRequestedPayload`, simplified `/streams/request` response) | `bun test` -> `tests/streaming-simple.test.ts` passed (`builds deterministic requested and started payloads`) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B3 | Update stream accept endpoint to set `streaming` and emit started | done | `Backend/routes/streams.ts:344-356` (`createStreamStartedPayload`, simplified accept response) | `bun test` -> `tests/streaming-simple.test.ts` passed (`builds deterministic requested and started payloads`) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B4 | Update stream end endpoint with proper status, end timestamp, lifecycle emit | done | `Backend/routes/streams.ts:660-721` (`status: nextStatus`, `createStreamEndedPayload`, simplified end response) | `bun test` -> `tests/streaming-simple.test.ts` passed (`normalizes ended payload and strips provider fields from API response`) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B5 | Remove media provider dependency in accept logic | done | `Backend/media/service.ts:17-24` (`mediaProviderRuntimeEnabled`, `createLiveMediaSession`), `Backend/routes/streams.ts:320-334` (accept uses wrapper result) | `bun test` -> `tests/media-config.test.ts`, `tests/streaming-simple.test.ts` both passed | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B6 | Gate/remove recording creation path in stream end logic | done | `Backend/media/config.ts:45,50`, `Backend/routes/streams.ts:681-683` (`streamRecordingEnabled`) | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B7 | Return minimal deterministic stream payloads | done | `Backend/streaming/simple.ts:35-73` (`createStream*Payload`, `toSimpleStreamSessionResponse`), `Backend/routes/streams.ts:184,356,721` | `bun test` -> `tests/streaming-simple.test.ts` passed (3 cases) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B8 | Document deprecated media fields in schema | done | `Backend/db/schema.ts:68-69` (legacy provider field comments) | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B9 | Guard media service calls behind non-simplified mode | done | `Backend/media/service.ts:17-24` (`mediaProviderRuntimeEnabled`, `createLiveMediaSession`) | `bun test` -> `tests/media-config.test.ts` passed (3 cases) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B10 | Annotate mock provider as metadata-only in phase-1 path | done | `Backend/media/providers/mock.ts:40-41` (runtime compatibility comment), `Backend/routes/streams.ts:320-334` (runtime no longer requires provider session in simplified mode) | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B11 | Ensure SFU service not required in simplified mode | done | `Backend/media/sfu/service.ts:1,6-8` (`simpleStreamingEnabled` short-circuit) | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| B12 | Deprecate command-table stream lifecycle usage under simplified mode | done | `Backend/routes/commands.ts:53`, `Backend/routes/streams.ts:168-184`, `Backend/realtime/gateway.ts:110-116` | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| R13 | Remove `stream:frame` event listener/sender from gateway | done | `Backend/realtime/gateway.ts:323-349` (`webrtc:signal` only in streaming path) | `bun test` passed all 17 tests in `Backend/tests/*` | `rg -n "stream:frame" Backend/realtime/gateway.ts` returned no matches; `bunx tsc --noEmit` exited 0 |
| R14 | Remove frame-relay participant cache and validation branches | done | `Backend/realtime/gateway.ts:240-349` (no `verifiedRelayTargets`, no frame validation branch) | `bun test` passed all 17 tests in `Backend/tests/*` | `rg -n "stream:frame" Backend/realtime/gateway.ts` returned no matches; `bunx tsc --noEmit` exited 0 |
| R15 | Keep only `webrtc:signal` relay logic for streaming | done | `Backend/realtime/gateway.ts:323-349` (`socket.on('webrtc:signal'...)`) | `bun test` -> `tests/streaming-simple.test.ts` passed (`only relays WebRTC signals between stream participants`) | `rg -n "stream:frame" Backend/realtime/gateway.ts` returned no matches; `bunx tsc --noEmit` exited 0 |
| R16 | Simplify signal validation to ownership + session checks | done | `Backend/realtime/gateway.ts:330-343` (`streamSessions` lookup + `canRelayWebrtcSignal`), `Backend/streaming/simple.ts:20-33` | `bun test` -> `tests/streaming-simple.test.ts` passed (`only relays WebRTC signals between stream participants`) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| R17 | Remove command retry polling for stream command queue when flag is enabled | done | `Backend/realtime/gateway.ts:110-116,155-161` (`start_stream` dispatch/retry disabled under `SIMPLE_STREAMING`) | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/` |
| R18 | Preserve `stream:started` and `stream:ended` event emission | done | `Backend/routes/streams.ts:344-353,685-714`, `Backend/realtime/gateway.ts:36-49` (`sendRealtimeToDevice`) | `bun test` -> `tests/streaming-simple.test.ts` passed (`builds deterministic requested and started payloads`, `normalizes ended payload`) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| R19 | Keep strict socket auth and room handling for devices | done | `Backend/realtime/gateway.ts:176-235` (token auth, role match, room join) | `bun test` -> `tests/device-token.test.ts` passed (2 cases) | `bunx tsc --noEmit` exited 0 in `Backend/` |
| W20 | Simplify web stream state machine | done | `WebApp/src/lib/app/controller.js:144-152,950-975`, `WebApp/src/lib/app/store.js:43-44` | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| W21 | Remove web fallback image mode and frame state | done | `WebApp/src/lib/app/store.js:43-44`, `WebApp/src/lib/app/controller.js:144-152`, `WebApp/src/routes/client/+page.svelte:183-189` | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `rg -n "stream:frame|clientFallbackFrame|getPublishCreds|getSubscribeCreds|frameRelay" WebApp/src` returned no matches; `npm run build` passed |
| W22 | Enforce video-only rendering path on client | done | `WebApp/src/routes/client/+page.svelte:183-189`, `WebApp/src/lib/app/controller.js:723,950-968` | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| W23 | Simplify `ontrack` handling | done | `WebApp/src/lib/app/controller.js:711-723` (`connection.ontrack`) | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| W24 | Add deterministic teardown path on end/unmount/navigation | done | `WebApp/src/lib/app/controller.js:596-614,975-992,1125-1132` (`teardownPeerConnection`, `stream:ended`, cleanup) | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| W25 | Remove frame capture/sender fallback on web camera page | done | `WebApp/src/lib/app/controller.js:869-882,908-928` (camera request handling now only starts preview/accept/offer), `WebApp/src/routes/camera/+page.svelte` remains preview-only | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `rg -n "stream:frame|clientFallbackFrame|getPublishCreds|getSubscribeCreds|frameRelay" WebApp/src` returned no matches; `npm run build` passed |
| W26 | Ensure camera only sends WebRTC offer path | done | `WebApp/src/lib/app/controller.js:738-749,869-882,908-928` (`startOfferToClient`, `handleCameraStreamRequest`) | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| W27 | Remove recording hooks tied to fallback transport | done | `WebApp/src/lib/app/controller.js:869-882,975-992` (recording kept, fallback transport removed), no frame relay refs remain in `WebApp/src` | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `rg -n "stream:frame|clientFallbackFrame|getPublishCreds|getSubscribeCreds|frameRelay" WebApp/src` returned no matches; `npm run build` passed |
| W28 | Remove client-side image fallback UI branches | done | `WebApp/src/routes/client/+page.svelte:183-189`, `WebApp/src/lib/app/store.js:43-44` | `npm run check` in `WebApp/` passed (`svelte-check found 0 errors and 0 warnings`) | `npm run build` in `WebApp/` passed |
| M29 | Remove mobile frame relay state and timer lifecycle | blocked | `MobileApp/src/app-context.tsx:86-87,175-213`, `MobileApp/README.md:75-79` show native mobile still depends on frame relay; `MobileApp/package.json` has no `react-native-webrtc` dependency | `npm run lint` in `MobileApp/` passed | `rg -n "react-native-webrtc" MobileApp/package.json` returned no matches; native WebRTC stack still absent |
| M30 | Align mobile state transitions with web logic | blocked | `MobileApp/src/app-context.tsx:105-113,349-381`, `MobileApp/src/state.ts:92-93`, `MobileApp/README.md:75-79` | `npm run lint` in `MobileApp/` passed | `npx tsc --noEmit` exited 0 in `MobileApp/`; implementation remains blocked by missing native WebRTC runtime |
| M31 | Remove mobile JPEG relay loop | blocked | `MobileApp/src/app-context.tsx:183-213,312-319`, `MobileApp/README.md:75-79` | `npm run lint` in `MobileApp/` passed | `rg -n "react-native-webrtc" MobileApp/package.json` returned no matches; removing the JPEG loop would break the only current mobile stream path |
| M32 | Remove mobile image fallback rendering path | blocked | `MobileApp/app/(tabs)/index.tsx:150-151,284`, `MobileApp/src/state.ts:92-93` | `npm run lint` in `MobileApp/` passed | `npx tsc --noEmit` exited 0 in `MobileApp/`; image fallback remains required until native WebRTC view/render support exists |
| M33 | Remove publish/subscribe credential calls from streaming runtime | blocked | `MobileApp/src/app-context.tsx:312,361`, `MobileApp/src/api.ts:84-85` | `npm run lint` in `MobileApp/` passed | `npx tsc --noEmit` exited 0 in `MobileApp/`; credential calls remain because mobile still follows the legacy relay path |
| M34 | Ensure mobile peer cleanup on end/unmount | blocked | `MobileApp/src/app-context.tsx:375-412` has no RTCPeerConnection lifecycle to clean up; `MobileApp/README.md:79` documents missing RN WebRTC stack | `npm run lint` in `MobileApp/` passed | `rg -n "react-native-webrtc" MobileApp/package.json` returned no matches; unblock by adding supported native WebRTC dependency and peer lifecycle code |
| C35 | Update OpenAPI streaming contract | done | `Backend/docs/openapi.ts:740,786,832`; legacy credential/playback stream paths removed from OpenAPI | `bunx tsc --noEmit` exited 0 in `Backend/` | `rg -n "publish-credentials|subscribe-credentials|playback-token" Backend/docs/openapi.ts` returned no matches |
| C36 | Update docs/comments to remove fallback as primary path | done | `Backend/README.md:133,147,191`, `MobileApp/README.md:75-79`, `Backend/public/backend-architecture.html:499-500`, `Backend/db/schema.ts:68-69` | `npm run check` in `WebApp/` passed; `bunx tsc --noEmit` in `Backend/` passed | `rg -n "stream:frame|frame relay|SIMPLE_STREAMING" Backend/README.md MobileApp/README.md Backend/public/backend-architecture.html docs/STREAMING_SIMPLIFICATION_ROLLOUT_AND_ROLLBACK.md` confirmed updated docs |
| C37 | Add migration and deprecation guidance | done | `docs/STREAMING_SIMPLIFICATION_ROLLOUT_AND_ROLLBACK.md:11-19`, `Backend/README.md:147-149` | `bunx tsc --noEmit` exited 0 in `Backend/` | `rg -n "Migration notes|Safe enablement sequence" docs/STREAMING_SIMPLIFICATION_ROLLOUT_AND_ROLLBACK.md` returned matches at lines 11 and 19 |
| C38 | Add structured stream lifecycle logging | done | `Backend/routes/streams.ts:171,230,359,719`, `Backend/realtime/gateway.ts:348` | `bun test` passed all 17 tests in `Backend/tests/*` | `bunx tsc --noEmit` exited 0 in `Backend/`; log markers present for request/accept/end/signal events |
| C39 | Add compile/build checks after cleanup | done | Validation spans `Backend/`, `WebApp/`, and `MobileApp/` | `bun test` passed (17/17), `npm run check` passed, `npm run lint` passed | `bunx tsc --noEmit` in `Backend/` exited 0, `npm run build` in `WebApp/` passed, `npx tsc --noEmit` in `MobileApp/` exited 0 |
| C40 | Add rollback runbook for flag behavior | done | `docs/STREAMING_SIMPLIFICATION_ROLLOUT_AND_ROLLBACK.md:35-43` | `bunx tsc --noEmit` exited 0 in `Backend/` | `rg -n "Rollback checklist|Known blocker" docs/STREAMING_SIMPLIFICATION_ROLLOUT_AND_ROLLBACK.md` returned matches at lines 35 and 43 |
