# Traceability Matrix

Maps every acceptance criterion and every restriction in `_docs/00_problem/` to the test scenarios that verify it (this directory) and the expected-result row in `_docs/00_problem/input_data/expected_results/results_report.md` that provides the quantifiable observable. Quarantined tests are marked `[Q]` — they assert against a Phase B target feature or a Step 4 fix that has not landed; they activate the day the implementation ships.

## Acceptance Criteria Coverage

| AC ID | Acceptance Criterion (short) | Tests | results_report rows | Coverage |
|-------|------------------------------|-------|---------------------|----------|
| AC-01 | `credentials:'include'` on every authenticated fetch | FT-P-01 (un-quarantined cycle 3 / 2026-05-13 by AZ-510 — bootstrap is now POST + `credentials:'include'` with chained `/users/me` per Vision P3; FT-P-01 runs as a regression guard on the wire shape), FT-P-02, NFT-PERF-02, NFT-SEC-04, NFT-RES-01, NFT-RES-08 | 01, 02, 03 | Covered |
| AC-02 | Bearer never written to client storage | NFT-SEC-01 | 04 | Covered |
| AC-03 | Refresh cookie `Secure HttpOnly SameSite=Strict` | NFT-SEC-02, NFT-SEC-03 | 05, 06, 07 | Covered |
| AC-04 | Numeric enums match suite spec | FT-P-04, FT-P-05, FT-P-06 | 14, 15, 16, 17, 18, 19 | Covered (`enum_spec_snapshot.json` committed — Phase 3 gate resolved) |
| AC-05 | Annotation save endpoint + required body fields | FT-P-07, FT-P-08 | 22, 23 | Covered |
| AC-06 | Selected-flight persistence path | FT-P-16, FT-P-17 | 32, 33 | Covered |
| AC-07 | Bulk-validate works | FT-P-20, FT-P-21, NFT-PERF-07 | 36, 37 | Covered |
| AC-08 | Live-GPS SSE per flight | FT-P-18, FT-P-19, NFT-PERF-04, NFT-PERF-05, NFT-RES-10, NFT-RES-LIM-06, NFT-RES-LIM-07 | 34, 35, 97 | Covered |
| AC-09 | Annotation-status SSE during page lifetime | FT-P-09, FT-P-10, NFT-PERF-06, NFT-RES-LIM-05 | 24, 25, 97 | Covered |
| AC-10 | Upload size cap 500 MB + UI error path | FT-N-06, NFT-RES-07, NFT-RES-LIM-02 | 38, 39 | Covered |
| AC-11 | Initial JS bundle ≤ 2 MB | NFT-PERF-01, NFT-RES-LIM-01 | 40 | Covered (documentary — no CI gate today) |
| AC-12 | i18n key parity en ↔ ua | FT-P-22, FT-P-23 | 45, 46 | Covered |
| AC-13 | i18n detector + persistence | FT-P-24 [Q], FT-P-25 [Q] | 47, 48 | Covered (quarantined — Step 4 fix) |
| AC-14 | Destructive actions require ConfirmDialog + alert() forbidden | FT-P-26, FT-P-27, FT-N-07, NFT-SEC-07, NFT-SEC-08 | 49, 50, 51 | Covered |
| AC-15 | ConfirmDialog a11y | FT-P-28, FT-P-29, FT-N-08 | 52, 53, 54 | Covered |
| AC-16 | Header flight dropdown a11y | FT-P-30, FT-P-31, FT-N-09 | 55, 56, 57 | Covered |
| AC-17 | ProtectedRoute spinner a11y + timeout | FT-P-32, FT-P-33 [Q], NFT-RES-04 [Q] | 58, 59 | Covered (quarantined for timeout) |
| AC-18 | Browser support — Chromium + Firefox latest 2 | FT-P-34, NFT-PERF-10 | 60, 98 | Covered (manual smoke, no automated gate today) |
| AC-19 | Mobile / desktop breakpoint variants | FT-P-35, FT-P-36 | 61, 62 | Covered |
| AC-20 | OpenWeatherMap key not in source | NFT-SEC-09 (all 3 steps active — source check un-quarantined on cycle 2 / 2026-05-12 by AZ-499) | 63 | Covered |
| AC-21 | UserSettings panel-width persistence | FT-P-37 [Q], FT-P-38 [Q], NFT-PERF-08 [Q] | 64, 65 | Covered (quarantined) |
| AC-22 | RBAC client-side route gates | FT-N-03 [Q], FT-N-04, FT-N-05 [Q], NFT-SEC-05 [Q], NFT-SEC-06 [Q], NFT-RES-08 | 08, 09, 10 | Covered (quarantined for `/admin` + `/settings` gates) |
| AC-23 | Auth refresh transparency | FT-P-02, FT-P-03, NFT-PERF-02, NFT-RES-01; "AC-4 (AZ-510)" colocated test in `src/auth/AuthContext.test.tsx` covers the bootstrap edge where POST refresh succeeds but chained `/users/me` returns 401 → bearer cleared, console.error logged (added cycle 3 / 2026-05-13 by AZ-510) | 11, 12 | Covered |
| AC-24 | SSE bearer-rotation reconnect | NFT-PERF-03 [Q], NFT-RES-02 [Q], NFT-RES-10 | 13, 97 | Covered (quarantined — Step 8 hardening) |
| AC-25 | Detect endpoint correctness (sync + async) | FT-P-11, FT-P-12 [Q], FT-P-13 [Q] | 26, 27, 28 | Covered (async path quarantined — F7 target) |
| AC-26 | Numeric input hygiene | FT-N-11 [Q], FT-N-12 [Q] | 66, 67 | Covered (quarantined — Step 4 fix) |
| AC-27 | Save error surfacing in settings | FT-N-13 [Q], FT-N-14 [Q], NFT-PERF-09 [Q], NFT-RES-05 [Q], NFT-RES-06 [Q] | 68, 69 | Covered (quarantined — Step 4 fix) |
| AC-28 | Annotation overlay time window `[-50, +150] ms` | FT-P-14, FT-P-15, FT-N-01, FT-N-02 | 29, 30, 31 | Covered |
| AC-29 | `mediaType` is typed (no magic literals) | FT-N-15 | 20, 21 | Covered |
| AC-30 | Class delete confirmation | FT-P-26, FT-N-07, NFT-SEC-08 | 49 | Covered (overlaps AC-14 row 49) |
| AC-31 | `mission-planner/` not in production bundle | NFT-RES-LIM-04 | 41 | Covered |
| AC-32 | CI image tag + OCI labels | NFT-RES-LIM-11, NFT-RES-LIM-12, NFT-RES-LIM-13 | 70, 71, 72 | Covered |
| AC-33 | Production runtime `nginx:alpine` only | NFT-RES-LIM-03 | 42 | Covered |
| AC-34 | nginx routes 9 services with prefix stripping | NFT-RES-LIM-09, NFT-RES-LIM-10 | 43, 44 | Covered |
| AC-35 | Manual bbox draw on CanvasEditor | FT-P-39 | 73 | Covered |
| AC-36 | 8-handle resize + Ctrl-multi-select + Ctrl-wheel zoom + Ctrl-drag pan | FT-P-40, FT-P-41, FT-P-42, FT-P-43 | 74, 75, 76, 77 | Covered |
| AC-37 | Class picker — load + hotkey + click + fallback | FT-P-44, FT-P-45, FT-P-46, FT-P-47 | 78, 79, 80, 81 | Covered (pending backend ordering check — Phase 3 gate) |
| AC-38 | PhotoMode switcher | FT-P-48, FT-P-49, FT-P-50 | 82, 83, 84 | Covered |
| AC-39 | Tile-splitting endpoint + parser | FT-P-51 [Q], FT-P-52, FT-P-53, FT-N-10 | 85, 86, 87, 88 | Covered (split surface quarantined) |
| AC-40 | Tile-zoom auto-zoom + indicator | FT-P-54 [Q], FT-P-55 [Q] | 89, 90 | Covered (quarantined — UX missing today) |
| AC-N1 | No collaborative-edit semantics | NFT-SEC-14 | 91 | Covered |
| AC-N2 | No in-browser ML | NFT-SEC-10 | 92 | Covered |
| AC-N3 | No offline mode | NFT-RES-03, NFT-SEC-12 | 93 | Covered |
| AC-N4 | No response-signature library | NFT-SEC-11 | 94 | Covered |
| AC-N5 | Dropped legacy features (Sound Detections, Drone Maintenance) | NFT-SEC-13 | 95 | Covered |
| AC-41 | Map tiles served by self-hosted `satellite-provider` via cookie auth; classic/satellite toggle removed (added cycle 2 / 2026-05-12, epic AZ-497, ticket AZ-498) | FT-P-56, FT-P-57, FT-P-58, FT-P-59, NFT-RES-11; STC-T1 (env-decl typecheck), STC-FP22 (i18n parity post-key removal), STC-ARCH-01 + STC-ARCH-02 (architecture gates stay green) | n/a — env-var plumbing + DOM observable + e2e contract; no `results_report.md` row required | Covered |
| AC-42 | mission-planner OpenWeatherMap key + base URL externalized via Vite env vars; fail-soft on missing key; STC-SEC1C source-tree literal scan defends against re-introduction (added cycle 2 / 2026-05-12, epic AZ-497, ticket AZ-499) | FT-P-60, FT-N-16; NFT-SEC-09 step 3 (STC-SEC1C); STC-T1 (env-decl typecheck) | 63 (literal-key scan shares row 63 with AC-20) | Covered (manual deliverable AZ-499 AC-7 — old key revocation at OWM dashboard — tracked separately, not a test) |
| AC-43 | mission-planner Google Geocode API key extracted to a new `services/GeocodeService.ts` module + externalized via Vite env var; fail-soft + console.warn on missing key; STC-SEC1D source-tree literal scan defends against re-introduction (added cycle 2 / 2026-05-12 from security audit `_docs/05_security/`, ticket AZ-501) | FT-P-61, FT-N-17; NFT-SEC-09b (STC-SEC1D); STC-T1 (env-decl typecheck) | n/a — env-var plumbing + console-warn assertion; no `results_report.md` row required | Covered (manual deliverable AZ-501 AC-6 — old key revocation at Google Cloud Console — tracked separately, not a test) |
| AC-44 | Vite + PostCSS upgraded past CVE-2026-39363 / GHSA-p9ff-h696-f583 / GHSA-4w7w-66w2-5vf9 / GHSA-qx2v-qp2m-jg93 in both roots via `package.json` `overrides` flooring transitive resolutions to safe versions (added cycle 2 / 2026-05-12 from security audit, ticket AZ-502) | `bun audit` (zero advisories in both roots after `bun install`) | n/a — supply-chain hygiene; verified by audit tool exit code | Covered (CI gate `bun audit --severity high` in `.woodpecker/build-arm.yml` is a Phase B follow-up — see `_docs/05_security/infrastructure_review.md` F-INF-1) |

