# Traceability Matrix

This matrix maps master-spec requirements to planned tests and implementation evidence. Test IDs are stable placeholders to be implemented phase by phase.

## Acceptance Criteria Traceability

| Requirement ID | Requirement | Phase | Planned tests | Evidence files |
|---|---|---:|---|---|
| AC-01 | Admin can create a wedding and upload all required images and sounds. | 1 | `BE-WED-001`, `BE-ASSET-001`, `E2E-ADMIN-001` | `server/tests/Integration/WeddingCrudTest.php`, `AssetUploadTest.php`, `tests/e2e/admin-setup.spec.ts` |
| AC-02 | QR link opens the correct themed game. | 1 | `BE-JOIN-001`, `FE-PWA-001` | `JoinResolveTest.php`, `tests/e2e/join-qr.spec.ts` |
| AC-03 | AirBridge adapter can resolve a valid compact join payload. | 6 | `AB-001`, `AB-EXT-001`, `AB-SEC-001` | `packages/platform/src/airbridge/*.test.ts` |
| AC-04 | Three reels display 40 stops and 20 identities. | 1 | `REEL-001`, `REEL-002`, `FE-REEL-001` | `ReelStripServiceTest.php`, `reel-engine.test.ts` |
| AC-05 | Server controls every outcome. | 2 | `SPIN-SEC-001`, `SPIN-SEC-002` | `SpinAuthorizationServiceTest.php`, `spin-controller.test.ts` |
| AC-06 | Celebration rate is configurable and statistically verified. | 2 | `STAT-001`, `STAT-002` | `OutcomeEngineStatisticalTest.php` |
| AC-07 | Every replaceable identity is equally selectable on wins. | 2 | `STAT-003` | `OutcomeEngineStatisticalTest.php` |
| AC-08 | Protected-image combinations trigger Made in Heaven and cannot open camera capture. | 2,4 | `PROT-001`, `PROT-002`, `CAP-SEC-001` | `OutcomeEngineTest.php`, `CaptureEntitlementTest.php` |
| AC-09 | A normal winner can submit one to three photos. | 4 | `CAP-001`, `CAP-002`, `IMG-001`, `E2E-CAP-001` | `ImageUploadTest.php`, `capture-flow.spec.ts` |
| AC-10 | Photos replace the matched identity across all clients. | 4 | `REP-001`, `RT-REP-001`, `E2E-REP-001` | `ReplacementWorkflowTest.php`, `realtime-replacement.spec.ts` |
| AC-11 | Added and removed guests are publicly announced. | 4 | `ANN-001`, `ANN-002` | `AnnouncementFormatterTest.php`, `replacement-announcement.test.ts` |
| AC-12 | Removed guest receives private encouragement when enabled. | 4 | `ANN-PRIV-001`, `ANN-PRIV-002` | `ReplacementWorkflowTest.php`, `realtime-private.spec.ts` |
| AC-13 | Removed media remains in history. | 4,5 | `HIST-001`, `ASSET-IMM-001` | `HistoryServiceTest.php`, `AssetImmutabilityTest.php` |
| AC-14 | Removed guest can later win back onto any replaceable identity. | 4,5 | `HIST-REENTRY-001`, `E2E-REENTRY-001` | `HistoryTimelineTest.php`, `reentry-flow.spec.ts` |
| AC-15 | Concurrent replacement attempts cannot corrupt state. | 4 | `REP-CONC-001`, `REP-IDEMP-001` | `ConcurrentReplacementTest.php` |
| AC-16 | Admin can pause, moderate, restore, close, and export. | 5 | `ADMIN-001`, `MOD-001`, `RESTORE-001`, `EXPORT-001` | `AdminWorkflowTest.php`, `ExportServiceTest.php` |
| AC-17 | Event close produces immutable final snapshot and chronological gallery. | 5 | `SNAP-001`, `SNAP-IMM-001`, `GALLERY-001` | `SnapshotServiceTest.php`, `GalleryExportTest.php` |
| AC-18 | PWA and extension use the same core code. | 1,7 | `BUILD-CORE-001`, `MV3-001` | workspace dependency tests, extension build scan |
| AC-19 | Core flows pass on iPhone, Android, desktop Chrome, and MV3 extension. | 7 | `DEVICE-IOS-001`, `DEVICE-ANDROID-001`, `DEVICE-MV3-001` | `docs/RELEASE_READINESS.md`, Playwright/manual evidence |
| AC-20 | No wager, payment, or cash-prize functionality exists. | 7 | `AUDIT-NOGAMBLE-001`, `SEC-ROUTE-001` | `docs/FINAL_AUDIT.md`, static route/schema scan |

