feat: complete release readiness work #28

Open
cesnimda wants to merge 110 commits from release-readiness into main
9 changed files with 189 additions and 38 deletions
Showing only changes of commit 0d487123af - Show all commits
+18 -4
View File
@@ -5,12 +5,19 @@ Updated: 2026-08-15
## Stripe billing ## Stripe billing
- **Blocked:** Activating roadmap item 7.5 in production. - **Blocked:** Activating roadmap item 7.5 in production.
- **Why:** Hosted Checkout, customer-portal sessions, signed subscription webhooks, persisted billing state, and Premium-role provisioning are implemented. The Stripe product, recurring price, portal, webhook registration, and production credentials must be created outside the repository. - **Why:** Hosted Checkout, customer-portal sessions, signed subscription webhooks, persisted billing state, and Pro-role provisioning are implemented. The Stripe product, recurring price, portal, webhook registration, and production credentials must be created outside the repository.
- **Required:** Configure the Premium recurring price, enable the Stripe customer portal, register `/api/billing/webhook` for `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`, then supply `STRIPE_SECRET_KEY`, `STRIPE_PRICE_PREMIUM`, and `STRIPE_WEBHOOK_SECRET` through the deployment environment. Do not place secret values in source control or chat. - **Required:** Configure the Pro recurring price, enable the Stripe customer portal, register `/api/billing/webhook` for `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`, then supply `STRIPE_SECRET_KEY`, the recurring `price_...` value in the legacy-named `STRIPE_PRICE_PREMIUM` setting, and `STRIPE_WEBHOOK_SECRET` through the deployment environment. Do not place secret values in source control or chat.
- **Recommended:** One monthly Premium price first; add annual billing only after the monthly flow is operating. - **Recommended:** One monthly Pro price first; add annual billing only after the monthly flow is operating.
- **Current access check:** Production has test-mode secret and webhook values, but `STRIPE_PRICE_PREMIUM` currently contains a `prod_...` Product ID. Checkout requires the recurring `price_...` Price ID. The publishable key is not used by hosted Checkout. - **Current access check:** Production has test-mode secret and webhook values, but `STRIPE_PRICE_PREMIUM` currently contains a `prod_...` Product ID. Checkout requires the recurring `price_...` Price ID. The publishable key is not used by hosted Checkout.
- **Runbook:** Follow `docs/operations/stripe-activation.md`, completing test mode before creating or installing live-mode values. - **Runbook:** Follow `docs/operations/stripe-activation.md`, completing test mode before creating or installing live-mode values.
## Document parser dependency and isolation
- **Blocked:** SEC-006 dependency remediation and the dependent SEC-007 parser-isolation package.
- **Why:** The repository contains reachable parser advisories. Resolving compatible fixed versions and proving the new environment requires package-index access, which repository policy does not authorize implicitly. SEC-007 deliberately follows that compatibility update so isolation is tested against the actual fixed stack.
- **Required:** Explicitly authorize package-index/internet access for the parser dependency resolution. No production data or malicious sample is required.
- **Recommended:** Resolve and hash compatible versions first, run the benign extraction corpus and audit, then implement bounded child-process/container isolation against that exact environment.
## Public registration verification ## Public registration verification
- **Blocked:** Completing a real-browser production signup check. - **Blocked:** Completing a real-browser production signup check.
@@ -26,7 +33,14 @@ Updated: 2026-08-15
- **Required:** After the current pull request passes CI and is approved, follow `docs/release-candidate-review.md` and `docs/release-checklist.md` on the production host. Confirm the admin-only version badge matches the deployed commit, then run the authenticated application workspace, Career, CV, attachment, email-verification and rollback checks. - **Required:** After the current pull request passes CI and is approved, follow `docs/release-candidate-review.md` and `docs/release-checklist.md` on the production host. Confirm the admin-only version badge matches the deployed commit, then run the authenticated application workspace, Career, CV, attachment, email-verification and rollback checks.
- **Recommended:** Verify backup/restore before deployment, then exercise login, existing application counts, Career Workspace, public CV refresh/download, AI, and attachments in order. - **Recommended:** Verify backup/restore before deployment, then exercise login, existing application counts, Career Workspace, public CV refresh/download, AI, and attachments in order.
- **Current access check:** Read-only SSH access is confirmed to the LAN production host as both `root` and `pi` using the existing `id_ed25519` identity. All four containers are healthy and the host has 44 GB free. No production change or deployment was attempted. - **Current access check:** Read-only SSH access is confirmed to the LAN production host as both `root` and `pi` using the existing `id_ed25519` identity. All four containers are healthy and the host has 44 GB free. No production change or deployment was attempted.
- **Current status:** Anonymous production checks confirm the frontend and `/api/auth/config` return HTTP 200. The public `/health` path currently returns the SPA HTML shell; the release branch proxies that exact path to the backend and includes a regression test. Gitea PR 28 exists and an earlier complete PR gate passed; the new local commits still need their remote CI run after push. React Router is now 7.18.2 and the recorded local dependency audit is clean, so the superseded router/runner blockers were removed. - **Current status:** Anonymous production checks confirm the frontend and `/api/auth/config` return HTTP 200. The public `/health` path currently returns the SPA HTML shell; the release branch proxies that exact path to the backend and includes a regression test. Gitea PR 28 exists and an earlier complete PR gate passed; the newest local checkpoint still needs its remote CI run after push. The current local release matrix passes, including Chromium 9/9. React Router is now 7.18.2 and the recorded local dependency audit is clean, so the superseded router/runner blockers were removed.
## Account deletion retention and restore policy
- **Blocked:** Enabling SEC-009 self-service deletion in production and declaring backup erasure complete.
- **Why:** Repository code can implement a readable export and idempotent live-data deletion behind a disabled gate, but it cannot truthfully choose legal retention periods, backup expiry, provider obligations or the tombstone lifetime needed to prevent restoration from resurrecting an erased account.
- **Required:** Decide retention periods for operational backups, audit/security records and deletion tombstones; identify any legal hold/export obligations; approve the restore behavior for deleted identities.
- **Recommended:** Keep production self-service deletion disabled until a restored-backup rehearsal proves that tombstones suppress resurrection. Continue repository export/deletion implementation with explicit retention metadata and no automatic backup deletion.
## Legacy job/application column cutover ## Legacy job/application column cutover
+1
View File
@@ -203,3 +203,4 @@ Output was reduced to filenames and commit counts. The token artifact appears un
| V-169 | Legacy-vs-dedicated workspace trace; failing package DTO/UI regressions; focused/full backend and frontend; optimized build; authenticated Playwright application journey; diff review | Repository root / `job-tracker-ui` | Close JOBS-002 application-package parity, marker encapsulation, dirty navigation, focus return, responsive/theme/history/error and tenant-safety gaps | PASS — focused backend 30/30, focused frontend 28/28 plus route/focus 6/6, backend 647/647, frontend 54 suites/227 tests, build and Playwright 7/7. Chromium covers keyboard row entry, Back/Forward, saved refresh, dirty-edit cancel, focus return, missing job and long data at 375/768/1440 in explicit light/dark with zero overflow. Cross-owner workspace read and draft write return not found | Synthetic local SQLite/account/browser only; no production/provider/private data. Two targeted browser iterations corrected locators, and a transient SQLite company-create 500 led to bounded idempotent setup retry; behavior assertions were not weakened. Existing GSI and Jest open-handle warnings remain | JOBS-002 repository/browser scope verified; production/native assistive-device gates remain | | V-169 | Legacy-vs-dedicated workspace trace; failing package DTO/UI regressions; focused/full backend and frontend; optimized build; authenticated Playwright application journey; diff review | Repository root / `job-tracker-ui` | Close JOBS-002 application-package parity, marker encapsulation, dirty navigation, focus return, responsive/theme/history/error and tenant-safety gaps | PASS — focused backend 30/30, focused frontend 28/28 plus route/focus 6/6, backend 647/647, frontend 54 suites/227 tests, build and Playwright 7/7. Chromium covers keyboard row entry, Back/Forward, saved refresh, dirty-edit cancel, focus return, missing job and long data at 375/768/1440 in explicit light/dark with zero overflow. Cross-owner workspace read and draft write return not found | Synthetic local SQLite/account/browser only; no production/provider/private data. Two targeted browser iterations corrected locators, and a transient SQLite company-create 500 led to bounded idempotent setup retry; behavior assertions were not weakened. Existing GSI and Jest open-handle warnings remain | JOBS-002 repository/browser scope verified; production/native assistive-device gates remain |
| V-170 | Accessibility code audit; focused/full frontend; optimized build; full and targeted authenticated Playwright; computed-style contrast and nested-frame overflow probes | Repository root / `job-tracker-ui` | Close confirmed icon-name, keyboard CV-card, dark Alert contrast and fixed-width public-CV accessibility defects | PASS — static audit finds no `IconButton` without an explicit name; focused 4 suites/9 tests, full frontend 54 suites/228 tests, build, full Playwright 7/7 and final targeted 2/2. Chromium measures dark missing-job Alert contrast >= 4.5:1 and proves a 375px public CV retains a full A4 inner viewport with no inner or outer horizontal overflow | Local synthetic account/CV only; no native screen reader, operating-system high-contrast mode or production environment. Jest retains the known force-exit/open-handle warning; GSI repeats its existing initialization warning in development | Scoped cross-application accessibility repository/browser work verified; native AT and production remain | | V-170 | Accessibility code audit; focused/full frontend; optimized build; full and targeted authenticated Playwright; computed-style contrast and nested-frame overflow probes | Repository root / `job-tracker-ui` | Close confirmed icon-name, keyboard CV-card, dark Alert contrast and fixed-width public-CV accessibility defects | PASS — static audit finds no `IconButton` without an explicit name; focused 4 suites/9 tests, full frontend 54 suites/228 tests, build, full Playwright 7/7 and final targeted 2/2. Chromium measures dark missing-job Alert contrast >= 4.5:1 and proves a 375px public CV retains a full A4 inner viewport with no inner or outer horizontal overflow | Local synthetic account/CV only; no native screen reader, operating-system high-contrast mode or production environment. Jest retains the known force-exit/open-handle warning; GSI repeats its existing initialization warning in development | Scoped cross-application accessibility repository/browser work verified; native AT and production remain |
| V-171 | Public/product claim inventory; plan/notice/usage focused Jest; current entitlement/billing-policy backend slice; full frontend; optimized build; full Playwright | Repository root / `job-tracker-ui` | Replace contradictory plan/commercial claims and prove respectful Free/Pro promotion without changing billing or enforcement | PASS — exactly Free/Pro comes from one catalogue; focused frontend 7 suites/30 tests, policy/billing backend 30/30, full frontend 57 suites/232 tests, build and Playwright 8/8. Chromium proves retired claims absent, explicit Light/Dark, 375/768/1440 no overflow and keyboard Free/Pro actions | Local synthetic account only; no Stripe checkout/webhook/portal, native AT or production. Commercial terms remain intentionally absent until configured Checkout; existing Jest/GSI warnings remain | PRODUCT-001 repository/browser scope verified; configured billing lifecycle and production remain | | V-171 | Public/product claim inventory; plan/notice/usage focused Jest; current entitlement/billing-policy backend slice; full frontend; optimized build; full Playwright | Repository root / `job-tracker-ui` | Replace contradictory plan/commercial claims and prove respectful Free/Pro promotion without changing billing or enforcement | PASS — exactly Free/Pro comes from one catalogue; focused frontend 7 suites/30 tests, policy/billing backend 30/30, full frontend 57 suites/232 tests, build and Playwright 8/8. Chromium proves retired claims absent, explicit Light/Dark, 375/768/1440 no overflow and keyboard Free/Pro actions | Local synthetic account only; no Stripe checkout/webhook/portal, native AT or production. Commercial terms remain intentionally absent until configured Checkout; existing Jest/GSI warnings remain | PRODUCT-001 repository/browser scope verified; configured billing lifecycle and production remain |
| V-172 | Action-matrix reconciliation; full backend/frontend/sidecar/build/Compose/preflight gates; expanded authenticated and anonymous Playwright | Repository root / `job-tracker-ui` / `tools/summarizer` | Complete VER-001 local release regression without promoting mocked/provider/external checks | PASS — backend 647/647, frontend 57 suites/232 tests, sidecar 22/22, production build, Compose config, API-down/wrong-base/malformed-JSON preflight and Chromium 9/9. Browser covers admin deployment identity/normal-user absence, notifications, honest Free, jobs, Career/CV, Kanban, responsive themes and public PDF | No external provider, private data, native AT or production mutation. Optional Compose variables remain unset; existing Jest/GSI/SWIG warnings remain. Windows CRLF materialization was normalized for shell execution; indexed LF policy was already correct | VER-001 verified locally; remote CI/provider/native-AT/production cells remain |
+15 -7
View File
@@ -17,15 +17,15 @@ This is the rolling action-level evidence index. `PASS (automated/runtime)` is n
| Attachments | upload/list/download | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` | | Attachments | upload/list/download | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` |
| Attachments | metadata rename/purpose/AI flag | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` | | Attachments | metadata rename/purpose/AI flag | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` |
| Attachments | delete/restart recovery/two-user denial | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` | | Attachments | delete/restart recovery/two-user denial | PASS | BLOCKED | NOT RUN | `sec-008-attachment-consistency.md` |
| Workers | two-owner rules, export, reminders and enrichment | PASS (real SQLite; fake email/AI) | BLOCKED pending notification UI | NOT RUN; switches off | `bg-001-tenant-workers.md` | | Workers | two-owner rules, export, reminders and enrichment | PASS (real SQLite; fake email/AI) | PARTIAL — notification popover/navigation verified; worker execution is not a browser action | NOT RUN; switches off | `bg-001-tenant-workers.md`, V-172 |
| Durable operations | idempotent create/claim/lease/retry/cancel/complete | PASS (real SQLite) | NOT APPLICABLE until API/UI slice | NOT RUN | `ops-001a-durable-operations.md` | | Durable operations | idempotent create/claim/lease/retry/cancel/complete | PASS (real SQLite) | NOT APPLICABLE until API/UI slice | NOT RUN | `ops-001a-durable-operations.md` |
| Notifications | atomic terminal record, owner list/read/dismiss | PASS (real SQLite; forced rollback) | NOT APPLICABLE until API/UI slice | NOT RUN | `ops-001b-notifications.md` | | Notifications | atomic terminal record, owner list/read/dismiss | PASS (real SQLite; forced rollback) | NOT APPLICABLE until API/UI slice | NOT RUN | `ops-001b-notifications.md` |
| Operations UI | owner list/detail/cancel/retry and persistent notification surface | PASS (two-user HTTP + components) | BLOCKED | NOT RUN | `ops-001c-operation-ui.md` | | Operations UI | owner list/detail/cancel/retry and persistent notification surface | PASS (two-user HTTP + components) | PARTIAL — notification bell/panel route verified | NOT RUN | `ops-001c-operation-ui.md`, V-172 |
| Entitlements | Free direct request to every explicit AI action | PASS (policy/route inventory) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` | | Entitlements | Free direct request to every explicit AI action | PASS (policy/route inventory) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` |
| Entitlements | stale Pro claim after downgrade | PASS (live-role policy test) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` | | Entitlements | stale Pro claim after downgrade | PASS (live-role policy test) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` |
| Entitlements | queued CV and enrichment worker recheck | PASS (fake AI; real SQLite worker scopes) | N/A | NOT RUN; workers off | `pol-001-free-pro-entitlements.md` | | Entitlements | queued CV and enrichment worker recheck | PASS (fake AI; real SQLite worker scopes) | N/A | NOT RUN; workers off | `pol-001-free-pro-entitlements.md` |
| Entitlements | Free core job create/detail and deterministic match data | PASS (automated) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` | | Entitlements | Free core job create/detail and deterministic match data | PASS (automated) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` |
| Entitlements | Free locked AI Workspace/Career/CV Builder/job-assistance states | PASS (components) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` | | Entitlements | Free locked AI Workspace/Career/CV Builder/job-assistance states | PASS (components) | PASS/PARTIAL — Free Career/Settings locked state, dismissal and manual editing in Chromium | NOT RUN | `pol-001-free-pro-entitlements.md`, V-172 |
| Entitlements | Pro/Admin AI admission | PASS (automated policy) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` | | Entitlements | Pro/Admin AI admission | PASS (automated policy) | BLOCKED | NOT RUN | `pol-001-free-pro-entitlements.md` |
| AI evaluation | synthetic task/category/privacy/constraint fixture coverage | PASS (19 cases; validator) | N/A | N/A | `prod-002-ai-evaluation.md` | | AI evaluation | synthetic task/category/privacy/constraint fixture coverage | PASS (19 cases; validator) | N/A | N/A | `prod-002-ai-evaluation.md` |
| AI privacy | disable AI for a current Pro user | PASS (live database policy + worker tests) | BLOCKED | NOT RUN | `pol-002-ai-privacy.md` | | AI privacy | disable AI for a current Pro user | PASS (live database policy + worker tests) | BLOCKED | NOT RUN | `pol-002-ai-privacy.md` |
@@ -43,7 +43,7 @@ This is the rolling action-level evidence index. `PASS (automated/runtime)` is n
| Strategy Snapshot | owner-scoped rehydration/result/operation and no partial malformed output | PASS (real SQLite; fake model) | BLOCKED | NOT RUN | `ai-003-strategy-snapshot-queue.md` | | Strategy Snapshot | owner-scoped rehydration/result/operation and no partial malformed output | PASS (real SQLite; fake model) | BLOCKED | NOT RUN | `ai-003-strategy-snapshot-queue.md` |
| CV processing | upload 202, active duplicate reuse, owner-scoped execution and review gate | PASS (real SQLite; synthetic CV/fake provider) | BLOCKED | NOT RUN; worker off | `ai-004-cv-processing-queue.md` | | CV processing | upload 202, active duplicate reuse, owner-scoped execution and review gate | PASS (real SQLite; synthetic CV/fake provider) | BLOCKED | NOT RUN; worker off | `ai-004-cv-processing-queue.md` |
| CV processing | retry provenance, durable refresh state and cancel/retry controls | PASS (backend + component tests) | BLOCKED | NOT RUN | `ai-004-cv-processing-queue.md` | | CV processing | retry provenance, durable refresh state and cancel/retry controls | PASS (backend + component tests) | BLOCKED | NOT RUN | `ai-004-cv-processing-queue.md` |
| Authentication UI | unified username/password and provider alternatives; invalid/cancel/return behavior | PASS (components; mocked providers) | PARTIAL — local dark-theme form at 375/768/1440 | NOT RUN | `ux-001-unified-authentication.md` | | Authentication UI | unified username/password and provider alternatives; invalid/cancel/return behavior | PASS (components; mocked providers) | PASS/PARTIAL — Light/Dark 375/768/1440 local form; real providers not run | NOT RUN | `ux-001-unified-authentication.md`, V-172 |
| Theme state | Light/Dark/System precedence, login/logout scope, refresh/navigation and two-tab synchronization | PASS (state/provider/bootstrap tests) | PASS/PARTIAL — anonymous local browser at 375/768/1440 | NOT RUN | `ux-002-deterministic-theme-state.md` | | Theme state | Light/Dark/System precedence, login/logout scope, refresh/navigation and two-tab synchronization | PASS (state/provider/bootstrap tests) | PASS/PARTIAL — anonymous local browser at 375/768/1440 | NOT RUN | `ux-002-deterministic-theme-state.md` |
| Accessibility | icon control names and keyboard-operable CV cards | PASS (components + static audit) | PASS/PARTIAL — Chromium keyboard activation | NOT RUN | `accessibility-evidence.md`, V-170 | | Accessibility | icon control names and keyboard-operable CV cards | PASS (components + static audit) | PASS/PARTIAL — Chromium keyboard activation | NOT RUN | `accessibility-evidence.md`, V-170 |
| Accessibility | dark semantic Alert text contrast | PASS (theme ownership) | PASS — computed Chromium contrast >= 4.5:1 | NOT RUN | `ux-002-deterministic-theme-state.md`, V-170 | | Accessibility | dark semantic Alert text contrast | PASS (theme ownership) | PASS — computed Chromium contrast >= 4.5:1 | NOT RUN | `ux-002-deterministic-theme-state.md`, V-170 |
@@ -52,13 +52,21 @@ This is the rolling action-level evidence index. `PASS (automated/runtime)` is n
| Public plans | Free registration and Pro sign-in-to-Settings actions | PASS (component) | PASS — keyboard activation | NOT RUN | `product-001-honest-plans.md`, V-171 | | Public plans | Free registration and Pro sign-in-to-Settings actions | PASS (component) | PASS — keyboard activation | NOT RUN | `product-001-honest-plans.md`, V-171 |
| Pro promotion | benefit-specific locked notice, preserved-data copy and session dismissal | PASS (components) | NOT RUN on every contextual surface | NOT RUN | `product-001-honest-plans.md`, V-171 | | Pro promotion | benefit-specific locked notice, preserved-data copy and session dismissal | PASS (components) | NOT RUN on every contextual surface | NOT RUN | `product-001-honest-plans.md`, V-171 |
| Billing presentation | checkout/portal only when server status permits; unconfigured deployment disclosed | PASS (components + policy slice) | NOT RUN with configured Stripe | NOT RUN | `product-001-honest-plans.md`, V-171 | | Billing presentation | checkout/portal only when server status permits; unconfigured deployment disclosed | PASS (components + policy slice) | NOT RUN with configured Stripe | NOT RUN | `product-001-honest-plans.md`, V-171 |
| Admin safety | self/other Admin demotion confirmation and final-admin API protection | PASS (controller + components) | NOT RUN | NOT RUN | V-161 |
| Deployment identity | admin-only version/commit badge; absent for normal users | PASS (API + shell components) | PASS — configured synthetic Admin/Free accounts | NOT RUN | V-166, V-172 |
| Notifications | bell opens recent-notification panel without routing to Reminders | PASS (components) | PASS — anchored panel, URL unchanged, keyboard-accessible close | NOT RUN | `ops-001c-operation-ui.md`, V-163, V-172 |
| Job discovery | source provenance, search/sort/import and duplicate handling | PASS (backend + components) | PASS/PARTIAL — mocked responsive Light/Dark reviewed import | NOT RUN against live NAV | `jobs-001-job-discovery.md` |
| Applications list | URL-owned filters/sort/page; whole-row open; row-control isolation; focus return | PASS (components) | PASS — keyboard open and focus return | NOT RUN | `jobs-002-application-workspace.md`, V-169 |
| Application workspace | direct/deep link, refresh, history, dirty navigation, long data and missing job | PASS (API + components) | PASS — Light/Dark 375/768/1440 | NOT RUN | `jobs-002-application-workspace.md`, V-169 |
| Kanban | themed board, pointer/keyboard movement, invalid/error/empty states | PASS (components) | PASS — Light/Dark 375/768/1440 and drag | NOT RUN | `ux-003-kanban-theme.md` |
| Job match terms | bilingual/noisy/short/technology-heavy/filler extraction and honest labels | PASS (seven fixtures + component tests) | NOT RUN | NOT RUN | `qa-001-job-term-quality.md` | | Job match terms | bilingual/noisy/short/technology-heavy/filler extraction and honest labels | PASS (seven fixtures + component tests) | NOT RUN | NOT RUN | `qa-001-job-term-quality.md` |
| Career Workspace | first/returning/incomplete/loading/import processing/review/failure and recent CV actions | PASS (components; approval gate regression) | NOT RUN | NOT RUN | `career-001-career-workspace.md` | | Career Workspace | first/returning/incomplete/loading/import processing/review/failure, reviewed-field persistence and recent CV actions | PASS (components + API; approval gate regression) | PASS/PARTIAL — Admin/Free, Light/Dark and 375/768/1440 route/manual-edit checks | NOT RUN with private CV | `career-001-career-workspace.md`, V-167, V-172 |
| CV Builder | edit/collapse/add/delete/reorder/hide, save states/latest-data retry, navigation warning and preview failure/retry | PASS (components) | NOT RUN | NOT RUN | `career-002-cv-builder.md` | | CV Builder | edit/collapse/add/delete/reorder/hide, save states/latest-data retry, navigation warning and preview failure/retry | PASS (components) | PASS/PARTIAL — authenticated editor Light/Dark at 375/768/1440 | NOT RUN | `career-002-cv-builder.md`, V-172 |
| CV rendering | long names/URLs, many entries/skills, multi-page preview/PDF and readable palettes | PASS (renderer + UI) | PASS — pathological local Chromium/PDF, responsive public frame | NOT RUN with production browser | `career-002-cv-builder.md`, V-165/V-168/V-170 |
| Job email hub | linked/review view switching, Gmail decision component reuse and legacy route redirect | PASS (components; mocked provider data) | PASS/PARTIAL — local empty/disconnected 1280px and legacy redirect | NOT RUN | `mail-001-job-email-hub.md` | | Job email hub | linked/review view switching, Gmail decision component reuse and legacy route redirect | PASS (components; mocked provider data) | PASS/PARTIAL — local empty/disconnected 1280px and legacy redirect | NOT RUN | `mail-001-job-email-hub.md` |
| Job email hub | provider status, owner-scoped search/detail and saved-copy fallback | PASS (fake providers + components) | PARTIAL — disconnected status/empty filter only | NOT RUN | `mail-001-job-email-hub.md` | | Job email hub | provider status, owner-scoped search/detail and saved-copy fallback | PASS (fake providers + components) | PARTIAL — disconnected status/empty filter only | NOT RUN | `mail-001-job-email-hub.md` |
| Job email send | explicit confirmation, owner isolation, idempotency, failure/uncertainty and restart recovery | PASS (real SQLite + fake providers) | NOT RUN | NOT RUN | `mail-001-job-email-hub.md` | | Job email send | explicit confirmation, owner isolation, idempotency, failure/uncertainty and restart recovery | PASS (real SQLite + fake providers) | NOT RUN | NOT RUN | `mail-001-job-email-hub.md` |
| Job email send | content-free encrypted/daily export and hard-job-delete cascade | PASS (real SQLite) | N/A | NOT RUN | `mail-001-job-email-hub.md` | | Job email send | content-free encrypted/daily export and hard-job-delete cascade | PASS (real SQLite) | N/A | NOT RUN | `mail-001-job-email-hub.md` |
| Follow-up draft | generate/edit/copy and open canonical Job email; legacy direct SMTP returns 410 | PASS (backend + components) | NOT RUN | NOT RUN | `mail-001-job-email-hub.md` | | Follow-up draft | generate/edit/copy and open canonical Job email; legacy direct SMTP returns 410 | PASS (backend + components) | NOT RUN | NOT RUN | `mail-001-job-email-hub.md` |
Remaining product actions are `NOT STARTED` in the master plan and will be added as their work packages enter verification. The in-app browser is available for local UI checks; configured/real-provider and production access are not documented/configured. The matrix distinguishes component/API, local Chromium, mocked-provider and production evidence. Remaining `NOT RUN`/`PARTIAL` cells require configured external providers, native assistive technology, private/synthetic production data or a deployed release; they are not silently promoted by the local regression pass.
@@ -0,0 +1,49 @@
# VER-001 complete local regression
Updated: 2026-08-15
Status: `VERIFIED LOCALLY`. The complete safe local gate set passes. Provider, native assistive-technology and deployed-production checks remain explicitly separate.
## Scope completed
- Reconciled the application action matrix against the current routes, roles, plans, controls and test evidence.
- Expanded Chromium coverage for the admin-only deployment badge, notification popover, honest Free behavior, responsive Career/CV editing, dedicated application workspace, discovery, Kanban and public CV rendering/PDF.
- Exercised explicit Light and Dark preferences at 375, 768 and 1440 pixels where the workflow owns responsive/theme behavior.
- Kept provider-backed and production-only actions classified as `PARTIAL`, `NOT RUN` or `BLOCKED`; local mocks are not presented as live-provider evidence.
## Final local gates
| Gate | Result |
|---|---|
| Backend tests | PASS — 647/647 |
| Frontend tests | PASS — 57 suites, 232/232 tests |
| AI sidecar tests | PASS — 22/22; five existing SWIG deprecation warnings |
| Production frontend build/TypeScript | PASS |
| Playwright Chromium | PASS — 9/9 |
| Docker Compose configuration | PASS; only expected unset optional-variable warnings |
| Deployment preflight negative cases | PASS — API down, wrong API base and malformed JSON all fail safely |
| Dependency audit | Current lockfile evidence remains PASS — 0 vulnerabilities; the lockfile did not change |
| Patch hygiene | PASS — `git diff --check` |
The local Windows checkout materialized the two shell preflight scripts with CRLF despite their indexed LF policy. They were normalized for execution, all negative tests passed, and `git add --renormalize` confirmed no repository diff because `.gitattributes` already owns LF shell endings.
## Browser evidence
- Public plans: exactly Free/Pro, no retired commercial claims, keyboard actions and no overflow at all three widths in both explicit themes.
- Admin identity: a configured admin sees `e2e-verification` and commit metadata; a synthetic Free user receives no deployment badge.
- Notifications: the bell opens the anchored panel without changing the current route.
- Free plan: manual Career editing remains enabled, AI actions are honestly locked, the contextual notice dismisses, and unconfigured billing exposes no false upgrade action.
- Jobs: discovery/import, whole-row and keyboard navigation, deep-link refresh, history, dirty-navigation cancellation, focus return, missing records and long data.
- Career/CV: authenticated responsive editing in both themes plus anonymous multi-page CV render and PDF download.
- Kanban: themed surfaces and the existing drag behavior.
## Remaining external gates
- Remote PR CI for the newest commits and deployed version-to-commit comparison.
- Production authentication, backup/restore, MariaDB, SMTP/email verification, configured Stripe and real provider journeys.
- Native screen-reader, switch-control and operating-system high-contrast checks.
- Production local-model selection, resource measurement, restart/canary and controlled fallback.
## Rollback
This package changes test configuration, browser coverage and evidence only. Revert its commit to remove the expanded local matrix; no schema, production configuration or stored data changed.
+7 -6
View File
@@ -2,17 +2,17 @@
Updated: 2026-08-15 Updated: 2026-08-15
- **Overall programme status:** Active. Seven packages are locally verified; twenty-four are implemented with verification incomplete; VER-001 is in progress. The prioritized admin-only version indicator, JOBS-002 workspace, scoped accessibility pass and honest Free/Pro product surfaces are implemented on the release branch; remote and production verification remain. - **Overall programme status:** Active. Eight packages are locally verified; twenty-four are implemented with verification incomplete; SEC-009 is in progress. The prioritized admin-only version indicator and every immediate repository/browser item are implemented on the release branch; remote and production verification remain.
- **Current work package:** `VER-001` — complete application action matrix and regression pass (`IN PROGRESS`). Reconcile the matrix against the current tree, run every local gate and classify external checks without overstating them. - **Current work package:** `SEC-009` — complete readable export and account deletion lifecycle (`IN PROGRESS`). Proceed with owner inventory and a disabled/dark repository launch while retention/restore policy continues to block production activation.
- **Completed work packages:** None are `DONE`; all repository security/AI packages still have applicable browser, provider and/or production gates. - **Completed work packages:** None are `DONE`; all repository security/AI packages still have applicable browser, provider and/or production gates.
- **Locally verified work:** SEC-001, SEC-002, SEC-003, SEC-005A, CORE-001, PROD-002 and DEP-001 (`VERIFIED LOCALLY`). - **Locally verified work:** SEC-001, SEC-002, SEC-003, SEC-005A, CORE-001, PROD-002, DEP-001 and VER-001 (`VERIFIED LOCALLY`).
- **Implemented, verification incomplete:** SEC-004, SEC-005B, SEC-008, CORE-002, BG-001, OPS-001A/B/C, POL-001/002, AI-001/002/003/004, UX-001/002/003, QA-001, CAREER-001/002, MAIL-001, JOBS-001/002 and PRODUCT-001 (`IMPLEMENTED — NOT VERIFIED`). Their safe repository/browser scope is implemented; production/native-device/provider gates remain where recorded. - **Implemented, verification incomplete:** SEC-004, SEC-005B, SEC-008, CORE-002, BG-001, OPS-001A/B/C, POL-001/002, AI-001/002/003/004, UX-001/002/003, QA-001, CAREER-001/002, MAIL-001, JOBS-001/002 and PRODUCT-001 (`IMPLEMENTED — NOT VERIFIED`). Their safe repository/browser scope is implemented; production/native-device/provider gates remain where recorded.
- **Production-verified work:** None. - **Production-verified work:** None.
- **Blocked work:** SEC-006 parser upgrades remain outside the scoped frontend advisory permission; PROD-001/003/004 and REL-001 require documented production access and unfinished dependencies. Real provider, SMTP/MariaDB and production environments are unavailable; DEP-001 awaits approved merge/live verification. The in-app browser is available for local UI checks. - **Blocked work:** SEC-006 parser upgrades remain outside the scoped frontend advisory permission; PROD-001/003/004 and REL-001 require documented production access and unfinished dependencies. Real provider, SMTP/MariaDB and production environments are unavailable; DEP-001 awaits approved merge/live verification. The in-app browser is available for local UI checks.
- **Deferred work:** None. Conditional multi-replica coordination, model deletion, realtime operation delivery and unrelated production changes remain outside current packages. - **Deferred work:** None. Conditional multi-replica coordination, model deletion, realtime operation delivery and unrelated production changes remain outside current packages.
- **Immediate order:** VER-001; tracking/blocker reconciliation. Admin version (`a6cffe0`), Career lossless persistence (`f0b9b22`), CV contact contrast (`3b86ea2`), JOBS-002 (`deed948`), accessibility (`a7c2549`) and PRODUCT-001 repository/browser scope are locally complete. External-only work remains skipped, not allowed to stall this queue. - **Immediate order:** SEC-009 owner inventory/export first, then its disabled deletion lifecycle. The eight-item immediate queue is complete locally: admin version (`a6cffe0`), Career persistence (`f0b9b22`), CV contrast (`3b86ea2`), JOBS-002 (`deed948`), accessibility (`a7c2549`), PRODUCT-001 (`a25c31b`), VER-001 and tracking reconciliation. External-only work remains skipped, not allowed to stall repository progress.
- **Status counts:** 7 `VERIFIED LOCALLY`; 24 `IMPLEMENTED — NOT VERIFIED`; 1 `IN PROGRESS`; 2 `NOT STARTED`; 5 `BLOCKED`; 0 `DONE`; 0 `DEFERRED`. - **Status counts:** 8 `VERIFIED LOCALLY`; 24 `IMPLEMENTED — NOT VERIFIED`; 1 `IN PROGRESS`; 1 `NOT STARTED`; 5 `BLOCKED`; 0 `DONE`; 0 `DEFERRED`.
- **Test status:** backend 647/647 remains current; PRODUCT policy/billing slice 30/30; frontend 57/57 suites and 232/232 tests; optimized production build/TypeScript pass; Playwright 8/8. Chromium now also proves exactly two honest public plans, explicit light/dark at 375/768/1440, no retired commercial claims, no overflow and keyboard plan actions. The application workspace and responsive public-CV evidence remains current. CV renderer/settings 25/25, AI sidecar 22/22 and npm audit 0 evidence remain current. Historical JT-019 and Jest force-exit/open-handle behavior remain recorded. - **Test status:** backend 647/647; frontend 57/57 suites and 232/232 tests; AI sidecar 22/22; optimized production build/TypeScript; Docker Compose config; safe-failure deployment preflight; and Playwright 9/9 pass. Chromium covers the admin deployment badge/normal-user absence, notification popover, honest Free behavior, explicit light/dark at 375/768/1440, application workspace, Career/CV, discovery, Kanban and public CV/PDF. npm audit 0 evidence remains current because the lockfile did not change. Historical JT-019 and Jest force-exit/open-handle behavior remain recorded.
- **Deployment status:** Gitea pull-request run 609 passed the complete CI job in 4m20s. Deploy was intentionally skipped because the workflow deploys only a `push` to `main`; live remains unchanged. No merge/deployment was performed directly, no production migrations were run and the AI operation worker remains disabled by default. - **Deployment status:** Gitea pull-request run 609 passed the complete CI job in 4m20s. Deploy was intentionally skipped because the workflow deploys only a `push` to `main`; live remains unchanged. No merge/deployment was performed directly, no production migrations were run and the AI operation worker remains disabled by default.
- **Production status:** Unchanged and unverified. No provider/model call, model pull, external request or paid API occurred. - **Production status:** Unchanged and unverified. No provider/model call, model pull, external request or paid API occurred.
- **Known regressions:** None found by automated/local browser checks. Jest still needs `--forceExit` and reports its existing open-handle notice. Email-provider/send tests are fake/local only; real delivery is not claimed. Current MAIL browser evidence is 1280×720 only because the browser surface could not resize or perform native Tab traversal. Interrupted attempts are aged after 15 minutes and notified without retry; the five-minute scan is unmeasured on a large ledger. Direct clean EF-only SQLite migration still hits the pre-existing historical blank-chain defect before later migrations; normal startup owns reconciliation. Cross-feature monthly AI usage accounting remains a rollout gap. - **Known regressions:** None found by automated/local browser checks. Jest still needs `--forceExit` and reports its existing open-handle notice. Email-provider/send tests are fake/local only; real delivery is not claimed. Current MAIL browser evidence is 1280×720 only because the browser surface could not resize or perform native Tab traversal. Interrupted attempts are aged after 15 minutes and notified without retry; the five-minute scan is unmeasured on a large ledger. Direct clean EF-only SQLite migration still hits the pre-existing historical blank-chain defect before later migrations; normal startup owns reconciliation. Cross-feature monthly AI usage accounting remains a rollout gap.
@@ -50,5 +50,6 @@ Updated: 2026-08-15
- `docs/verification/jobs-001-job-discovery.md` - `docs/verification/jobs-001-job-discovery.md`
- `docs/verification/ux-003-kanban-theme.md` - `docs/verification/ux-003-kanban-theme.md`
- `docs/verification/product-001-honest-plans.md` - `docs/verification/product-001-honest-plans.md`
- `docs/verification/ver-001-complete-regression.md`
- `docs/verification/prod-002-ai-evaluation.md` - `docs/verification/prod-002-ai-evaluation.md`
- `docs/work-programmes/master-work-plan.md` - `docs/work-programmes/master-work-plan.md`
+10 -10
View File
@@ -16,7 +16,7 @@ Allowed statuses are `NOT STARTED`, `IN PROGRESS`, `IMPLEMENTED — NOT VERIFIED
`DONE` requires every applicable acceptance criterion, focused and regression tests, browser/accessibility/theme/mobile checks, tenant and entitlement checks, documentation, migration/rollback evidence, and production verification. Repository-only work that still requires production is at most `VERIFIED LOCALLY`. `DONE` requires every applicable acceptance criterion, focused and regression tests, browser/accessibility/theme/mobile checks, tenant and entitlement checks, documentation, migration/rollback evidence, and production verification. Repository-only work that still requires production is at most `VERIFIED LOCALLY`.
Exactly one implementation item may be `IN PROGRESS`. As of this revision it is **VER-001**. Exactly one implementation item may be `IN PROGRESS`. As of this revision it is **SEC-009**.
## Consolidated dependency order ## Consolidated dependency order
@@ -60,8 +60,8 @@ This queue records the highest-value work that can proceed without production cr
| 4 | Dedicated Job Details parity and JOBS-002 closure | JOBS-002 | Locally complete. Application answers/recruiter drafts now live on the dedicated page, note markers are encapsulated, edits are lossless, dirty navigation is guarded, focus returns to the row, tenant regressions pass, and Chromium covers 375/768/1440 light/dark/history/error/long data. Production smoke remains. | | 4 | Dedicated Job Details parity and JOBS-002 closure | JOBS-002 | Locally complete. Application answers/recruiter drafts now live on the dedicated page, note markers are encapsulated, edits are lossless, dirty navigation is guarded, focus returns to the row, tenant regressions pass, and Chromium covers 375/768/1440 light/dark/history/error/long data. Production smoke remains. |
| 5 | Cross-application contrast/accessibility pass | UX-002, UX-003, VER-001 | Locally complete. All icon controls own programmatic names; CV cards are keyboard links; the A4 public CV scales without inner/outer mobile overflow; dark Alert contrast is measured in Chromium at WCAG AA; full frontend/build/Playwright pass. Native assistive-technology and a general CI crawler remain external/future gates. | | 5 | Cross-application contrast/accessibility pass | UX-002, UX-003, VER-001 | Locally complete. All icon controls own programmatic names; CV cards are keyboard links; the A4 public CV scales without inner/outer mobile overflow; dark Alert contrast is measured in Chromium at WCAG AA; full frontend/build/Playwright pass. Native assistive-technology and a general CI crawler remain external/future gates. |
| 6 | Honest Free/Pro homepage and upgrade surfaces | PRODUCT-001 | Locally complete. One catalogue drives exactly Free/Pro; retired tier/price/Free-AI/unlimited claims are gone; configured billing state controls the real upgrade action; contextual notices are reusable/dismissible. Frontend 232/232, policy/billing 30/30, build and Chromium 8/8 pass. | | 6 | Honest Free/Pro homepage and upgrade surfaces | PRODUCT-001 | Locally complete. One catalogue drives exactly Free/Pro; retired tier/price/Free-AI/unlimited claims are gone; configured billing state controls the real upgrade action; contextual notices are reusable/dismissible. Frontend 232/232, policy/billing 30/30, build and Chromium 8/8 pass. |
| 7 | Complete application action matrix and full regression | VER-001 | In progress. Reconcile the rolling matrix, run the complete backend/frontend/sidecar/E2E/configuration gates and accurately classify external production/provider checks. | | 7 | Complete application action matrix and full regression | VER-001 | Locally complete. Backend 647/647, frontend 232/232, sidecar 22/22, build, Compose configuration, safe-failure preflight and Chromium 9/9 pass; external provider/native-AT/production cells remain explicitly unverified. |
| 8 | Tracking and blocker reconciliation | All | Keep this plan, progress, handoff, verification log and `BLOCKERS.md` aligned after every logical increment; remove stale CI/dependency statements only when current evidence proves them obsolete. | | 8 | Tracking and blocker reconciliation | All | Complete for this checkpoint. The plan, progress, handoff, verification log, action matrix and `BLOCKERS.md` distinguish repository work from external gates; continue updating them with each later package. |
## Requirement coverage index ## Requirement coverage index
@@ -268,8 +268,8 @@ This queue records the highest-value work that can proceed without production cr
- **Required tests:** two users/every entity, manifest/checksums/redaction, fault/restart/idempotence, provider failures, disposable restore replay. - **Required tests:** two users/every entity, manifest/checksums/redaction, fault/restart/idempotence, provider failures, disposable restore replay.
- **Required browser verification:** disposable self/admin export/delete and confirmations. - **Required browser verification:** disposable self/admin export/delete and confirmations.
- **Required production verification:** backup retention/tombstone rehearsal before self-service enablement. - **Required production verification:** backup retention/tombstone rehearsal before self-service enablement.
- **Status:** `NOT STARTED`. - **Status:** `IN PROGRESS`.
- **Blocker:** legal/operator retention and production restore decisions; repository work can proceed to disabled/dark launch. - **Blocker:** legal/operator retention and production restore decisions block activation, not the repository-side disabled/dark launch.
- **Evidence:** audit JT-009 inventory/design. - **Evidence:** audit JT-009 inventory/design.
- **Commit:** none. - **Commit:** none.
- **Remaining work:** owner inventory/export first, deletion second. - **Remaining work:** owner inventory/export first, deletion second.
@@ -754,11 +754,11 @@ This queue records the highest-value work that can proceed without production cr
- **Required tests:** full backend/frontend/Python/E2E plus regressions for confirmed defects. - **Required tests:** full backend/frontend/Python/E2E plus regressions for confirmed defects.
- **Required browser verification:** running app, synthetic users/data, 375/768/1440, themes/keyboard/focus/refresh/back/tabs/slow/error; no real email/paid provider/destructive production action. - **Required browser verification:** running app, synthetic users/data, 375/768/1440, themes/keyboard/focus/refresh/back/tabs/slow/error; no real email/paid provider/destructive production action.
- **Required production verification:** applicable smoke actions only after deployment; local and production classifications remain distinct. - **Required production verification:** applicable smoke actions only after deployment; local and production classifications remain distinct.
- **Status:** `IN PROGRESS`. - **Status:** `VERIFIED LOCALLY`.
- **Blocker:** browser tooling/access and external providers may block individual rows, not the matrix. - **Blocker:** remote CI, external providers, native assistive technology and production access block individual external cells, not the completed local matrix.
- **Evidence:** audit user-journey/action gaps. - **Evidence:** `docs/verification/ver-001-complete-regression.md`; V-172. Backend 647/647, frontend 57 suites/232 tests, sidecar 22/22, production build, Compose config, preflight negative tests and Chromium 9/9 pass.
- **Commit:** none. - **Commit:** none.
- **Remaining work:** create early and update per package; final sweep last. - **Remaining work:** keep the rolling matrix current; execute only its provider/native-AT/production cells when those environments and approvals exist.
### DEP-001 — Frontend advisory deployment gate ### DEP-001 — Frontend advisory deployment gate
@@ -801,7 +801,7 @@ This queue records the highest-value work that can proceed without production cr
Full decisions are in `docs/work-programmes/decisions.md`. Full decisions are in `docs/work-programmes/decisions.md`.
1. **AI provider architecture:** ADR-004/current roadmap say one deployment provider; the newer Ollama programme explicitly requires local-first plus controlled fallback. The new programme is the target, implemented centrally and compatibly; old config/models remain for rollback. 1. **AI provider architecture:** ADR-004/current roadmap say one deployment provider; the newer Ollama programme explicitly requires local-first plus controlled fallback. The new programme is the target, implemented centrally and compatibly; old config/models remain for rollback.
2. **Free AI:** current code gives Free users limited AI; the new programme says Free has no AI. POL-001 must change behavior server-side without deleting existing user data or renaming persisted roles prematurely. 2. **Free AI:** resolved by POL-001/PRODUCT-001. Free has no AI admission at the server boundary, manual/existing data remains accessible, and public copy now matches that behavior without renaming persisted roles.
3. **Production authority:** Work says no production deploy unless instructed; Ollama programme and the current request authorize only scoped local-AI production work after inventory/backup/rollback. No other production mutation is authorized. 3. **Production authority:** Work says no production deploy unless instructed; Ollama programme and the current request authorize only scoped local-AI production work after inventory/backup/rollback. No other production mutation is authorized.
4. **Schema ownership:** OPS-001A chose one EF-owned, provider-conditional migration for `UserOperations` and deliberately omitted reconciler DDL. MariaDB script generation passes; executable server verification remains. 4. **Schema ownership:** OPS-001A chose one EF-owned, provider-conditional migration for `UserOperations` and deliberately omitted reconciler DDL. MariaDB script generation passes; executable server verification remains.
5. **Compose documentation:** docs claim a separate dev override, but the filename is auto-loaded by production deploy. SEC-002 corrects actual behavior. 5. **Compose documentation:** docs claim a separate dev override, but the filename is auto-loaded by production deploy. SEC-002 corrects actual behavior.
+8 -8
View File
@@ -2,17 +2,17 @@
Updated: 2026-08-15 Updated: 2026-08-15
- **Exact current task:** commit/push PRODUCT-001, then execute VER-001 full action-matrix and regression reconciliation. - **Exact current task:** begin SEC-009 with the owner inventory/readable export, then implement the deletion lifecycle behind a disabled production gate.
- **Last completed step:** replaced contradictory three-tier/fixed-price/Free-AI/unlimited claims with exactly Free/Pro, centralized public capability copy and reused dismissible contextual upgrade notices. - **Last completed step:** reconciled VER-001 and completed the safe local release matrix, including the prioritized admin deployment identity and all immediate repository/browser work.
- **Files currently modified:** plan catalogue, homepage, active AI notices, billing-state explanation, focused tests, product documentation and programme evidence. - **Files currently modified:** expanded Playwright configuration/journeys plus VER-001 action-matrix and programme evidence.
- **Commands already run:** PRODUCT frontend 30/30; policy/billing backend 30/30; full frontend 57 suites/232 tests; optimized build; full Playwright 8/8; claim searches and diff review. - **Commands already run:** backend 647/647; frontend 57 suites/232 tests; sidecar 22/22; optimized build; Compose config; preflight negative cases; full Playwright 9/9; diff hygiene.
- **Test results:** all listed tests pass. Chromium covers exactly two plans, retired-claim absence, explicit light/dark, 375/768/1440 no-overflow and keyboard actions. Jest retains the documented force-exit/open-handle notice. - **Test results:** all listed local gates pass. Provider/native-AT/production cells remain explicitly partial, not run or blocked. Jest retains the documented force-exit/open-handle notice.
- **Services currently running:** none on task-owned ports 3000/5202. Playwright stopped its disposable API/Next servers. Pre-existing Docker services were not changed. - **Services currently running:** none on task-owned ports 3000/5202. Playwright stopped its disposable API/Next servers. Pre-existing Docker services were not changed.
- **Temporary files or processes:** no task-owned process is running and the failed disposable migration database was removed. Existing synthetic browser evidence/account and startup-created local backup remain documented. No provider account, real email, private content, paid service or production service was accessed. - **Temporary files or processes:** no task-owned process is running and the failed disposable migration database was removed. Existing synthetic browser evidence/account and startup-created local backup remain documented. No provider account, real email, private content, paid service or production service was accessed.
- **Production changes currently active:** none. No deployment, migration, provider connection/sync/send or production payload occurred. - **Production changes currently active:** none. No deployment, migration, provider connection/sync/send or production payload occurred.
- **Rollback status:** downgrade `20260810080858_AddEmailDraftClientRequestId`, then `20260810075206_AddEmailDrafts`, before reverting draft commits; then follow the existing MAIL rollback order (`ee5ef7e`, `449faeb`, `123fc55`/`e9937ac`, ledger downgrade before `653f011`). No production migration/deploy/provider grant occurred. - **Rollback status:** downgrade `20260810080858_AddEmailDraftClientRequestId`, then `20260810075206_AddEmailDrafts`, before reverting draft commits; then follow the existing MAIL rollback order (`ee5ef7e`, `449faeb`, `123fc55`/`e9937ac`, ledger downgrade before `653f011`). No production migration/deploy/provider grant occurred.
- **Uncommitted changes:** V-171 PRODUCT-001 presentation/documentation increment; no backend/dependency/schema/config/migration change. V-166 through V-170 are pushed as `a6cffe0`, `f0b9b22`, `3b86ea2`, `deed948` and `a7c2549`. - **Uncommitted changes:** V-172 test/evidence increment only; no application dependency, schema or production configuration change. V-166 through V-171 are pushed as `a6cffe0`, `f0b9b22`, `3b86ea2`, `deed948`, `a7c2549` and `a25c31b`.
- **Known failures:** live deployment is not verified because PR deploy is intentionally skipped and the active branch is not approved for merge. Draft export/API/UI, full thread/category actions and non-Gmail review remain; existing accounts need re-consent and IMAP stays read-only. A clean full-chain SQLite apply fails in the pre-existing JT-019 migration before the new draft migration. Browser/provider/MariaDB/production unavailable or unverified; recovery scan performance is unmeasured at large ledger scale; Jest open handles; SEC-006 parser dependency work is still separately gated; parser isolation remains SEC-007. - **Known failures:** live deployment is not verified because PR deploy is intentionally skipped and the active branch is not approved for merge. Draft export/API/UI, full thread/category actions and non-Gmail review remain; existing accounts need re-consent and IMAP stays read-only. A clean full-chain SQLite apply fails in the pre-existing JT-019 migration before the new draft migration. Browser/provider/MariaDB/production unavailable or unverified; recovery scan performance is unmeasured at large ledger scale; Jest open handles; SEC-006 parser dependency work is still separately gated; parser isolation remains SEC-007.
- **Exact next action:** commit/push V-171, reconcile `application-action-matrix.md` against the current repository and run the complete local VER-001 gate set. - **Exact next action:** commit/push V-172, then inventory every user-owned row/file/token/cache/queue boundary for SEC-009 before implementing export.
- **Work that can continue independently:** VER-001 and tracking reconciliation. UX/JOBS/PRODUCT production, MAIL provider mutations, SEC-006/007 and PROD packages retain their recorded external gates. - **Work that can continue independently:** SEC-009 repository-side owner inventory/export and disabled deletion lifecycle. UX/JOBS/PRODUCT production, MAIL provider mutations, SEC-006/007 and PROD packages retain their recorded external gates.
- **Decisions still required from the user:** none for synthetic/code-inspected repository work. Any provider connection or send test, internet/package upgrades, private data, external/paid providers and production actions retain explicit approval/safety gates; SEC-009 retention/legal policy remains unresolved. - **Decisions still required from the user:** none for synthetic/code-inspected repository work. Any provider connection or send test, internet/package upgrades, private data, external/paid providers and production actions retain explicit approval/safety gates; SEC-009 retention/legal policy remains unresolved.
+79 -3
View File
@@ -34,15 +34,19 @@ function contrastRatio(foreground: Rgba, background: Rgba) {
/ (Math.min(foregroundLuminance, backgroundLuminance) + 0.05); / (Math.min(foregroundLuminance, backgroundLuminance) + 0.05);
} }
async function login(page: Page) { async function loginAs(page: Page, email: string, password: string) {
await page.goto("/login"); await page.goto("/login");
await page.getByLabel("Email").fill("e2e@example.test"); await page.getByLabel("Email").fill(email);
await page.getByLabel("Current password").fill("E2ePassword123!"); await page.getByLabel("Current password").fill(password);
await page.getByRole("button", { name: "Sign in", exact: true }).click(); await page.getByRole("button", { name: "Sign in", exact: true }).click();
await expect(page).toHaveURL(/\/dashboard$/); await expect(page).toHaveURL(/\/dashboard$/);
await expect(page.getByRole("heading", { name: "Dashboard", exact: true })).toBeVisible(); await expect(page.getByRole("heading", { name: "Dashboard", exact: true })).toBeVisible();
} }
async function login(page: Page) {
await loginAs(page, "e2e@example.test", "E2ePassword123!");
}
async function csrfHeader(page: Page) { async function csrfHeader(page: Page) {
const cookie = (await page.context().cookies()).find((value) => value.name === "XSRF-TOKEN"); const cookie = (await page.context().cookies()).find((value) => value.name === "XSRF-TOKEN");
expect(cookie, "login should issue a CSRF cookie").toBeTruthy(); expect(cookie, "login should issue a CSRF cookie").toBeTruthy();
@@ -69,8 +73,17 @@ test("public plans stay honest, responsive and keyboard accessible", async ({ pa
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth); const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow).toBeLessThanOrEqual(1); expect(overflow).toBeLessThanOrEqual(1);
} }
await page.goto("/login");
await expect(page.getByRole("heading", { name: "Sign in", exact: true })).toBeVisible();
for (const width of [375, 768, 1440]) {
await page.setViewportSize({ width, height: 900 });
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow).toBeLessThanOrEqual(1);
}
} }
await page.goto("/");
const freeAction = page.getByRole("button", { name: "Create a Free account" }); const freeAction = page.getByRole("button", { name: "Create a Free account" });
await freeAction.focus(); await freeAction.focus();
await page.keyboard.press("Enter"); await page.keyboard.press("Enter");
@@ -86,6 +99,46 @@ test("public plans stay honest, responsive and keyboard accessible", async ({ pa
test("login establishes an authenticated session", async ({ page }) => { test("login establishes an authenticated session", async ({ page }) => {
await login(page); await login(page);
await expect(page.getByText("e2e@example.test").first()).toBeVisible(); await expect(page.getByText("e2e@example.test").first()).toBeVisible();
await expect(page.getByTestId("admin-version-badge")).toHaveText("ve2e-verification");
await expect(page.getByLabel("Application version e2e-verification, commit e2e1234")).toBeVisible();
await page.getByRole("button", { name: "Notifications" }).click();
await expect(page.getByLabel("Notifications panel")).toBeVisible();
await expect(page).toHaveURL(/\/dashboard$/);
await page.getByRole("button", { name: "Close" }).click();
});
test("a Free account keeps manual work available while AI actions stay honestly locked", async ({ page }) => {
const suffix = Date.now().toString();
const email = `free-${suffix}@example.test`;
const password = "FreeUserPassword123!";
await login(page);
const headers = await csrfHeader(page);
const createUser = await page.request.post(`${apiUrl}/users`, {
headers,
data: { email, password, displayName: "Free E2E User", roles: [] },
});
expect(createUser.ok()).toBeTruthy();
await page.context().clearCookies();
await loginAs(page, email, password);
await expect(page.getByTestId("admin-version-badge")).toHaveCount(0);
await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "dark"));
await page.setViewportSize({ width: 375, height: 900 });
await page.goto("/career");
await expect(page.getByText(/Build your Career Profile faster with Pro/)).toBeVisible();
await expect(page.getByLabel("Professional headline")).toBeEnabled();
await page.getByRole("button", { name: "Dismiss Build your Career Profile faster with Pro." }).click();
await expect(page.getByText(/Build your Career Profile faster with Pro/)).toHaveCount(0);
await page.goto("/settings");
await expect(page.getByText(/Free plan includes core job tracking without AI/i)).toBeVisible();
await expect(page.getByText(/Pro upgrades are not available in this deployment yet/i)).toBeVisible();
await expect(page.getByRole("button", { name: "Upgrade to Pro" })).toHaveCount(0);
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow).toBeLessThanOrEqual(1);
}); });
test("a saved job can be created through the reviewed UI flow", async ({ page }) => { test("a saved job can be created through the reviewed UI flow", async ({ page }) => {
@@ -233,9 +286,32 @@ test("the dedicated application workspace survives deep links, long data and uns
test("Career Workspace loads from the authenticated application shell", async ({ page }) => { test("Career Workspace loads from the authenticated application shell", async ({ page }) => {
await login(page); await login(page);
await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "light"));
await page.goto("/career"); await page.goto("/career");
await expect(page.getByRole("heading", { name: "Career Workspace" })).toBeVisible(); await expect(page.getByRole("heading", { name: "Career Workspace" })).toBeVisible();
await expect(page.getByRole("link", { name: "Open CV Builder" })).toHaveAttribute("href", "/career/builder"); await expect(page.getByRole("link", { name: "Open CV Builder" })).toHaveAttribute("href", "/career/builder");
for (const width of [375, 768, 1440]) {
await page.setViewportSize({ width, height: 900 });
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow).toBeLessThanOrEqual(1);
}
await page.getByRole("link", { name: "Open CV Builder" }).click();
await expect(page).toHaveURL(/\/career\/builder$/);
await page.getByRole("button", { name: "New CV" }).first().click();
await expect(page).toHaveURL(/\/career\/builder\/\d+$/);
await expect(page.getByLabel("CV name")).toBeVisible();
await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "dark"));
await page.reload();
await expect(page.locator("html")).toHaveAttribute("data-color-scheme", "dark");
for (const width of [375, 768, 1440]) {
await page.setViewportSize({ width, height: 900 });
await expect(page.getByLabel("CV name")).toBeVisible();
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow).toBeLessThanOrEqual(1);
}
}); });
test("a public CV renders anonymously and downloads as PDF", async ({ page }) => { test("a public CV renders anonymously and downloads as PDF", async ({ page }) => {
+2
View File
@@ -31,6 +31,8 @@ export default defineConfig({
Auth__AdminEmail: "e2e@example.test", Auth__AdminEmail: "e2e@example.test",
Auth__AdminPassword: "E2ePassword123!", Auth__AdminPassword: "E2ePassword123!",
Auth__AllowRegistration: "false", Auth__AllowRegistration: "false",
App__Version: "e2e-verification",
App__CommitSha: "e2e1234",
Cors__Origins__0: appUrl, Cors__Origins__0: appUrl,
Data__Root: dataRoot, Data__Root: dataRoot,
HttpsRedirection__Enabled: "false", HttpsRedirection__Enabled: "false",