## Restrictions Coverage

| RID | Restriction (short) | Tests / Mechanism | Coverage |
|-----|---------------------|-------------------|----------|
| H1 | ARM64-only production image | NFT-RES-LIM-03 (image base check); the build pipeline produces ARM64 only — meta-config | Covered |
| H2 | Edge-device deployment target | NFT-PERF-10, NFT-RES-LIM-08 | Covered (documentary) |
| H3 | No GPU expectation in UI image | environment.md (no GPU in test rig); NFT-SEC-10 (no ML libs) — together they verify the constraint | Covered (by composition) |
| H4 | HTML5 video + canvas + EventSource on Chromium / Firefox latest 2 | FT-P-34 | Covered |
| S1 | TypeScript strict mode | STC-S1: static read of `tsconfig.json` for `"strict": true` (planned static check — added by Phase 3 if accepted) | NOT COVERED — Phase 3 to add |
| S2 | React 19 | STC-S2: `package.json` dep version pin | NOT COVERED — Phase 3 to add |
| S3 | Vite 6 | STC-S3: `package.json` dep version pin | NOT COVERED — Phase 3 to add |
| S4 | Bun 1.3.11 | STC-S4: `package.json` `packageManager` field + Dockerfile base image pin | NOT COVERED — Phase 3 to add |
| S5 | Static-bundle output only (no Node in prod image) | NFT-RES-LIM-03 | Covered |
| S6 | REST + SSE only (no WebSocket / GraphQL / gRPC-Web) | STC-S6: dep scan for `ws`, `socket.io`, `graphql`, `apollo`, `grpc-web` (planned) | NOT COVERED — Phase 3 to add |
| S7 | Two React Contexts only (no Redux / Zustand / TanStack Query) | STC-S7: dep scan for `redux`, `zustand`, `@reduxjs/.*`, `@tanstack/.*` | NOT COVERED — Phase 3 to add |
| S8 | Tailwind 4 + `az-*` design tokens | STC-S8: dep version pin + presence of token CSS vars | NOT COVERED — Phase 3 to add |
| S9 | `leaflet@1.9.4` + `react-leaflet@5` + `leaflet-draw` + `leaflet-polylinedecorator` | STC-S9: `package.json` version pin set | NOT COVERED — Phase 3 to add |
| S10 | `chart.js@4` + `react-chartjs-2@4` | STC-S10 | NOT COVERED — Phase 3 to add |
| S11 | `@hello-pangea/dnd@18` | STC-S11 | NOT COVERED — Phase 3 to add |
| S12 | `i18next` + `react-i18next` with EN + UA bundles only | FT-P-22, FT-P-23 + STC-S12 (no other locale bundle files) | Partially Covered |
| S13 | No client-side persistence library | NFT-SEC-01 + STC-S13 (dep scan for `localforage`, `idb`, `dexie`) | Partially Covered |
| S14 | No test framework configured today | META — these tests' very existence supersedes this restriction; resolved at Step 5 (Decompose Tests) per `acceptance_criteria.md` AC-14 / S14 note | N/A — meta |
| E1 | Air-gap-friendly bundle | NFT-RES-03 (offline boot) + external-dep stubs in environment.md | Partially Covered |
| E2 | nginx strips `/api/<service>/` per service | NFT-RES-LIM-09, NFT-RES-LIM-10 | Covered |
| E3 | `Secure HttpOnly SameSite=Strict` refresh cookie | NFT-SEC-03 | Covered |
| E4 | Vite dev proxy at `/api → http://localhost:8080` | dev-only; not testable in production runtime | NOT COVERED — meta-config (Phase 3 to confirm) |
| E5 | `AZAION_REVISION` stamped at build | NFT-RES-LIM-13 | Covered |
| E6 | OCI image labels | NFT-RES-LIM-12 | Covered |
| E7 | Image registry + tag scheme | NFT-RES-LIM-11 | Covered |
| E8 | Branch triggers (`dev` / `stage` / `main`) | STC-E8: parse `.woodpecker/build-arm.yml` triggers (planned) | NOT COVERED — Phase 3 to add |
| E9 | `client_max_body_size 500M` | NFT-RES-LIM-02 | Covered |
| E10 | OpenWeatherMap direct-from-browser today | NFT-SEC-09 (key check) + environment.md `owm-stub` (E2E isolation) | Covered |
| O1 | Bilingual UI mandatory | FT-P-22, FT-P-23 | Covered |
| O2 | Bearer never in localStorage / sessionStorage | NFT-SEC-01 | Covered |
| O3 | `credentials:'include'` on every authenticated fetch | NFT-SEC-04 | Covered |
| O4 | RBAC is server-enforced (UI must NOT trust `AuthUser.role`) | meta-design + FT-N-04 (unauth → /login regardless of any client claim); STC-O4 (no `if (user.role === 'admin')` gating sensitive data, only UI hide/show) | Partially Covered — Phase 3 may add the static gate-pattern lint |
| O5 | Refresh cookie attributes | NFT-SEC-03 | Covered |
| O6 | No hardcoded credentials | NFT-SEC-09 | Covered |
| O7 | Spec is source of truth for numeric enums | FT-P-04, FT-P-05, FT-P-06 | Covered |
| O8 | Persist what you type (panel widths) | FT-P-37 [Q], FT-P-38 [Q] | Covered (quarantined) |
| O9 | Admin can edit existing detection classes (P12) | FT-P-62, FT-N-18 — landed cycle 4 / 2026-05-13 by AZ-512 (UI-side; user-authorized Option B path — implementation shipped against MSW stubs). **Live deploy gate remains** until AZ-513 ships on `admin/` and is deployed: `POST | PATCH | DELETE /classes` is verified-missing on the live admin service today; leftover `_docs/_process_leftovers/2026-05-13_az-512-admin-classes-prereq.md` stays open until then. | Covered (UI implementation + stub-tested); cross-workspace deploy gate pending AZ-513 on `admin/` |
| O10 | Destructive actions require ConfirmDialog | NFT-SEC-08, FT-P-26, FT-P-27, FT-N-07 | Covered |
| O11 | No SSR / RSC | NFT-RES-LIM-03 (no Node in image) + STC-O11 (no `react-dom/server` import) | Partially Covered |
| O12 | `mission-planner/` not compiled by production Vite build | NFT-RES-LIM-04 | Covered |
| O13 | Bundle size budget ≤ ~2 MB gzipped initial JS | NFT-PERF-01, NFT-RES-LIM-01 | Covered (target — no CI gate today) |
| O14 | No CI test step today | META — resolved at Step 5 (Decompose Tests) | N/A — meta |
| O15 | No vuln scan / SBOM / image signing | NOT COVERED — Step 6 / security_approach surface; Phase B addition | NOT COVERED |