## Domain and Workflow Requirement Traceability

| Requirement ID | Requirement | Phase | Planned tests |
|---|---|---:|---|
| DOM-001 | Exactly 20 logical symbol identities exist per wedding. | 1 | `SymbolIdentitySeedTest` |
| DOM-002 | IDs 1-3 are protected and IDs 4-20 are replaceable. | 1 | `SymbolIdentitySeedTest`, `ProtectedReplacementRejectedTest` |
| DOM-003 | Each reel strip has 40 stops with two occurrences of each identity. | 1 | `ReelStripServiceTest` |
| DOM-004 | Stop mapping maps authorized logical outcomes to valid stop indices. | 2 | `StopMappingServiceTest` |
| DOM-005 | Non-winning results never accidentally form normal or protected matches. | 2 | `NonWinningOutcomeTest` |
| DOM-006 | Every server decision is logged with commitment/hash. | 2 | `SpinCommitmentAuditTest` |
| JOIN-001 | Join token resolves via QR/link/AirBridge/extension. | 1,6 | `JoinResolveTest`, `AirbridgeJoinTest` |
| JOIN-002 | Notification permission is requested only after explanation. | 1,7 | `NotificationPermissionUxTest`, manual device checklist |
| SPIN-001 | `POST /spins` validates event state, session, rate limit, and version. | 2 | `SpinAuthorizationValidationTest` |
| SPIN-002 | Client animates only returned authorization. | 2 | `spin-controller.test.ts`, E2E spin smoke |
| SPIN-003 | Completion acknowledgment records animation completion. | 2 | `SpinCompletionTest` |
| PAUSE-001 | Initial release uses `finish_in_progress`. | 3,4 | `PausePolicyTest` |
| PAUSE-002 | Wedding states include OPEN, REPLACEMENT_PENDING, COMMITTING_REPLACEMENT, ANNOUNCING, PAUSED_BY_ADMIN, CLOSED. | 3 | `WeddingStateMachineTest` |
| CAP-001 | Entitlement expires without replacement after timeout. | 4 | `EntitlementTimeoutTest` |
| CAP-002 | Client supports getUserMedia and file-input fallback. | 4,7 | `camera-capture.test.ts`, device checklist |
| IMG-001 | Server produces 1024, 512, and 160 variants. | 4 | `ImageProcessorVariantTest` |
| IMG-002 | Server validates MIME by content and re-encodes. | 4 | `ImageSecurityTest` |
| REP-001 | Replacement writes old end time and new start time in one transaction. | 4 | `ReplacementTransactionTest` |
| REP-002 | Protected identities cannot be replaced. | 4 | `ProtectedReplacementRejectedTest` |
| RT-001 | Realtime events include eventId, weddingId, sequence, stateVersion, type, occurredAt, payload. | 3 | `RealtimeEnvelopeTest` |
| RT-002 | Clients discard duplicate events and refresh after sequence gap. | 3 | `RealtimeGapRecoveryTest` |
| RT-003 | Polling fallback works every 3-5 seconds. | 3 | `PollingFallbackTest` |
| HIST-001 | Event history preserves wins, uploads, replacements, arrivals, departures, protected matches. | 5 | `HistoryCompletenessTest` |
| CLOSE-001 | Event close rejects new spins and creates immutable snapshot. | 5 | `CloseWeddingTest`, `SnapshotImmutabilityTest` |
| AIR-001 | AirBridge carries only discovery fields. | 6 | `AirbridgePayloadSchemaTest` |
| AIR-002 | AirBridge validation rejects expired/tampered/wrong audience payloads. | 6 | `AirbridgeValidationTest` |
| SEC-001 | HTTPS, secure cookies, CSRF, rate limits, signed short-lived tokens. | 0-7 | `SecurityMiddlewareTest`, final audit |
| A11Y-001 | 44px targets, keyboard controls, reduced motion, live regions. | 1-7 | `AccessibilitySmokeTest`, manual audit |
| OFF-001 | Offline disables spin and refreshes state before enabling on reconnect. | 3,7 | `OfflineBehaviorTest` |
| LOAD-001 | 500 connected clients and 50 spins/sec burst. | 7 | `k6`/load test evidence |

## Baseline Test Status

No tests exist yet. The first implementation phase must create the test harness before product features are added.
