diff --git a/JobTrackerApi.Tests/CvAiReadinessTests.cs b/JobTrackerApi.Tests/CvAiReadinessTests.cs index 8b5dd6a..f5e0b1a 100644 --- a/JobTrackerApi.Tests/CvAiReadinessTests.cs +++ b/JobTrackerApi.Tests/CvAiReadinessTests.cs @@ -54,12 +54,12 @@ public sealed class CvAiReadinessTests public Task Generate(string? context = null, string target = "section:summary") => Suggestions.GenerateAsync("owner", Cv.Id, 1, target, "improve", Source, context, "Rewrite supported facts only.", default); - public CvVariantController Controller() + public CvVariantController Controller(bool reviewAvailable = true) { var user = new ApplicationUser { Id = "owner" }; var users = TestHostFactory.CreateUserManager(user); users.Setup(value => value.GetUserAsync(It.IsAny())).ReturnsAsync(user); - return new(users.Object, Variants, Mock.Of(), Ai.Object, suggestions: Suggestions) + return new(users.Object, Variants, Mock.Of(), Ai.Object, suggestions: reviewAvailable ? Suggestions : null) { ControllerContext = new() { HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "owner") }, "local")) } } }; } @@ -283,6 +283,22 @@ public sealed class CvAiReadinessTests await fixture.AssertUnchanged(); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Unavailable_review_service_blocks_generation_and_apply_without_side_effects(bool apply) + { + await using var fixture = new Fixture(); await fixture.Open(); + var controller = fixture.Controller(reviewAvailable: false); + var response = apply + ? Assert.IsType((await controller.ApplyAi(fixture.Cv.Id, new("unused-proposal", Paraphrase), default)).Result) + : Assert.IsType((await controller.AiAssist(new("improve", Source, null, null, "en", fixture.Cv.Id, 1, "section:summary"), default)).Result); + Assert.Equal(503, response.StatusCode); + Assert.Equal("cv_ai_unavailable", JsonSerializer.SerializeToElement(response.Value).GetProperty("code").GetString()); + fixture.Ai.VerifyNoOtherCalls(); + await fixture.AssertUnchanged(); + } + [Fact] public async Task Confirmed_provider_fabrication_reproduction_is_now_an_API_rejection() { diff --git a/JobTrackerApi/Program.cs b/JobTrackerApi/Program.cs index 2998d19..705008c 100644 --- a/JobTrackerApi/Program.cs +++ b/JobTrackerApi/Program.cs @@ -75,7 +75,8 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +// CV review remains withheld in Production until configured-model qualification is accepted. +if (!builder.Environment.IsProduction()) builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/docs/redesign/phase-5/OPEN_BLOCKERS.md b/docs/redesign/phase-5/OPEN_BLOCKERS.md index c851a35..19b6ea1 100644 --- a/docs/redesign/phase-5/OPEN_BLOCKERS.md +++ b/docs/redesign/phase-5/OPEN_BLOCKERS.md @@ -41,6 +41,7 @@ Reconciled against [P4-06](../phase-4/p4-06/README.md#opendeferred-issue-reconci | Backup/restore/rollback and legacy schema cutover | Production restore/cutover evidence pending | **Separate release/schema gate**; no schema in P5. Required before any external prerequisite that actually needs one | | Stripe activation, paid deletion/retention/provider cleanup | Configuration/policy/provider proof pending; deletion remains gated | **Separate product/backend/release work**; no new billing/trial/delete UX claims or Settings migration | | Provider mail/AI/calendar/OAuth delivery | Partial local mocks/service tests, no universal live provider certification | **Does not block unchanged navigation/presentation**; actual send/reconnect/provider semantics changes wait for sandbox/operator proof. AI truthfulness is not guaranteed by a review dialog | +| P5-13 — AI Model Semantic Qualification / AI Review UI | **DEFERRED — BLOCKED / NOT QUALIFIED**, by Connor's 2026-10-08 instruction. Local Ollama `qwen2.5:7b` is configured; deployed identity is unverified. Frozen corpus: **32 synthetic cases, 366 required calls, 0 completed calls, 0 human reviews; critical factuality failures unmeasured**. Docker Desktop remains blocked by the AF_UNIX socket reparse-point issue; no destructive recovery attempted. Deterministic grounding/proposal protections pass; P5-13 AI review UI remains unimplemented | **Outstanding technical/product debt**; [qualification and recovery evidence](p5-13-semantic-qualification/README.md), [deterministic readiness](p5-13-readiness/README.md) and exact return conditions below. Carry into P5-14/P5-15 and subsequent acceptance reports; no semantic, UI or unconditional Phase 5 acceptance | | Full screen-reader/touch/zoom/forced-colors coverage | P4 manual browser checks partial; incomplete axe nodes remain | **Affected-slice accessibility acceptance gates** per visual protocol; unavailable evidence must stay open, not counted as success. Public certification remains blocked | | P5-04b-R01 command entry/focus timing | One full-run failure on unchanged command/theme/test code; trace shows keyboard focus-visible gained then lost around the dialog's entry callback. Three unchanged focused reruns passed | **Separate shell accessibility debt before P5-15**, not query-population parity. [Observation](p5-04b-readiness/README.md#unrelated-baseline-observation-p5-04b-r01); no assertion weakened or shell repair attempted | | P5-04b-R02 CV section-expansion smoke | One full-run failure on unchanged CV editor/test, before PDF export; three unchanged focused reruns passed; cause unproven | **Existing CV readiness owner**, not Jobs integration. [Observation](p5-04b-readiness/README.md#unrelated-baseline-observation-p5-04b-r02); keep the regression and investigate before broad CV migration | @@ -48,6 +49,28 @@ Reconciled against [P4-06](../phase-4/p4-06/README.md#opendeferred-issue-reconci | Original P4 unnamed targeted controls / preview keyboard defect | Closed for P4-02/03 targets only | **Not a blocker**, retain tests; advanced untouched controls still need their own loaded-state proof | | Historical TS2571 | No longer present; standalone gate passed | **Not a blocker**, retain CI type gate; do not describe as current expected failure | +## P5-13 deferred debt and return conditions — 2026-10-08 + +**P5-13 — AI Model Semantic Qualification / AI Review UI: DEFERRED — BLOCKED / NOT QUALIFIED.** This records Connor's explicit deferral at source checkpoint `9c9157507937b3e084a7ca1e79a2ebd77d0b0928`; it does not complete P5-13 or remove its [approved requirements](PHASE5_PLAN.md#p5-13--cv-ai-review-presentation). + +Local configuration selects Ollama `qwen2.5:7b`; actual deployed provider/model/digest/settings remain unverified. Docker Desktop is blocked while starting its inference manager by an AF_UNIX socket reparse-point (`IO_REPARSE_TAG_AF_UNIX`) that cannot be removed/opened normally (Windows error 1920). The deeper filesystem cause remains unknown. No destructive recovery was attempted; the failed bounded rename and supported Model Runner disable/start attempts remain documented. Do not spend another checkpoint retrying Docker recovery or repeat recovery attempts during unrelated phases. + +The frozen qualification corpus contains **32 synthetic cases**. Required calls remain **366**; completed calls **0**, human reviews **0**, and critical factuality failures **unmeasured**. Zero runs cannot establish factuality. Deterministic grounding/proposal, ownership, source freshness and revision/history protections are implemented and passing independently; [fresh release-candidate regression results](release-readiness/README.md#local-validation-and-preservation) remain separate from configured-model semantic qualification. **The P5-13 AI review UI remains unimplemented.** Retain the frozen [corpus](p5-13-semantic-qualification/corpus.json), [rubric](p5-13-semantic-qualification/RUBRIC.md), [qualification results](p5-13-semantic-qualification/qualification-results.json), [initial environment evidence](p5-13-semantic-qualification/environment-checkpoint.json) and [recovery evidence](p5-13-semantic-qualification/environment-recovery-checkpoint.json), including failed observations. + +Before marking P5-13 complete: + +1. Verify the actual deployed provider/model/digest/settings, generation/evaluation routing, runtime/API/sidecar image revisions and prompt-source identity; local defaults and partial health diagnostics alone do not satisfy the identity gate. +2. Establish a working isolated, production-equivalent qualification environment through a supported non-destructive recovery or a verified equivalent transport. Confirm reachability and one uncached synthetic smoke request through the application routing; preserve existing privacy/consent and authentication boundaries. +3. Run the unchanged frozen corpus and rubric: all **366 required calls**, with actual uncached generation/evaluation calls and all outputs/errors retained. Preserve the three repeats per case/probe and existing assessment lane; synthetic provider regressions do not count as model calls. +4. Complete the required human review for every output/repeat, with dated reviewer evidence. An assistant review cannot replace human acceptance. +5. Resolve critical factuality failures, false approvals and unresolved ambiguity with a bounded, reviewed correction; retain failures and rerun the frozen full corpus after a justified fix. Require usable grounded rewriting and scope/language acceptance without weakening expectations. +6. Implement and validate the P5-13 AI review UI against its retained source/target, compare/edit/accept/reject/regenerate/error/locked, keyboard, theme/locale and mobile requirements. +7. Repeat relevant regression testing, preserving deterministic AI protections, ownership/privacy, revision/history, source isolation, rendering/PDF and affected workflow/accessibility contracts. + +**Authorized continuation scope:** prepare and verify the completed redesign's release to the actual production branch, **`main`**, first, subject to every production/release gate. Repository inspection identifies [the configured `main` CI/deployment workflow](../../../.gitea/workflows/ci-deploy.yml); a `main` push triggers automatic production deployment, so merge/push remains **NO-GO pending production safety proof**, including F04 ingress and backup/restore/rollback evidence. The requested `master` wording does not override the instruction to determine the actual configured branch. Only after successful release verification may a new development branch from updated `main` continue **P5-14 for currently implemented CV capabilities**: desktop/tablet/mobile editor-preview switching, section editing/navigation, Career Profile source/override clarity, save/conflict recovery, keyboard/pointer/touch, document controls, preview scroll/zoom, PDF fidelity, accessibility and localisation. This is a conditional scope clarification; the [historical P5-14 requirement](PHASE5_PLAN.md#p5-14--responsive-cv-workflow-checkpoint) for accepted 09–13 and a complete AI-review journey remains recorded. Do not fabricate an AI-review workflow, claim deferred P5-13-specific responsiveness passed, or remove the existing automated AI protection tests. Carry that missing coverage into P5-14 acceptance explicitly. + +P5-15 must carry this debt and distinguish completed/verified capabilities, explicitly deferred capabilities, production-release blockers and non-blocking limitations. Full Phase 5 acceptance remains conditional/partial while mandatory retained requirements are unmet; no unconditional GO without an explicit documented authorization revising the full acceptance scope. The release/P5-14 clarification does not waive F04, release safety, human accessibility acceptance or unrelated debt. Preserve Connor's requirement to **push every individual P5-15 change/checkpoint**; outside P5-15, commit and push at each phase end. No release or deployment success is asserted by this register update. + ## Product/new-requirement boundaries Final name/logo/primary color remain OD-01–03: use current provisional values, so no shell delay. Email provider (OD-05), external jobs/calendar integrations (OD-06), monetization (OD-07), favorite/priority (OD-08), aggregate admin/privacy definitions (OD-09), intake (OD-10) and weekly goals (OD-11) are separate decisions before their future features. Do not invent LinkedIn integration or scheduled interviews. diff --git a/docs/redesign/phase-5/PHASE5_PLAN.md b/docs/redesign/phase-5/PHASE5_PLAN.md index d7ba9e0..440037c 100644 --- a/docs/redesign/phase-5/PHASE5_PLAN.md +++ b/docs/redesign/phase-5/PHASE5_PLAN.md @@ -4,6 +4,8 @@ Sources: [Phase 3 sequencing](../phase-3/PHASE4_IMPLEMENTATION_PLAN.md), [P4-06 conditional acceptance](../phase-4/p4-06/README.md), [readiness gates](READINESS_GATES.md), [navigation contract](NAVIGATION_MIGRATION.md), [57-contract impact](PRESERVATION_IMPACT.md), [visual acceptance](VISUAL_ACCEPTANCE.md). This plan makes Phase 3 proposals concrete; it does not supersede preserved functionality or turn missing APIs into existing capabilities. +**Scope clarification — 2026-10-08:** Connor explicitly deferred P5-13 configured-model qualification and review UI; neither is completed or qualified. Keep its full requirements below and [return conditions](OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08). After a successfully verified release to the actual production branch `main`, P5-14 may assess/refine **currently implemented P5-09–12 CV capabilities**. Its P5-13 AI-review responsiveness remains deferred and must not be fabricated or accepted. P5-15 must distinguish implemented, deferred, release-blocking and nonblocking work, retain conditional/partial acceptance when mandatory evidence is missing, and push every individual P5-15 change/checkpoint. This does not waive F04 or release/backup/rollback gates; no P5-14 begins before verified release. No repeated Docker recovery during unrelated work. + ## Order and conditional branches | Order / ID | Name | Type / user impact | Dependency and checkpoint boundary | diff --git a/docs/redesign/phase-5/README.md b/docs/redesign/phase-5/README.md index 4a90fd0..a7785c6 100644 --- a/docs/redesign/phase-5/README.md +++ b/docs/redesign/phase-5/README.md @@ -1,5 +1,9 @@ # Phase 5 — Representative screens / major UI redesign plan +**Current status — 2026-10-08:** P5-12 template/document controls is the latest completed UI slice. P5-13 **AI Model Semantic Qualification / AI Review UI is DEFERRED — BLOCKED / NOT QUALIFIED** by Connor's explicit decision; [the debt register](OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08) retains every return condition and frozen evidence. [Release preparation](release-readiness/README.md) targets the actual production branch **`main`**, not a nonexistent `master`. Production release remains gated by F04, runtime recovery/configuration evidence and protected CI. P5-14 is authorized only after verified release, for implemented CV capabilities; P5-13-specific responsiveness and full Phase 5 acceptance remain incomplete. No further Docker recovery is part of unrelated work. + +The successor entries below retain their historical checkpoint decisions; they do not override this current status. + **Current successor: [P5-11 live preview presentation](p5-11/README.md) — accepted locally, stop before P5-12.** Compact fit/count/return chrome, neutral canvas, white paper, stable busy/error/retry and retained scroll reuse the existing native renderer and editor owner. Baseline: **941 backend / 434 frontend / 108 actual browser passes**, security 9/6/1, configuration 3; revision 5/5 and fidelity 16/16, 36 aligned pages and all 16 renderer HTML hashes unchanged. Forty-four final viewport captures and 211 axe scans (zero reported violations, incomplete checks retained) record EN/Bokmål, light/dark, desktop/intermediate/320px proof. The first 107-pass/one ambiguous smoke-locator failure and its strengthened exact-button correction are retained. Human screen-reader/pointer/reflow/font/photo qualifications, F04 and other recorded debt remain open. No P5-12+, Phase 8 or B07 implementation occurred. **Previous implementation: [P5-10 CV section editing/source clarity](p5-10/README.md).** Compact source-backed/CV-only forms, field-specific reset, editable omitted content and add/delete/reorder focus reuse the P5-09 frame and existing save/history/source owners. Baseline: **941 backend / 430 frontend / 106 actual browser passes**, security 9/6/1, configuration 3; revision 5/5 and fidelity 16/16 with 36 aligned pages and unchanged renderer HTML. EN/Bokmål, light/dark, desktop/intermediate/320px evidence is retained. Human screen-reader/incomplete checks, broader pointer/reflow/font/photo qualification, F04 and separately recorded debt remained open. No P5-11+, Phase 8 or B07 implementation occurred at that checkpoint. diff --git a/docs/redesign/phase-5/release-readiness/PRESERVATION_REVIEW.md b/docs/redesign/phase-5/release-readiness/PRESERVATION_REVIEW.md new file mode 100644 index 0000000..cba741f --- /dev/null +++ b/docs/redesign/phase-5/release-readiness/PRESERVATION_REVIEW.md @@ -0,0 +1,130 @@ +# Release-candidate preservation review — 2026-10-08 + +Source checkpoint: `9c9157507937b3e084a7ca1e79a2ebd77d0b0928`, branch `codex/ui-redesign-phase4`. This is a bounded review of the existing redesign plus the separately validated temporary Production CV-AI withholding correction. It is **not a main release, fresh regression result, deployment confirmation, unconditional Phase 5 GO or full preservation acceptance**. The root release record must supply the final candidate commit and actual fresh results after validation completes. + +All **57 original PRES groups** below retain the complete original requirements and sub-workflows from the [Phase 1 inventory](../../audit/FUNCTIONALITY_INVENTORY.md). Short labels do not narrow them. [Phase 2](../../phase-2/PRESERVATION_MATRIX.md), [P4-06 acceptance](../../phase-4/p4-06/PRESERVATION_ACCEPTANCE.md) and [Phase 5 impact](../PRESERVATION_IMPACT.md) supply the original behavioral anchors and gaps; implementation successor records below supply scoped changes/evidence. Links are regression anchors, not an assertion that every sub-workflow was tested or passed at this checkpoint. + +“Direct” means implemented presentation/composition or authoritative integrity work; “entry only” means navigation moved while its domain workflow remained with its existing owner; “unchanged” still receives shared shell/theme exposure. Every authenticated surface therefore retains account-disposal, auth/CSRF/ownership, theme/locale, dirty-state and safe error requirements. Selected tests are historical executable anchors; the complete applicable backend/frontend/browser/sidecar, auth/tenant/revision/PDF/settings/security/type/lint/build/secret gates are being run separately by the root. + +## Capability matrix — 57 original groups + +| Original PRES ID / capability | Implemented touch / unchanged entry | Existing regression anchors | Remaining provider / manual / production gaps and exact limit | +|---|---|---|---| +| **PRES-E01** — Public product/plans; honest unavailable billing | Unchanged public product/plans; [P5-01](../p5-01/README.md) route regression. | [F:landing-page](../../../../job-tracker-ui/src/landing-page.test.tsx); [F:planCatalog](../../../../job-tracker-ui/src/planCatalog.test.ts); [B:AccountPlans](../../../../JobTrackerApi.Tests/AccountPlansTests.cs) | Actual checkout/billing provider availability and public mobile/keyboard acceptance remain unverified. | +| **PRES-E02** — Local login/register/remember, challenge, reset and verification | Entry retained by [P5-01](../p5-01/README.md); existing local auth/challenge/reset/verification owners. | [F:login-page](../../../../job-tracker-ui/src/login-page.test.tsx); [F:verify-email-page](../../../../job-tracker-ui/src/verify-email-page.test.tsx); [B:LocalAuthIdentity](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); [B:AuthAndSystemController](../../../../JobTrackerApi.Tests/AuthAndSystemControllerTests.cs) | Real reset-mail delivery, Turnstile/browser configuration and complete token-reset submit journey remain qualified. | +| **PRES-E03** — Google/Microsoft login, link, legacy relink and popup results | Entry retained by [P5-01](../p5-01/README.md); provider sign-in remains separate from Connections. | [F:login-page](../../../../job-tracker-ui/src/login-page.test.tsx); [F:microsoft-legacy-relink-page](../../../../job-tracker-ui/src/microsoft-legacy-relink-page.test.tsx); [B:GoogleTokenValidator](../../../../JobTrackerApi.Tests/GoogleTokenValidatorTests.cs); [B:MicrosoftTokenValidator](../../../../JobTrackerApi.Tests/MicrosoftTokenValidatorTests.cs) | Real provider consent/popups, revoked grants and sandbox outcomes remain unverified; origin/state contracts remain required. | +| **PRES-E04** — 2FA challenge/recovery/setup/disable; trusted-device revocation | Entry relocation only in [P5-01](../p5-01/README.md); Profile/login security forms unchanged. | [F:two-factor-settings](../../../../job-tracker-ui/src/two-factor-settings.test.tsx); [F:login-page](../../../../job-tracker-ui/src/login-page.test.tsx); [B:TwoFactorController](../../../../JobTrackerApi.Tests/TwoFactorControllerTests.cs); [B:SessionsController](../../../../JobTrackerApi.Tests/SessionsControllerTests.cs) | Real mobile authenticator/recovery and trusted-device UI traversal remain open; no security-form acceptance inferred from navigation. | +| **PRES-E05** — Session list/current device, revoke one/others, logout | Direct shell logout/private utility changes in [P5-00](../p5-00/README.md)–[P5-02](../p5-02/README.md); session-list owner unchanged. | [F:session-boundary](../../../../job-tracker-ui/src/session-boundary.test.ts); [F:account-scoped-state](../../../../job-tracker-ui/src/account-scoped-state.test.tsx); [B:SessionsController](../../../../JobTrackerApi.Tests/SessionsControllerTests.cs); [B:AuthSessionRevocation](../../../../JobTrackerApi.Tests/AuthSessionRevocationTests.cs) | Session-card selection/refresh after remote revocation remains open; broad device/AT acceptance is not established. | +| **PRES-E06** — Avatar, account names/headline, email change and password | Account/security entry only in [P5-01](../p5-01/README.md); avatar/account identity and confirm-email-change route retained. | [F:profile-page](../../../../job-tracker-ui/src/profile-page.test.tsx); [F:verify-email-page](../../../../job-tracker-ui/src/verify-email-page.test.tsx); [B:AvatarStorage](../../../../JobTrackerApi.Tests/AvatarStorageTests.cs); [B:LocalAuthIdentity](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs) | Avatar upload/remove and password-change browser journeys remain qualified; account identity stays distinct from Career Profile. | +| **PRES-E07** — Desktop collapse/mobile drawer, active nav and command search/actions | Direct [shell/navigation/utilities](../p5-02/README.md), [Jobs Table/Board](../p5-04b/README.md), [Analytics](../p5-07/README.md) and [workspace sections](../p5-08b/README.md). | [F:sidebar-active-nav](../../../../job-tracker-ui/src/sidebar-active-nav.test.ts); [F:app-shell-notifications](../../../../job-tracker-ui/src/app-shell-notifications.test.tsx); [B:JobApplicationsAuthorization](../../../../JobTrackerApi.Tests/JobApplicationsAuthorizationTests.cs); [B:CompanyRelationship](../../../../JobTrackerApi.Tests/CompanyRelationshipTests.cs) | Original route/command/drawer defects have scoped successor evidence; manual screen reader and inherited command/focus timing debt remain open. This census is not browser route acceptance. | +| **PRES-E08** — Theme/system, EN/NB hydration, toast/confirm/prompt and errors | Direct semantic theme/feedback controls in [P5-00](../p5-00/README.md); EN/Bokmål and light/dark regressions carried through [P5-12](../p5-12/README.md). | [F:theme-state](../../../../job-tracker-ui/src/theme-state.test.tsx); [F:i18n-provider](../../../../job-tracker-ui/src/i18n-provider.test.tsx); [B:LocalAuthIdentity](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs) | Full theme/locale/state/OS cross-product, spoken names/announcements, incomplete axe, zoom/forced-colours/text-spacing and shared-dialog timing remain qualified. | +| **PRES-E09** — Account-switch private-state disposal and stale request rejection | Private-state/session boundary unchanged; new shell/utility/workspace/CV relationships regression-protected in [readiness](../p5-13-readiness/README.md). | [F:session-boundary](../../../../job-tracker-ui/src/session-boundary.test.ts); [F:account-scoped-state](../../../../job-tracker-ui/src/account-scoped-state.test.tsx); [B:SessionContextMiddleware](../../../../JobTrackerApi.Tests/SessionContextMiddlewareTests.cs); [B:CurrentUserIdLiveEvaluation](../../../../JobTrackerApi.Tests/CurrentUserIdLiveEvaluationTests.cs) | Real BFCache variations/long offline retries and deployed old-bundle/session behavior remain qualified; images and mocked components cannot prove tenant isolation. | +| **PRES-J01** — NAV discovery/filter/sort/source/deadline/details | Entry only: [P5-01](../p5-01/README.md) groups Discover under Jobs; discovery page/service unchanged. | [F:job-discovery](../../../../job-tracker-ui/src/job-discovery.test.tsx); [B:JobDiscoveryController](../../../../JobTrackerApi.Tests/JobDiscoveryControllerTests.cs); [B:JobOpportunitySync](../../../../JobTrackerApi.Tests/JobOpportunitySyncTests.cs) | Live NAV freshness/availability and long result keyboard traversal remain open. | +| **PRES-J02** — Saved searches, run/delete/alerts, result changes/dismissal | Entry only in [P5-01](../p5-01/README.md); saved discovery search/alert service and controls unchanged. | [F:job-discovery](../../../../job-tracker-ui/src/job-discovery.test.tsx); [B:SavedJobSearchAlert](../../../../JobTrackerApi.Tests/SavedJobSearchAlertTests.cs); [B:JobDiscoveryController](../../../../JobTrackerApi.Tests/JobDiscoveryControllerTests.cs) | Scheduler-to-notification browser journey and mobile delete confirmation remain qualified; no new producer or delivery certification. | +| **PRES-J03** — Reviewed manual/URL/paste job create, company/tags/dates, duplicates | Existing reviewed Add modal shared by [P5-03](../p5-03/README.md)/[P5-04b](../p5-04b/README.md); no creation on route/view mount. | [F:quick-capture](../../../../job-tracker-ui/src/quick-capture.test.tsx); [B:JobImportService](../../../../JobTrackerApi.Tests/JobImportServiceTests.cs); [B:JobImportHttpTransport](../../../../JobTrackerApi.Tests/JobImportHttpTransportTests.cs) | Duplicate/company/date edge UI and creation-intent idempotency remain independent gaps; import network boundary evidence is separate from live site success. | +| **PRES-J04** — Extension/bookmarklet/share capture; post-create attachment/CV | Capture/add/addtext review entry retained in [P5-01](../p5-01/README.md)/[P5-03](../p5-03/README.md); extension and post-create owners unchanged. | [F:captureUrl](../../../../job-tracker-ui/src/captureUrl.test.ts); [F:quick-capture](../../../../job-tracker-ui/src/quick-capture.test.tsx); [B:JobImportService](../../../../JobTrackerApi.Tests/JobImportServiceTests.cs); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | Installed extension permissions/share flow and optional attachment failure recovery remain qualified. | +| **PRES-J05** — Job filters/sort/page/columns, saved views and row/mobile actions | Direct [P5-03](../p5-03/README.md) Jobs/Trash presentation and [P5-04b](../p5-04b/README.md) shared complete-query view integration. | [F:application-workspace-overlay](../../../../job-tracker-ui/src/application-workspace-overlay.test.tsx); [F:account-scoped-state](../../../../job-tracker-ui/src/account-scoped-state.test.tsx); [B:JobApplicationsController](../../../../JobTrackerApi.Tests/JobApplicationsControllerTests.cs); [B:JobApplicationsEndpointBehavior](../../../../JobTrackerApi.Tests/JobApplicationsEndpointBehaviorTests.cs) | Finite saved-view/filter/Back/error/selection fixtures do not exhaust saved-view CRUD or dirty nested page-size combinations; full-array scaling remains limited. | +| **PRES-J06** — Bulk status/delete, soft delete/trash/restore and job edit | Direct [P5-03](../p5-03/README.md) table/Trash and [P5-04b](../p5-04b/README.md) selection/view integration; CRUD/soft-delete owner retained. | [F:application-workspace-overlay](../../../../job-tracker-ui/src/application-workspace-overlay.test.tsx); [F:confirm-flow](../../../../job-tracker-ui/src/confirm-flow.test.tsx); [B:JobApplicationsController](../../../../JobTrackerApi.Tests/JobApplicationsControllerTests.cs); [B:JobApplicationsAuthorization](../../../../JobTrackerApi.Tests/JobApplicationsAuthorizationTests.cs) | Scoped native restore and bulk/mutation fixtures supersede earlier bare-confirm gaps; all bulk partial-failure/dirty-state combinations and deeper manual AT remain qualified. | +| **PRES-J07** — Kanban grouped statuses, pointer/keyboard move and precise menu | Direct [P5-04a](../p5-04a/README.md)/[P5-04b](../p5-04b/README.md); complete shared query, precise status and /kanban alias retained. | [F:kanban-grouped-board](../../../../job-tracker-ui/src/kanban-grouped-board.test.tsx); [F:pipeline](../../../../job-tracker-ui/src/pipeline.test.ts); [B:JobPipeline](../../../../JobTrackerApi.Tests/JobPipelineTests.cs) | Physical touch/native drag, broader responsive focus/cancel combinations and full-result scaling remain open; grouped statuses are not a new pipeline. | +| **PRES-J08** — Company/contact edits, pipeline dates and linked-job history | Company/contacts/history entry only in [P5-01](../p5-01/README.md)/[P5-02](../p5-02/README.md); existing Companies form retained. | [F:companies-relationship](../../../../job-tracker-ui/src/companies-relationship.test.tsx); [F:quick-command-preservation](../../../../job-tracker-ui/src/quick-command-preservation.test.tsx); [B:CompanyRelationship](../../../../JobTrackerApi.Tests/CompanyRelationshipTests.cs) | All contact/date edits and source-URL safety browser journeys remain qualified; P4-02-D02 inaccessible modal-save error is open for its owner. | +| **PRES-J09** — Recorded offers/compensation/deadlines/notes and source links | Offers entry retained; report source links reviewed in [P5-06](../p5-06/README.md)/[P5-07](../p5-07/README.md); recorded offer page unchanged. | [F:offer-comparison](../../../../job-tracker-ui/src/offer-comparison.test.tsx); [B:AnalyticsSalary](../../../../JobTrackerApi.Tests/AnalyticsSalaryTests.cs); [B:JobApplicationsEndpointBehavior](../../../../JobTrackerApi.Tests/JobApplicationsEndpointBehaviorTests.cs) | Mobile many-offer comparison and localized currency/date visual acceptance remain open; no new salary facts are claimed. | +| **PRES-J10** — CSV/JSON export, JSON import and CSV-to-JSON conversion | Settings Data import/export entry retained by [P5-01](../p5-01/README.md)/[P5-03](../p5-03/README.md); serializers unchanged. | [F:csv-export](../../../../job-tracker-ui/src/csv-export.test.tsx); [B:CsvExport](../../../../JobTrackerApi.Tests/CsvExportTests.cs); [B:JobApplicationsController](../../../../JobTrackerApi.Tests/JobApplicationsControllerTests.cs) | Full JSON import/count/roundtrip browser proof and spreadsheet-client compatibility remain separately bounded; byte/formula/Unicode fixtures are not exhaustive. | +| **PRES-W01** — Full workspace, sections, legacy links and optional reusable overlay | Direct dedicated workspace header/Overview [P5-08a](../p5-08a/README.md) and URL sections [P5-08b](../p5-08b/README.md); Jobs/legacy aliases retained. | [F:application-workspace-overlay](../../../../job-tracker-ui/src/application-workspace-overlay.test.tsx); [F:applicationWorkspace](../../../../job-tracker-ui/src/applicationWorkspace.test.ts); [B:ApplicationWorkspace](../../../../JobTrackerApi.Tests/ApplicationWorkspaceTests.cs) | Reusable overlay has no active production host; followMode metadata retained but mode-specific UI explicitly deferred to mail. Full manual AT and historical transition-capture limits remain. | +| **PRES-W02** — Detail/status/progression, recruiter/dates/description/timeline | Direct [P5-08a](../p5-08a/README.md)/[P5-08b](../p5-08b/README.md) header/progress/detail/timeline composition with existing status/date handlers. | [F:application-intelligence](../../../../job-tracker-ui/src/application-intelligence.test.tsx); [F:workflow-trust-signals](../../../../job-tracker-ui/src/workflow-trust-signals.test.tsx); [B:JobApplicationsWorkflowSignals](../../../../JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs); [B:JobApplicationsAppliedDateHistory](../../../../JobTrackerApi.Tests/JobApplicationsAppliedDateHistoryTests.cs) | Localized backend event/content text, timezone/reload/status-to-timeline combinations and human AT remain qualified; job revision semantics were not repaired. | +| **PRES-W03** — Analysis, match/gaps, strategy and reviewed status/workflow suggestions | Existing contextual analysis/match/strategy/status owners recomposed by [P5-08b](../p5-08b/README.md); opening does not invoke AI. | [F:application-intelligence](../../../../job-tracker-ui/src/application-intelligence.test.tsx); [F:application-workflow-assist](../../../../job-tracker-ui/src/application-workflow-assist.test.tsx); [B:ApplicationIntelligence](../../../../JobTrackerApi.Tests/ApplicationIntelligenceTests.cs); [B:StrategySnapshotOperation](../../../../JobTrackerApi.Tests/StrategySnapshotOperationTests.cs) | Live model truthfulness, freshness/cancelled generation and provider quality remain qualified; P5-13 production CV withholding must not disable these unrelated AI paths. | +| **PRES-W04** — Checklist create/edit/complete/delete/order and next action | Existing checklist owner/ordered controls recomposed by [P5-08b](../p5-08b/README.md); manual/system/dismissed distinctions retained. | [F:application-checklist](../../../../job-tracker-ui/src/application-checklist.test.tsx); [B:ApplicationChecklist](../../../../JobTrackerApi.Tests/ApplicationChecklistTests.cs) | Real mobile interruption/edit/delete combinations and human AT remain open; no task due-date schema or automatic notification added. | +| **PRES-W05** — Attach/select/create/tailor CV and source context | Existing job-CV attach/create/tailor source relationships recomposed by [P5-08b](../p5-08b/README.md); [native readiness](../p5-08b-readiness/README.md) supersedes P2-D01. | [F:application-assets](../../../../job-tracker-ui/src/application-assets.test.tsx); [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [B:ApplicationAssets](../../../../JobTrackerApi.Tests/ApplicationAssetsTests.cs); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | P2-D01 is an ordinary passing native regression, not current expected failure. Broader attach-render combinations, provider tailoring quality and deployed restore remain qualified; CV review production exception stays distinct. | +| **PRES-W06** — Cover-letter manual/AI review, versions/restore and dirty protection | Existing manual/AI cover-letter/history/dirty owner recomposed in [P5-08b](../p5-08b/README.md); literal-context defect corrected in [readiness](../p5-08b-readiness/README.md). | [F:application-assets](../../../../job-tracker-ui/src/application-assets.test.tsx); [F:application-workspace-overlay](../../../../job-tracker-ui/src/application-workspace-overlay.test.tsx); [B:ApplicationAssets](../../../../JobTrackerApi.Tests/ApplicationAssetsTests.cs) | Native/mocked review/history evidence does not establish live-model or provider quality; full screen-reader and every reject/history sequence remain qualified. | +| **PRES-W07** — Application drafts and immutable submitted package/archived binaries | Existing drafts/frozen submission/archive owners recomposed by [P5-08b](../p5-08b/README.md); [native SQLite/archive/ZIP proof](../p5-08b-readiness/README.md) retained. | [F:application-assets](../../../../job-tracker-ui/src/application-assets.test.tsx); [F:application-drafts](../../../../job-tracker-ui/src/application-drafts.test.ts); [B:SubmittedApplicationPackage](../../../../JobTrackerApi.Tests/SubmittedApplicationPackageTests.cs); [B:JobApplicationsApplicationPackage](../../../../JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs) | Earlier P2-D01 capture expected failure is superseded by ordinary native passing evidence. Production restore/rollback and all storage/provider combinations remain unverified; capture is not external send. | +| **PRES-W08** — Attachments upload/category/name/AI consent/preview/download/delete | Existing attachments CRUD/consent/protected downloads retained; named narrow table/empty state in [P5-08b](../p5-08b/README.md), archive proof in [readiness](../p5-08b-readiness/README.md). | [F:attachments](../../../../job-tracker-ui/src/attachments.test.tsx); [B:AttachmentsController](../../../../JobTrackerApi.Tests/AttachmentsControllerTests.cs); [B:AttachmentConsistency](../../../../JobTrackerApi.Tests/AttachmentConsistencyTests.cs) | Archive gate is locally satisfied for recorded native fixtures; physical drag/drop, broad rename/download/manual AT and production storage behavior remain qualified. | +| **PRES-W09** — Interview questions/answers/ready/manual removal/AI review | Existing interview questions/answers/manual removal/AI review/readiness recomposed by [P5-08b](../p5-08b/README.md). | [F:interview-prep](../../../../job-tracker-ui/src/interview-prep.test.tsx); [B:InterviewPrepPersistence](../../../../JobTrackerApi.Tests/InterviewPrepPersistenceTests.cs); [B:InterviewAiContext](../../../../JobTrackerApi.Tests/InterviewAiContextTests.cs) | Real-model quality, physical mobile keyboard/populated reload and manual AT remain open; prep does not establish scheduled interview data. | +| **PRES-W10** — Debrief/follow-up draft/date/readiness | Existing debrief/follow-up draft/date/readiness owner recomposed by [P5-08b](../p5-08b/README.md); no automatic send. | [F:interview-prep](../../../../job-tracker-ui/src/interview-prep.test.tsx); [B:JobApplicationsFollowUpDraft](../../../../JobTrackerApi.Tests/JobApplicationsFollowUpDraftTests.cs); [B:InterviewPrep](../../../../JobTrackerApi.Tests/InterviewPrepTests.cs) | Timezone/reload chains and provider delivery remain unverified; followMode-specific compose UI is deferred rather than implemented. | +| **PRES-W11** — Reminder rules/actions/notifications, ICS and Google/Outlook events | Reminder/calendar links retained by [P5-01](../p5-01/README.md)/[P5-02](../p5-02/README.md), Dashboard and [P5-08b](../p5-08b/README.md); calendar/rules APIs unchanged. | [F:daily-control-loop](../../../../job-tracker-ui/src/daily-control-loop.test.tsx); [F:application-calendar](../../../../job-tracker-ui/src/application-calendar.test.tsx); [B:ApplicationCalendarController](../../../../JobTrackerApi.Tests/ApplicationCalendarControllerTests.cs); [B:RulesEngineProspect](../../../../JobTrackerApi.Tests/RulesEngineProspectTests.cs) | F21 DST/date-only/provider timezone gap, actual Google/Outlook events, scheduler delivery and historical unconfirmed rules-save 500 remain open. | +| **PRES-W12** — Async progress/failure/retry/cancel/notifications | Operations remains reachable utility; progress/result/cancel/retry links retained by [P5-02](../p5-02/README.md)/[P5-08b](../p5-08b/README.md); store/worker unchanged. | [F:operations-page](../../../../job-tracker-ui/src/operations-page.test.tsx); [F:profile-page](../../../../job-tracker-ui/src/profile-page.test.tsx); [B:OperationsController](../../../../JobTrackerApi.Tests/OperationsControllerTests.cs); [B:UserOperationStore](../../../../JobTrackerApi.Tests/UserOperationStoreTests.cs) | Long disconnect/reconnect and F20 enabled worker fault containment remain operational gaps; no live job/worker recovery was certified. | +| **PRES-C01** — Canonical structured career data and long-tail/custom sections | Career entry retained; canonical/source scope reviewed in [P5-10](../p5-10/README.md), [P5-12](../p5-12/README.md) and [AI readiness](../p5-13-readiness/README.md). | [F:profile-page](../../../../job-tracker-ui/src/profile-page.test.tsx); [B:CareerProfileController](../../../../JobTrackerApi.Tests/CareerProfileControllerTests.cs); [B:CareerProfileService](../../../../JobTrackerApi.Tests/CareerProfileServiceTests.cs) | Full long-tail Career/mobile save and canonical concurrent updates remain separate; scoped CV acceptance never implies canonical-profile revision safety. | +| **PRES-C02** — Profile overview/completeness/import guidance/raw copy/history/restore | Career overview/import/raw/history owner unchanged; source relation regression retained by [P5-10](../p5-10/README.md)/[P5-12](../p5-12/README.md). | [F:career-workspace-page](../../../../job-tracker-ui/src/career-workspace-page.test.tsx); [F:profile-page](../../../../job-tracker-ui/src/profile-page.test.tsx); [B:CareerProfileService](../../../../JobTrackerApi.Tests/CareerProfileServiceTests.cs) | Clipboard/avatar and complete native profile historical restore/manual AT remain qualified; real extraction quality is separate. | +| **PRES-C03** — Upload/extract/rebuild/reprocess/diff/select/accept/discard/retry/cancel | Entry only: existing Career upload/extraction/reprocess/diff/accept/discard/retry/cancel owners retained. | [F:profile-page](../../../../job-tracker-ui/src/profile-page.test.tsx); [B:ProfileCvController](../../../../JobTrackerApi.Tests/ProfileCvControllerTests.cs); [B:CvProfileDiffService](../../../../JobTrackerApi.Tests/CvProfileDiffServiceTests.cs) | Unusual/scanned/OCR document quality and full low-confidence deselection/discard browser acceptance remain unverified; no provider certification. | +| **PRES-C04** — Evidence bank source/category/tags/add/list/delete | Evidence-bank owner unchanged; job source relationships retained through [P5-08b](../p5-08b/README.md). | [F:career-evidence](../../../../job-tracker-ui/src/career-evidence.test.tsx); [B:CareerEvidenceController](../../../../JobTrackerApi.Tests/CareerEvidenceControllerTests.cs) | Full delete/many-item search/keyboard browser acceptance remains open; broader Career page work stays Phase 7. | +| **PRES-C05** — CV library create/copy/delete/templates/share/publication/PDF | Library/CRUD/public ownership retained; editor actions in [P5-09](../p5-09/README.md) and shared template gallery in [P5-12](../p5-12/README.md). | [F:cv-builder-page](../../../../job-tracker-ui/src/cv-builder-page.test.tsx); [F:cv-template-thumbnail](../../../../job-tracker-ui/src/cv-template-thumbnail.test.tsx); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs); [B:PublicCvController](../../../../JobTrackerApi.Tests/PublicCvControllerTests.cs) | Complete publish/unpublish/old-link revocation chain and every library/template combination remain qualified; library redesign is not claimed. | +| **PRES-C06** — Studio tabs, preview debounce/pages/fit/save state/mobile panes | Direct [P5-09](../p5-09/README.md) frame/navigation, [P5-11](../p5-11/README.md) live preview and [P5-12](../p5-12/README.md) controls; one save/preview/mobile owner. | [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | Known preview keyboard defect has scoped repair; additional P5-14 integrated responsive journey, manual touch/AT/zoom/sticky-boundary acceptance and production rendering remain open. | +| **PRES-C07** — Visibility/order/custom sections and item/document overrides | Direct [P5-10](../p5-10/README.md) source/item/custom editing and [P5-12](../p5-12/README.md) settings retention; explicit reset/inclusion/order retained. | [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [F:cvBuilder](../../../../job-tracker-ui/src/cvBuilder.test.ts); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | Physical touch/native drag and P5-10-O01 nested drag/drop ownership remain open; finite reset/sibling/source fixtures do not certify all saved overrides. | +| **PRES-C08** — Capability-aware templates/typography/color/header/skills/sidebar/photo | Direct [P5-12](../p5-12/README.md) nine-template capability/control presentation and [P5-11](../p5-11/README.md) preview; renderer/template IDs retained. | [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [F:cvBuilder](../../../../job-tracker-ui/src/cvBuilder.test.ts); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | All-template/font/photo/wrapped-line/browser/control combinations and broad custom-colour/manual AT remain qualified; finite capability matrix and Pro locks are not exhaustive. | +| **PRES-C09** — A4/Letter/density/margins/dates/document locale/section presentation | Direct [P5-12](../p5-12/README.md) A4/Letter/density/margin/date/language/columns controls; [pagination repair](../p5-09-pagination-readiness/README.md) retained. | [F:cvBuilder](../../../../job-tracker-ui/src/cvBuilder.test.ts); [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | Recorded unchanged-tolerance local fidelity supersedes prior six-fixture failures; all advanced combinations, deployment fonts/photo/wrapped text and manual print inspection remain open. | +| **PRES-C10** — Undo/redo, save queue, dirty guard, history restore/preview lifecycle | Existing save/undo/history owner retained in [P5-09](../p5-09/README.md)–[P5-12](../p5-12/README.md); [CV revision protocol](../p5-09-readiness/README.md) and stale AI guard retained. | [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [B:CvBuilder](../../../../JobTrackerApi.Tests/CvBuilderTests.cs) | CV stale-write/history safety has scoped native evidence; long offline/history combinations and profile/job concurrent edits remain separate. No new save owner or history store. | +| **PRES-C11** — Section and whole-document AI improve/translate/instruction/grammar review | **Authorized temporary production exception / deferred**: candidate correction withholds CvAiSuggestionService-backed CV generation/apply only in Production with 503 unavailable; Development deterministic path retained. [P5-13 debt](../OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08). | [F:ai-section-assistant](../../../../job-tracker-ui/src/ai-section-assistant.test.tsx); [F:cv-builder-deep-link](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx); [B:AiWorkspace](../../../../JobTrackerApi.Tests/AiWorkspaceTests.cs); [B:AiPrivacyPolicy](../../../../JobTrackerApi.Tests/AiPrivacyPolicyTests.cs) | **Full PRES-C11 acceptance is unmet.** Configured model identity unverified; 32 cases/366 calls planned, 0 completed, 0 human reviews, critical factuality unmeasured; AI review UI unimplemented. Production withholding requires fresh negative/no-write proof and must preserve unrelated AI; no responsiveness pass. | +| **PRES-C12** — Private PDF and published anonymous CV/PDF, long searchable pages | Private/public PDF ownership and shared admission retained through [P5-11](../p5-11/README.md)/[P5-12](../p5-12/README.md); native preview/PDF corpus unchanged. | [F:public-cv-page](../../../../job-tracker-ui/src/public-cv-page.test.tsx); [B:PublicCvController](../../../../JobTrackerApi.Tests/PublicCvControllerTests.cs); [B:PdfRenderAdmission](../../../../JobTrackerApi.Tests/PdfRenderAdmissionTests.cs) | 16-fixture/36-page and eight settings-export/24-page historical gates are finite local evidence; deployed Chromium/Linux/fonts/photo/all-print-engine behavior remains unverified. | +| **PRES-M01** — Job-scoped manual correspondence/search/delete/paste import | Existing job manual correspondence/search/import/delete owner recomposed by [P5-08b](../p5-08b/README.md); global entry retained. | [F:end-to-end-trust-loop](../../../../job-tracker-ui/src/end-to-end-trust-loop.test.tsx); [F:correspondence-search-context](../../../../job-tracker-ui/src/correspondence-search-context.test.ts); [B:CorrespondenceController](../../../../JobTrackerApi.Tests/CorrespondenceControllerTests.cs) | Full manual edit/delete/paste-import browser combinations and manual AT remain qualified; logging correspondence is not sending mail. | +| **PRES-M02** — Gmail candidate/thread import/refresh/sync/unlink/relink/move | Existing job Gmail candidate/thread/import/sync/move/unlink owners recomposed by [P5-08b](../p5-08b/README.md); provider/API behavior unchanged. | [F:correspondence-gmail-import](../../../../job-tracker-ui/src/correspondence-gmail-import.test.tsx); [B:GmailController](../../../../JobTrackerApi.Tests/GmailControllerTests.cs); [B:EmailOwnershipIntegration](../../../../JobTrackerApi.Tests/EmailOwnershipIntegrationTests.cs) | Live provider threads, multi-account reconnect/revoked grants and sync failures remain unverified. | +| **PRES-M03** — Global inbox filters/page/provider/link/direction/detail/source links | Entry only via [P5-01](../p5-01/README.md); global inbox filters/page/provider/detail/source owners unchanged. | [F:correspondence-inbox-page](../../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx); [B:EmailController](../../../../JobTrackerApi.Tests/EmailControllerTests.cs); [B:EmailOwnershipIntegration](../../../../JobTrackerApi.Tests/EmailOwnershipIntegrationTests.cs) | Real large-mailbox/attachment-binary flows and complete native inbox/AT acceptance remain open; global inbox redesign stays Phase 7. | +| **PRES-M04** — Compose/reply/provider/recipient/job; draft conflicts; confirm send/uncertainty | Compose/reply/revision/send/uncertainty owner unchanged; [P5-08b](../p5-08b/README.md) navigation regression only. | [F:correspondence-inbox-page](../../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx); [B:EmailDraftsController](../../../../JobTrackerApi.Tests/EmailDraftsControllerTests.cs); [B:EmailDraftPersistence](../../../../JobTrackerApi.Tests/EmailDraftPersistenceTests.cs) | Actual sandbox mail delivery/reconnect and every dirty/send interruption remain qualified; no automatic uncertain-send retry. followMode-specific UI remains deferred. | +| **PRES-M05** — Review proposed jobs/link/reject/keep/notes/sync/create | Review alias and inbox entry retained in [P5-01](../p5-01/README.md)/[P5-08b](../p5-08b/README.md); reviewed decisions/create owner unchanged. | [F:gmail-review-page](../../../../job-tracker-ui/src/gmail-review-page.test.tsx); [F:correspondence-inbox-page](../../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx); [B:GmailController](../../../../JobTrackerApi.Tests/GmailControllerTests.cs) | Real provider review and complete suggested-job creation browser journey remain qualified; no automatic creation from navigation. | +| **PRES-M06** — Gmail/Graph/IMAP connect/status/disconnect separate from sign-in | Connections entry retained in [P5-01](../p5-01/README.md)/[P5-02](../p5-02/README.md); existing Gmail/Graph/IMAP controls separate from sign-in. | [F:email-provider-connections](../../../../job-tracker-ui/src/email-provider-connections.test.tsx); [B:MicrosoftGraphController](../../../../JobTrackerApi.Tests/MicrosoftGraphControllerTests.cs); [B:ImapController](../../../../JobTrackerApi.Tests/ImapControllerTests.cs) | Actual provider authorization/revocation/token expiry/reconnect remain unverified; no credentials or live provider operations in this review. | +| **PRES-S01** — Personal metrics/activity/funnel/company/skills/stage/salary/next actions | Direct accurate report labels/cohorts in [P5-06](../p5-06/README.md) and meaningful [P5-07 Analytics](../p5-07/README.md); existing server facts retained. | [F:daily-control-loop](../../../../job-tracker-ui/src/daily-control-loop.test.tsx); [F:workflow-trust-signals](../../../../job-tracker-ui/src/workflow-trust-signals.test.tsx); [B:StageAnalytics](../../../../JobTrackerApi.Tests/StageAnalyticsTests.cs); [B:AnalyticsSalary](../../../../JobTrackerApi.Tests/AnalyticsSalaryTests.cs) | Scoped native chart/value/population transformations supersede earlier unmapped chart gaps; server timezone/date/population limits and unsupported NEW metrics remain explicit. | +| **PRES-S02** — Owner-local five visibility preferences/onboarding dismiss/notifications | Direct [P5-02](../p5-02/README.md) notifications and [P5-06](../p5-06/README.md) five owner-local Dashboard flags/onboarding; Analytics independent. | [F:onboarding-checklist](../../../../job-tracker-ui/src/onboarding-checklist.test.tsx); [F:notifications-popover](../../../../job-tracker-ui/src/notifications-popover.test.tsx); [B:JobLifecycleEvent](../../../../JobTrackerApi.Tests/JobLifecycleEventTests.cs) | Scoped owner/reload fixtures do not establish all preference concurrency; P5-06-O01 language-preference 500 remains unproven. Phase 8 order/resize/reset remains deferred. | +| **PRES-S03** — Rules/reminder/table/theme/language preferences and account links | P4 Settings controls retained; [P5-00](../p5-00/README.md) feedback/shared tokens and [P5-03](../p5-03/README.md)/[P5-04b](../p5-04b/README.md) table preferences integration. | [F:settings-view](../../../../job-tracker-ui/src/settings-view.test.tsx); [F:theme-state](../../../../job-tracker-ui/src/theme-state.test.tsx); [B:NotificationSettingsController](../../../../JobTrackerApi.Tests/NotificationSettingsControllerTests.cs); [B:RulesEngineProspect](../../../../JobTrackerApi.Tests/RulesEngineProspectTests.cs) | P4-04-O02 concurrent SQLite notification saves, unconfirmed rules 500 and rule drafts lost on tab unmount remain open; router/preference lifecycle is only scoped-tested. | +| **PRES-S04** — AI privacy/usage/limits/Free-Pro/server entitlement/conditional billing | Existing privacy/usage/entitlements/billing readiness retained; deterministic AI metering in [readiness](../p5-13-readiness/README.md); Production CV review exception only. | [F:settings-view](../../../../job-tracker-ui/src/settings-view.test.tsx); [F:ai-usage-card](../../../../job-tracker-ui/src/ai-usage-card.test.tsx); [B:AiPrivacyPolicy](../../../../JobTrackerApi.Tests/AiPrivacyPolicyTests.cs); [B:AiUsageMeter](../../../../JobTrackerApi.Tests/AiUsageMeterTests.cs) | Actual checkout/webhooks/portal and provider consent/delivery remain qualified. Production CV unavailability is temporary authorized P5-13 debt, not fulfillment or disabling other AI. | +| **PRES-S05** — Account ZIP/encrypted backup/lifecycle/deletion confirmations | Account ZIP/backup/deletion controls and independent saves retained; [P5-00](../p5-00/README.md) feedback clearance and [native package/ZIP evidence](../p5-08b-readiness/README.md). | [F:account-data-export](../../../../job-tracker-ui/src/account-data-export.test.tsx); [B:AccountDataExport](../../../../JobTrackerApi.Tests/AccountDataExportTests.cs); [B:BackupController](../../../../JobTrackerApi.Tests/BackupControllerTests.cs) | Actual database/account restore, verified recoverable backups, paid deletion/provider cancellation and rollback remain production release gates; no destructive rehearsal occurred. | +| **PRES-A01** — Admin user/create/roles/reset/delete/last-admin/self guards | Admin Users route/entry retained by [P5-01](../p5-01/README.md); server authorization/last-admin/self guards unchanged. | [F:admin-users-page](../../../../job-tracker-ui/src/admin-users-page.test.tsx); [B:UsersController](../../../../JobTrackerApi.Tests/UsersControllerTests.cs); [B:ApiAuthorizationPosture](../../../../JobTrackerApi.Tests/ApiAuthorizationPostureTests.cs) | Mounted-view role revocation, full mutations and actual reset delivery remain unverified; hidden nav/synthetic shell never proves authorization. | +| **PRES-A02** — Audit list/detail/supported undo/job restore | Admin Audit route/entry retained by [P5-01](../p5-01/README.md); supported server undo/restore owner unchanged. | [F:admin-audit-page](../../../../job-tracker-ui/src/admin-audit-page.test.tsx); [B:AuthAndSystemController](../../../../JobTrackerApi.Tests/AuthAndSystemControllerTests.cs); [B:ApiAuthorizationPosture](../../../../JobTrackerApi.Tests/ApiAuthorizationPostureTests.cs) | Complete successful native undo/job restore browser acceptance remains open; role posture is not undo behavior proof. | +| **PRES-A03** — System/build/DB/AI/mail/SMTP/test/probe/benchmark/maintenance | Admin System route/entry/build metadata retained in [P5-00](../p5-00/README.md)/[P5-01](../p5-01/README.md); diagnostics/maintenance owner unchanged. | [F:admin-system-page](../../../../job-tracker-ui/src/admin-system-page.test.tsx); [B:AuthAndSystemController](../../../../JobTrackerApi.Tests/AuthAndSystemControllerTests.cs); [B:MaintenanceJobDispatcher](../../../../JobTrackerApi.Tests/MaintenanceJobDispatcherTests.cs) | Actual production SMTP/model/probes/benchmark/maintenance and sensitive-output qualification remain unverified; no live jobs launched. | + +The matrix maps **9 entry/account + 10 Jobs + 12 workspace + 12 Career/CV + 6 mail + 5 Settings/insights + 3 Admin = 57** groups. Mapping completeness is not coverage percentage or acceptance. The source matrices' original unlisted sub-capability gaps remain authoritative unless a linked successor explicitly supplies their proof. In particular the former P2-D01 SQLite package/tailoring expected failure has an ordinary native passing successor; it must not be reclassified as current open debt. Conversely P5-02 human screen-reader acceptance, F04 and the other [open blocker register](../OPEN_BLOCKERS.md) items are not closed by the local successors. + +## P5-13 / PRES-C11 temporary production exception + +**P5-13 — AI Model Semantic Qualification / AI Review UI remains DEFERRED — BLOCKED / NOT QUALIFIED.** The local configuration candidate is Ollama `qwen2.5:7b`; actual deployed provider/model/digest/settings are unverified. The frozen corpus contains 32 synthetic cases and requires 366 calls; completed calls and human reviews are both zero, and critical factuality failures are unmeasured. The AI review UI is unimplemented. Deterministic grounded-proposal, source freshness, owner/CV binding, revision/history, no-write reject/error and metering/privacy protections have independent recorded regression evidence, which does not qualify model accuracy. + +The user-authorized release candidate correction is bounded to **CvAiSuggestionService-backed CV generation and Apply in Production**, using the existing optional-service unavailable/503 seam. It must prevent new generation or acceptance of an old protected proposal, and preserve existing entitlement/auth behavior, unrelated AI functions, ordinary CV manual editing, PDF/export and the Development deterministic evaluation path. Its fresh negative/no-write tests and final candidate source must be recorded by the root before any release decision. This review does not claim the candidate correction has deployed. + +This temporary withholding is an **explicit exception/deferred product capability**, not fulfilled full PRES-C11 acceptance. Availability of a route, a passing synthetic-provider fixture or safe production unavailability cannot be counted as successful CV rewriting/review. Retain the [frozen qualification/recovery package](../p5-13-semantic-qualification/README.md), [readiness evidence](../p5-13-readiness/README.md) and [exact return conditions](../OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08). P5-14-specific AI responsiveness remains unaccepted; P5-15 must carry the exception and cannot issue unconditional full Phase 5 GO while mandatory retained requirements remain unmet without a separately documented scope revision. + +## Route census and compatibility + +The [original audited route map](../../audit/ROUTE_MAP.md) contains **31 concrete patterns: 29 page patterns and two aliases**. The current [App.tsx](../../../../job-tracker-ui/src/App.tsx) has **35 route declarations**, counted from both outer router objects and inner `Route path` elements. Excluding outer `/*`, inner `*` and the inner `/` redirect gives **32 unique concrete patterns: all 31 originals plus `/analytics`**. The inner root redirect is not another public page; the outer LandingPage owns that pattern. + +Current disposition is **29 page patterns and three compatibility aliases**: Analytics adds a page and the original Kanban page becomes the third alias. A static declaration census proves path presence, not runtime entry, redirect fidelity, permission behavior, Back/Forward, dirty cancellation or deployed health. Those remain release regression requirements. + +| Concrete pattern | Candidate disposition / original compatibility | Regression anchors and evidence limit | +|---|---|---| +| `/` | Original public LandingPage; existing authenticated redirect | [landing/auth redirect](../../../../job-tracker-ui/src/LandingPage.authRedirect.test.tsx), [landing](../../../../job-tracker-ui/src/landing-page.test.tsx); provider/mobile limits in E01 | +| `/login` | Original LoginPage/local/provider/2FA entry | [login](../../../../job-tracker-ui/src/login-page.test.tsx), [smoke](../../../../job-tracker-ui/e2e/smoke.spec.ts); live auth/provider limits E02–E04 | +| `/register` | Original configured LoginPage registration mode | [login](../../../../job-tracker-ui/src/login-page.test.tsx), [local auth](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); configured/provider limits E02 | +| `/forgot-password` | Original request-reset page | [local auth](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); complete browser/mail journey remains E02 gap | +| `/reset-password` | Original token-reset page | [local auth](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); complete token submit/mail journey remains E02 gap | +| `/verify-email` | Original verification page | [verification](../../../../job-tracker-ui/src/verify-email-page.test.tsx), [local auth](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); actual mail E02 | +| `/confirm-email-change` | Original verification page with email-change mode | [verification](../../../../job-tracker-ui/src/verify-email-page.test.tsx), [local auth](../../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs); account mutation gaps E06 | +| `/microsoft-legacy-relink` | Original provider account-recovery page | [relink](../../../../job-tracker-ui/src/microsoft-legacy-relink-page.test.tsx), [token validator](../../../../JobTrackerApi.Tests/MicrosoftTokenValidatorTests.cs); real consent E03 | +| `/cv/:slug` | Original published-only anonymous CV/PDF page | [public CV](../../../../job-tracker-ui/src/public-cv-page.test.tsx), [PublicCvController](../../../../JobTrackerApi.Tests/PublicCvControllerTests.cs), [smoke](../../../../job-tracker-ui/e2e/smoke.spec.ts); deployed fonts/publication lifecycle C05/C12 | +| `/dashboard` | Original Home reports/onboarding/preferences; P5-06 presentation | [P5-06 evidence](../p5-06/README.md), [daily loop](../../../../job-tracker-ui/src/daily-control-loop.test.tsx); metric/preference limits S01/S02 | +| `/analytics` | **Added P5-07 meaningful personal reports page** | [P5-07 evidence](../p5-07/README.md); no new server facts/populations or deployed acceptance S01 | +| `/discover` | Original discovery page, Jobs secondary entry | [discovery](../../../../job-tracker-ui/src/job-discovery.test.tsx), [smoke](../../../../job-tracker-ui/e2e/smoke.spec.ts); live NAV J01/J02 | +| `/jobs` | Original tracked jobs; Table default, Board query integration | [P5-03](../p5-03/README.md), [P5-04b](../p5-04b/README.md), [native Board/query integration](../../../../job-tracker-ui/e2e/board-presentation.spec.ts), [integration component](../../../../job-tracker-ui/src/jobs-view-integration.test.tsx); finite-query/scaling limits J03–J07 | +| `/jobs/:id` | Original full job workspace; seven canonical sections | [P5-08b](../p5-08b/README.md), [route contracts](../../../../job-tracker-ui/src/application-route-contracts.test.ts), [preservation browser](../../../../job-tracker-ui/e2e/redesign-preservation.spec.ts); deferred followMode/manual/provider limits W01–W12 | +| `/reminders` | Original follow-up/reminder page | [daily loop](../../../../job-tracker-ui/src/daily-control-loop.test.tsx), [calendar](../../../../job-tracker-ui/src/application-calendar.test.tsx); F21/provider W11 | +| `/operations` | Original processing activity/progress page, utility entry | [operations](../../../../job-tracker-ui/src/operations-page.test.tsx), [OperationsController](../../../../JobTrackerApi.Tests/OperationsControllerTests.cs); worker/disconnect W12 | +| `/kanban` | **Original pattern; now compatibility alias** to `/jobs?view=board`; replace history, retain other query/hash/state | [P5-04b](../p5-04b/README.md), [native Board/query integration](../../../../job-tracker-ui/e2e/board-presentation.spec.ts), [App redirect](../../../../job-tracker-ui/src/App.tsx); physical touch/scaling J07 | +| `/companies` | Original directory/contact page; `?edit=id` retained | [companies](../../../../job-tracker-ui/src/companies-relationship.test.tsx), [command](../../../../job-tracker-ui/src/quick-command-preservation.test.tsx); modal-save accessibility J08 | +| `/offers` | Original recorded offers comparison page | [offers](../../../../job-tracker-ui/src/offer-comparison.test.tsx), [P5-07 links](../p5-07/README.md); full mobile/currency review J09 | +| `/correspondence` | Original global inbox/drafts/compose/review page | [inbox](../../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx), [draft persistence](../../../../JobTrackerApi.Tests/EmailDraftPersistenceTests.cs); live mail/reconnect M01–M06 | +| `/correspondence/review` | Original replace alias to `/correspondence?view=review` | [inbox](../../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx), [review](../../../../job-tracker-ui/src/gmail-review-page.test.tsx); actual provider/create chain M05 | +| `/profile` | Original account identity/security page; account/settings entry | [profile](../../../../job-tracker-ui/src/profile-page.test.tsx), [2FA](../../../../job-tracker-ui/src/two-factor-settings.test.tsx); complete account/device journeys E04–E06 | +| `/applications/:id` | Original replace alias to `/jobs/:id`, retaining search and router state | [P5-08b](../p5-08b/README.md), [workspace](../../../../job-tracker-ui/src/application-workspace-overlay.test.tsx), [App redirect](../../../../job-tracker-ui/src/App.tsx); legacy sections/followMode W01 | +| `/career` | Original canonical Career Profile/import/evidence page with section queries | [Career workspace](../../../../job-tracker-ui/src/career-workspace-page.test.tsx), [profile](../../../../job-tracker-ui/src/profile-page.test.tsx); long-tail/import/provider C01–C04 | +| `/career/builder` | Original CV library page; shared P5-12 gallery touch | [builder library](../../../../job-tracker-ui/src/cv-builder-page.test.tsx), [P5-12](../p5-12/README.md); full library/publication chain C05 | +| `/career/builder/:id` | Original numeric CV editor; P5-09–12 presentation; CV-AI Production exception | [editor](../../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx), [P5-12](../p5-12/README.md), [AI readiness](../p5-13-readiness/README.md); P5-13/P5-14/manual/rendering limits C06–C12 | +| `/admin/audit` | Original Admin Audit page; server role checks retained | [audit](../../../../job-tracker-ui/src/admin-audit-page.test.tsx), [authorization](../../../../JobTrackerApi.Tests/ApiAuthorizationPostureTests.cs); native undo A02 | +| `/admin/users` | Original Admin Users page; server role/last-admin/self checks retained | [users](../../../../job-tracker-ui/src/admin-users-page.test.tsx), [UsersController](../../../../JobTrackerApi.Tests/UsersControllerTests.cs); revoke/reset A01 | +| `/admin/system` | Original Admin System page; no aggregate Admin page invented | [system](../../../../job-tracker-ui/src/admin-system-page.test.tsx), [maintenance](../../../../JobTrackerApi.Tests/MaintenanceJobDispatcherTests.cs); deployed probes A03 | +| `/trash` | Original deleted-only JobTable/restore page | [P5-03](../p5-03/README.md), [table density](../../../../job-tracker-ui/e2e/table-density.spec.ts); finite restore/bulk/manual J06 | +| `/settings` | Original Settings tabs/data/privacy/backup/links page | [Settings](../../../../job-tracker-ui/src/settings-view.test.tsx), [native layout](../../../../job-tracker-ui/e2e/settings-page-layout.spec.ts); concurrent saves/billing/restore S03–S05 | +| `/settings/connected-accounts` | Original provider connections page | [connections](../../../../job-tracker-ui/src/email-provider-connections.test.tsx), [native Settings](../../../../job-tracker-ui/e2e/settings-page-layout.spec.ts); actual OAuth/mail/expiry M06 | + +Queries and non-route entries remain governed by [navigation migration](../NAVIGATION_MIGRATION.md) and [Phase 3 route/query contracts](../../phase-3/ROUTE_PLAN.md): `add/addtext`, Jobs filters/sort/page/`view`, return `from/focusJobId`, workspace `section/followMode`, company `edit`, correspondence `view`, token URLs, command actions, bell/operations links and dirty/session boundaries. Unknown/legacy keys must not cause implicit writes. Provider callbacks/postMessage flows are separate from the React page census and retain origin/state requirements. Admin path presence does not grant API access; public slug identity remains separate from numeric private CV identity. + +The actual census does **not** include `/career/profile`, `/documents`, `/notifications` or an aggregate `/admin`. Some older slice prose mentions `/career/profile`; the original preserved route and current App entry are `/career` with section queries. No extra route is inferred from that prose, and no route is removed to reconcile it. + +## Release and next-checkpoint limits + +The configured production branch is **main**, with automatic deployment after its CI test job under [the deployment workflow](../../../../.gitea/workflows/ci-deploy.yml). This preservation review does not satisfy F04 deployed peer/ingress/firewall proof, current recoverable backup/restore/migration/user-data/rollback proof, remote CI/deployment protections or deployed health/login/navigation/Jobs/Dashboard/CV/PDF verification. Merge/push is **NO-GO pending production safety proof** even if local regressions pass. No migration, production access, Docker recovery, model call or destructive operation was performed for this review. + +After a successfully verified release, P5-14 may address the user-authorized currently implemented CV scope; its deferred P5-13-specific coverage must remain explicit. P5-15 must distinguish completed/verified scope, deferred capability exceptions, release blockers and known limitations; unconditional full Phase 5 acceptance is unavailable while retained mandatory scope is unmet. Existing unrelated AI paths and all deterministic AI protections remain regression requirements. diff --git a/docs/redesign/phase-5/release-readiness/README.md b/docs/redesign/phase-5/release-readiness/README.md new file mode 100644 index 0000000..c062866 --- /dev/null +++ b/docs/redesign/phase-5/release-readiness/README.md @@ -0,0 +1,98 @@ +# Completed redesign release preparation — 2026-10-08 + +**Production decision: NO-GO. No production-branch merge/push or deployment occurred.** This is a release-candidate/deferred-work checkpoint, not a release record asserting that the application is live. Connor authorized release only after safety gates and P5-14 only after verified release. Those conditions remain unmet. No Docker recovery was attempted. + +Source: `9c9157507937b3e084a7ca1e79a2ebd77d0b0928`, `codex/ui-redesign-phase4`. Fetched production target: `origin/main` **`27657f31131cd95d42f0e1290853ec9c9b3959a4`**. The source is ahead by 43 commits with zero target-only commits at inspection. Authoritative remote: `origin`, `https://git.cesnimda.uk/cesnimda/jobtrackingapp.git`. No remote `master` exists. The final candidate/debt checkpoint is identified by Git when committed; **release commit and merge commit: none**. + +## Release routing and protections + +[CI](../../../../.gitea/workflows/ci-deploy.yml) runs on `main` pushes and pull requests. Deployment automatically follows its successful `test` job only for a push to `refs/heads/main`; it uses the established `PROD_HOST`, `PROD_USER`, `PROD_SSH_KEY` mechanism, resets the server checkout to the workflow SHA and invokes [deploy.sh](../../../../deploy/deploy.sh). Do not create/push a new `master`, force-push or treat a feature-branch push as production deployment. No CI secret was read; no current authorized deployment connection/session is available here. Remote protected-runner acceptance remains unverified; local checks cannot replace it. + +The normal deployment script validates environment/ingress, takes database/files backups before replacement and aborts if backup fails, then deploys commit-tagged images. Failure rolls back prior backend/frontend images and remains a failure. [Current deployment](../../../infrastructure/deployment.md), [backup](../../../infrastructure/backups.md) and [disaster-recovery](../../../infrastructure/disaster-recovery.md) runbooks require current version/counts, complete restorable recovery set, protected keys/tombstones and actual rollback/restore evidence. The existence of a script or historical seeded restore does not establish a fresh production recovery set. + +No new database migration exists between fetched `main` and the source: three historical migration files differ only in documentation comments. The existing CV `Version` property gains concurrency metadata in the model snapshot; no new DDL migration was added. Startup still runs existing migration/reconciliation behavior. Actual deployed schema/provider/connection settings remain unverified; API fallback to SQLite (F19) is still open and must not substitute for confirming correct deployment configuration. Compose is unchanged. New optional external-AI routing entries in `.env.example` were already introduced by grounding readiness; no production environment update is assumed or performed. + +## Candidate scope and deferred capability + +| Completed local slice | Implementation checkpoint | +|---|---| +| P5-00 shell readiness | `926f2e5`, followed by baseline/concurrent initialization proofs `38cf37e`, `57a6bd0` | +| P5-01 AppShell/grouped navigation | `8e56cea` | +| P5-02 existing global shell utilities | `0f54007`; human screen-reader acceptance remains open | +| P5-03 Jobs Table/mobile cards | `7127005` | +| P5-04a Board presentation | `42a696b` | +| P5-04b shared query/workspace integration | readiness `6fc8937`, integration `384dfa8` | +| P5-06 personal Dashboard | `ec6baae` | +| P5-07 existing-report Analytics destination | `42a6e42` | +| P5-08a Job header/Overview | `fadf99a` | +| P5-08b deeper Job sections | readiness `acd1d94`, implementation `ac6d782` | +| P5-09 CV frame/navigation | revision readiness `046dc30`, pagination repair `efc9e7b`, implementation `44b944e` | +| P5-10 CV section editing/source clarity | `fc9598b` | +| P5-11 live-preview chrome | `673cff1` | +| P5-12 template/document controls | `d8d262e` | +| Deterministic CV grounding/proposal prerequisites | `2398ff3`; model qualification and P5-13 review UI **not accepted** | + +Phase 1–4 foundations/evidence remain in the source history. P5-05 quick preview remains deferred. P5-13 semantic qualification/UI remains **DEFERRED — BLOCKED / NOT QUALIFIED** in [OPEN_BLOCKERS](../OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08); the frozen [corpus/rubric/recovery package](../p5-13-semantic-qualification/README.md) remains intact. No model qualification calls or human reviews were added. No Phase 5 completion claim is made. + +### Withholding unqualified CV review + +The candidate exposed both new CV proposal endpoints through the previously shipped CV assistant affordances. A deferred UI alone would not withhold the new API. The smallest release-safety correction uses the controller's existing optional suggestion-service seam: **omit `CvAiSuggestionService` registration in Production**, so generation and Apply return the established **503 `cv_ai_unavailable`** before model requests or CV/profile/history mutation. No feature flag, new concurrency/grounding system or global AI disable is introduced. Development qualification/regression routing remains intact; `ISummarizerService`, AI workspace, job analysis, letters/interview preparation and other AI registrations remain available under their existing authorization/privacy/provider conditions. + +Legacy CV assistant controls may remain visible and report existing unavailable errors; no P5-13 review UI is implemented. This is temporary withholding under the explicit deferral, not fulfillment of PRES-C11 model/UI acceptance. Ordinary CV editing/save/history/preview/PDF stays available. The candidate's local Production-mode API proof is separate from live verification: **production availability cannot be asserted without the deployed SHA/session**. This correction has not been deployed. + +The application-code change is confined to `JobTrackerApi/Program.cs`: one existing service registration becomes environment-conditional. `CvAiReadinessTests.cs` adds the generation/apply no-write theory cases; `playwright.cv-ai.config.ts` adds a disposable, isolated Production API using the existing fixture configuration; `cv-ai-readiness.spec.ts` verifies the actual HTTP constructor/registration boundary and continued unrelated AI availability. The Production fixture disables launch-profile override and retains Secure-cookie semantics over its explicit test-only loopback transport. No controller, prompt/provider, frontend application, renderer, environment file, Compose, CI, dependency or migration implementation was changed for this checkpoint. + +## Production blockers and next evidence + +| Gate | Result / action needed | +|---|---| +| **F04 actual ingress/runtime** | **Open, release-blocking.** Existing G-RELEASE requires real Traefik socket peer/nginx trust, effective client IP, listeners/direct/spoofed access, firewall/NAT/IPv6, DNS/TLS/redirect and restart evidence. Local 6-case ingress/3-case Compose checks do not close it. Historical public HTTPS success and connection failures do not prove it; the prior HTTP-to-unreachable-`:444` observation remains unverified today | +| **Current recovery/configuration/schema/rollback** | **Unverified, release-blocking.** Operator must inspect current backend SHA/version and counts, correct provider/connection settings, a fresh complete DB/files/keys/tombstones recovery set and required restore/rollback evidence. No database reset/volume deletion/destructive migration is authorized | +| Protected CI and deploy outcome | **Unverified.** The `main` test job must pass; actual deploy status, deployed SHA and authenticated smoke must be recorded. No main push was performed to discover whether unsafe production gates might pass | +| P5-13 qualification/UI | Explicitly deferred; production CV proposal workflow must stay unavailable until the [return conditions](../OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08) pass. Local candidate withholding does not qualify the model or verify current production | +| Human accessibility/font/photo/pointer/touch qualification | Remains open with scope/limitations in each slice; no complete screen-reader/physical-touch certification. Mandatory P5-15 items retained | + +Separate debt remains: Dashboard preference-save 500, Board full-result scaling/native touch, deferred `followMode` UI, nested CV drag/drop ownership, incomplete axe/manual checks and other [recorded blockers](../OPEN_BLOCKERS.md). Default-disabled workers, paid-deletion/billing activation, provider delivery and calendar semantics are not enabled or silently changed by this candidate. No unrelated remediation occurred. + +## Local validation and preservation + +Final executed results are recorded here after the candidate correction. They do not assert live production acceptance. All 57 capability groups and retained routes are reconciled in [PRESERVATION_REVIEW](PRESERVATION_REVIEW.md); mapped contracts are not an exhaustive provider/manual/production coverage percentage. PRES-C11 includes the explicit production deferral; ordinary revision/rendering/source boundaries remain required. + +All applicable local suites were executed after the final application correction. The sanitized [validation summary](VALIDATION.json) records actual results, timings, unchanged fidelity tolerances and incomplete accessibility counts; raw disposable data, authentication state, traces and synthetic provider payloads remain outside Git. + +| Validation | Final result | Change from inherited baseline | +|---|---|---| +| Complete backend, including auth/authz/account ownership | **1,023/1,023** | **+2** unavailable-service generation/apply theory cases | +| Focused AI/privacy/proposal subset | **108/108** | **+2**, the same cases already included in the backend total | +| CV revision safety subset | **5/5** | Unchanged, included in backend total | +| Frontend | **455/455**, 81 suites | Unchanged | +| Complete Chromium browser | **112/112** | Unchanged; 18.9 minutes, no retries/skips/expected failures. P2-D01 remains ordinary passing | +| Isolated real-HTTP AI contract | **2/2** | **+1** Production withholding/unrelated-AI proof; Development grounding/stale/no-write proof retained | +| Sidecar | **49/49** | Unchanged; deterministic fixtures, no configured-model qualification | +| Standard native rendering fidelity | **16/16; 36 preview = 36 PDF pages** | Unchanged tolerances, no measured failures | +| Settings/native exports | **8/8; 24 preview = 24 PDF pages** | Unchanged tolerances, no measured failures | +| Rate-limit / ingress / PDF admission / configuration | **9 / 6 / 1 / 3** | Unchanged; isolated local APIs, not real production ingress | +| Supply-chain helpers / offline evaluation harness / extension | **3 / 5 / 3** | Existing checks; offline harness is not a model run | +| TypeScript / isolated HTTP fixture TypeScript / lint | **Pass** | No baseline/configuration change | +| Frontend production / API Release build | **Pass** | API `-warnaserror`: zero warnings/errors | +| Tracked-secret / whitespace / current local-document targets | **Pass** | 154 current/root Markdown documents, zero missing targets; historical archive excluded. Frozen qualification evidence unchanged | + +The two new backend cases prove 503 `cv_ai_unavailable`, no provider calls and unchanged CV/profile/history for generation and Apply when the existing optional service is absent. The new native Production HTTP case failed before the correction (expected 503, received 200), then passed with real authentication/Pro scope, section/document generation and Apply unavailable, unchanged persisted snapshots and zero provider calls. It also proves an existing profile-CV rewrite and AI workspace read remain available. Existing grounding evaluation, stale expected-version/history protection, tenant isolation, frozen package/attachment readback and private/public exports pass. A passing mock/synthetic-provider contract does not establish deployed availability or model factuality. + +### Rendered and accessibility evidence + +The unchanged browser suite exercises English/Bokmål, light/dark, desktop/intermediate/320px layouts, shell entry/return, commands/notifications, Jobs Table/Board/Trash and density, Dashboard/Analytics, Job deep sections/frozen content and CV frame/source/preview/settings/history. Fresh assistant visual inspection of `dashboard-desktop-light-en.png`, `dashboard-320-dark-nb.png`, `desktop-content.png` and `one-page-code-fit-320.png` confirms the existing hierarchy/reflow, white document canvas and visible preview focus remain intact in those captures. These are samples, not complete visual certification; the earlier per-slice evidence and limitations remain authoritative. + +**229 automated axe scans report zero violations**, with incomplete node occurrences retained: `color-contrast` 1,466; `aria-hidden-focus` 33; `aria-prohibited-attr` 191; `aria-valid-attr-value` 18; `th-has-data-cells` 4. These are repeated node occurrences across scans, not unique defects or passed checks. Automated browser-driven keyboard contracts pass; no human spoken-name/live-announcement, physical touch, production font/photo, forced-colour or full reflow acceptance was performed. No open item is closed from these automated results. + +### Reproduction and evidence boundaries + +Use the existing installed SDK, bundled Python and sidecar virtual environment, with every shell command prefixed through `rtk`. Root checks: `dotnet build JobTrackerApi/JobTrackerApi.csproj --configuration Release --no-restore -warnaserror`; complete `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-build`; focused `CvAi|AiWorkspace|AiPrivacyPolicy|MeteredSummarizerService` and `CvRevisionReadinessTests` filters; sidecar `pytest`; the existing `scripts/test-ingress.py`, `scripts/test-supply-chain.py`, `scripts/test-ollama-evaluation.py` and extension capture tests. Native export comparisons reuse `scripts/verify-cv-fidelity.py` for the standard and assembled four-pair settings reports, exactly as documented in [P5-12](../p5-12/README.md#reproduction-commands). + +UI checks: `npm test -- --runInBand --silent`; `npm run typecheck`; strict standalone `tsc` for `playwright.cv-ai.config.ts` and `ai-tests/cv-ai-readiness.spec.ts`; `npm run lint`; `npm run build`; complete Playwright Chromium suite with `PLAYWRIGHT_STATIC_EXPORT=true` and fresh `CV_FIDELITY_OUTPUT` / `CV_SETTINGS_FIDELITY_OUTPUT` destinations; separate `playwright.cv-ai.config.ts`, rate-limit, ingress and PDF configurations. The last three share port 5302 and ran sequentially after the complete browser run. All APIs used disposable synthetic local data, inert or deterministic provider fixtures and no production/model access. Local artifacts are under `.artifacts/p5-release-readiness/`; use the sanitized summary for committed counts. + +## Stop and continuation boundary + +**NO-GO for production release; P5-14 not started.** No production target commit, merge, deployment, runtime health/login/navigation/Jobs/Dashboard/CV/PDF smoke or new development branch from released `main` exists for this task. Only the existing development branch receives the bounded debt/safety checkpoint. Do not claim that the changes are live. + +Next operator task: supply the existing authorized production connection or sanitized current runtime/configuration/recovery/ingress evidence and complete the already documented G-RELEASE procedure. After those conditions and protected CI are satisfied, revalidate the final candidate, merge history-preservingly into `main`, push without force, verify deployed SHA/data/authenticated workflows, then create a `codex/` development branch from verified `main` for conditionally scoped P5-14. P5-15 must retain the P5-13 debt, conditional acceptance and individual-checkpoint push rule. No P5-13 UI, P5-14, P5-15 or B07 implementation occurs here. diff --git a/docs/redesign/phase-5/release-readiness/VALIDATION.json b/docs/redesign/phase-5/release-readiness/VALIDATION.json new file mode 100644 index 0000000..5985f64 --- /dev/null +++ b/docs/redesign/phase-5/release-readiness/VALIDATION.json @@ -0,0 +1,187 @@ +{ + "date": "2026-10-08", + "sourceCheckpoint": "9c9157507937b3e084a7ca1e79a2ebd77d0b0928", + "candidateBranch": "codex/ui-redesign-phase4", + "productionBranch": "main", + "inspectedProductionHead": "27657f31131cd95d42f0e1290853ec9c9b3959a4", + "productionDecision": "NO-GO", + "productionMergedOrPushed": false, + "deployed": false, + "backend": { + "passed": 1023, + "failed": 0, + "skipped": 0 + }, + "focusedAiSubset": { + "passed": 108, + "failed": 0, + "skipped": 0 + }, + "revisionSubset": { + "passed": 5, + "failed": 0, + "skipped": 0 + }, + "frontend": { + "passed": 455, + "suites": 81, + "failed": 0, + "skipped": 0 + }, + "sidecar": { + "passed": 49, + "failed": 0, + "skipped": 0 + }, + "browser": { + "passed": 112, + "failed": 0, + "skipped": 0, + "retries": 0, + "startTime": "2026-10-08T16:13:55.959Z", + "durationSeconds": 1134.034, + "axe": { + "scans": 229, + "reportedViolations": 0, + "incompleteNodeOccurrencesByRule": { + "aria-hidden-focus": 33, + "aria-prohibited-attr": 191, + "aria-valid-attr-value": 18, + "color-contrast": 1466, + "th-has-data-cells": 4 + }, + "humanScreenReaderAcceptance": "open" + } + }, + "realHttp": { + "passed": 2, + "failed": 0, + "skipped": 0, + "retries": 0, + "startTime": "2026-10-08T16:19:24.151Z", + "durationSeconds": 13.529, + "axe": { + "scans": 0, + "reportedViolations": 0, + "incompleteNodeOccurrencesByRule": {}, + "humanScreenReaderAcceptance": "open" + } + }, + "rateLimit": { + "passed": 9, + "failed": 0, + "skipped": 0, + "retries": 0, + "startTime": "2026-10-08T16:33:20.996Z", + "durationSeconds": 10.265, + "axe": { + "scans": 0, + "reportedViolations": 0, + "incompleteNodeOccurrencesByRule": {}, + "humanScreenReaderAcceptance": "open" + } + }, + "ingress": { + "passed": 6, + "failed": 0, + "skipped": 0, + "retries": 0, + "startTime": "2026-10-08T16:34:20.457Z", + "durationSeconds": 5.961, + "axe": { + "scans": 0, + "reportedViolations": 0, + "incompleteNodeOccurrencesByRule": {}, + "humanScreenReaderAcceptance": "open" + } + }, + "pdfAdmission": { + "passed": 1, + "failed": 0, + "skipped": 0, + "retries": 0, + "startTime": "2026-10-08T16:34:34.892Z", + "durationSeconds": 7.704, + "axe": { + "scans": 0, + "reportedViolations": 0, + "incompleteNodeOccurrencesByRule": {}, + "humanScreenReaderAcceptance": "open" + } + }, + "fidelity": { + "passed": 16, + "total": 16, + "previewPages": 36, + "pdfPages": 36, + "tolerances": { + "pageDimensionMm": 0.5, + "positionMm": 2, + "fontPt": 0.5, + "rgbComponent": 0.00392156862745098, + "pageCountAndMembership": "exact" + } + }, + "settingsExports": { + "passed": 8, + "total": 8, + "previewPages": 24, + "pdfPages": 24, + "tolerances": { + "pageDimensionMm": 0.5, + "positionMm": 2, + "fontPt": 0.5, + "rgbComponent": 0.00392156862745098, + "pageCountAndMembership": "exact" + } + }, + "configuration": { + "passed": 3 + }, + "supplyChainHelpers": { + "passed": 3 + }, + "offlineEvaluationHarness": { + "passed": 5 + }, + "browserExtension": { + "passed": 3 + }, + "checks": { + "typeScript": "pass", + "isolatedHttpTypeScript": "pass", + "lint": "pass", + "frontendProductionBuild": "pass", + "apiReleaseBuildWarningsAsErrors": "pass", + "trackedSecretScan": "pass", + "whitespaceWorkingTree": "pass", + "whitespaceStaged": "pass", + "localDocumentLinks": { + "documents": 154, + "missingTargets": 0, + "historicalArchiveExcluded": true + }, + "frozenQualificationEvidence": "unchanged vs source" + }, + "preservation": { + "mappedGroups": 57, + "originalRoutesRetained": 31, + "currentConcreteRoutes": 32, + "exhaustiveCoverageClaim": false, + "presC11": "explicit temporary Production exception; model/UI acceptance unmet" + }, + "qualification": { + "cases": 32, + "requiredCalls": 366, + "completedCalls": 0, + "humanReviews": 0, + "criticalFactualityFailures": null, + "decision": "DEFERRED — BLOCKED / NOT QUALIFIED" + }, + "countChanges": { + "backend": "+2 unavailable-service generation/apply theory cases", + "focusedAiSubset": "+2 same cases, included in backend total", + "realHttp": "+1 native Production withholding/unrelated-AI case", + "otherInheritedCounts": "unchanged" + } +} diff --git a/docs/roadmap/todo.md b/docs/roadmap/todo.md index 9dc1944..4df605c 100644 --- a/docs/roadmap/todo.md +++ b/docs/roadmap/todo.md @@ -1,9 +1,11 @@ # TODO -Status reconciled: 2026-10-07. +Status reconciled: 2026-10-08. ## Current repository work +- **P5-13 — DEFERRED / BLOCKED / NOT QUALIFIED:** [outstanding-work register](../redesign/phase-5/OPEN_BLOCKERS.md#p5-13-deferred-debt-and-return-conditions--2026-10-08) retains 32 frozen cases, 366 required/0 completed model calls, 0 human reviews, unmeasured factuality, unavailable environment/unverified deployed identity and unimplemented AI review UI. Deterministic protections remain; no unrelated Docker recovery retries. [Release preparation](../redesign/phase-5/release-readiness/README.md) targets configured `main`, with production evidence gates intact. P5-14 remains conditional on verified release and excludes deferred AI-review acceptance; P5-15 must carry the debt and push each checkpoint. + - **P5-11 — live preview presentation complete:** [implementation record](../redesign/phase-5/p5-11/README.md) retains the native renderer, physical geometry, settings/history/source owners and pane modes. Fit/count/return chrome, readable busy/error/retry, semantic canvas/white paper and stable label slots have native keyboard/scroll evidence. Baseline: **941 backend / 434 frontend (+4) / 108 actual browser passes (+2)**, security 9/6/1, configuration 3; revision 5/5, fidelity 16/16 and 36 aligned pages. Forty-four final captures/211 axe scans retain incomplete/manual/sticky-boundary qualifications. The first complete smoke-selector failure and exact-mode regression correction are documented. Stop before P5-12+ or B07; F04, human screen-reader, production font/photo, pointer/reflow and separate debt remain open. - **P5-10 — CV section editing/source clarity complete:** [implementation record](../redesign/phase-5/p5-10/README.md) retains P5-09's frame and existing canonical/settings/history/rendering owners. Scope-labelled fields, independent reset, editable omitted entries and compact custom-entry actions have native persistence/focus evidence. Baseline: **941 backend / 430 frontend (+4) / 106 actual browser passes (+4)**, security 9/6/1, configuration 3; revision 5/5 and fidelity 16/16, 36 aligned pages. EN/Bokmål, light/dark, desktop/intermediate/320px evidence retained; 205 axe scans report zero violations but retain incomplete findings. Stop before P5-11+ or B07. F04 and human screen-reader/font/photo/pointer qualifications stay open. diff --git a/job-tracker-ui/ai-tests/cv-ai-readiness.spec.ts b/job-tracker-ui/ai-tests/cv-ai-readiness.spec.ts index 283b9d1..d074046 100644 --- a/job-tracker-ui/ai-tests/cv-ai-readiness.spec.ts +++ b/job-tracker-ui/ai-tests/cv-ai-readiness.spec.ts @@ -128,3 +128,58 @@ test("bound CV proposals use real owned saves and reject fabricated or stale out expect(state.calls.some((call: { path: string; body: { output_mode?: string } }) => call.path === "/cv/rewrite" && call.body.output_mode === "cv_blocks_json")).toBe(true); await testInfo.attach("synthetic-provider-contract-calls", { body: JSON.stringify(state, null, 2), contentType: "application/json" }); }); + +test("Production withholds CV review before provider calls or content writes while existing AI remains available", async ({ request, playwright }) => { + const productionUrl = `${process.env.CV_AI_READINESS_PRODUCTION_API_URL}/api`; + const api = await playwright.request.newContext(); + try { + const login = await api.post(`${productionUrl}/auth/login`, { data: { email: "cv-ai-readiness@example.test", password } }); + expect(login.status()).toBe(200); + // This is an isolated loopback API behind an HTTPS canonical origin. Keep its Secure cookies + // unchanged and explicitly transport them across the test-only internal HTTP connection. + const cookies = login.headersArray().filter(header => header.name.toLowerCase() === "set-cookie").map(header => header.value.split(";")[0]); + const headers: Record = { Cookie: cookies.join("; "), "X-CSRF-TOKEN": cookies.find(cookie => cookie.startsWith("XSRF-TOKEN="))!.slice("XSRF-TOKEN=".length) }; + const me = await api.get(`${productionUrl}/auth/me`, { headers }); + expect(me.status()).toBe(200); + const account = await me.json(); + expect(account.entitlements.ai).toBe(true); + headers["X-Session-Context"] = account.sessionContext; + expect((await request.post(`${providerUrl}/fixture/reset`)).status()).toBe(200); + + const profile = { version: "1", contact: { fullName: "Production Gate Fixture", headline: source }, summary: [source] }; + expect((await api.put(`${productionUrl}/career/profile`, { headers, data: { profile } })).status()).toBe(200); + const created = await api.post(`${productionUrl}/cv/variants`, { headers, data: { name: "Withheld AI review", settings: { themeId: "minimal", language: "en", sections: [{ key: "summary" }] } } }); + expect(created.status()).toBe(200); + const cv = await created.json(); + const snapshot = async () => { + const responses = await Promise.all([ + api.get(`${productionUrl}/cv/variants/${cv.id}`, { headers }), api.get(`${productionUrl}/cv/variants/${cv.id}/versions`, { headers }), + api.get(`${productionUrl}/career/profile`, { headers }), api.get(`${productionUrl}/career/profile/versions`, { headers }), + ]); + for (const response of responses) expect(response.status()).toBe(200); + return Promise.all(responses.map(response => response.json())); + }; + const before = await snapshot(); + for (const action of ["improve", "document-improve"]) { + const response = await api.post(`${productionUrl}/cv/ai/assist`, { headers, data: { + variantId: cv.id, expectedVersion: cv.version, action, language: "en", + ...(action.startsWith("document-") ? {} : { targetId: "section:summary", text: source }), + } }); + expect(response.status()).toBe(503); + expect(await response.json()).toEqual({ code: "cv_ai_unavailable" }); + } + const applied = await api.post(`${productionUrl}/cv/variants/${cv.id}/ai/apply`, { headers, data: { proposalToken: "unused-proposal", result: rewrite } }); + expect(applied.status()).toBe(503); + expect(await applied.json()).toEqual({ code: "cv_ai_unavailable" }); + expect(await snapshot()).toEqual(before); + expect(await (await request.get(`${providerUrl}/fixture/state`)).json()).toEqual({ mode: "supported", counts: { rewrite: 0, evaluate: 0 }, calls: [] }); + + expect((await api.get(`${productionUrl}/jobapplications/1/ai/modules`, { headers })).status()).toBe(200); + const legacy = await api.post(`${productionUrl}/profile-cv/rewrite-section`, { headers, data: { sourceText: source, language: "en" } }); + expect(legacy.status()).toBe(200); + expect((await legacy.json()).text).toBe(rewrite); + expect(await snapshot()).toEqual(before); + const state = await (await request.get(`${providerUrl}/fixture/state`)).json(); + expect(state.counts).toEqual({ rewrite: 1, evaluate: 0 }); + } finally { await api.dispose(); } +}); diff --git a/job-tracker-ui/playwright.cv-ai.config.ts b/job-tracker-ui/playwright.cv-ai.config.ts index 1f65e34..48c9339 100644 --- a/job-tracker-ui/playwright.cv-ai.config.ts +++ b/job-tracker-ui/playwright.cv-ai.config.ts @@ -6,12 +6,14 @@ import path from "node:path"; // Separate real-HTTP contract suite. Neither process uses the normal browser-suite ports. const apiUrl = "http://127.0.0.1:15313"; const providerUrl = "http://127.0.0.1:18133"; +const productionApiUrl = "http://127.0.0.1:15314"; const dataRoot = process.env.CV_AI_READINESS_DATA_ROOT ??= fs.mkdtempSync(path.join(os.tmpdir(), "jobtracker-cv-ai-readiness-")); process.env.CV_AI_READINESS_API_URL = apiUrl; process.env.CV_AI_READINESS_PROVIDER_URL = providerUrl; +process.env.CV_AI_READINESS_PRODUCTION_API_URL = productionApiUrl; const quote = (value: string) => `"${value.replaceAll('"', '\\"')}"`; -export default defineConfig({ +const config = defineConfig({ testDir: "./ai-tests", testMatch: "cv-ai-readiness.spec.ts", workers: 1, @@ -61,3 +63,22 @@ export default defineConfig({ }, ], }); + +const webServers = Array.isArray(config.webServer) ? config.webServer : [config.webServer!]; +const backend = webServers[1]; +export default defineConfig({ + ...config, + webServer: [...webServers, { + ...backend, + // Launch settings otherwise override the Production environment with Development. + command: backend.command.replace(" run ", " run --no-launch-profile ").replace(apiUrl, productionApiUrl), + url: `${productionApiUrl}/ready`, + env: { + ...backend.env, + ASPNETCORE_ENVIRONMENT: "Production", + App__PublicBaseUrl: productionApiUrl.replace("http:", "https:"), + Data__Root: path.join(dataRoot, "production"), + ConnectionStrings__JobTracker: `Data Source=${path.join(dataRoot, "production", "readiness.sqlite")}`, + }, + }], +});