## Coverage Summary

| Category | Total Items | Covered | Partially Covered | Not Covered | N/A (meta) | Coverage % (Covered+Partial) |
|----------|-------------|---------|-------------------|-------------|-----------|--------------------|
| Acceptance Criteria | 44 | 44 | 0 | 0 | 0 | 100% (cycle-2 deltas: AC-41, AC-42, AC-43, AC-44 added; AC-20 source check no longer quarantined. Cycle 3 deltas: FT-P-01 bootstrap part un-quarantined by AZ-510 — closes Vision P3 / Finding B3; AC-23 row gained the AZ-510 chained-`/users/me` failure-path test reference.) |
| Anti-Criteria | 5 | 5 | 0 | 0 | 0 | 100% |
| Restrictions | 41 | 17 | 8 | 13 | 3 | 61% |
| **Total** | **90** | **66** | **8** | **13** | **3** | **82%** |

Acceptance criterion coverage exceeds the 75 % template threshold. Restriction coverage is short of 75 % because most of the un-covered restrictions are dependency-version pins (S1-S11) for which a single static check pass (planned `STC-S*` family) would lift them to Covered without changing the SPA's observable behavior.

## Uncovered Items Analysis

| Item | Reason Not Covered | Risk | Mitigation |
|------|-------------------|------|-----------|
| S1-S11 (TS strict, React/Vite/Bun version pins, Tailwind, Leaflet, Chart.js, DnD) | Dependency-version restrictions need a static `package.json` / `tsconfig.json` parser pass; not authored in this phase | Drift between pinned and installed versions (e.g., transitive resolution); accidental upgrade in a refactor breaking ADRs (ADR-001 …) | Phase 3 to confirm adding the `STC-S*` family; otherwise Step 4 / Step 8 may add them as part of the testability fix |
| S12, S13 partials | `STC-S12` (no other locale bundles) and `STC-S13` (no IndexedDB / localForage / Dexie deps) need explicit dep scans | Low — currently aligned per `package.json`; risk only on dep additions | Phase 3 promotion to a single static dep-scan job (run alongside the dep-license lint) |
| E4, E8 | Dev-only proxy and pipeline branch triggers are not consumer-observable from a production build | None today; future risk if the proxy diverges from the prod nginx | Document-only; Phase 3 confirms |
| O4 partial (RBAC trust pattern) | No lint rule today; the design intent is captured but not asserted in code | UI accidentally gates sensitive data on a client claim | Phase 3 to add an `STC-O4` lint that bans `if (user.role === 'admin') { /* reveal data */ }` patterns; FT-N-04 already locks the unauth path |
| O9 (admin can edit classes — P12) | The feature does not exist today (only add + delete); cannot test absence of a regression | Functionality missing relative to spec | Phase B feature cycle will add `PATCH /api/admin/classes/{id}` plus FT-P-XX in the cycle that ships it; AC-37 / AC-30 already enforce the surrounding contract |
| O11 partial | NFT-RES-LIM-03 confirms no Node binary in the image; an explicit "no `react-dom/server` import" lint is missing | Could regress to SSR by accident on a refactor; the image base check would still pass | Phase 3 confirms `STC-O11` |
| O15 (vuln scan / SBOM / signing) | Pipeline does not emit any of these today | Supply-chain risk | Addressed at Step 6 / `security_approach.md`; outside the test-spec scope |
| AC-11, AC-18, AC-24, AC-40, AC-25 async path | Phase B / target features with quarantined tests | Tests do not gate today — risk = the feature ships without the assertion being un-quarantined | Phase 3 chooses: keep quarantined (gates the day the feature ships) OR downgrade to documentary; recommendation: keep quarantined |
| AC-04 enum spec numeric values for `MediaStatus` / `Affiliation` / `CombatReadiness` | The exact spec values are not pinned in `enum_spec_snapshot.json` yet | Tests use symbolic comparison and may silently match a wrong UI state | Phase 3 to require population of the snapshot before AC-04 tests gate CI; recommendation: BLOCK Step 4 until the snapshot is committed |
| AC-37 backend ordering | The class-hotkey contract requires `[0..N-1, 20..20+N-1, 40..40+N-1]` ordering from the suite; not yet verified | Hotkey test fails at integration; ambiguous responsibility | Phase 3 to surface; fix can land server-side or via a client-side resort, depending on the verification result |

