diff --git a/docs/audits/evidence/ux-001/README.md b/docs/audits/evidence/ux-001/README.md new file mode 100644 index 0000000..89c0c6c --- /dev/null +++ b/docs/audits/evidence/ux-001/README.md @@ -0,0 +1,9 @@ +# UX-001 browser evidence + +Synthetic/local evidence only. No credentials, tokens or personal data are present. + +- `login-dark-375.png` — local sign-in form at 375 × 812. +- `login-dark-768.png` — local sign-in form at 768 × 900. +- `login-dark-1440.png` — local sign-in form at 1440 × 1000. + +The isolated browser had no API configuration service, so configured Google/Microsoft alternatives were covered by mocked component tests rather than these captures. The browser used its dark system theme. A full-page capture mode produced an invalid rendering artifact and was discarded; the retained viewport captures match computed DOM bounds and visible browser state. diff --git a/docs/audits/evidence/ux-001/login-dark-1440.png b/docs/audits/evidence/ux-001/login-dark-1440.png new file mode 100644 index 0000000..c89032b Binary files /dev/null and b/docs/audits/evidence/ux-001/login-dark-1440.png differ diff --git a/docs/audits/evidence/ux-001/login-dark-375.png b/docs/audits/evidence/ux-001/login-dark-375.png new file mode 100644 index 0000000..5a443f3 Binary files /dev/null and b/docs/audits/evidence/ux-001/login-dark-375.png differ diff --git a/docs/audits/evidence/ux-001/login-dark-768.png b/docs/audits/evidence/ux-001/login-dark-768.png new file mode 100644 index 0000000..39d3bd7 Binary files /dev/null and b/docs/audits/evidence/ux-001/login-dark-768.png differ diff --git a/docs/audits/verification-log.md b/docs/audits/verification-log.md index 851068e..a9f0471 100644 --- a/docs/audits/verification-log.md +++ b/docs/audits/verification-log.md @@ -139,3 +139,6 @@ Output was reduced to filenames and commit counts. The token artifact appears un | V-101 | Bounded `rg`/`Get-Content` trace of Strategy button, Focus Plan tab/cache, controller/model calls, owner filters, proxy/queue/routing configuration and tests | Repository root | Revalidate AI-003 complete execution path before design | PASS — one UI action could start candidate fit plus four sequential synchronous focus-plan model calls; Pro and owner filters existed, durable state did not | Live timeout reproduction blocked; this is code-path evidence | Application-related | | V-102 | `dotnet test ... --filter "...StrategySnapshotOperationTests|...AiWorkspaceNotePersistenceTests|...AiOperationQueueTests|...ProEntitlementAuthorizationTests"`; `npm.cmd test -- job-details-generated-drafts.test.tsx --runInBand --forceExit` | Repository root / `job-tracker-ui` | Focused 202/handler/cache/tenant/provider-shape and queued/cancel/fail/retry UI checks | PASS — backend 34/34; frontend 6/6 | Fake model only; Jest reports the existing force-exit/open-handle notice | N/A | | V-103 | Full `dotnet test ... --no-restore`; full `npm.cmd test -- --runInBand --forceExit`; `npm.cmd run build`; `git diff --check` | Repository root / `job-tracker-ui` | AI-003 regression, TypeScript production build and patch hygiene | PASS — backend 592/592; frontend 47/47 suites, 160/160; build; no whitespace errors | Initial sandboxed build attempted blocked NuGet restore; previously approved build path restored from existing cache and passed. Line-ending notices only | Environmental command path corrected | +| V-108 | Bounded source trace of `LoginPage`, Google/Microsoft account cards, auth API/config, translations and login tests | Repository root | Revalidate UX-001 local/provider execution and identity boundaries | PASS — backend already accepts username or email; UI imposed email-only validation and separate provider tabs; provider exchange and account-link endpoints are distinct | No identity/config/schema behavior changed | N/A | +| V-109 | `npm.cmd test -- --runInBand --forceExit src/login-page.test.tsx`; full `npm.cmd test -- --runInBand --forceExit`; `npm.cmd run build`; `git diff --check` | `job-tracker-ui` / repository root | Verify unified form, invalid credentials, provider cancellation/return, full regression, TypeScript and patch hygiene | PASS — focused 13/13; full 47/47 suites and 166/166 tests; production build; no whitespace errors | Jest reports its existing force-exit/open-handle notice; provider tokens are synthetic mocks | N/A | +| V-110 | In-app browser at `http://localhost:3000/login`; dark-theme viewport/DOM checks and screenshots at 375×812, 768×900, 1440×1000 | Local frontend | Verify running local form, accessible names and responsive layout | PASS/PARTIAL — local form readable; viewport and document widths match with no overflow; evidence captured | API config service absent, so provider alternatives were mocked only; light/System and real-provider paths not run. Full-page screenshot mode produced an artifact and was discarded | Environmental/provider limitation | diff --git a/docs/verification/application-action-matrix.md b/docs/verification/application-action-matrix.md index b88b4a8..24d2e2a 100644 --- a/docs/verification/application-action-matrix.md +++ b/docs/verification/application-action-matrix.md @@ -43,5 +43,6 @@ This is the rolling action-level evidence index. `PASS (automated/runtime)` is n | Strategy Snapshot | owner-scoped rehydration/result/operation and no partial malformed output | PASS (real SQLite; fake model) | BLOCKED | NOT RUN | `ai-003-strategy-snapshot-queue.md` | | CV processing | upload 202, active duplicate reuse, owner-scoped execution and review gate | PASS (real SQLite; synthetic CV/fake provider) | BLOCKED | NOT RUN; worker off | `ai-004-cv-processing-queue.md` | | CV processing | retry provenance, durable refresh state and cancel/retry controls | PASS (backend + component tests) | BLOCKED | NOT RUN | `ai-004-cv-processing-queue.md` | +| Authentication UI | unified username/password and provider alternatives; invalid/cancel/return behavior | PASS (components; mocked providers) | PARTIAL — local dark-theme form at 375/768/1440 | NOT RUN | `ux-001-unified-authentication.md` | -Remaining product actions are `NOT STARTED` in the master plan and will be added as their work packages enter verification. Browser localhost is currently denied by administrator policy; production access is not documented/configured. +Remaining product actions are `NOT STARTED` in the master plan and will be added as their work packages enter verification. The in-app browser is available for local UI checks; configured/real-provider and production access are not documented/configured. diff --git a/docs/verification/ux-001-unified-authentication.md b/docs/verification/ux-001-unified-authentication.md new file mode 100644 index 0000000..a19cd52 --- /dev/null +++ b/docs/verification/ux-001-unified-authentication.md @@ -0,0 +1,45 @@ +# UX-001 unified authentication page + +Updated: 2026-08-09 + +Status: `IMPLEMENTED — NOT VERIFIED`. The unified local/provider presentation, component tests, responsive dark-theme browser smoke, full frontend regression suite and production build pass. Light-theme browser, configured-provider browser, real-provider and production checks remain. + +## Revalidated behavior + +- The API local-login endpoint already accepts either email or username. The previous browser form constrained the value to an email, so the UI did not expose the supported username path. +- `LoginPage` previously separated local, Google and Microsoft sign-in into tabs. The provider components also combined signed-out authentication with signed-in link/unlink account management, which caused profile-oriented status copy to appear in the authentication surface. +- Google and Microsoft exchanges already use their hardened `/auth/google/exchange` and `/auth/microsoft/exchange` endpoints. Account linking uses distinct authenticated link endpoints. The presentation change does not alter those backend contracts or identity decisions. + +## Implemented contract + +- Signed-out users receive one username-or-email/password form, one visual `or` separator, and enabled Google/Microsoft alternatives in the same card. +- Registration remains a distinct mode and still requires an email-formatted address, password confirmation and the existing registration policy checks. +- Provider components accept an explicit sign-in presentation that omits `/auth/me`, link/unlink state and linking copy while reusing the existing provider exchange, two-factor challenge and safe return-path behavior. +- Invalid local credentials remain on the page. Microsoft cancellation produces an error without an exchange or navigation. Synthetic Microsoft and Google provider returns use their exchange endpoints and navigate only after an authenticated response. +- No tenant, issuer, account-linking, registration, recovery, session or authorization backend behavior changed. + +## Verification + +- Focused login components: 13/13 tests. +- Full frontend: 47/47 suites and 166/166 tests. +- Production frontend build and TypeScript: pass. +- `git diff --check`: pass; line-ending notices only. +- Browser dark-theme smoke: the local form rendered at 375, 768 and 1440 CSS pixels; measured document width matched the viewport at every size. Normal viewport captures show readable controls without clipping. DOM inspection confirmed accessible names for username/email, password, remember-me, recovery and submit controls. +- Configured provider alternatives, local invalid credentials, Microsoft cancellation/direct return and Google credential return were exercised with mocked services. No real provider token or credential was used. + +## Remaining gates + +- The isolated browser did not have an API configuration service, so it displayed the local form and optional-auth banner only. Enabled provider buttons were not exercised in a running browser. +- The in-app browser exposed the current dark system theme but did not expose page storage for switching the anonymous preference. Light-theme and System-mode browser checks remain under UX-002. +- Real Google/Microsoft cancellation/return and production smoke require authorized disposable accounts and deployed configuration. +- Registration, verification, reset and account-recovery lifecycle behavior remains owned by SEC-005A/B; this package did not weaken or reimplement those paths. + +## Evidence + +- Screenshots: `docs/audits/evidence/ux-001/` +- Commands/results: `docs/audits/verification-log.md` V-108–V-110 +- Tests: `job-tracker-ui/src/login-page.test.tsx` + +## Rollback + +Revert the UX-001 implementation commit. No schema, dependency, API, identity record or configuration migration is involved. The separate provider tabs and account-oriented card presentation would return; existing provider links and sessions remain unchanged. diff --git a/docs/work-programmes/decisions.md b/docs/work-programmes/decisions.md index 3243d91..9af5701 100644 --- a/docs/work-programmes/decisions.md +++ b/docs/work-programmes/decisions.md @@ -309,3 +309,13 @@ - **Consequences:** all four long CV actions share one default-off worker and operation UI. Parser-version/process isolation remains SEC-006/007; browser/model/MariaDB/production gates remain before rollout. Existing clients must accept the upload endpoint's 202 operation response. - **User approval required:** No; both programmes explicitly require one durable operation foundation and preservation of human review. - **Reversible:** Yes. Keep the worker off, revert `c3c5af8`, and retain operation/extraction rows. Cancel or drain `cv.process` rows before removing the handler. + +## DEC-032 — Provider account management and signed-out authentication share logic, not presentation + +- **Date:** 2026-08-09 +- **Decision:** Add an explicit sign-in presentation to the existing Google and Microsoft components. It reuses provider token exchange and two-factor handling but skips signed-in account discovery, link/unlink controls and linking copy. Keep the full account presentation unchanged for authenticated profile/settings surfaces. +- **Reason/evidence:** the programme requires a conventional single sign-in card without implying account linking. Duplicating provider callback code would risk divergence from the hardened tenant/linking path, while rendering account-state panels on login creates the prohibited clutter and misleading relationship. +- **Alternatives considered:** retain tabs; create duplicate login-only provider clients; hide copy with CSS; combine provider exchange and account linking. These preserve the UX defect, duplicate sensitive logic, hide rather than remove inaccessible state, or weaken the identity boundary. +- **Consequences:** login presentation becomes simpler without changing backend identity ownership. Provider account management remains available only in its existing authenticated surfaces. Real-provider and production verification are still required. +- **User approval required:** No; this is the smallest implementation of the explicit UX-001 requirement and preserves the prior security contracts. +- **Reversible:** Yes. Reverting UX-001 restores the tabbed presentation; no provider link, session, schema or configuration data changes. diff --git a/docs/work-programmes/master-progress.md b/docs/work-programmes/master-progress.md index 1e5fb06..dddb5e9 100644 --- a/docs/work-programmes/master-progress.md +++ b/docs/work-programmes/master-progress.md @@ -2,17 +2,17 @@ Updated: 2026-08-09 -- **Overall programme status:** Active. Six packages are locally verified; fourteen packages through AI-004 are implemented with automated/runtime evidence but blocked from applicable parser/browser/model/provider/production gates; UX-001 is in progress. -- **Current work package:** `UX-001` — unified authentication page (`IN PROGRESS`); source requirement re-read and existing tab/provider-card structure traced. +- **Overall programme status:** Active. Six packages are locally verified; fifteen packages through UX-001 are implemented with automated/runtime evidence but blocked from applicable theme/provider/production gates; UX-002 is in progress. +- **Current work package:** `UX-002` — deterministic theme state (`IN PROGRESS`); UX-001 browser evidence showed that explicit anonymous preference/refresh behavior must be verified here. - **Completed work packages:** None are `DONE`; all repository security/AI packages still have applicable browser, provider and/or production gates. - **Locally verified work:** SEC-001, SEC-002, SEC-003, SEC-005A, CORE-001 and PROD-002 (`VERIFIED LOCALLY`). -- **Implemented, verification incomplete:** SEC-004, SEC-005B, SEC-008, CORE-002, BG-001, OPS-001A/B/C, POL-001/002, AI-001/002/003/004 (`IMPLEMENTED — NOT VERIFIED`). AI-004 now returns 202 for upload and uses the shared typed worker/status/notification/UI contract; the worker remains default-off and parser hardening remains blocked. +- **Implemented, verification incomplete:** SEC-004, SEC-005B, SEC-008, CORE-002, BG-001, OPS-001A/B/C, POL-001/002, AI-001/002/003/004 and UX-001 (`IMPLEMENTED — NOT VERIFIED`). UX-001 now presents one local/provider sign-in card and passes component, full frontend, build and responsive dark-theme browser checks; light/System/configured-provider/production gates remain. - **Production-verified work:** None. -- **Blocked work:** SEC-006 requires explicit internet/package-index permission; PROD-001/003/004 and REL-001 require documented production access and unfinished dependencies. Browser access is denied by browser administrator policy; SMTP/MariaDB environments are unavailable. +- **Blocked work:** SEC-006 requires explicit internet/package-index permission; PROD-001/003/004 and REL-001 require documented production access and unfinished dependencies. Real provider, SMTP/MariaDB and production environments are unavailable; the in-app browser is available for local UI checks. - **Deferred work:** None. Conditional multi-replica coordination, model deletion, realtime operation delivery and unrelated production changes remain outside current packages. -- **Next five work packages:** UX-001 unified authentication; QA-001 job-analysis/keyword quality; UX-002 deterministic theme state; CAREER-001 Career Workspace redesign; CAREER-002 CV Builder redesign. SEC-006/007 resume after package-index permission. -- **Status counts:** 6 `VERIFIED LOCALLY`; 14 `IMPLEMENTED — NOT VERIFIED`; 1 `IN PROGRESS`; 13 `NOT STARTED`; 5 `BLOCKED`; 0 `DONE`; 0 `DEFERRED`. -- **Test status:** backend 594/594; AI-004 focused backend 40/40; frontend 47/47 suites and 161/161 tests, AI-004 focused UI 10/10, production build pass; prior sidecar 22/22. Patch check passes. Browser/model/MariaDB/production checks were not run. +- **Next five work packages:** UX-002 deterministic theme state; QA-001 job-analysis/keyword quality; CAREER-001 Career Workspace redesign; CAREER-002 CV Builder redesign; EMAIL-001 consolidated email experience. SEC-006/007 resume after package-index permission. +- **Status counts:** 6 `VERIFIED LOCALLY`; 15 `IMPLEMENTED — NOT VERIFIED`; 1 `IN PROGRESS`; 12 `NOT STARTED`; 5 `BLOCKED`; 0 `DONE`; 0 `DEFERRED`. +- **Test status:** backend 594/594; AI-004 focused backend 40/40; frontend 47/47 suites and 166/166 tests, UX-001 focused 13/13, production build pass; prior sidecar 22/22. Patch check passes. UX-001 dark-theme browser smoke passed at 375/768/1440; configured-provider/light-theme/model/MariaDB/production checks were not run. - **Deployment status:** No deployment performed. No production migrations were run. AI operation worker remains disabled by default. - **Production status:** Unchanged and unverified. No provider/model call, model pull, external request or paid API occurred. - **Known regressions:** None found by automated suites. Jest still needs `--forceExit` and reports its existing open-handle notice. Direct clean EF-only SQLite migration still hits the pre-existing historical blank-chain defect before later migrations; normal startup owns reconciliation. Cross-feature monthly AI usage accounting remains a rollout gap. @@ -41,5 +41,6 @@ Updated: 2026-08-09 - `docs/verification/ai-002-provider-routing.md` - `docs/verification/ai-003-strategy-snapshot-queue.md` - `docs/verification/ai-004-cv-processing-queue.md` +- `docs/verification/ux-001-unified-authentication.md` - `docs/verification/prod-002-ai-evaluation.md` - `docs/work-programmes/master-work-plan.md` diff --git a/docs/work-programmes/master-work-plan.md b/docs/work-programmes/master-work-plan.md index e59bbc8..aa940b2 100644 --- a/docs/work-programmes/master-work-plan.md +++ b/docs/work-programmes/master-work-plan.md @@ -16,7 +16,7 @@ Allowed statuses are `NOT STARTED`, `IN PROGRESS`, `IMPLEMENTED — NOT VERIFIED `DONE` requires every applicable acceptance criterion, focused and regression tests, browser/accessibility/theme/mobile checks, tenant and entitlement checks, documentation, migration/rollback evidence, and production verification. Repository-only work that still requires production is at most `VERIFIED LOCALLY`. -Exactly one implementation item may be `IN PROGRESS`. As of this revision it is **UX-001**. +Exactly one implementation item may be `IN PROGRESS`. As of this revision it is **UX-002**. ## Consolidated dependency order @@ -559,11 +559,11 @@ Ordering differences from the suggested list: - **Required tests:** invalid credentials/provider failure/cancel/return, focus/order/labels. - **Required browser verification:** 375/768/1440, light/dark, keyboard/focus, logged-out/provider mocks. - **Required production verification:** real provider smoke only with authorized accounts. -- **Status:** `IN PROGRESS`. -- **Blocker:** browser localhost policy and real-provider/production checks; component/source work can continue safely. -- **Evidence:** source requirement re-read; initial trace confirms `LoginPage` still renders separate local/Google/Microsoft tabs and provider-card components. -- **Commit:** none. -- **Remaining work:** keep visual change separate from identity migration. +- **Status:** `IMPLEMENTED — NOT VERIFIED`. +- **Blocker:** light/System-theme browser, configured/real-provider and production checks require the UX-002 preference work plus authorized provider/deployment environments. +- **Evidence:** `docs/verification/ux-001-unified-authentication.md`; V-108–V-110; focused 13/13, full frontend 47/47 suites and 166/166 tests, production build, responsive dark-theme browser captures at 375/768/1440. +- **Commit:** `93b8692` (`feat(auth): unify sign-in options`). +- **Remaining work:** light/System theme browser; configured-provider browser; real authorized Google/Microsoft cancel/return; production smoke. Keep identity migration separate. ### UX-002 — Deterministic theme state @@ -577,9 +577,9 @@ Ordering differences from the suggested list: - **Required tests:** Light/Dark/System, login/logout/refresh/navigation/storage/preference listeners/tabs. - **Required browser verification:** 375/768/1440, light/dark/system, refresh/navigation/two tabs/reduced motion. - **Required production verification:** normal browser smoke after deploy. -- **Status:** `NOT STARTED`. +- **Status:** `IN PROGRESS`. - **Blocker:** none. -- **Evidence:** reported behavior not yet reproduced. +- **Evidence:** source requirement re-read is next; UX-001 browser storage limitation makes deterministic anonymous preference/refresh behavior the immediate dependency. - **Commit:** none. - **Remaining work:** trace root precedence before changing UI. diff --git a/docs/work-programmes/session-handoff.md b/docs/work-programmes/session-handoff.md index 420edef..0280d5e 100644 --- a/docs/work-programmes/session-handoff.md +++ b/docs/work-programmes/session-handoff.md @@ -2,17 +2,17 @@ Updated: 2026-08-09 -- **Exact current task:** UX-001 — replace `LoginPage` local/Google/Microsoft tabs with one accessible sign-in card while preserving the hardened provider callbacks and separate registration behavior. -- **Last completed step:** AI-004 implementation `c3c5af8` was committed and pushed. Upload/reprocess/rebuild/improve now use one durable `cv.process` operation; duplicate active work is reused; provider failure state, persistent notifications, review gate and operation UI are covered. UX-001 source requirements were re-read and the current separate-tab/provider-card path was located. -- **Files currently modified:** tracking/evidence documents for AI-004 and the UX-001 status transition. No UX application code is modified yet. -- **Commands already run:** initial clean-tree review and push through `39e9804`; AI-004 source trace; local-cache-only restore; backend builds/focused/full tests; focused/full frontend tests/build; diff review; implementation commit/push; UX-001 source/route trace. See V-104–V-107. -- **Test results:** backend 594/594; AI-004 focused backend 40/40; frontend 47/47 suites and 161/161 tests; profile UI 10/10; production frontend build and diff check pass. Synthetic CV/fake model only. -- **Services currently running:** none started by this session. Node/Jest/build processes exited. Pre-existing Docker services were not changed. -- **Temporary files or processes:** none created for AI-004. No dependency declaration, database or artifact was changed. +- **Exact current task:** UX-002 — revalidate every theme-state source and implement deterministic saved-user/anonymous/system precedence without startup flash or cross-tab loops. +- **Last completed step:** UX-001 implementation `93b8692` was committed. Login now uses one username-or-email/password card with sign-in-only Google/Microsoft presentations; focused/full frontend tests, build and local responsive dark-theme browser checks pass. Evidence/tracking are ready for their own commit and push. +- **Files currently modified:** UX-001 verification/evidence/tracking documents and three synthetic screenshots under `docs/audits/evidence/ux-001/`. UX-001 application code is committed. +- **Commands already run:** initial clean-tree review/push; AI-004 implementation/evidence commits/push; UX-001 complete source trace; focused 13/13 and full 166/166 frontend tests; production build; diff checks; local browser at 375/768/1440; implementation commit. See V-104–V-110. +- **Test results:** backend baseline 594/594; frontend 47/47 suites and 166/166 tests; UX-001 focused 13/13; production frontend build and diff check pass. Browser local form passed in dark theme at 375/768/1440 with no measured overflow. Provider browser tests remain mocked. +- **Services currently running:** Next development server on `http://localhost:3000` in exec session `62719`; in-app browser tab open at `/login`. Pre-existing Docker services were not changed. +- **Temporary files or processes:** only the local Next development server and in-app browser tab. Stop the server before final handoff. No dependency declaration, database or private artifact changed. - **Production changes currently active:** none. No deployment, provider/model call, private CV access, model pull, paid service, production migration or external payload occurred. -- **Rollback status:** AI-004 rollback is documented in `docs/verification/ai-004-cv-processing-queue.md`; worker switches remain default-off. Production is unchanged. -- **Uncommitted changes:** AI-004 evidence/master tracking status updates only; commit and push them before UX code. -- **Known failures:** browser localhost denied; MariaDB/SMTP/production unavailable; SEC-006 upgrades require explicit internet/package-index permission; complete parser cancellation/isolation remains SEC-007; historical clean EF-only SQLite chain needs startup reconciliation; Jest reports its existing force-exit/open-handle notice. Live CV 504/restart/private-file behavior is not claimed. -- **Exact next action:** read `LoginPage.tsx`, `GoogleAuthCard.tsx`, `MicrosoftAuthCard.tsx` and `login-page.test.tsx` completely; isolate sign-in-only button rendering from profile linking controls; replace tabs with one form/separator/two alternative buttons and add invalid/provider cancel/return/accessibility component tests. -- **Work that can continue independently:** UX-001 repository UI/tests; then UX-002/QA-001 source work. SEC-006/007 await package-index permission; PROD-001/003/004 await production access. +- **Rollback status:** UX-001 has no schema/config migration; revert `93b8692` to restore tabs. AI-004 rollback is documented in its verification record; worker switches remain default-off. Production is unchanged. +- **Uncommitted changes:** UX-001 evidence/master tracking documents and screenshots only; commit/push these before UX-002 application code. +- **Known failures:** light/System and configured/real-provider UX-001 browser checks remain; MariaDB/SMTP/production unavailable; SEC-006 upgrades require explicit internet/package-index permission; complete parser cancellation/isolation remains SEC-007; historical clean EF-only SQLite chain needs startup reconciliation; Jest reports its existing force-exit/open-handle notice. +- **Exact next action:** commit and push UX-001 evidence, then read `work.md:102-133`, `App.tsx`, `themePrefs.ts`, auth user-key transitions and theme tests completely; reproduce refresh/login/logout/cross-tab precedence before editing. +- **Work that can continue independently:** UX-002 and QA-001 repository work. SEC-006/007 await package-index permission; PROD-001/003/004 await production access. - **Decisions still required from the user:** none for synthetic repository work. Internet/package upgrades, private CV access, external/paid providers and production actions retain their explicit approval/safety gates; SEC-009 retention/legal policy remains unresolved.