docs(theme): record deterministic state evidence
CI and Deploy / test (pull_request) Failing after 1m31s
CI and Deploy / deploy (pull_request) Has been skipped

This commit is contained in:
cesnimda
2026-08-09 18:37:52 +02:00
parent 11734ee058
commit f2d1963c61
11 changed files with 99 additions and 26 deletions
@@ -44,5 +44,6 @@ This is the rolling action-level evidence index. `PASS (automated/runtime)` is n
| 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` |
| Theme state | Light/Dark/System precedence, login/logout scope, refresh/navigation and two-tab synchronization | PASS (state/provider/bootstrap tests) | PASS/PARTIAL — anonymous local browser at 375/768/1440 | NOT RUN | `ux-002-deterministic-theme-state.md` |
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.
@@ -0,0 +1,49 @@
# UX-002 deterministic theme state
Updated: 2026-08-09
Status: `IMPLEMENTED — NOT VERIFIED`. Automated, build and local browser checks pass. Production and authenticated multi-user browser checks remain.
## Confirmed root cause
The theme preference was keyed by the last `authUserKey`, but login completion emitted the general authentication event before `/auth/me` stored the new user key. `Shell` then stored that key with event emission disabled. Theme state therefore continued using the anonymous preference until a refresh, when the user key was already present and the page appeared to switch theme randomly. Logout had a similar asynchronous boundary.
Theme changes also keyed `CssVarsProvider` and captured `themeMode` in the router memo. A preference change remounted the provider and recreated the router, risking loss of in-page state even though the URL did not intentionally change. MUI also retained its own default local-storage mode, creating another potential source of truth.
## Implemented contract
- Preference resolution is explicit user key, then anonymous preference for a user without a saved choice, then the documented `System` default.
- Explicit Light and Dark ignore operating-system changes. Only System resolves through the current media query.
- Auth user-key changes have a dedicated event. It updates theme state without re-running authentication requests or creating an event loop.
- Relevant `storage` events update another tab without writing back. Unrelated storage events are ignored.
- MUI mode is changed in place through its color-scheme context with its private persistence disabled. The app/router tree is not keyed or recreated by theme changes.
- A Next `beforeInteractive` bootstrap applies the same user/anonymous/System resolution before client application paint.
- Settings tabs are scrollable at narrow widths; this removes the mobile overflow discovered during the required theme browser pass.
No backend, database, dependency, entitlement or production configuration changed.
## Verification
- Focused deterministic theme suite: 6/6.
- Full frontend: 48/48 suites and 172/172 tests.
- Production frontend build/TypeScript and `git diff --check`: pass.
- Browser: explicit Light persisted across Settings → Dashboard navigation and refresh; explicit Dark switched without navigation; System selected the browser's dark preference; a second tab inherited Dark and changing it to Light updated the first tab without reload.
- Browser widths: 375, 768 and 1440; document width did not exceed the viewport after the tabs correction. Light 375/768 and Dark 1440 evidence is retained.
- Browser console warnings/errors after the final interactive pass: none. Development HMR emitted transient module-update messages while source files were being edited; they were not present in the captured tab diagnostics and the clean production build passes.
## Remaining gates
- Authenticated User A/User B scoped preference switching was proven at the storage/event unit boundary but not with two live browser accounts because no isolated API authentication environment was running.
- A real operating-system preference-change event was tested at the resolver/provider boundary, not by changing the host OS during browser automation.
- Production deployment/browser smoke is not authorized/configured.
## Evidence
- Screenshots: `docs/audits/evidence/ux-002/`
- Commands/results: `docs/audits/verification-log.md` V-111V-113
- Tests: `job-tracker-ui/src/theme-state.test.tsx`
- Implementation commit: `11734ee`
## Rollback
Revert `11734ee`. No data migration is required; existing `themeMode:<user>` and `themeMode:anon` values remain compatible. Reversion restores the prior delayed-login theme and provider/router remount behavior.