## Quarantine List (running)

The following 16 tests assert against a Phase B target or a Step 4 fix and are quarantined until the implementation lands. Phase 3 will decide their disposition. (Cycle 2 / 2026-05-12 update: NFT-SEC-09 source check REMOVED — closed by AZ-499 + STC-SEC1C; new AC-41 / AC-42 tests added in this cycle are NOT quarantined. Cycle 3 / 2026-05-13 update: FT-P-01 bootstrap part REMOVED — closed by AZ-510, runs as a regression guard now.)

| Test | Reason | Activates when |
|------|--------|---------------|
| FT-P-12, FT-P-13 | Async video detect (F7) not wired | Phase B feature cycle |
| FT-P-24, FT-P-25 | i18n detector + persistence missing | Step 4 fix |
| FT-P-33 (timeout) | ProtectedRoute timeout missing | Step 4 fix |
| FT-P-37, FT-P-38 | Panel-width writer missing (`useResizablePanel`) | Step 4 fix |
| FT-P-51 | Split surface not on dataset page today | Phase B |
| FT-P-54, FT-P-55 | Tile-zoom UX missing (finding #24) | Phase B |
| FT-N-03, FT-N-05 | `/admin` and `/settings` role-gates missing | Step 4 / Step 8 |
| FT-N-11, FT-N-12, FT-N-13, FT-N-14 | Settings form hygiene fixes missing | Step 4 |
| NFT-PERF-03 / NFT-RES-02 | SSE refresh-rotation reconnect missing | Step 8 hardening |
| NFT-PERF-08 / NFT-PERF-09 | Tied to FT-P-37 / FT-N-13 quarantines | per above |
| NFT-SEC-05, NFT-SEC-06 | Tied to FT-N-03, FT-N-05 | per above |
| NFT-RES-04 | Tied to FT-P-33 | per above |

## Phase 3 (Data Validation Gate) — Open Items to Resolve

### Resolved in Phase 3

1. ~~**`enum_spec_snapshot.json`** — populate from the suite spec before AC-04 tests gate CI.~~ → **Resolved:** snapshot committed at `_docs/00_problem/input_data/enum_spec_snapshot.json`. `verification_pending: true` markers remain for `CombatReadiness` and `MediaType` (numeric ordering inferred from schema member-listing); Step 4 .NET-service inspection lifts those.
2. ~~**NFT-RES-09** — no `results_report.md` row binding.~~ → **Resolved:** row 96 added (tainted-canvas fallback observable).
3. ~~**NFT-RES-10** — no `results_report.md` row binding.~~ → **Resolved:** row 97 added (SSE server-disconnect observable; ≤ 10 s indicator-or-reconnect; reconnect attempts ≤ 1 in window).
4. ~~**NFT-PERF-10** — FCP baseline has no `results_report.md` row.~~ → **Resolved:** row 98 added (`FCP ≤ 3 000 ms` on warm-cache navigation to `/flights`, headless Chromium, 2 vCPU / 4 GB edge profile).

### Still open (carry forward to Step 4 / runner)

5. **AC-37 backend ordering** — verify the `annotations/` service response shape and either confirm matches or schedule a fix on the appropriate side.
6. **STC family** — confirm adding the `STC-S*` / `STC-O4` / `STC-O11` static-check IDs to lift the restriction coverage above 75 %.
7. **Quarantine disposition** — accept the quarantine list above; decide whether quarantined tests gate CI today (recommended: no, but they are picked up automatically the day the feature lands).
8. **AC-04 UI enum drift in `src/types/index.ts`** — tests will FAIL until the Step 4 fix lands per `acceptance_criteria.md`; quarantine until Step 4 OR run them and use the failure as the gate to schedule Step 4. The drift list is pinned in `enum_spec_snapshot.json` → `ui_drift_summary` (5 enums).
9. **Parent-suite doc fixes (leftover)** — `../_docs/01_annotations.md` line 208 and `../_docs/09_dataset_explorer.md` line 165 show stale `affiliation: 2 // Hostile` examples; should be 20 per `00_database_schema.md`. Record as a leftover in `_docs/_process_leftovers/` when raised against the parent suite.
