# Phase 2 — Preservation regression checkpoint **Completed 2026-09-10 from `2d0f131` on `codex/ui-redesign-phase2`.** This checkpoint adds regression protection and an explicit TypeScript CI gate. **No visual redesign, application behavior change, route/layout/component restructuring, schema change or B07 work.** The Phase 1 source/audit remains intact. ## Preservation coverage - **57/57 protected capability groups mapped (100%)**, with stable `PRES-` aliases of the original E/J/W/C/M/S/A IDs. - **44 high-risk groups**, all mapped to existing behavioral assertions. High risk includes private identity, data edits/history/relationships, irreversible actions and shared navigation likely to be restructured. - **147 referenced existing/new automated test files** across frontend and backend. Each row records route/entry, component/service owners, protected behavior, missing proof and expected later redesign impact. - This percentage means **at least one core automated behavioral assertion per capability group**. It is not exhaustive sub-workflow, code, provider, mobile/accessibility or visual coverage. The matrix explicitly retains partial coverage and one native package-capture blocker. Read the [complete preservation matrix](PRESERVATION_MATRIX.md), [traceability contract and Phase 2 change ledger](TRACEABILITY.md), and [baseline defects/intentional gaps](BASELINE_DEFECTS.md). ## High-risk additions and preserved evidence | Workflow | New meaningful regression | |---|---| | Command/navigation/capture | Three component cases: job/company destination, closing clears query, add opens review without creating; real browser Ctrl+K search, legacy match link, reviewed add | | CV section AI | Four cases: Reject/Close clear proposal without applying, edited proposal applies only on acceptance, failure retry leaves content untouched | | Whole-CV AI | Five cases: explicit Apply/Reject; invalid JSON, missing IDs and duplicate IDs cannot become edits; save targets only selected CV | | Cover-letter AI | One case: Reject preserves saved draft, disabled Save/no dirty state/no PUT | | Settings | Two component cases: retry failed notification save with retained draft; changing one rule keeps other scenarios | | Canonical profile → derived CV | Browser mobile edit/preview → reload → desktop preview; stored headline changes only selected CV, complete canonical profile and sibling remain unchanged | | Documents/submission | Native profile/job/CV/letter/file fixture + legacy entry and capture; **expected failure P2-D01**, with desired immutable HTML/letter/archive-byte checks retained but not reached | | Responsive preferences | Browser mobile→desktop rule draft stays, native save persists; notification false survives reload; separate direct API rule save | | Permissions | Non-admin admin-menu entries absent, direct users GET/POST forbidden, normal CV create allowed, Free AI actions disabled and API 403 | Existing B01 connection-time outbound protections, B02 ownership/session/cache checks, B03 rendering admission, B04 trusted principal/IP limits, B05 CSV bytes, and B06 application/configuration tests are unchanged. Mail draft revisions/uncertain sends, profile extraction acceptance, CV history, long PDF, job dirty navigation and other existing tests were retained. ## Baseline and fresh verification Fresh local execution uses installed .NET **9.0.317**, Node dependencies already locked in the checkout, Windows/Chromium and Playwright's disposable SQLite API. There were no production requests or provider credentials. Test fixtures use only synthetic accounts and local URLs. | Gate | Recorded Phase 1 baseline | Fresh Phase 2 result | |---|---|---| | Backend Release suite | 916 passing | **916 passed, 0 failed, 0 skipped**; no exclusions, count unchanged | | Frontend Jest | 298 tests / 67 suites | **313 passed / 68 suites**; +15 cases, +1 test file; no existing test removed | | General browser | 18 passing | **23 actually passed + 1 expected failure**, 0 unexpected failures/skips/flaky; original 18 still pass, +6 cases | | B04 real HTTP | 9 cases | **9 passed** | | B06 production-mode API/forwarding HTTP | 6 cases | **6 passed**; not nginx/Traefik runtime proof | | B03 PDF burst/admission | 1 case | **1 passed**, multi-route capacity/recovery oracle unchanged | | Compose ingress/configuration | 3 tests/17 hostile mutations | **3 passed** | | Backend build | Release | **Pass, 0 warnings/errors**, warnings-as-errors | | Frontend build | Next production static export | **Pass** | | Standalone type check | Historical TS2571 repaired before Phase 2 | **Pass**; new explicit CI command, unchanged strictness | | New browser-spec TypeScript | Previously no whole-Playwright type gate | **Pass** with temporary Node-aware config for this new spec only | | ESLint | Zero-warning gate | **Pass**, no suppressions added | | Tracked secret scan; diff whitespace | Required | **Pass** | Playwright's list reporter says “24 passed” because expected failures count as expected outcomes. Its JSON records **23 `expectedStatus=passed/actual=passed` and one `expectedStatus=failed/actual=failed`**. Do not present this as 24 successful workflows. The failed native package test is not a regression introduced by application changes: there are no such changes in this branch. See P2-D01. Intermediate test-authoring corrections: one missing test-fixture brace, Testing Library's unsupported `exact` role options, a Playwright callback named `use` misidentified as a React hook, and package capture's actual CV-tab location. Corrected test code rather than weakening lint/types or changing UI. The temporary isolated TypeScript config initially lacked Node type roots; setting the existing installed Node declarations resolved Buffer. No new dependency installed. One initial rules-save 500 did not reproduce in the direct or repeated browser path; retained as observation P2-O01, not asserted as a diagnosed defect. The reproducible SQLite package/tailoring failure is recorded separately. No blanket skipping or gate bypass was added. ## Exact commands From the repository root (PowerShell): ```powershell $env:DOTNET_ROOT='C:/Users/Connor/.dotnet' & C:/Users/Connor/.dotnet/dotnet.exe test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-restore --logger 'trx;LogFileName=phase2.trx' --results-directory .artifacts/redesign-phase2 -- xUnit.parallelizeTestCollections=false xUnit.maxParallelThreads=1 & C:/Users/Connor/.dotnet/dotnet.exe build JobTrackerApi/JobTrackerApi.csproj --configuration Release --no-restore -warnaserror python scripts/test-ingress.py python scripts/supply-chain.py scan-secrets git diff --check ``` From `job-tracker-ui`: ```powershell npm test -- --watchAll=false --runInBand npm run typecheck npm run lint $env:NEXT_PUBLIC_API_BASE_URL='http://localhost:5302/api' $env:NEXT_TELEMETRY_DISABLED='1' npm run build $env:DOTNET_ROOT='C:/Users/Connor/.dotnet' $env:DOTNET_HOST_PATH='C:/Users/Connor/.dotnet/dotnet.exe' $env:PLAYWRIGHT_STATIC_EXPORT='true' $env:PLAYWRIGHT_PREBUILT_EXPORT='true' $env:PLAYWRIGHT_JSON_OUTPUT_FILE='../.artifacts/phase2-browser-results.json' node node_modules/@playwright/test/cli.js test --reporter=list,json node node_modules/@playwright/test/cli.js test --config=playwright.rate-limits.config.ts node node_modules/@playwright/test/cli.js test --config=playwright.ingress.config.ts node node_modules/@playwright/test/cli.js test --config=playwright.pdf.config.ts ``` Initial focused command: `npm test -- --watchAll=false --runInBand --runTestsByPath src/quick-command-preservation.test.tsx src/ai-section-assistant.test.tsx src/cv-builder-deep-link.test.tsx src/settings-view.test.tsx` → 31 passed. Final full Jest includes the additional cover-letter reject case. Final browser rerun after narrowing the known-failure annotation: `node node_modules/@playwright/test/cli.js test e2e/redesign-preservation.spec.ts` → five actual passes and the same one expected HTTP-500 capture failure (23.8s); no unexpected failures. Final lint and isolated browser-spec typing also pass. Additional isolated browser-spec typing used `node node_modules/typescript/bin/tsc --project ../.artifacts/phase2-browser-tsconfig.json --noEmit`. Temporary config extends the frontend tsconfig, includes only `../job-tracker-ui/e2e/redesign-preservation.spec.ts`, sets `incremental:false`, `typeRoots:["../job-tracker-ui/node_modules/@types"]`, `types:["node"]`. This is a local check, not a claim that every pre-existing Playwright/config source is covered by the new CI type gate. Local logs: `.artifacts/phase2-{backend,jest,build,api-build,typecheck,browser-typecheck,lint,browser,rate-limits,ingress,pdf,compose,secrets}.log`; backend TRX under `.artifacts/redesign-phase2`; browser JSON and sanitized outcome summary under `.artifacts`. Durable conclusions and reproduction remain in these committed documents/tests; raw traces with synthetic session material are not published. The matrix was checked against the original ledger: 57 rows, 57 unique IDs, no missing/extra IDs, and all 147 test-reference paths exist. No production source file changed. Full baseline execution was not repeated for documentation-only edits. ## Remaining gaps and next phase **Phase 2 is complete as a regression/planning checkpoint, with its documented baseline failure.** Phase 3 may define UX architecture: grouped sidebar, page/route destination and backwards compatibility, one Jobs table/board entry, canonical Career Profile/derived-document workflows, contextual AI review, and explicit mobile task rules. Keep the existing MUI/Emotion/React Router/API stack while planning. Do not implement those layouts or components in this checkpoint. Before a later code migration, close that surface's matrix gaps or establish a deliberately scoped additional fixture. W07 package/tailoring needs native-provider success first; shared shell needs drawer/focus and bulk/saved-view cases; career/mail/admin need their specified interactive and provider proof. Screen-reader/touch/reflow and the full EN/NB × light/dark × desktop/mobile matrix remain visual/UX gates. **F04 remains open.** The B06 repository/application changes are complete, but actual deployed proxy peer/listeners, firewall/NAT/IPv6, client IP, DNS/TLS/redirect and restart behavior remain unverified; follow the existing [operator commands](../../audits/2026-09-07/validation/b06-completion.md). Prior main CI run 743 failed in the browser worker and did not deploy; this branch's local success does not repair or certify that runner. Pushing this feature branch is a preservation checkpoint, not a production deployment or a release-readiness claim. No Phase 3 implementation, visual redesign, component-library migration, B07 or later security ticket has begun.