From 1a1b7c82213c24fbbc9bd4e1553a92f4c76eabd9 Mon Sep 17 00:00:00 2001 From: cesnimda Date: Sat, 24 Oct 2026 13:20:47 +0200 Subject: [PATCH] test: prepare phase 9 requalification harness and blocker register --- .../phase-9/p9-requal-01/CI_FINDINGS.md | 8 +- .../p9-requal-01/CI_OPERATOR_HANDOFF.md | 2 +- .../redesign/phase-9/p9-requal-01/COMMANDS.md | 104 + .../redesign/phase-9/p9-requal-01/FINDINGS.md | 92 + .../p9-requal-01/LOCAL_DOCKER_RECOVERY.md | 27 + .../phase-9/p9-requal-01/MANUAL_ACCEPTANCE.md | 155 + .../phase-9/p9-requal-01/PERFORMANCE.md | 54 + .../phase-9/p9-requal-01/PRESERVATION.md | 109 + .../phase-9/p9-requal-01/PYTHON_SECURITY.md | 55 + .../phase-9/p9-requal-01/RD21_CLOSURE.md | 20 + .../redesign/phase-9/p9-requal-01/SECURITY.md | 12 +- .../phase-9/p9-requal-01/ci-findings.json | 28 +- .../phase-9/p9-requal-01/findings.json | 1613 +++++++ .../phase-9/p9-requal-01/linux-run.py | 141 + .../p9-requal-01/linux/playwright.config.ts | 17 + .../phase-9/p9-requal-01/mariadb-lane.py | 229 + .../observations/persistence.spec.ts | 77 + .../observations/playwright.config.ts | 4 + .../phase-9/p9-requal-01/pdf-proof.py | 91 + .../performance/mariadb-proof.mjs | 29 + .../p9-requal-01/performance/metrics.mjs | 38 + .../performance/playwright.config.ts | 14 + .../performance/sustained.spec.ts | 191 + .../phase-9/p9-requal-01/preservation.json | 3818 +++++++++++++++++ .../p9-requal-01/python-advisories.json | 365 ++ .../phase-9/p9-requal-01/reconcile.py | 187 + .../phase-9/p9-requal-01/test-linux-run.py | 59 + .../p9-requal-01/test-project-advisories.json | 20 + .../phase-9/p9-requal-01/test-reconcile.py | 82 + 29 files changed, 7637 insertions(+), 4 deletions(-) create mode 100644 docs/redesign/phase-9/p9-requal-01/COMMANDS.md create mode 100644 docs/redesign/phase-9/p9-requal-01/FINDINGS.md create mode 100644 docs/redesign/phase-9/p9-requal-01/LOCAL_DOCKER_RECOVERY.md create mode 100644 docs/redesign/phase-9/p9-requal-01/MANUAL_ACCEPTANCE.md create mode 100644 docs/redesign/phase-9/p9-requal-01/PERFORMANCE.md create mode 100644 docs/redesign/phase-9/p9-requal-01/PRESERVATION.md create mode 100644 docs/redesign/phase-9/p9-requal-01/PYTHON_SECURITY.md create mode 100644 docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md create mode 100644 docs/redesign/phase-9/p9-requal-01/findings.json create mode 100644 docs/redesign/phase-9/p9-requal-01/linux-run.py create mode 100644 docs/redesign/phase-9/p9-requal-01/linux/playwright.config.ts create mode 100644 docs/redesign/phase-9/p9-requal-01/mariadb-lane.py create mode 100644 docs/redesign/phase-9/p9-requal-01/observations/persistence.spec.ts create mode 100644 docs/redesign/phase-9/p9-requal-01/observations/playwright.config.ts create mode 100644 docs/redesign/phase-9/p9-requal-01/pdf-proof.py create mode 100644 docs/redesign/phase-9/p9-requal-01/performance/mariadb-proof.mjs create mode 100644 docs/redesign/phase-9/p9-requal-01/performance/metrics.mjs create mode 100644 docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts create mode 100644 docs/redesign/phase-9/p9-requal-01/performance/sustained.spec.ts create mode 100644 docs/redesign/phase-9/p9-requal-01/preservation.json create mode 100644 docs/redesign/phase-9/p9-requal-01/python-advisories.json create mode 100644 docs/redesign/phase-9/p9-requal-01/reconcile.py create mode 100644 docs/redesign/phase-9/p9-requal-01/test-linux-run.py create mode 100644 docs/redesign/phase-9/p9-requal-01/test-project-advisories.json create mode 100644 docs/redesign/phase-9/p9-requal-01/test-reconcile.py diff --git a/docs/redesign/phase-9/p9-requal-01/CI_FINDINGS.md b/docs/redesign/phase-9/p9-requal-01/CI_FINDINGS.md index dc60d6a..b52aeed 100644 --- a/docs/redesign/phase-9/p9-requal-01/CI_FINDINGS.md +++ b/docs/redesign/phase-9/p9-requal-01/CI_FINDINGS.md @@ -29,7 +29,13 @@ This establishes source capability only. The installed binary has not been match ## Bounded workflow change -Retain the existing push branch and add `fix/p9-ci-and-requalification`. Add an unconditional failing isolation preflight before all workflow Docker/Compose/database commands. It reports this handoff and requires a later reviewed workflow change after operator evidence; no self-attested repository variable bypass exists. Existing checkout, SDK, five guard tests, integration command and artifact action remain. No services, socket mount, privileges, Docker CLI installation, deployment workflow or runner configuration was added. +Retain the existing push branch and add `fix/p9-ci-and-requalification`. Add an unconditional failing isolation preflight as the first step, before checkout, SDK setup, repository scripts and all workflow Docker/Compose/database commands. It reports this handoff and requires a later reviewed workflow change after operator evidence; no self-attested repository variable bypass exists. Existing checkout, SDK, five guard tests, integration command and artifact action remain downstream. No services, socket mount, privileges, Docker CLI installation, deployment workflow or runner configuration was added. + +### Fresh hosted blocker verification + +Owner-pushed commit `75cd04cfc2da0837b556bdcf1424846349c4c73d` triggered [run 847](https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/847), job 1737, on runner 5 `Live-Runner`. The raw log records the first isolation step emitting explicit `BLOCKED` at **2026-10-24 06:56:14 UTC**, then exit 1. Checkout and SDK main steps were skipped; no repository guard/integration script or workflow Docker/Compose command executed. The artifact action found no integration files. No MariaDB service was declared or started. This verifies fail-closed workflow behavior only; hosted MariaDB qualification remains BLOCKED. + +Runner preparation still creates its job container with the existing host network/socket, pulls the job image and prefetches action repositories before the first step. The preflight cannot prevent runner-owned preparation. Its container and generated workspace volumes were removed afterward; this does not establish private database service lifecycle behavior. The job API again labels all steps failure, so raw logs distinguish the actual blocker from skipped downstream steps. Read-only follow-up refreshed `.artifacts/mariadb/requal-ci-api.json`; the JSON report carries its new hash and separate run-847 API/log hashes. Do not remove the blocker merely because Docker becomes available. Under the observed configuration that could grant the job control of an unidentified host daemon. The desired future native service must use `mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00` on the already documented linux/amd64 platform, no published service ports, private job networking and verified disposable storage. No version upgrade is proposed. diff --git a/docs/redesign/phase-9/p9-requal-01/CI_OPERATOR_HANDOFF.md b/docs/redesign/phase-9/p9-requal-01/CI_OPERATOR_HANDOFF.md index 0977ad0..e6b9602 100644 --- a/docs/redesign/phase-9/p9-requal-01/CI_OPERATOR_HANDOFF.md +++ b/docs/redesign/phase-9/p9-requal-01/CI_OPERATOR_HANDOFF.md @@ -1,6 +1,6 @@ # Hosted MariaDB lane: operator handoff -Status: **BLOCKED**. The workflow intentionally exits before Docker/Compose/database execution. No repository-variable toggle can enable it. The existing runner already injects a host Docker socket and host networking; this task has not changed or used those facilities. +Status: **BLOCKED**. The workflow intentionally exits at its first step before checkout, SDK setup, repository scripts and workflow Docker/Compose/database execution. Run 847 at `75cd04cfc2da0837b556bdcf1424846349c4c73d` verifies the explicit BLOCKED/exit1 outcome. No repository-variable toggle can enable it. The existing runner already injects a host Docker socket and host networking; this task has not changed or used those facilities. Runner-owned job-container creation and action prefetch still occur before the first step. The infrastructure owner must supply sanitized evidence for the following before a reviewed workflow change can enable native services: diff --git a/docs/redesign/phase-9/p9-requal-01/COMMANDS.md b/docs/redesign/phase-9/p9-requal-01/COMMANDS.md new file mode 100644 index 0000000..2e4c02e --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/COMMANDS.md @@ -0,0 +1,104 @@ +# Reproducing the qualification lanes + +Run from the repository root on the dedicated development branch. Use the pinned .NET9 SDK +and the existing frontend lock. Build Release API/tests and the production static export before +browser execution. Preserve each prior run directory; a successor is separate evidence, never a +hidden retry. The accepted result ledger records actual commands, timestamps, process outcomes, +native case identities and report hashes. Commands below describe the mechanism, not passing results. + +All shell commands in this environment use `rtk proxy`. Windows examples use the existing native +MariaDB client under `.artifacts/mariadb/runtime/mariadb-12.2.2-winx64/bin/`; obtain and verify it +using the [database setup instructions](../../../database/mariadb-standardisation/README.md). +No command connects to production. Development credentials in fixtures are intentionally local. + +## Existing full suites + +- Backend: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-restore --logger "trx;LogFileName=backend.trx" --results-directory /backend`. +- Real provider: `python scripts/mariadb-integration.py --output /mariadb`. +- Frontend, from `job-tracker-ui`: `node node_modules/jest/bin/jest.js --runInBand --json --outputFile=/frontend.json`. +- Types/lint/static build, from that directory: `node node_modules/typescript/bin/tsc --noEmit --incremental false`, `node node_modules/eslint/bin/eslint.js . --max-warnings=0`, `node --max-old-space-size=4096 node_modules/next/dist/bin/next build`. +- Sidecar, from `tools/summarizer`: set `SKIP_MODEL_LOAD=1` and `AI_SERVICE_SKIP_MODEL_LOAD=1`, then `.venv/Scripts/python.exe -m pytest -q tests --junitxml=/sidecar.xml`. This does not qualify a model. + +For ordinary browser discovery and execution, use the production static export with +`PLAYWRIGHT_STATIC_EXPORT=true`, `PLAYWRIGHT_PREBUILT_EXPORT=true`, +`PLAYWRIGHT_REUSE_SERVERS=false`, `NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api` and +`DOTNET_HOST_PATH=`. Direct fidelity outputs to fresh +`CV_FIDELITY_OUTPUT` and `CV_SETTINGS_FIDELITY_OUTPUT` directories. From `job-tracker-ui`, run +`node node_modules/@playwright/test/cli.js test --list --reporter=json`, then four **serial** +executions with `--shard=1/4` through `--shard=4/4`, each with `--retries=0 --reporter=list,json`, +a unique `--output` directory and `PLAYWRIGHT_JSON_OUTPUT_NAME`. Discovery-only empty results +are not runtime skips. Reconciliation requires exact discovery membership across all four shards. + +Run each separate config serially with the same zero-retry/report settings: + +| Lane | Config relative to `job-tracker-ui` | +| --- | --- | +| AI contract | `playwright.cv-ai.config.ts` | +| Auth recovery | `playwright.auth-recovery.config.ts` | +| Rate limits | `playwright.rate-limits.config.ts` | +| Ingress | `playwright.ingress.config.ts` | +| PDF admission | `playwright.pdf.config.ts` | +| Preferences | `../docs/redesign/phase-5/p5-15/p5-15-01/diagnostics/playwright.config.ts` | +| RD21 | `../docs/redesign/phase-9/rd21-remediation/diagnostics/playwright.config.ts` | +| Corrected diagnostics | `../docs/redesign/phase-9/p9-05/diagnostics/playwright.config.ts` | +| Volume | `../docs/redesign/phase-9/p9-05/volume/playwright.config.ts` | +| RD21 volume | `../docs/redesign/phase-9/rd21-remediation/volume/playwright.config.ts` | + +Ordinary and these historical contract fixtures retain transitional SQLite where their current +configuration specifies it. They are never counted as MariaDB qualification. + +## Dedicated MariaDB browser and sustained workload + +Use only the pinned disposable service from `docker-compose.database.yml`, project +`jobtracker-it-p9-requal`, integration profile, with `MARIADB_TEST_PORT=33308`. Start only +`mariadb-test` with `up -d --wait`. The persistent `mariadb-dev` service and its volume are separate. +The helper verifies the exact container, Compose ownership, image pin, tmpfs, loopback binding +and server version before creating its generated schema. It refuses to overwrite earlier evidence. + +With ports5302/3300 free and no other qualification workload, run these separately: + +```powershell +rtk proxy python docs/redesign/phase-9/p9-requal-01/mariadb-lane.py mariadb-browser +rtk proxy python docs/redesign/phase-9/p9-requal-01/mariadb-lane.py mariadb-observations +rtk proxy python docs/redesign/phase-9/p9-requal-01/mariadb-lane.py performance +``` + +The performance lane takes at least15minutes after setup/preflight. Do not shorten it or run +competing tests/builds. Read [PERFORMANCE.md](PERFORMANCE.md) for its bounded claims. +Each invocation drops only the exact schema it created, after stopping its own test process. +Failures retain logs and cleanup evidence; an uncertain process shutdown retains the schema. +After all lanes, remove only this owned disposable service using Compose `rm --stop --force mariadb-test` +with the same file/project/profile. Never use `down -v` or remove the development volume. + +## Native and Linux PDF fidelity + +Once both existing CV producer files have completed, use Python with the repository's existing +PDF tooling (`pdfplumber`, `pypdfium2`, Pillow): + +```powershell +rtk proxy -B docs/redesign/phase-9/p9-requal-01/pdf-proof.py --platform windows --fidelity-root .artifacts/p9-requal-01/fidelity --settings-root .artifacts/p9-requal-01/settings-fidelity --output .artifacts/p9-requal-01/windows-pdf-oracle --record .artifacts/p9-requal-01/native-pdf.json +``` + +The helper stages copies, merges all eight settings states, runs the **unchanged** existing oracle, +checks fixture/page membership and hashes original inputs before/after. It will not overwrite output. + +The Linux lane builds the **existing** API Dockerfile locally with tag +`jobtracker-p9-requal-api:security-check`, while retaining the build log and source identity. +With all other browser/API lanes stopped and the same verified disposable MariaDB service running, +execute `rtk proxy python docs/redesign/phase-9/p9-requal-01/linux-run.py`. It starts a generated, +task-labelled API container with tmpfs data and a private network, publishes only loopback5302, +verifies API identity/readiness and actual migration history, and executes five unchanged CV +producer cases. It records renderer/runtime/image identities and removes only its own resources. +Then run `pdf-proof.py --platform linux` against `.artifacts/p9-requal-01/linux/fidelity` and +`linux/settings-fidelity`, using fresh `linux-pdf-oracle` output and `linux-pdf.json` record. +This qualifies the Linux API renderer with a Windows Chromium preview client; physical printing, +Linux desktop browser behavior and human visual acceptance remain distinct. + +## Fail-closed evidence checks + +`test-reconcile.py`, `test-linux-run.py` and `mariadb-lane.py self-check` are offline harness +checks, not provider tests. `reconcile.py` reads the fixed fresh artifact paths and writes +`validation.json`; its default process fails if required gates are missing or not passing. +`--collect-only` deliberately collects partial evidence and cannot establish acceptance. +Frozen runtime input hashes must still match. Advisory findings and unavailable human/provider/ +production evidence retain their own dispositions even when functional tests pass. diff --git a/docs/redesign/phase-9/p9-requal-01/FINDINGS.md b/docs/redesign/phase-9/p9-requal-01/FINDINGS.md new file mode 100644 index 0000000..3217533 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/FINDINGS.md @@ -0,0 +1,92 @@ +# P9-REQUAL-01 findings and independent gate register + +Source review dated 24 October 2026 on `fix/p9-ci-and-requalification`, baseline `549b2cba5a791862ba3f854312ea819a86dc42a0`. This register covers RD01–RD28, every retained P9 finding, and M09-01–10. [Machine-readable register](findings.json) contains source, evidence, impact, dependency, owner, status and required closure for each entry. Fresh execution is pending the root-owned validation ledger; every result referenced below is historical unless explicitly updated there. + +The original [REQUEST §§6,13,18](../REQUEST.md) distinguishes completed assessment from acceptance and explicitly says “Carry uncompleted checks into the release gates.” It permits transparent human-check carry-forward; it does not invent human PASS results. Production-only storage/backup/deployment conditions do not automatically veto isolated functional QA. Each unmet functional criterion still needs a specific disposition. The [master cleanup criterion](../../IMPLEMENTATION_PLAN.md#phase-10--cleanup) requires proof that no route still uses removed code, tests pass and the functionality inventory is satisfied. Neither conditional Phase9 acceptance nor an open manual checklist satisfies these deletion criteria by itself. No Phase10 implementation is authorized. + +The historical [Phase9 report](../p9-07/FINAL_ACCEPTANCE.md) and [handoff](../p9-07/PHASE10_HANDOFF.md) remain intact. The [RD21 addendum](../rd21-remediation/ACCEPTANCE_ADDENDUM_2026-10-23.md) repaired SQLite but withheld provider closure; the later [MariaDB acceptance](../../../database/mariadb-standardisation/ACCEPTANCE.md) supplies bounded real-provider closure. Thus the old RD21 stale-save FAIL and missing-MariaDB statement describe their original source, not the latest qualified save/concurrency state. [RD21 closure](RD21_CLOSURE.md) preserves separate creation-idempotency, mixed-version deployment and historical-recovery limits. + +| ID | Current disposition | Phase9 implication | Phase10 implication | Production / debt | Owner and exact closure source | +|---|---|---|---|---|---| +| RD01 | OPEN; local static/loopback ingress contracts only | operator release gate | candidate-specific ingress compatibility proof | BLOCKED pending actual ingress identity; open operational qualification | Release operator: actual TLS/IPv6/firewall/topology/trusted peer and deployed auth evidence | +| RD02 | NOT TESTED: independently verified off-disk complete backup/restore | no independent veto of isolated functional QA | candidate restore dependency | BLOCKED backup/restore; open operational qualification | Release operator: isolated restore of DB/files/CVs/keys/tombstones, hashes and recovery rehearsal | +| RD03 | MariaDB 12.2.2 RD21 runtime scope verified historically (32 provider cases, 1 native journey); broader provider/deployment parity still PARTIAL | bounded provider save qualification historical PASS; full fresh matrix pending | provider migration proof per candidate | BLOCKED exact deployed parity/migrations; partial broad provider qualification | Database owner: actual approved MariaDB migration, restart, CRUD/constraints/concurrency and effective configuration proof | +| RD04 | NOT TESTED: intended Linux rollback | no independent veto of isolated functional QA | rollback proof per candidate | BLOCKED actual rollback; open operational qualification | Release operator: isolated failure/rollback rehearsal using complete prior images/configuration/recovery set | +| RD05 | Hosted database CI BLOCKED: merged host socket binding found; private isolation/lifecycle unproven; deployed identity remains separate | fresh required CI pending root evidence | testpass criterion pending root evidence | BLOCKED deployed identity and operator diagnosis; open CI/release qualification | Infrastructure owner: native core/operator diagnosis, successful protected CI, exact deployed SHA and authenticated smoke | +| RD06 | PARTIAL: finite axe/DOM/keyboard evidence; human checks open | manual carry-forward allowed only as explicit release qualification (REQUEST §6), no human PASS | affected functionality must remain satisfied; no deletion permission | BLOCKED applicable human accessibility; open human qualification | Accessibility tester: [M09-01–06](../p9-03/MANUAL_CHECKLIST.md), contextual contrast/reader evidence; triage every applicable incomplete | +| RD07 | NOT TESTED: physical input/AT/alternate browsers/forced colors | manual carry-forward release qualification; no physical/AT PASS | affected functionality proof still required | BLOCKED supported device/browser/input acceptance; open human qualification | Product/accessibility owners: actual supported devices/browser/input versions and complete workflows | +| RD08 | DEFERRED; no new model qualification or activation | C11 explicitly withheld; separate scope | no activation/deletion eligibility | BLOCKED AI activation unless separately qualified; DEFERRED product/model scope | Separate AI qualification owner: production-equivalent identity/inference, original 366-call protocol, independent human semantics, review UI/integration evidence | +| RD09 | Local withheld-operation contract retained; deployed withholding NOT TESTED | local withholding contract needs fresh successor | retain withholding and callers | BLOCKED deployed withholding untested; open deployment qualification | Release/AI owners: keep 503/no-provider/no-write guards, verify actual deployment independently | +| RD10 | PARTIAL: native local PDF corpus and visual sheets; deployed fonts/photo/print absent | finite output qualification; human/Linux/print not passed | affected rendering must preserve output contracts | BLOCKED intended output environment; open output qualification | Document owner: intended Linux/fonts/photo/crop/print and alternate-browser proof, original bytes/geometry | +| RD11 | Scoped SQLite bootstrap/WAL mechanism repaired before entry; broad reliability remains PARTIAL | scoped WAL repair retained; broad reliability qualification open | retain provider/concurrency safeguards | provider contention remains qualified; retained broader reliability | Database owner: retain held-reader/write proof, distinguish old reproduced mechanism from unproven provider/contention cases | +| RD12 | PARTIAL: notification draft/failure recovery and SQLite tests; complete contention/provider behavior unqualified | no newly established failure; provider overlap remains qualification | candidate must preserve drafts and recovery | intended-provider qualification open; retained reliability | Database/settings owners: intended-provider overlapping writes and failure/reload recovery with no data loss | +| RD13 | Historical Rules 500 mechanism remains UNCONFIRMED | historical causal mechanism UNCONFIRMED; not relabelled resolved | candidate must preserve Rules recovery | no complete reliability claim; unconfirmed historical observation | Rules/API owners: original failure trace plus controlled causal reproduction and successor regression; passing retry alone insufficient | +| RD14 | Historical command/dialog focus incident remains UNCONFIRMED; settled drawer proof is a separate finite result | historical causal mechanism UNCONFIRMED; human focus qualification | candidate must preserve trap/return/error states | applicable human checks open; unconfirmed historical observation | Shared UI owner: preserve original observations, reproduce affected modal transitions and actual reader/trap/return behavior | +| RD15 | Historical intermittent CV section expansion cause unproven | historical cause UNCONFIRMED; no invented current defect | candidate must preserve expansion state | broader reliability qualification; unconfirmed historical observation | CV owner: retain failed observation and reproduce causally before closing; do not weaken expansion assertions | +| RD16 | Scoped company-error repair retained; wider reader/dialog/date contract PARTIAL | scoped repair historical PASS; broader human contract open | candidate-specific recovery proof | human/provider qualification open; partial preserved contract | Company/UI owners: native failed-save → retained draft → successful retry plus human dialogue checks | +| RD17 | Board remains O(N); 200/1,000-job and new bounded 250-job observations are finite | finite capacity evidence; fresh sustained lane pending | measured bottleneck and full membership before optimization | no production capacity/SLA claim; O(N) known design limit | Jobs owner: agreed budget, bounded sustained profile and CPU/frame attribution before optimization; preserve full membership | +| RD18 | NOT TESTED: physical drag/drop/cancel/browser variants | manual carry-forward release qualification; physical behavior not passed | retain accessible reorder alternatives | BLOCKED physical input variants; open device qualification | Input/device tester: real Board/CV selection and named alternatives, no hidden result cap | +| RD19 | DEFERRED: reviewed `followMode` consumer | accepted deferred reviewed consumer; no activation | ineligible to remove metadata/paths | separate activation gate; DEFERRED product scope | Product/mail owner: separate explicit mode→review/action/fallback design; no auto-send or uncertain resend | +| RD20 | Optional P5-05 quick preview DEFERRED; Phase 8 Dashboard scope was delivered separately | optional preview DEFERRED; full workspace retained | no deletion of full workspace/aliases | no independent veto while optional scope remains deferred; DEFERRED optional scope | Product owner: explicit separate brief; retain existing full workspace and all routes | +| RD21 | RESOLVED within qualified MariaDB 12.2.2 save/concurrency scope; current branch successor qualification pending root ledger; creation-intent idempotency remains separate OPEN debt | bounded save/concurrency resolved historically; fresh full successor pending; creation idempotency separate | no compatibility removal without all-caller/rollback proof | BLOCKED deployment/rollback parity; no historical recovery claim; creation-intent idempotency OPEN, separate concern | Domain/API/UI owners: separate bounded contract issue covering both callers, server compare-and-swap/transaction semantics, conflict recovery and backward compatibility; characterization is not safety acceptance | +| RD22 | NOT TESTED: enabled-worker outage recovery/durability | isolated fixtures do not accept enabled producer | retain stable IDs and recovery paths | BLOCKED enabled-worker recovery; open operational qualification | Worker owner: isolated enabled-producer failure/restart/recovery, no-loss/no-duplicate proof before activation | +| RD23 | OPEN: actual calendar offset/DST/date-only semantics | actual offset/DST/date-only unqualified | retain calendar semantics until dedicated proof | BLOCKED calendar activation qualification; open provider semantics | Calendar owner: dedicated boundary/DST/provider proof in authorised sandbox before semantic changes | +| RD24 | NOT TESTED: billing/deletion/retention/provider cleanup policy and configuration | policy and destructive lifecycle outside functional proof | no removal without approved lifecycle policy | BLOCKED policy/restore/provider cleanup; open policy qualification | Product/security/operator owners: approved policy, explicit destructive-action authority, isolated recovery/cleanup proof | +| RD25 | PARTIAL: local SMTP/HTTP/provider contracts; actual OAuth/Turnstile/mail/calendar/model unavailable | sandbox/provider qualifications remain; fixtures do not pass them | candidate must preserve auth/delivery contracts | BLOCKED applicable real provider evidence; open provider qualification | Approved provider/human tester: sandbox consent/revoke/reconnect/origin/state/delivery/uncertain-attempt proof | +| RD26 | Legacy Job/Application cutover OPEN | no legacy cutover authorized | BLOCKED deletion until expand/verify/contract and all readers/writers | BLOCKED unqualified cutover; open migration scope | Migration owner: expand/verify/contract, restore/rollback and all readers/writers/aliases before removal | +| RD27 | NOT TESTED: actual monitoring/alert/recovery coverage | no independent veto of isolated functional QA | candidate observability proof where affected | BLOCKED actual alert/recovery; open operational qualification | Operations owner: effective sink, alert trigger, responder/runbook and recovery observations | +| RD28 | Ongoing evidence/provenance obligation | fresh exact evidence and source binding required | required exact candidate evidence | required exact deployment evidence; ongoing obligation | QA owner: exact source hashes/counts, original failures, no retries/skips/assertion relaxation; separate characterization from safe behavior | +| P9-OPS-01 | Previously reported EXT4/Docker storage errors UNRECHECKED | not a standalone functional defect; retain stated qualification | no permission to delete; affected-candidate proof | BLOCKED until stated operator closure; retained gate | Production operator only: independent storage-health/repair and recovery qualification under separate authority | +| P9-SEC-01 | Inherited advisory/review gate retained. Fresh live audit observations linked as P9-REQUAL-SEC01–03; compatible local pins and post-pin audits zero, full final-source successors pending. No production deployment or app-reachable exploit claimed. | local dependency fixes and post-pin zero audits recorded; complete frozen successors pending | no permission to delete; affected-candidate proof | BLOCKED independent deployed versions, exposure and release gates; no production fix claimed; inherited live-advisory gate retained; three new observations independently tracked | Dependency owner: authorised live advisory refresh, actual locked versions/paths and pre-expiry exception review; offline fixed-date policy tests do not clear current advisories. No environment bypass | +| P9-PUB-01 | Initial HTTP502 blockage recovered on23October; all checkpoint ancestors published in normal push; direct feature equality verified at `0fb108bd673ea91749f6fa057295e5b6d15d557f` | not a standalone functional defect; retain stated qualification | no permission to delete; affected-candidate proof | BLOCKED until stated operator closure; retained gate | QA: retain failed attempts and verify each subsequent normal push; no force push | +| P9-T01 | RESOLVED within historical tested scope; fresh successor pending | fresh affected regression required | candidate proof only; no cleanup authority | does not clear independent release gates; Resolved in tested Windows environment; Linux run remains separate. | QA; `.artifacts/phase9/sidecar-entry-failed.*`, `sidecar-fixture-red.*`, `sidecar-fixture-green.*`, `sidecar.xml` | +| P9-L01 | RESOLVED within historical tested scope; fresh successor pending | fresh affected regression required | candidate proof only; no cleanup authority | does not clear independent release gates; Resolved in observed local integration; no authorisation, pagination or data contract change. | Frontend; `admin-users-page.test.tsx`, `AdminUsersPage.tsx`; retained RED/GREEN logs/JSON | +| P9-V01 | RESOLVED within historical tested scope; fresh successor pending | fresh affected regression required | candidate proof only; no cleanup authority | does not clear independent release gates; Bounded fix verified by native geometry/build; the complete final 362-case ordinary successor also passed. | Frontend; `LandingPage.tsx`, new `landing-presentation.spec.ts`; `landing-red`, `landing-qualified`, `landing-accepted` raw reports | +| P9-V02 | RESOLVED within historical tested scope; fresh successor pending | fresh affected regression required | candidate proof only; no cleanup authority | does not clear independent release gates; bounded CTA repair separate from P9-V01 four-h2 repair | Frontend/QA: preserve existing LandingPage lineHeight1.4 and exact CTA+heading geometry assertions; qualify fresh complete landing and ordinary successors on frozen source, retain original RED/GREEN evidence and native-width images; original source: [FINAL_ACCEPTANCE.md](../p9-07/FINAL_ACCEPTANCE.md), line51. | +| P9-L02 | RETAINED low development debt | nonblocking development debt with visible limit | candidate proof only; no cleanup authority | does not clear independent release gates; Retained nonblocking development qualification; no data mutation proposed. | UI/localisation owner; separately map known event enums with unknown-value fallback and history/audit tests; human wording review | +| P9-T02 | RESOLVED within historical tested scope; fresh successor pending | fresh affected regression required | candidate proof only; no cleanup authority | does not clear independent release gates; Test-only repair; no product or authorisation change. | QA; `phase7-admin-users.spec.ts`; original shard report/trace and `admin-grid-green` retained. Other English-name callers belong to the separate English JobTable owner and remain unchanged. | +| P9-PERF-01 | RETAINED low development debt | nonblocking development debt with visible limit | candidate proof only; no cleanup authority | does not clear independent release gates; Accepted existing development debt; no Phase 10 implementation here. | Shared reminder read owner; measured benefit and independent shell/dashboard failure/loading tests before consolidation. | +| P9-T03 | RESOLVED historical fixture; fresh successor pending | fresh exact fixture/case successor | preserve isolation and assertions | not enabled-worker acceptance; no product fix inferred | QA: retain failed run, unchanged no-write assertions, fixture config delta and fresh full successor | +| M09-01 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Names, roles, values, selected state, headings, reading order and errors are understandable; retain reader/version and spoken observations. No hidden background content is announced. | +| M09-02 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Visible focus, logical order, genuine traps only while modal, Escape and focus restoration; no off-screen/hidden tab stops. Record any transition-specific failure. | +| M09-03 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Each action/position/save/error announces once and agrees with visible DOM order; pointer drag has an equivalent keyboard route. | +| M09-04 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Applicable normal text ≥4.5:1, large text ≥3:1 and necessary UI boundaries/focus ≥3:1. Record sampled colors/ratios/state. An axe incomplete is not sufficient to close the row. | +| M09-05 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Invisible zero badge is absent from announcements; live unread count remains meaningful; closed drawer is neither read nor tabbable. Runtime DOM checks cover only the tested states. | +| M09-06 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | accessibility tester: Essential controls remain reachable/readable, no lost content or focus; distinguish intentional table/document scrollers from root clipping. Preserve fixed A4/Letter geometry. | +| M09-07 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | product owner with physical devices: No keyboard-obscured primary action/data loss; reachable touch targets, no accidental destructive action; record device/input mode. Emulated touch does not close this. | +| M09-08 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | Bokmål reviewer: Natural professional Bokmål, consistent established terms, meaningful messages. Separate authored English content, technical names and provider strings from untranslated application copy. | +| M09-09 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | document reviewer: Legible fonts, intact glyphs/diacritics, margins, page boundaries, searchable text, photo/crop, correct language/date output and no missing/duplicated content. Retain original bytes, renderer/font versions and print observations. | +| M09-10 | NOT TESTED | explicit carry-forward qualification under REQUEST §6; no human result inferred | affected functionality proof required; no deletion authority | BLOCKED until applicable genuine human/provider evidence; open qualification | approved provider tester: Correlated origin/state, explicit confirmation, no accidental resend, correct ownership/timezone. Local SMTP/HTTP fixtures do not close external-provider qualification. | + +## New requalification security findings + +| ID | Current disposition | Phase9 implication | Phase10 implication | Production / debt | Owner and exact closure | +|---|---|---|---|---|---| +| P9-REQUAL-SEC01 | LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED | bounded dependency remediation observed locally; full frozen successor qualification pending | testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority | NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained; published vulnerable package version repaired locally; remaining evidence qualification | Dependency/QA owner: Direct compatible package override System.Security.Cryptography.Pkcs8.0.2; retain MimeKit4.17.0 ownership. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. | +| P9-REQUAL-SEC02 | LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED | bounded dependency remediation observed locally; full frozen successor qualification pending | testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority | NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained; published vulnerable package version repaired locally; remaining evidence qualification | Dependency/QA owner: Pin Next and eslint-config-next exactly16.4.1. Existing static export, unoptimized images and Sharp0.35.5 mitigate the image-serving path; they do not close every package advisory. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. | +| P9-REQUAL-SEC03 | LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED | bounded dependency remediation observed locally; full frozen successor qualification pending | testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority | NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained; published vulnerable package version repaired locally; remaining evidence qualification | Dependency/QA owner: Use compatible existing ^4 dependency range via Zod4.6.6 override; do not add runtime functionality. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. | +| P9-REQUAL-SEC04 | OPEN; locked Python advisory coverage INCOMPLETE; critical/high provider labels retained; exploitability NOT ASSESSED | REQUEST §9 explicit security risk review required and NOT CLOSED; zero NuGet/npm findings cannot clear Python findings | entry security uncertainty remains inherited and UNWAIVED; no cleanup authority | RELEASE BLOCKER pending security/sidecar disposition and qualified remediation; no production fix/deployment claimed; open locked Python security findings and coverage gap; major ML/parser transition requires separate validated scope | Security/sidecar owners: preserve exact lock hash and raw provider records, resolve/document PyPI torch+cpu query gap while retaining successful exact OSV evidence, assess applicability/reachability and supported fixes, propose bounded separately validated ML/parser dependency transition with affected regression and model/parser compatibility evidence. No automatic dependency rewrite, model activation or production action. | + +The stable review IDs are P9-REQUAL-SEC01, P9-REQUAL-SEC02, P9-REQUAL-SEC03 and P9-REQUAL-SEC04. Original RED live audits remain under `.artifacts/p9-requal-01/security-before-pins/`. Post-pin [NuGet log](../../../../.artifacts/p9-requal-01/security/nuget-advisories.log), [frontend audit JSON](../../../../.artifacts/p9-requal-01/security/frontend-audit.json) and [npm log](../../../../.artifacts/p9-requal-01/security/npm-advisories.log) report zero NuGet findings and npm0 vulnerabilities. Root will record exact raw hashes and final source binding. This confirms package advisory remediation locally, not a reachable exploit before the fix or a deployed production fix. + +The fresh locked Python evidence under `.artifacts/p9-requal-01/security/python-locked/` is **OPEN / coverage INCOMPLETE**. It contains49 pins/98 queries:97 successful,1 PyPI404 for `torch2.6.0+cpu`; exact OSV lookup succeeds.249 provider records yield109 advisory alias groups across certifi, filelock, pillow, pypdf, setuptools, torch, transformers and urllib3. Some provider labels are critical/high; exploitability is not assessed.109 alias groups are **not109 independent CVEs**. Locked-file SHA256:`36f2912965d183e59f2d8320f3817ca8dd0fee6d76e05cfd63ac92defe6c6031`. CI is preparing tracked `python-advisories.json` and `PYTHON_SECURITY.md`; this register does not claim those summaries complete. REQUEST §9 security review remains unclosed, Phase10 entry uncertainty remains unwaived and production release remains blocked. A major ML/parser dependency transition needs separately validated scope; no automatic dependency rewrite or model activation is authorized. Zero NuGet/npm findings cannot support blanket security PASS. + +## Current requalification changes awaiting final source freeze + +Root's authorized live audits identified the vulnerable dependency versions recorded above. Local compatible corrections are Pkcs8.0.2, Next/eslint-config-next16.4.1 and Zod4.6.6. Post-pin NuGet/npm audits show zero findings. Post-pin backend1123, MariaDB32 and build/types/lint pass; complete frontend and browser successors are still pending. Pre-pin frontend934 cannot qualify the final dependency source. Exact source/report hashes and final complete successors remain root-owned. No application-reachable exploit or production repair is claimed. + +Hosted database CI remains **BLOCKED**: root investigation found merged host-Docker-socket binding; private service isolation/lifecycle is not proven. Keep the explicit workflow gate. Local real-MariaDB evidence does not cure hosted isolation, and hosted isolation does not invalidate local provider persistence results. Final evidence and operator handoff belong to the root CI report. + +## Inherited accessibility causes + +The [original triage](../p9-03/inherited-axe-triage.json) reconciles64 inherited occurrences into four cause groups. Fresh scans have separate repeated occurrences; neither count is a unique defect count. These four entries also appear with independent gate/dependency fields in findings.json. + +| ID | Underlying cause / historical occurrences | Disposition / exact closure | +|---|---|---| +| P9-AX-01 | drawer/focus: focusable-modal-open, 1 occurrences | Requires manual inspection. Shared Dashboard drawer settled predicate, Escape focus and24Tab proof pass. Original Analytics transition cause is not proven; human reader/transition qualification remains. | +| P9-AX-02 | dashboard size selector: bgOverlap, 48 occurrences | Requires manual inspection. Contextual foreground/background measurement remains required. | +| P9-AX-03 | text/control with obscured background: bgOverlap, 5 occurrences | Requires manual inspection. Contextual foreground/background measurement remains required. | +| P9-AX-04 | hidden badge: shortTextContent, 10 occurrences | Not applicable in tested settled hidden state. Four current native EN/NB theme vectors: aria-hidden=true and zero area. Actual reader/live unread-state remains separate. | + + +No current final verdict is locked by this source register. Root must reconcile fresh hosted CI, full regression, source binding, sustained workload and review before issuing the five independent recommendations. Open rows remain visible even if another lane passes. P9-L02 and P9-PERF-01 are low development debt; RD19/RD20 and C11 are deferred product/model scope; production-only operations stay operator gates. The 57 preservation groups are capabilities with individual residuals, not 57 confirmed defects; see [preservation](PRESERVATION.md). No test counts are summed across overlapping lanes. diff --git a/docs/redesign/phase-9/p9-requal-01/LOCAL_DOCKER_RECOVERY.md b/docs/redesign/phase-9/p9-requal-01/LOCAL_DOCKER_RECOVERY.md new file mode 100644 index 0000000..2af03cc --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/LOCAL_DOCKER_RECOVERY.md @@ -0,0 +1,27 @@ +# Local socket recurrence — 24 October 2026 + +At11:05UTC the local Desktop engine pipe was absent and Desktop/backend processes were stopped. +Starting the local engine reproduced the exact `initializing Inference manager ... dockerInference` +startup error at11:07:41UTC. This was a local workstation failure, separate from the unsafe hosted +runner configuration and the application tests. No production host was accessed. + +The [previous socket recovery](../../../database/mariadb-standardisation/DOCKER_LOCAL_RECOVERY.md) +was rechecked. Both named directories contained only zero-byte reparse-point socket entries: +three in `%LOCALAPPDATA%/Docker/run`, one in `%LOCALAPPDATA%/docker-secrets-engine`. +Only Desktop/backend processes started by this attempt were stopped after identity/start-time checks. +The directories were moved to verified sibling archive paths and fresh empty originals created: + +- `C:/Users/Connor/AppData/Local/Docker/run.stale-20261024-p9-requal-cccb40b8` +- `C:/Users/Connor/AppData/Local/docker-secrets-engine.stale-20261024-p9-requal-660ce455` + +Archive metadata records11:11:31UTC. Subsequent Desktop startup exited0 and the engine reported +29.7.2. The task-owned disposable MariaDB service alone was started and became healthy on loopback33308. +The persistent development service was left stopped; its container/volume were not removed. +There was no factory reset, image/data/volume deletion, WSL disk operation or production restart. + +Raw scoped recovery script and metadata remain in `.artifacts/p9-requal-01/`. Initial recovery +guard attempts stopped on a timezone comparison and a changed process identity; neither moved +directories. The process set and UTC comparison were corrected before the successful archive. +No application qualification is inferred from recovery alone. Socket recurrence and workstation +lifecycle remain local tooling limitations; preserve the archives and diagnose another recurrence +before repeating any action. Do not archive broader Docker data directories. diff --git a/docs/redesign/phase-9/p9-requal-01/MANUAL_ACCEPTANCE.md b/docs/redesign/phase-9/p9-requal-01/MANUAL_ACCEPTANCE.md new file mode 100644 index 0000000..112dfc5 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/MANUAL_ACCEPTANCE.md @@ -0,0 +1,155 @@ +# Manual acceptance cards — P9-REQUAL-01 + +**All M09-01–10 remain NOT TESTED by a human in this requalification.** These cards expand the unchanged [original checklist](../p9-03/MANUAL_CHECKLIST.md); they record no fabricated execution. Under [REQUEST §6](../REQUEST.md#6-accessibility-qualification), unfinished checks carry into release gates. They are not automatically57 preservation defects or proof of a present failure. Relevant RD06/07/10/14/18/23/25 qualifications remain independent of local automation. + +Before each card, record exact final application commit, static-export/API assembly/source-manifest hashes, environment URL, MariaDB image/config digest and effective nonproduction configuration. Use the final qualified build from the root validation ledger; no card may silently run against a stale build. Record tester name/role, UTC start/end, OS/browser/AT/device/font/printer versions and test-data IDs. Use isolated development or specifically approved sandbox environments, never production. If any environment/permission/device is absent, leave that applicable portion NOT TESTED and record the dependency; no implication of failure or pass. + +Synthetic pack: one owner plus separate admin and foreign tenant accounts, two independent same-owner sessions;250 jobs only when the approved isolated fixture provides them; one ordinary job with long title/notes/timeline; long Career history with8 roles/48 distinct bullets, Åse/æ/ø, one-/multi-page CVs, optional sections and synthetic photo; notifications0/1/many, all9 Dashboard widgets. Use controlled provider inboxes for M09-10. Verify seed readback first. Do not create/delete/reset live records. Preserve frozen document hashes before/after any relevant workflow. Controlled failure injection is an approved harness action, not an invitation to stop a real service. + +Priority P1 identifies release/accessibility/data/output/provider qualification; P2 is professional language review. Priority does not grant production or provider authority. Complete cards against both English and Bokmål and light/dark where applicable, retaining per-state evidence rather than one unexplained aggregate checkmark. + +## M09-01 — Reader landmarks and complete forms (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: NVDA with a supported Windows browser, then VoiceOver with Safari on supported Apple hardware. Record actual versions. + +Steps: With reader speech enabled, traverse /login, /jobs, /jobs/{synthetic-id}, /career, /career/builder/{synthetic-id}, /documents and /settings by headings, landmarks, tab/form navigation. Trigger an invalid field and a failed save in the approved test harness, then recover. Open and settle-close drawer/dialog/menu. Repeat equivalent journey with VoiceOver. + +Pass criterion: Names/roles/values/selection, hierarchy, errors and reading order understandable; modal background not announced; successful/error status accurately announced. + +Fail criterion: Missing or misleading name/state, hidden content spoken, unreachable form or unannounced blocking error. + +Evidence to retain: Spoken transcript or recording, reader settings and exact failing/successful control; no real personal data. + +## M09-02 — Focus and modal transitions (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: Supported desktop browser, keyboard only; repeat drawer at narrow width. Actual reader can supplement, never substitute keyboard navigation. + +Steps: Start at skip link; Tab/Shift+Tab through navigation and command dialog. Open Add/Edit Job, confirmation, select and menu; Cancel, Escape and submit/retry after a controlled failed save. Move through job sections and CV preview/history. Open/close drawer repeatedly including during ordinary transitions. + +Pass criterion: Visible logical focus; modal trap only while open; Escape/cancel returns focus to initiating usable control; no closed/offscreen tab stops or lost focus. + +Fail criterion: Keyboard trap outside modal, disappearing focus, background tabbing during modal or inability to recover after failure. + +Evidence to retain: Short video plus focus sequence/control names and transition timing; preserve historical RD14 observation even if current run passes. + +## M09-03 — Dashboard announcements and deliberate recovery (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: Supported browser and actual reader; two independent authenticated sessions for same synthetic owner. Approved isolated harness for failed response. + +Steps: On /dashboard open Customize. Hide/show a widget, Earlier/Later, resize, Cancel; reopen, Reset cancel then confirm. Create stale layout in second session and save it; first session Save must conflict, retain draft and offer review/reload. Inject one save failure using approved harness, then deliberately recover. Save empty layout and restore visible widgets. + +Pass criterion: Each action/order/save/error announced once, spoken position agrees with DOM order, keyboard alternative to pointer exists, conflicts/failures retain draft and never claim saved. + +Fail criterion: Silent/misleading status, inaccessible reordering or lost rejected draft. + +Evidence to retain: Reader transcript, before/after order/revision and response status; do not capture credentials. + +## M09-04 — Contextual painted contrast (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: Actual supported browser, light/dark, painted-color sampling tool; include focused/hover/disabled/native-select/scrolled states. + +Steps: Use original P9-AX-02/03 affected nodes from inherited triage. Inspect size controls, all53 painted-background occurrences grouped by cause, scrolled CV editor and fixed chrome. Open native select and inspect applicable text/UI/focus in both themes; retain each affected cause/node/state mapping. + +Pass criterion: Normal text >=4.5:1; large text >=3:1; necessary UI boundaries/focus >=3:1. Apply documented WCAG exceptions only to truly inactive controls; record why. + +Fail criterion: Any applicable ratio below threshold or no reliable painted sample for a required state; unresolved sample stays NOT TESTED. + +Evidence to retain: Foreground/background actual paint colors, ratio, node/state and screenshot; automation incomplete alone is not closure. + +## M09-05 — Hidden badges and settled drawer (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: Actual reader plus browser accessibility tree; Dashboard and original Analytics drawer context. + +Steps: Inspect unread=0 hidden badge, then synthetic positive unread count. Open drawer; inspect modal background and reading/tab order; settle-close and repeat reader traversal and24 Tab presses. Repeat in Analytics context matching inherited occurrence. + +Pass criterion: Zero badge absent from announcements, positive count meaningful, open modal excludes background appropriately; settled closed drawer neither spoken nor tabbable. + +Fail criterion: Hidden zero announcement, missing positive count, closed drawer reader/focus access or background leakage during modal. + +Evidence to retain: Accessibility tree, speech and focus record per exact state. Passing settled Dashboard does not retroactively explain original Analytics cause. + +## M09-06 — Reflow, clipping and visible controls (P1) + +Owner: Accessibility tester. Status: **NOT TESTED**. + +Environment: Real browser100/200/400% zoom, text-only enlargement where supported, increased text spacing and forced colors; record OS/browser and actual zoom method. + +Steps: At each setting traverse Jobs pagination, job/document section tabs, CV tabs/controls, Settings inputs and significant forms using keyboard. Scroll intentional table/document/Board scrollers, then reach every primary action. Check long EN/NB labels and error states. + +Pass criterion: Essential content and focused actions readable/reachable, no root clipping or lost focus; intentional scrollers remain usable; fixed A4/Letter document geometry preserved. + +Fail criterion: Unreachable clipped control/text, obscured primary action or focus, broken forced-colors affordance. + +Evidence to retain: Screenshot at each setting, focused control and scroll path. The historical16 offviewport states remain explicit targets; zero root overflow alone is insufficient. + +## M09-07 — Physical input and interruption (P1) + +Owner: Product owner with physical devices. Status: **NOT TESTED**. + +Environment: Actual supported phone and tablet, portrait/landscape, software keyboard, touch/pointer as applicable; record model/OS/browser/input. + +Steps: Edit long Career/job/letter text while keyboard is open. Open drawer/dialog/select, rotate, recover after Cancel and controlled failed save. Reorder Dashboard/Board using supported touch action and named alternative; cancel drag. Traverse CV preview; download synthetic PDF. + +Pass criterion: Primary action not obscured by keyboard; draft retained across intended interruptions; reachable touch targets; no unintended destructive/move operation; alternatives usable. + +Fail criterion: Obscured save, lost draft, accidental destructive/move, unusable touch target or failed supported download. + +Evidence to retain: Device video/screenshots including keyboard/rotation and result readback. Emulated touch cannot close this card. + +## M09-08 — Professional Bokmål and terminology (P2) + +Owner: Professional Bokmål reviewer. Status: **NOT TESTED**. + +Environment: Application nb locale on exact build; both themes, narrow and desktop, ordinary user and separate synthetic admin. Include dates/numbers/plural states. + +Steps: Review registration/recovery, errors/validation, onboarding, Dashboard customization, Jobs/Board/history, Career/import, CV/library, documents/mail, notifications, Settings/Admin. Use long names,0/1/many counts and boundary date/number values. Inspect accessible names with reader. Record raw Created metadata separately from application copy. + +Pass criterion: Natural professional Bokmål, consistent established terms, meaningful validation/names and correct date/number presentation. Distinguish authored/provider English and technical names. + +Fail criterion: Untranslated application string, unnatural/misleading term, incorrect locale format or inaccessible label; authored English alone is not defect. + +Evidence to retain: Exact key/control and screenshot, proposed wording and reviewer rationale. P9-L02 remains low debt until separately implemented/reviewed. + +## M09-09 — Intended-environment PDF fidelity (P1) + +Owner: Document reviewer. Status: **NOT TESTED**. + +Environment: Intended Linux renderer/font set, supported primary and alternate browsers and actual printer or approved print workflow. Record versions/fonts/template/page size. + +Steps: Generate synthetic one- and multi-page EN/NB CVs in every supported template, with long words/employment/bullets, missing optional sections, Å/æ/ø/special characters and permitted synthetic photo. Compare preview with downloaded originals; inspect/search/copy text; print representative pages including first/last/page-break boundaries. + +Pass criterion: Legible fonts/glyphs, correct language/date, no missing/duplicate content, intact margins/header/footer/page breaks, photo/crop and preview/export agreement. + +Fail criterion: Missing glyph/content, overflow/cutoff, duplicate blocks, wrong pagination/font/photo or illegible printed output. + +Evidence to retain: Original PDF bytes+SHA256, page count, renderer/font/browser versions, screenshots/print observations and named template. Existing60-page automated oracle is separate. + +## M09-10 — Real provider consent, delivery and uncertain outcomes (P1) + +Owner: Approved provider tester. Status: **NOT TESTED**. + +Environment: Explicitly authorized nonproduction OAuth/Turnstile/mail/calendar sandbox accounts, controlled recipient inboxes and timezone/DST scenarios. No production credentials or real personal documents. + +Steps: Test Google/Microsoft consent and denied/cancelled popup; validate expected origin/state. Verify/reset email to sandbox inbox including used/expired token. Link mailbox, revoke grant and reconnect. Simulate uncertain send only with approved sandbox fixture, then review rather than automatically resend. Create calendar events around DST transitions, explicit offsets and date-only boundaries. + +Pass criterion: Correct owner/origin/state, explicit confirmation, recoverable revoke/reconnect, actual intended mail delivery, no accidental resend and correct timezone/date semantics. + +Fail criterion: Cross-owner/mismatched state accepted, resend without deliberate review, failed intended delivery or wrong event time/date. + +Evidence to retain: Correlated sanitized provider request/response/delivery/event timestamps, exact account scope and timezone expectation. Local SMTP/HTTP tests do not close provider semantics. + +## Recording and closure + +For each state, retain a row: `card ID | tester | UTC | commit/build hashes | environment | OS/browser/AT/device | synthetic IDs | steps actually executed | expected | observed | PASS/FAIL/NOT TESTED | evidence path/hash | defect ID/owner/retest`. A failed observation gets a bounded reproducible defect and linked evidence; keep the original failure, then record a new successor after repair. Untested subcases stay explicit; completing one browser/device never closes another. Redact tokens, credentials and unrelated personal information. Store recordings/reader transcript/PDF bytes in approved nonproduction evidence storage and link them from the final ledger. + +A genuine tester reviews every applicable subcase before closing the card; product/accessibility/provider owners accept any documented non-applicable state with a reason. An AI screenshot review, DOM assertion, healthy endpoint or axe0-violation result cannot sign these cards. C11/P5-13 semantics, infrastructure/backup/restore/rollback, monitoring, creation idempotency and enabled-worker recovery have separate gates and are not authorized by this checklist. No Phase10 implementation or release approval follows automatically. diff --git a/docs/redesign/phase-9/p9-requal-01/PERFORMANCE.md b/docs/redesign/phase-9/p9-requal-01/PERFORMANCE.md new file mode 100644 index 0000000..46cffea --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/PERFORMANCE.md @@ -0,0 +1,54 @@ +# P9-REQUAL-01 performance protocol + +Status: **source prepared; real workload not executed by fixture author**. Historical P9-05 and RD21 sustained fixtures remain unchanged. Their short SQLite observations are not evidence for this lane. Actual runner results must be added below after the exclusive run. + +The only new executable source is in `performance/`. It extends `job-tracker-ui/playwright.mariadb.config.ts`, preserving the canonical disposable-schema guard, MariaDB provider/version and `reuseExistingServer: false` on both servers. The additional guard requires port `33308` and a prebuilt production static frontend. No production code, dependencies, SQLite database, mock database or mocked API response is introduced. + +## Runner prerequisites + +- Run alone after other test/build/browser/load lanes stop. Free ports 5302 and 3300; existing listeners cause failure, never reuse. +- The trusted root runner creates and later cleans up one generated `jt_it_<32 lowercase hex>` schema on its pinned `mariadb:12.2.2` disposable Docker instance at `127.0.0.1:33308`. +- Supply `JOBTRACKER_MARIADB_BROWSER_PORT=33308`, `JOBTRACKER_MARIADB_CLIENT=`, and `JOBTRACKER_MARIADB_BROWSER_CONNECTION=Server=127.0.0.1;Port=33308;Database=;User ID=root;Password=jt-integration-only;SslMode=None`. +- Supply `PLAYWRIGHT_STATIC_EXPORT=true` and `PLAYWRIGHT_PREBUILT_EXPORT=true`. Build Release backend and frontend from the frozen source before this lane. Preserve source/build/report hashes and timestamps in the root evidence ledger. This fixture does not establish source freshness itself. +- Execute from `job-tracker-ui` so the inherited server commands and `.artifacts` paths resolve correctly. Do not enable server reuse or rerun failed tests silently. The config sets retries to zero even in CI. + +Run after setting the above environment in the runner (all shell invocations use RTK): + +```powershell +rtk node node_modules/@playwright/test/cli.js test --config=../docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts +``` + +Fresh output is at repository-root `.artifacts/p9-requal-01/performance/`: `playwright-results.json` plus `test-results/`, including a JSON attachment named `p9-requal-01-mariadb-performance`. Preserve failure attachments as well as successful ones. + +## Measured workload and invariants + +Setup uses the current API contract: create one free synthetic owner, one owned company, exactly 250 applications (record every returned ID), eight Career Profile roles with six long multilingual bullets each using the current expected revision, and one minimal CV variant. Free membership avoids the existing Premium creation-time model summarizer; this is a database/UI workload. Setup ends before the measured clock starts. SQL independently verifies MariaDB `12.2.2` and reads committed state in read-only transactions through the supplied native client. + +Before starting that clock, fail-fast preflight checks each of the four endpoint response shapes/content once and performs one readiness-checked navigation to each workspace. Preflight navigation/telemetry is separately labelled and excluded from workload counts and percentiles. The attachment records setup/preflight/workload/preservation/complete phase and `preflightPassed`; a preflight failure does not pretend a 15-minute run occurred. Source checks confirm `CareerProfileService` derives `startDate`/`endDate` from supplied `start`/`end`, and `CvRenderModel` consumes normalized dates with source-date fallback. `JobTable` owns `data-job-row-id`; Dashboard renders the English `Tracked jobs: 250` accessible link without a paid-role condition when its default summary widget has jobs. + +The measured interval is an actual monotonic-clock **900000 ms minimum**, enforced in source with no duration override. The test timeout is 18 minutes, including setup and final checks. Exactly two independent API reader contexts run until the deadline. Each sequential reader rotates stats, board, Career Profile and documents, waits at least 500 ms after completion before its next request, has a 10-second per-request timeout, and never catches up with bursts. Native browser requests are additional UI traffic and are not counted as synthetic reader operations. Response bodies are disposed after measurement to avoid accumulating load-generator storage. + +Twenty browser navigations are scheduled every 45 seconds across the interval (five rounds of Dashboard, Table, Board and long CV). Dashboard must show 250 jobs, Table must render a row, and Board must contain the exact seeded ID set. CV assertions retain the historical page-readiness and final-marker-on-last-page checks. Errors are recorded once and the timed interval continues; all failures fail the final gate. Playwright locator polling is ordinary readiness checking, not a workload retry. + +Before and after the interval, independent SQL snapshots must match exactly: 250 unique application IDs, owned/deleted counts, every tenant's application count, canonical profile JSON and revision, Identity projection JSON and Career Profile history count. API board membership and full saved-profile equality are checked again afterward; board and profile reader responses also assert exact content throughout. The fixture leaves synthetic data for the trusted disposable-schema cleanup; it never deletes or changes other tenants. + +The attachment retains every reader attempt (worker/endpoint/start offset/duration/status/bytes/error), all navigation outcomes, p50/p95/p99/max successful response latency with explicit attempt/failure counts overall and per endpoint, and failures separately for navigation. Percentiles use the nearest-rank rule. Descriptive telemetry includes Chromium CDP metrics and DOM count, host free memory/load average, and Node process memory/CPU counters sampled on successful navigations. Windows load-average zeros are platform limitations; Node is the load generator, and no server CPU attribution is implied. Optional root-runner Docker/process telemetry may accompany the attachment but must identify its source and sampling interval. + +Acceptance requires zero reader/navigation failures, all 20 navigations, both readers active into the final 15 seconds, pacing checks, minimum duration, exact before/after preservation and a passing process exit. Request counts vary with response duration; there is no invented fixed-count target, SLA threshold or capacity claim. This provides bounded local synthetic MariaDB evidence only. + +## Harness validation + +The fixture author ran the following without launching services, browsers, builds or the long workload; both exited 0: + +```powershell +# From repository root +rtk node docs/redesign/phase-9/p9-requal-01/performance/metrics.mjs --self-test +# From job-tracker-ui +rtk node node_modules/typescript/bin/tsc --noEmit --skipLibCheck --strict --allowJs --esModuleInterop --target es2023 --module esnext --moduleResolution bundler ../docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts ../docs/redesign/phase-9/p9-requal-01/performance/sustained.spec.ts +``` + +The dependency-free self-check exercises empty percentiles, exact percentile boundaries, exclusion/counting of HTTP and transport failures, reversed membership, missing/duplicate/substituted IDs, and the fixed duration/pace constants. Strict TypeScript validates the fixture and inherited configs; this is harness validation, not workload evidence. + +## Actual results + +Pending root runner execution and evidence reconciliation. No measured duration, latency, throughput, preservation or capacity outcome is claimed yet. diff --git a/docs/redesign/phase-9/p9-requal-01/PRESERVATION.md b/docs/redesign/phase-9/p9-requal-01/PRESERVATION.md new file mode 100644 index 0000000..0865943 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/PRESERVATION.md @@ -0,0 +1,109 @@ +# P9-REQUAL-01 preservation and route register + +All **57 groups / 33 routes** are retained. The historical qualification states remain **56 PARTIAL / PRES-C11 DEFERRED, zero promoted to PASS**. These are capability qualifications, not 57 confirmed defects or automatic blanket failures. Each row retains its individual residual and owner in [preservation.json](preservation.json). This source review does not rerun a browser or certify a human workflow; fresh results belong to the root-owned validation ledger. + +Source criteria: [original functionality matrix](../../phase-2/PRESERVATION_MATRIX.md), [later Phase7 residuals](../../phase-7/PRESERVATION.md), [Phase9 matrix](../PRESERVATION.md), [RD21 reconciliation](../rd21-remediation/PRESERVATION.md). The newer [MariaDB acceptance](../../../database/mariadb-standardisation/ACCEPTANCE.md) closes bounded RD21 save/concurrency provider proof; it does not close creation idempotency, every independent editor, production rollback or human acceptance. P2-D01 and existing CV variant/frozen contracts stay passing in their tested scope; canonical replacement risk is separately mapped. + +For Phase9, examine each exact residual and classify its effect. REQUEST §6 carries unfinished genuine human checks into release gates. For Phase10, [IMPLEMENTATION_PLAN §Phase10](../../IMPLEMENTATION_PLAN.md#phase-10--cleanup) separately requires unused-route proof, passing tests and a satisfied functionality inventory. None of these statuses authorizes deletion or starts Phase10. Production retains applicable human/provider/output/operator gates. Partial capability coverage is not silently converted to complete acceptance. + +| Group | Owner | Retained status | Exact remaining closure / dependency | +|---|---|---|---| +| PRES-E01 | LandingPage, planCatalog; AccountPlans | PARTIAL | Public-page complete mobile/keyboard review and actual billing availability; no invented prices Dependencies: applicable human rows M09-01–09. | +| PRES-E02 | LoginPage, TurnstileWidget, VerifyEmailPage; AuthController | PARTIAL | Real mail/reset submit/Turnstile and token expiry/used-token cases; query loss is repaired for its tested scope Dependencies: intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-E03 | GoogleAuthCard, MicrosoftAuthCard, MicrosoftLegacyRelinkPage; token validators | PARTIAL | Actual consent/popups/revoked grants/relink; mailbox grants remain separate from sign-in Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-E04 | TwoFactorSettingsCard, TwoFactorChallenge; TwoFactorController | PARTIAL | Real authenticator/recovery and reader/trusted-device traversal; sensitive confirmations retained Dependencies: applicable human rows M09-01–09. | +| PRES-E05 | SessionsSettingsCard, AppShell, auth; SessionsController | PARTIAL | Native session-card refresh after remote revocation and complete device/AT acceptance Dependencies: applicable human rows M09-01–09. | +| PRES-E06 | ProfilePage; AuthController, AvatarStorage | PARTIAL | Complete avatar/remove/password/email-change native flow; account identity remains distinct from career facts Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-E07 | AppShell, QuickCommandDialog; job/company search APIs | PARTIAL | Spoken names/live state, settled drawer AX-name triage and historical command/dialog timing; no route silently hidden Dependencies: applicable human rows M09-01–09. | +| PRES-E08 | themePrefs, I18nProvider, confirm, prompt; auth preference | PARTIAL | Full OS/locale/state cross-product, contrast/incomplete axe, reader/reflow; save feedback is distinct from server500 root-cause repair Dependencies: applicable human rows M09-01–09. | +| PRES-E09 | App, api, sessionBoundary; SessionContextMiddleware | PARTIAL | Broader BFCache/offline/old-bundle/deployed cases; presentation never becomes authorization Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-J01 | JobDiscoveryPage; JobDiscoveryController | PARTIAL | Live NAV availability/freshness and long-result keyboard/narrow traversal Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-J02 | JobDiscoveryPage; saved-search/alert services | PARTIAL | Actual scheduler-to-owned-notification delivery, human/mobile delete acceptance and intended-provider qualification; deterministic runner is not live NAV Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-J03 | AddJobModal; JobImportService, JobApplicationsController | PARTIAL | Duplicate/company/date/interrupted creation and distinct creation-intent idempotency debt; preview/open is no-write Dependencies: applicable human rows M09-01–09. | +| PRES-J04 | App, captureUrl, QuickCaptureCard; job/CV APIs | PARTIAL | Installed extension/share/no-replay and attachment failure recovery; keep payload and safe-return contracts Dependencies: applicable human rows M09-01–09. | +| PRES-J05 | JobTable, SavedViewsMenu; JobApplicationsController | PARTIAL | Full saved-view CRUD/dirty page-size/history combinations and supported capacity; server query semantics unchanged Dependencies: applicable human rows M09-01–09; separate AI/model qualification; no activation. | +| PRES-J06 | JobTable, EditJobDialog; job lifecycle/controller | PARTIAL | Complete selected-scope/partial-failure/dirty/manual combinations; no hard-delete substitution Dependencies: applicable human rows M09-01–09. | +| PRES-J07 | KanbanBoard, pipeline; status endpoint | PARTIAL | Physical drag/touch/browser variants and O(N) full-array capacity; no capped hidden results or pipeline redefinition Dependencies: applicable human rows M09-01–09. | +| PRES-J08 | CompaniesTable; company relationship APIs | PARTIAL | Scoped in-modal failure proof follows P6 manifest; complete contact/date/source-link and human acceptance remain Dependencies: applicable human rows M09-01–09. | +| PRES-J09 | OfferComparisonPage; job API | PARTIAL | Many-offer mobile/currency/date acceptance; no invented salary normalization Dependencies: applicable human rows M09-01–09. | +| PRES-J10 | ImportExportJobs; CSV/job controller | PARTIAL | Complete native roundtrip and target spreadsheet compatibility; job import is not account restore Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-W01 | ApplicationWorkspacePage, jobWorkspaceRoute; workspace API | PARTIAL | `followMode` metadata retained; compose consumer deferred. P5-05 optional preview lacks production host; full page remains Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-W02 | WorkspaceHeader, JobDetailsSection, ApplicationProgress/Timeline; workflow APIs | PARTIAL | Stored-event localisation/timezones/status-reload combinations ; job stale-replacement contract repaired within qualified MariaDB 12.2.2 scope Dependencies: applicable human rows M09-01–09. | +| PRES-W03 | ApplicationAnalysis/Match/StrategySnapshot/StatusSuggestion; intelligence/AI services | PARTIAL | Real-model truthfulness/freshness/cancel quality; route entry never auto-generates; unrelated AI survives C11 withholding Dependencies: applicable human rows M09-01–09; separate AI/model qualification; no activation. | +| PRES-W04 | ApplicationChecklist; checklist service/controller | PARTIAL | Mobile interruption/edit/delete/reader; item identity and keyboard alternatives retained; no invented due-date schema Dependencies: applicable human rows M09-01–09. | +| PRES-W05 | ApplicationCvSection/TailoringSection; ApplicationAssetsService | PARTIAL | **P2-D01 remains ordinary passing**; broader attach-render/model/deployed combinations remain; owner/job association unchanged Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification; separate AI/model qualification; no activation. | +| PRES-W06 | ApplicationCoverLetterSection, CoverLetterAiAssistant; assets/history | PARTIAL | Complete native history/reject/reader/model combinations; no canonical mutation or auto-send Dependencies: applicable human rows M09-01–09; separate AI/model qualification; no activation. | +| PRES-W07 | ApplicationPackageDraftsSection, SubmittedPackagesSection; package service/storage | PARTIAL | Actual production restore/rollback/all-storage combinations; current edits/delete cannot mutate frozen bytes; capture is not delivery Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25; independent output/storage/deployment qualification. | +| PRES-W08 | Attachments; AttachmentsController, AttachmentStorage | PARTIAL | Physical drop, full rename/download/reader and deployed storage; AI inclusion remains explicit Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-W09 | InterviewPrep; interview persistence/AI endpoints | PARTIAL | Real-model and physical software-keyboard/reload/reader; preparation is not a scheduled interview Dependencies: applicable human rows M09-01–09; separate AI/model qualification; no activation. | +| PRES-W10 | InterviewPrep; follow-up draft services | PARTIAL | Timezones/provider delivery; `followMode` reviewed compose UI remains deferred, no automatic send Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-W11 | RemindersView, RulesSettingsCard, ApplicationCalendarActions; calendar/rules APIs | PARTIAL | F21 DST/date-only/offsets, real provider events/scheduler delivery and historical unconfirmed Rules500 cause Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-W12 | OperationsPage, CareerProfilePage; operation store/worker | PARTIAL | Disconnect/reconnect and F20 enabled-worker fault recovery; stable operation IDs/no duplicate starts Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-C01 | CareerProfilePage, career views; CareerProfileService/controller | PARTIAL | Full long-tail mobile/human acceptance; canonical concurrency has bounded SQLite/MariaDB repair proof; singleton source distinct from identified variants Dependencies: applicable human rows M09-01–09. | +| PRES-C02 | CareerWorkspacePage, CareerProfilePage; version service | PARTIAL | Complete native historical restore/clipboard/avatar/reader; live inherited CVs may reflect later source changes Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-C03 | CareerProfilePage; profile-CV/processing/diff services | PARTIAL | Scanned/OCR corpus and complete low-confidence/discard/native-reader flow; extracted proposal is not canonical truth Dependencies: applicable human rows M09-01–09. | +| PRES-C04 | CareerEvidenceBank; CareerEvidenceController | PARTIAL | Many-item/delete/keyboard/human acceptance; SQLite compatibility repaired with owner SQL preserved, full frontend/production acceptance remains qualified Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-C05 | CvBuilderPage, thumbnails; CvVariantService/PublicCvController | PARTIAL | Library migration not complete; publish/unpublish/old-slug revocation and every template combination required Dependencies: applicable human rows M09-01–09. | +| PRES-C06 | CvBuilderEditor, CvPreviewPane; preview API | PARTIAL | Physical keyboard/touch/AT and broader short-height/wrapped/deployed cases; one editor/save/preview owner Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-C07 | CvBuilderEditor, CV controls/useDragReorder; resolver/settings | PARTIAL | Physical selection/drop/all-browser and exhaustive reset/inheritance combinations; sibling/canonical/frozen separation retained Dependencies: applicable human rows M09-01–09. | +| PRES-C08 | CvCustomizeTab, registry; ThemedCvRenderer | PARTIAL | Production fonts/portraits/wrapped lines/custom color/reader; schematic gallery is not final-photo qualification Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-C09 | cvBuilder, CvCustomizeTab; settings normalization/render model | PARTIAL | Advanced cross-product/manual print/deployed fonts; UI locale distinct from document locale; no print geometry styling change Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-C10 | CvBuilderEditor; CvVariantService version history | PARTIAL | Long offline/history and IF-CV-UNSAVED-01 trace; settings history is not immutable historical profile/PDF; profile/job saves remain separate Dependencies: applicable human rows M09-01–09. | +| PRES-C11 | AiSectionAssistant, DocumentAiTab; CV AI assist | DEFERRED | **0/366 configured-target calls;0 human semantic reviews;review UI absent.** Production503 `cv_ai_unavailable`/no provider/no write remains; safe withholding is not generation acceptance Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25; independent output/storage/deployment qualification; separate AI/model qualification; no activation. | +| PRES-C12 | PublicCvPage, cvBuilder; HtmlPdfGenerator/shared admission | PARTIAL | Deployed Linux/font/photo/browser/manual-print qualification and complete revoke/busy-recovery cases; white print pages retained Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification. | +| PRES-M01 | Correspondence; CorrespondenceController | PARTIAL | Full edit/delete/paste/reader native combinations; logging is not sending Dependencies: applicable human rows M09-01–09. | +| PRES-M02 | Correspondence; GmailController/provider | PARTIAL | Actual provider threads/multi-account revoke/reconnect/sync failures; cross-job changes owner-bound Dependencies: intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-M03 | CorrespondenceInboxPage; EmailController | PARTIAL | Large mailbox/native attachments/complete reader acceptance; global inbox remains Phase7 migration Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-M04 | CorrespondenceInboxPage; EmailDrafts/Send/attempt store | PARTIAL | Sandbox delivery/reconnect/dirty interruption; no automatic uncertain resend; reviewed `followMode` UI deferred Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-M05 | GmailReviewPage, CorrespondenceInboxPage; Gmail review | PARTIAL | Real provider and complete proposed-job create flow; route opening is no-write Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-M06 | EmailProviderConnections; Google/Graph/IMAP controllers | PARTIAL | Real grants/revoke/token expiry/reconnect/IMAP safety; keep sign-in identity separate Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-S01 | DashboardView; analytics/controllers | PARTIAL | Exact cohort/timezone/sample/unsupported metrics and whole reader acceptance; no fabricated statistics or Analytics rebuild Dependencies: applicable human rows M09-01–09. | +| PRES-S02 | DashboardView, OnboardingChecklist, NotificationsPopover; notification APIs | PARTIAL | Historical500 causes unproved; full human/notification acceptance; order/resize/reset/cross-device design remains Phase8 Dependencies: applicable human rows M09-01–09. | +| PRES-S03 | SettingsView, RulesSettingsCard, theme/i18n; rules/notification/auth | PARTIAL | Language failure visibility is separate from RD11 server cause; RD12 notification locking/RD13 Rules500 and human/provider acceptance retained Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-S04 | AiPrivacySettingsCard, AiUsageCard, AccountPlanProvider; billing/entitlement | PARTIAL | Checkout/webhook/portal and provider delivery; temporary C11 withholding cannot disable unrelated AI or imply successful review Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25; separate AI/model qualification; no activation. | +| PRES-S05 | BackupCard; export/backup/deletion services | PARTIAL | Current complete backup/restore/keys/tombstones/rollback and deletion/provider policy; downloading backup is not restore proof Dependencies: intended provider/operator sandbox evidence M09-10/RD22–25; independent output/storage/deployment qualification. | +| PRES-A01 | AdminUsersPage; UsersController | PARTIAL | Mounted-role revoke/full persisted mutations/reset delivery; hiding navigation never authorizes API calls Dependencies: applicable human rows M09-01–09; intended provider/operator sandbox evidence M09-10/RD22–25. | +| PRES-A02 | AdminAuditPage; AdminAuditController | PARTIAL | Native successful persisted undo/restore and unsupported-action denial; no generic undo semantics Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification; separate AI/model qualification; no activation. | +| PRES-A03 | AdminSystemPage; AdminSystemController/maintenance/benchmark | PARTIAL | Actual guarded diagnostic/SMTP/model/maintenance and sensitive-output qualification; no production jobs launched Dependencies: applicable human rows M09-01–09; independent output/storage/deployment qualification; separate AI/model qualification; no activation. | + +## All 33 routes + +Source: [App.tsx](../../../../job-tracker-ui/src/App.tsx) lines420–524. Public `/` and authenticated `/` share one unique path. Wildcard fallback/shell routes are structural and do not inflate the 33-path inventory. Legacy aliases remain consumers, not deletion candidates. Historical route captures and ordinary test mappings remain in [inventory](../p9-00/INVENTORY.md), [QA matrix](../QA_MATRIX.md) and [visual report](../p9-02/README.md); presence and finite captures do not prove every human/device/provider state. + +| Route | Source owner | Current disposition / closure | +|---|---|---| +| `/` | Navigate, LandingPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/dashboard` | DashboardView | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/analytics` | AnalyticsPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/discover` | JobDiscoveryPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/jobs` | JobTable | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/jobs/:id` | ApplicationWorkspacePage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/reminders` | RemindersView | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/operations` | OperationsPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/kanban` | LegacyBoardRedirect | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/companies` | CompaniesTable | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/offers` | OfferComparisonPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/correspondence` | CorrespondenceInboxPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/correspondence/review` | LegacyCorrespondenceReviewRedirect | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/profile` | ProfilePage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/applications/:id` | LegacyApplicationRedirect | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/career` | CareerWorkspacePage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/career/builder` | CvBuilderPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/career/builder/:id` | CvBuilderEditor | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/documents` | DocumentsPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/admin/audit` | AdminAuditPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/admin/users` | AdminUsersPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/admin/system` | AdminSystemPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/trash` | JobTable | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/settings` | SettingsView | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/settings/connected-accounts` | ConnectedAccountsPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/login` | LoginPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/register` | LoginPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/forgot-password` | ForgotPasswordPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/reset-password` | ResetPasswordPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/verify-email` | VerifyEmailPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/confirm-email-change` | VerifyEmailPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/microsoft-legacy-relink` | MicrosoftLegacyRelinkPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | +| `/cv/:slug` | PublicCvPage | Present in current source census; retain route/identity/query/hash/section semantics. Fresh connected workflow result pending root ledger; applicable manual/provider criteria remain. | + +No cleanup candidate has been proven unused by this census. Any future candidate needs its own import/caller/route/alias census, affected preservation criteria, rollback path and passing regression. Historical evidence is preserved unchanged. diff --git a/docs/redesign/phase-9/p9-requal-01/PYTHON_SECURITY.md b/docs/redesign/phase-9/p9-requal-01/PYTHON_SECURITY.md new file mode 100644 index 0000000..ede0d40 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/PYTHON_SECURITY.md @@ -0,0 +1,55 @@ +# Python locked advisory gate: OPEN + +The Python sidecar dependency gate remains **OPEN**, with **INCOMPLETE** advisory coverage. NuGet/npm remediation is a separate result and cannot close this gate. No Python dependency, lockfile, model, parser or runtime was changed during this review. + +The 2026-10-24 07:27:05-07:27:13 UTC review queried all **49 exact pins** in `tools/summarizer/requirements-linux.lock` through the public OSV version query and PyPI release-specific JSON APIs: **98 queries, 97 successes, one error**. PyPI returns 404 for the vendor CPU version `torch==2.6.0+cpu`; its exact OSV query succeeds. No substitute `torch==2.6.0` query or dependency resolution was used. + +The responses contain **249 provider records** (137 OSV, 112 PyPI), combined by published alias equivalence into **109 advisory groups across eight packages**. These are separate counts; the groups are not a claim of 109 independent CVEs. No returned group has withdrawn metadata in this snapshot. + +| Exact affected query pin | Published alias groups | +| --- | ---: | +| certifi 2026.7.22 | 1 | +| filelock 3.32.4 | 3 | +| pillow 12.3.0 | 41 | +| pypdf 6.16.2 | 19 | +| setuptools 84.0.0 | 1 | +| torch 2.6.0+cpu | 19 | +| transformers 4.48.3 | 22 | +| urllib3 2.7.0 | 3 | + +[python-advisories.json](python-advisories.json) retains exact membership, every group ID/alias, package/version, published primary record links, fixed-version events and provider `database_specific.severity` labels. No severity score was invented. Fixed events can differ by branch and are not a compatible upgrade selection. Raw byte responses, query scopes, timestamps, response hashes, parser self-check and membership/accounting checks remain in `.artifacts/p9-requal-01/security/python-locked/`. + +- Lock SHA-256: `36f2912965d183e59f2d8320f3817ca8dd0fee6d76e05cfd63ac92defe6c6031`. +- Raw 202-file evidence manifest SHA-256: `3dac31a50d803e4c4a27c43e683dcf7ee7f2587a122cfb8c38fc5276fb7233ec`. +- Raw aggregate response summary SHA-256: `31fe495d72a9b11564c8e78943be7901610e023a8606b5aeb53710871092ca20`. + +API semantics: [OSV version query/pagination](https://google.github.io/osv.dev/post-v1-query/) and [PyPI release-specific vulnerabilities](https://docs.pypi.org/api/json/#get-a-release). This is public advisory metadata, not exploit testing or a deployed package inventory. + +## Observed sidecar call sites + +Static source inspection was made at checkout HEAD `780b9bc64f0923237c5a03f89d240bbe331f058e`; the hashes below identify the actual files read. It establishes application call sites and existing bounds only. It does not determine whether each advisory is reachable, reproduce an exploit or establish production exposure. + +| Surface | Verified source evidence | Qualification | +| --- | --- | --- | +| Uploaded document entry | `tools/summarizer/app.py:1317-1336`: `/extract-text` accepts uploaded bytes, checks empty/5 MiB input, extension allowlist and signature, then calls `_run_parser_child`. File/pixel defaults are at `app.py:99-110`. | PDF and image parsers have a route from uploaded documents. No malicious upload or live request was made. | +| PyPDF | `tools/summarizer/parser_child.py:158-178`: constructs `PdfReader(io.BytesIO(data))`, obtains pages, enforces 40-page default and calls `page.extract_text(extraction_mode="layout")` with compatibility fallback. | Reader construction/page enumeration occurs before the explicit page-count check. This call site does not map or dismiss individual advisory conditions. | +| Pillow image path | `tools/summarizer/parser_child.py:150-155`: `Image.open` on uploaded image bytes, image-size check, then OCR; `_ocr_image` can call `image.convert("RGB")` at lines 142-147. Allowed image extensions are PNG/JPEG/WebP at line 26. | Opening occurs before application size validation. An allowlist/size check is not evidence that Pillow advisories are eliminated. | +| PDF OCR fallback | `tools/summarizer/parser_child.py:178-202`: short extracted text falls back to `fitz.open`, rasterizes pages, checks per-page/total pixel budgets, then opens PNG bytes through Pillow for OCR. | Pillow is also used on renderer-produced PNGs. Rasterization occurs before the explicit pixel-budget check. No claim is made about a specific advisory's applicability. | +| Child execution bounds | `tools/summarizer/app.py:1196-1208,1260-1314`: allowlisted child environment, one parser capacity slot, separate temporary directory/process group, default 25-second timeout and result-size checks; timeout termination is at lines 1232-1251 and 1292-1299. `parser_child.py:35-44,237-239` applies POSIX CPU/address-space/file/descriptor/core limits before extraction. | These are existing application controls. POSIX limits return without application on non-POSIX systems. A child process/resource bound is not proof of a security sandbox or closure of parser advisories. | +| Transformers/model loading | `tools/summarizer/app.py:4,19,96,161-169`: imports Transformers and torch; fixed repository name `sshleifer/distilbart-cnn-12-6`; `AutoTokenizer.from_pretrained(MODEL_NAME)` and `AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME)`. | Calls have no explicit revision, `trust_remote_code`, `weights_only` or `use_safetensors` argument in this source. No runtime serialization format, downloaded revision, dependency default or model safety property was verified. | +| Local inference | `tools/summarizer/app.py:172-195,512-518`: lazy/eager runtime loading, tokenizer invocation and `model.generate`; disabled-load path is explicit at lines 174-176. | No model was loaded or executed for this review. Test-time load disabling does not adjudicate the deployed inference path. | +| Direct deserialization search | A search of sidecar Python sources for `torch.load`, `weights_only`, `trust_remote_code`, `use_safetensors` and `revision=` found no explicit call/argument. | Absence in application source does not establish absence in Transformers/torch internals. Those third-party runtime paths were not traced. | +| Service access | `tools/summarizer/app.py:38-42,59-68`: optional service token middleware rejects mismatched/missing headers when the token is configured; health is exempt. | Runtime token/network configuration was not inspected. Conditional authentication is not an advisory mitigation verdict. | +| Installation boundary | `tools/summarizer/Dockerfile:14-16`: copies the Linux lock, upgrades bootstrap `pip setuptools wheel`, then installs with `--require-hashes` and the PyTorch CPU extra index. Runtime switches to user `app` at lines 18-22. | Explains the `+cpu` pin's external index. This lock-only advisory audit excludes bootstrap version drift, base image, native OS/OCR libraries and actual built/deployed identities. | + +Inspected source SHA-256 values: + +| File | SHA-256 | +| --- | --- | +| `tools/summarizer/app.py` | `a721a7633f7ed93b7353f2135536a168e096494629506634c96b456b7ae713c2` | +| `tools/summarizer/parser_child.py` | `0074a05e9a0d511e26a329a057f98568cdc1723b2cc37168e0b59975b5424451` | +| `tools/summarizer/Dockerfile` | `d0b8777e81a74ed7099fe1d93f608b6601da39efc43b50ec0b3b058613207443` | + +## Required next decision + +The owner must decide a separately scoped Python/ML/parser dependency remediation with compatible lock generation, model-loading/inference validation and representative benign document parsing/regression checks, or explicitly retain the open gate. A major ML/parser upgrade is not safe to perform automatically inside this requalification checkpoint. Existing controls and passing mocked/unit tests do not clear these advisory records; there is no current Python security PASS. diff --git a/docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md b/docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md new file mode 100644 index 0000000..cbc2703 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md @@ -0,0 +1,20 @@ +# RD21 closure map and remaining limits + +This map evaluates the unchanged [six original closure clauses](../p9-04/RD21_CONCURRENCY_ISSUE.md#required-closure-evidence), rather than inventing a broader fix. Historical baseline: `549b2cba5a791862ba3f854312ea819a86dc42a0`. Source/test inspection only in this register; fresh execution must be bound to the root-owned result ledger before final acceptance. + +The [SQLite remediation addendum](../rd21-remediation/ACCEPTANCE_ADDENDUM_2026-10-23.md) recorded a repaired implementation but withheld RD21 because MariaDB had not run. The later [MariaDB acceptance](../../../database/mariadb-standardisation/ACCEPTANCE.md) explicitly resolves the bounded MariaDB12.2.2 save/concurrency scope using32 real-provider cases and1 native browser journey. [Historical raw case index](../../../database/mariadb-standardisation/validation.json) retains actual reports/failures. These are historical results, not fresh P9-REQUAL-01 passes. Neither old report is edited. + +| Original required closure clause | Existing concrete cases and source | Evidence boundary / remaining limit | +|---|---|---| +| Independent concurrent clients editing different and same fields cannot silently overwrite an acknowledged save | [MariaDB Career tests](../../../../JobTrackerApi.MariaDb.Tests/Rd21CareerPersistenceTests.cs): `Independent_stale_snapshot_cannot_replace_acknowledged_career_edit`; [job tests](../../../../JobTrackerApi.MariaDb.Tests/Rd21JobPersistenceTests.cs): `Stale_or_unversioned_snapshot_cannot_erase_an_acknowledged_job_edit`, `Related_text_save_cannot_silently_replace_a_newer_acknowledged_draft`, `Structured_tailored_cv_snapshot_cannot_replace_a_newer_approved_document`, `Write_that_overlaps_a_delayed_save_wins_without_partial_events_or_opportunity_changes`. Parallel SQLite names in JobTrackerApi.Tests. [Native A/B ordering](../rd21-remediation/diagnostics/persistence.spec.ts): original two-session ordering case preserves each winner through immediate independent SQL reads, navigation and a new authenticated session. | Historical qualified same-owner source snapshots and database interleavings; not exhaustive every-field/editor/order testing. Rejection is safe conflict, not silent merge. Native MariaDB journey directly covers Career, while job provider behavior is covered by real-provider controller/persistence cases. | +| Actual owner-and-revision preconditions on database write; simultaneous submissions and first saves | Career `Stale_tracked_entity_is_guarded_at_database_update_and_stale_restore_is_rejected`, `Competing_first_save_sources_have_one_acknowledged_winner`; job delayed-save overlap and `Versioned_job_save_cannot_cross_tenant_job_or_company_ownership`. [Save contract](../rd21-remediation/SAVE_CONTRACT.md) identifies Career Version and job EF token; final database predicate guards the interval after controller validation. | Real provider contexts/connections, not a client-only comparison. Narrow lifecycle/background tracked writers advance job version. This does not make every narrow command ordering a full-editor merge contract. First canonical save is distinct from create-job intent idempotency. | +| SQLite and supported MariaDB runtime, including constraints, held readers/writers and partial failure | [SQLite Career](../../../../JobTrackerApi.Tests/Rd21CareerPersistenceTests.cs) / [SQLite job](../../../../JobTrackerApi.Tests/Rd21JobPersistenceTests.cs). [MariaDB startup/lock](../../../../JobTrackerApi.MariaDb.Tests/StartupAndLockTests.cs): `Full_startup_creates_every_table_and_column_required_by_the_persisted_EF_model`, `Fresh_repeated_and_populated_startup_preserve_owned_data_and_complete_migrations`, `Rd21_additive_migration_preserves_existing_job_fields_and_backfills_revision_one`, `Open_reader_does_not_block_independent_usage_and_identity_writes`. Job `Held_writer_timeout_rolls_back_and_a_reviewed_save_recovers_after_release`; Career `Identity_failure_rolls_back_canonical_children_history_and_projection`, `Database_failure_after_deletion_restores_children_history_and_revision_and_clears_tracker`; job `Failed_job_transaction_cannot_acknowledge_or_leave_partial_data_for_a_later_save`. | Historical actual pinned Linux/amd64 MariaDB12.2.2, InnoDB and independent TCP readbacks. Identity/summarizer doubles in controller tests are disclosed. Version parity does not prove exact production image/configuration parity. Not MariaDB12.3, power-loss durability or production rollback. Hosted prerequisite failure remains separate from local provider proof; fresh hosted lane pending root results. | +| Conflicts preserve drafts and offer explicit current-data review/reload; account switch and stale session fail closed | [MariaDB browser](../../../../job-tracker-ui/mariadb-tests/save-recovery.spec.ts): native Career conflict/network-failure/reviewed-retry case; [remediation browser](../rd21-remediation/diagnostics/persistence.spec.ts): native editor retention/recovery, missing-revision rejection, cross-origin committed header and successive Answers, fresh source after letter save. [Account isolation](../../../../job-tracker-ui/e2e/account-isolation.spec.ts): retained A request with B cookies/CSRF; missing/forged contexts; two-tab account switch and Back navigation. | Controlled aborted request, actual API/SQL reads and session-boundary tests. Not physical device/reader acceptance. Unknown commit outcome requires deliberate read/review, never fetching a new token to authorize an old body. No automatic retry is claimed. | +| Imports, history restores, generic job updates, lifecycle/bulk and old callers follow agreed compatibility contract | Career `Replacement_restore_parse_and_import_fail_closed_without_valid_revision`, `Import_acceptance_requires_the_revision_shown_in_its_diff`, `Reviewed_import_commits_or_rolls_back_canonical_projection_and_application_metadata`, `Parsing_commits_or_rolls_back_its_entire_import_application`; job missing/stale snapshot and related-text/tailored tests above. [SAVE_CONTRACT](../rd21-remediation/SAVE_CONTRACT.md) inventories endpoints/statuses; [related review](../rd21-remediation/RELATED_REVIEW.md) inventories narrow lifecycle/background writers, extension/create consumers and already-guarded Dashboard/CV/email owners. [MariaDB fixture delta](../../../database/mariadb-standardisation/fixture-delta.json) retains old unversioned failure and explicit3 fixture repairs with original assertions. | Source/caller review plus contract tests, not certification of every independent editor or mixed old/new deployment. Career missing precondition400; valid stale409; job missing/invalid/stale409. Old unversioned writers intentionally fail closed. Extension/bookmarklet is a create consumer. No compatibility alias removal. | +| Complete affected regression, frozen bytes and no unrelated Identity replay | Historical addendum reports1109 backend,934 frontend/105 suites,362 ordinary,23 separate,56 sidecar and6 remediation cases, separate conforming volume3; explicit obsolete historical diagnostic failures retained. Later MariaDB acceptance reports1123 backend,32 provider,1 provider-browser, corrected diagnostics18 andvolume3. Frozen contracts and canonical/variant/null-as-inherit ownership remain independently mapped in [preservation](PRESERVATION.md); original PDF oracle16/36 pages plus8/24 pages unchanged. Career transaction/Identity failure and read-only coherent snapshot tests cover projection boundary; identity-only endpoint keeps ownership. | These are separate historical lanes, not added totals or fresh full regression. Root must obtain complete fresh successors and frozen-byte/PDF proof on final source. Do not treat database conflict pass as frozen-byte proof, print acceptance or release acceptance. | + +Creation-intent idempotency is explicitly a **separate retained RD21 concern**, not one of the stale-replacement repairs. No new duplicate-create reproduction or idempotency implementation is claimed. Record owner/domain follow-up with interrupted-create/replay semantics and a separate acceptance contract before changing it. Canonical first-save uniqueness is not create-intent idempotency. + +Historical acknowledged edits lost before repair are not proven recoverable; no live records were inspected. Extraction discard/accept lifecycle concurrency was considered but not reproduced. Independent settings/company/contact records were source-reviewed without a newly reproduced shared RD21 defect; full multi-session acceptance of them is not implied. [RELATED_REVIEW](../rd21-remediation/RELATED_REVIEW.md) preserves these boundaries. + +Current recommendation is therefore conditional on the exact decision: retain **bounded save/concurrency closure from historical MariaDB evidence**, require fresh source-bound successors for this requalification, retain separate idempotency and release limits, and let the root acceptance addendum issue the final RD21/Phase9/Phase10/production decisions. Do not reopen repaired stale loss merely because creation debt remains, and do not close creation debt merely because stale loss is repaired. diff --git a/docs/redesign/phase-9/p9-requal-01/SECURITY.md b/docs/redesign/phase-9/p9-requal-01/SECURITY.md index 8bdde54..39fb6c9 100644 --- a/docs/redesign/phase-9/p9-requal-01/SECURITY.md +++ b/docs/redesign/phase-9/p9-requal-01/SECURITY.md @@ -10,6 +10,16 @@ or proof of application reachability. No production package, service or image wa | P9-REQUAL-SEC01 | MimeKit4.17.0 resolves Pkcs8.0.1; high and moderate denial-of-service advisories | Direct Pkcs8.0.2 security floor, preserving supported8.x API; refresh API and both test-project locks | Live API NuGet graph reports no vulnerable packages | | P9-REQUAL-SEC02 | Next16.3.8 matches critical/high advisories | Pin Next and matching ESLint config16.4.1; matching Next compiler/environment packages change together | Live npm policy passes, zero reported vulnerabilities | | P9-REQUAL-SEC03 | Dev-only ESLint hooks chain resolves Zod4.5.4 | Override4.6.6, within existing compatible4.x range | Live npm policy passes; no exception bypass | +| P9-REQUAL-SEC04 | Sidecar Linux hash lock contains reported advisories across eight packages, including upload parsers and ML dependencies | No broad parser/ML transition attempted; separately validated remediation required | OPEN; exact-pin advisory coverage also INCOMPLETE | + +The additional [Python review](PYTHON_SECURITY.md) queries all49 exact Linux lock pins. Its +[machine-readable evidence](python-advisories.json) records98 queries,97 successful responses and +one PyPI404 for the vendor-local `torch==2.6.0+cpu` release; the exact OSV query succeeds. The249 +provider records group into109 sets of published aliases across eight packages. These are not109 +independent CVEs or reproduced exploits. Published records include critical/high labels. The +untrusted-upload path reaches the PDF/image libraries; existing limits do not close these findings. +Major parser/ML compatibility, model integrity and complete release validation are separate work. +The sidecar source, hash lock and configured model remain unchanged. Overall security is **OPEN**. The current static export does not run the Next server's image optimizer, Server Actions or `use cache`. Existing Sharp0.35.5 also satisfies the published image-optimizer workaround. Those @@ -33,7 +43,7 @@ are retained as superseded evidence rather than added to these totals. Existing offline supply-chain/evaluator/browser-runtime/ingress/SMTP/dependency-policy/extension guards pass. Tracked-secret scanning and SBOM generation pass. Those checks are narrower than an -application security certification. The inherited temporary dev-advisory policy expires on +application security certification or a clean Python advisory gate. The inherited temporary dev-advisory policy expires on 1November2026UTC; it was neither broadened nor extended, and the current npm audit uses no exception. Production still requires independent ingress, deployed identity, storage/recovery, provider, monitoring and human release qualifications. diff --git a/docs/redesign/phase-9/p9-requal-01/ci-findings.json b/docs/redesign/phase-9/p9-requal-01/ci-findings.json index f12ec37..8db1224 100644 --- a/docs/redesign/phase-9/p9-requal-01/ci-findings.json +++ b/docs/redesign/phase-9/p9-requal-01/ci-findings.json @@ -52,16 +52,42 @@ "addedPushBranch": "fix/p9-ci-and-requalification", "originalPushBranchRetained": true, "unconditionalIsolationBlockBeforeDocker": true, + "isolationBlockIsFirstStep": true, "variableBypass": false, "nativeServicesAdded": false, "runnerConfigurationChanged": false, "deploymentWorkflowsChanged": false, "hostedRunStartedByInvestigation": false }, + "freshHostedBlockerVerification": { + "commit": "75cd04cfc2da0837b556bdcf1424846349c4c73d", + "runId": 847, + "jobId": 1737, + "runnerId": 5, + "runnerName": "Live-Runner", + "status": "completed", + "conclusion": "failure", + "blockedMessageUtc": "2026-10-24T06:56:14Z", + "firstStep": "Require verified runner isolation", + "explicitBlockedMessage": true, + "exitCode": 1, + "checkoutExecuted": false, + "sdkSetupExecuted": false, + "repositoryTestsExecuted": false, + "workflowDockerComposeCommandsExecuted": false, + "mariaDbServiceStarted": false, + "integrationArtifactUploaded": false, + "runnerPreparationCaveat": "Runner created its job container with existing host socket/network and prefetched actions before the first step; preflight cannot prevent runner preparation", + "jobContainerAndWorkspaceRemovalLogged": true, + "privateServiceLifecycleProven": false, + "qualification": "Expected fail-closed blocker verified; hosted MariaDB remains BLOCKED" + }, "futureImage": "mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00", "nextAction": "Infrastructure owner supplies dedicated-runner identity, effective private network/socket suppression and complete lifecycle proof; repository owner reviews transport/workflow before enabling execution", "rawEvidenceSha256": { - ".artifacts/mariadb/requal-ci-api.json": "3369a245165a40e20553f633ff7751f14bc8396d0523c379f658adff16f863ac", + ".artifacts/mariadb/requal-ci-api.json": "1ef25fa5433e8151d3ac6c6b368ba0212410cfca8033e2fb9620d5e3c33d8bc0", + ".artifacts/mariadb/requal-ci-api-847.json": "9ed3863cd897c52bcc87d09956464813d16c36e744d465a8cfc41bd6a4327db9", + ".artifacts/mariadb/hosted-ci-847.log": "251b863b10d0ec3d8a94103367ae41d5d259cc7cf6e103870d219b4910545c68", ".artifacts/mariadb/hosted-ci-843.log": "47ba05d12f08eb7a16a5649f71dde18cd582176a2bed818f3e045932ec025891", ".artifacts/mariadb/hosted-ci-844.log": "e03d82a3d24329482b9acd66866bdc500244a85af89932691d09f00d881fdaf9", ".artifacts/mariadb/act-runner-v0.4.1/go.mod": "9863a6049f423c537b02caf6307c8bb6c7dcfe809fb314193b1856274a160824", diff --git a/docs/redesign/phase-9/p9-requal-01/findings.json b/docs/redesign/phase-9/p9-requal-01/findings.json new file mode 100644 index 0000000..4faf6de --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/findings.json @@ -0,0 +1,1613 @@ +{ + "schemaVersion": 1, + "reportDate": "2026-10-24", + "baselineCommit": "549b2cba5a791862ba3f854312ea819a86dc42a0", + "branch": "fix/p9-ci-and-requalification", + "scope": "source-based register; historical evidence distinguished from fresh execution; final decisions owned by root acceptance addendum", + "freshExecution": "PENDING root-owned validation ledger; this register does not run or attest tests", + "gateRules": { + "phase9": "REQUEST §§6,13,18: classify each item independently; unfinished genuine human checks remain release gates. No production-only condition automatically vetoes local functional QA. Remaining mandatory functional criteria require evidence.", + "phase10": "IMPLEMENTATION_PLAN.md:164-170: no route uses removed code + tests pass + functionality inventory satisfied. REQUEST prohibits automatically starting Phase10. No blanket conditional deletion eligibility.", + "production": "REQUEST §16 independent release/operator/provider/manual gates; no operations authorized", + "debt": "accepted optional or low debt remains visible, never relabelled a pass" + }, + "findings": [ + { + "id": "RD01", + "aliases": [ + "F04" + ], + "criterion": "OPEN; local static/loopback ingress contracts only", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 9 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High: wrong client identity or exposed ingress", + "dependency": "Production", + "ownerAndRequiredClosure": "Release operator: actual TLS/IPv6/firewall/topology/trusted peer and deployed auth evidence", + "status": "OPEN; local static/loopback ingress contracts only", + "gates": { + "phase9": "operator release gate", + "phase10": "candidate-specific ingress compatibility proof", + "production": "BLOCKED pending actual ingress identity", + "debt": "open operational qualification" + } + }, + { + "id": "RD02", + "aliases": [], + "criterion": "NOT TESTED: independently verified off-disk complete backup/restore", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 10 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Critical if recovery needed: irreversible loss", + "dependency": "Production", + "ownerAndRequiredClosure": "Release operator: isolated restore of DB/files/CVs/keys/tombstones, hashes and recovery rehearsal", + "status": "NOT TESTED: independently verified off-disk complete backup/restore", + "gates": { + "phase9": "no independent veto of isolated functional QA", + "phase10": "candidate restore dependency", + "production": "BLOCKED backup/restore", + "debt": "open operational qualification" + } + }, + { + "id": "RD03", + "aliases": [ + "F19" + ], + "criterion": "PARTIAL: SQLite and generated MariaDB SQL; MariaDB runtime unavailable", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 11 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + }, + { + "path": "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "kind": "historical superseding bounded provider evidence" + }, + { + "path": "docs/database/mariadb-standardisation/validation.json", + "kind": "historical raw result index" + } + ], + "severityAndImpact": "High: schema/provider/startup disagreement", + "dependency": "Production; provider acceptance", + "ownerAndRequiredClosure": "Database owner: actual approved MariaDB migration, restart, CRUD/constraints/concurrency and effective configuration proof", + "status": "MariaDB 12.2.2 RD21 runtime scope verified historically (32 provider cases, 1 native journey); broader provider/deployment parity still PARTIAL", + "gates": { + "phase9": "bounded provider save qualification historical PASS; full fresh matrix pending", + "phase10": "provider migration proof per candidate", + "production": "BLOCKED exact deployed parity/migrations", + "debt": "partial broad provider qualification" + } + }, + { + "id": "RD04", + "aliases": [], + "criterion": "NOT TESTED: intended Linux rollback", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 12 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High: failed release cannot be reversed", + "dependency": "Production", + "ownerAndRequiredClosure": "Release operator: isolated failure/rollback rehearsal using complete prior images/configuration/recovery set", + "status": "NOT TESTED: intended Linux rollback", + "gates": { + "phase9": "no independent veto of isolated functional QA", + "phase10": "rollback proof per candidate", + "production": "BLOCKED actual rollback", + "debt": "open operational qualification" + } + }, + { + "id": "RD05", + "aliases": [], + "criterion": "OPEN: old runner crashes/deployed identity not superseded", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 13 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + }, + { + "kind": "current root-reported hosted investigation; final evidence pending root CI report", + "detail": "Merged host Docker socket binding found. No privileged socket fallback or production host access authorized; explicit blocked workflow gate retained." + } + ], + "severityAndImpact": "High: healthy endpoint may serve wrong release", + "dependency": "Production", + "ownerAndRequiredClosure": "CI/operator owner: prove isolated private service execution and lifecycle without host socket/privileges/public ports/production coupling, then successful exact hosted TRX and cleanup. Keep workflow BLOCKED while isolation cannot be proven. Separate deployed runner/storage/release identity remains unqualified.", + "status": "Hosted database lane BLOCKED: root investigation found merged runner host Docker socket binding; private service isolation/lifecycle unknown. Local historical MariaDB proof is independent.", + "gates": { + "phase9": "fresh required CI pending root evidence", + "phase10": "testpass criterion pending root evidence", + "production": "BLOCKED deployed identity and operator diagnosis", + "debt": "open CI/release qualification" + } + }, + { + "id": "RD06", + "aliases": [], + "criterion": "PARTIAL: finite axe/DOM/keyboard evidence; human checks open", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 14 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High accessibility impact", + "dependency": "Acceptance qualification; production", + "ownerAndRequiredClosure": "Accessibility tester: [M09-01–06](p9-03/MANUAL_CHECKLIST.md), contextual contrast/reader evidence; triage every applicable incomplete", + "status": "PARTIAL: finite axe/DOM/keyboard evidence; human checks open", + "gates": { + "phase9": "manual carry-forward allowed only as explicit release qualification (REQUEST §6), no human PASS", + "phase10": "affected functionality must remain satisfied; no deletion permission", + "production": "BLOCKED applicable human accessibility", + "debt": "open human qualification" + } + }, + { + "id": "RD07", + "aliases": [], + "criterion": "NOT TESTED: physical input/AT/alternate browsers/forced colors", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 15 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium/High usability exclusion", + "dependency": "Acceptance qualification; production", + "ownerAndRequiredClosure": "Product/accessibility owners: actual supported devices/browser/input versions and complete workflows", + "status": "NOT TESTED: physical input/AT/alternate browsers/forced colors", + "gates": { + "phase9": "manual carry-forward release qualification; no physical/AT PASS", + "phase10": "affected functionality proof still required", + "production": "BLOCKED supported device/browser/input acceptance", + "debt": "open human qualification" + } + }, + { + "id": "RD08", + "aliases": [ + "C11", + "P5-13" + ], + "criterion": "DEFERRED; no new model qualification or activation", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 16 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High: unqualified proposal semantics", + "dependency": "AI activation; production", + "ownerAndRequiredClosure": "Separate AI qualification owner: production-equivalent identity/inference, original 366-call protocol, independent human semantics, review UI/integration evidence", + "status": "DEFERRED; no new model qualification or activation", + "gates": { + "phase9": "C11 explicitly withheld; separate scope", + "phase10": "no activation/deletion eligibility", + "production": "BLOCKED AI activation unless separately qualified", + "debt": "DEFERRED product/model scope" + } + }, + { + "id": "RD09", + "aliases": [], + "criterion": "Local withheld-operation contract retained; deployed withholding NOT TESTED", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 17 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High: unreviewed AI write/external request", + "dependency": "Production / AI", + "ownerAndRequiredClosure": "Release/AI owners: keep 503/no-provider/no-write guards, verify actual deployment independently", + "status": "Local withheld-operation contract retained; deployed withholding NOT TESTED", + "gates": { + "phase9": "local withholding contract needs fresh successor", + "phase10": "retain withholding and callers", + "production": "BLOCKED deployed withholding untested", + "debt": "open deployment qualification" + } + }, + { + "id": "RD10", + "aliases": [], + "criterion": "PARTIAL: native local PDF corpus and visual sheets; deployed fonts/photo/print absent", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 18 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium/High document reliability", + "dependency": "Acceptance qualification; production", + "ownerAndRequiredClosure": "Document owner: intended Linux/fonts/photo/crop/print and alternate-browser proof, original bytes/geometry", + "status": "PARTIAL: native local PDF corpus and visual sheets; deployed fonts/photo/print absent", + "gates": { + "phase9": "finite output qualification; human/Linux/print not passed", + "phase10": "affected rendering must preserve output contracts", + "production": "BLOCKED intended output environment", + "debt": "open output qualification" + } + }, + { + "id": "RD11", + "aliases": [], + "criterion": "Scoped SQLite bootstrap/WAL mechanism repaired before entry; broad reliability remains PARTIAL", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 19 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High if preference save fails", + "dependency": "Reliability qualification", + "ownerAndRequiredClosure": "Database owner: retain held-reader/write proof, distinguish old reproduced mechanism from unproven provider/contention cases", + "status": "Scoped SQLite bootstrap/WAL mechanism repaired before entry; broad reliability remains PARTIAL", + "gates": { + "phase9": "scoped WAL repair retained; broad reliability qualification open", + "phase10": "retain provider/concurrency safeguards", + "production": "provider contention remains qualified", + "debt": "retained broader reliability" + } + }, + { + "id": "RD12", + "aliases": [], + "criterion": "PARTIAL: notification draft/failure recovery and SQLite tests; complete contention/provider behavior unqualified", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 20 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: settings may not persist", + "dependency": "Reliability qualification", + "ownerAndRequiredClosure": "Database/settings owners: intended-provider overlapping writes and failure/reload recovery with no data loss", + "status": "PARTIAL: notification draft/failure recovery and SQLite tests; complete contention/provider behavior unqualified", + "gates": { + "phase9": "no newly established failure; provider overlap remains qualification", + "phase10": "candidate must preserve drafts and recovery", + "production": "intended-provider qualification open", + "debt": "retained reliability" + } + }, + { + "id": "RD13", + "aliases": [], + "criterion": "Historical Rules 500 mechanism remains UNCONFIRMED", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 21 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: failed save/draft retention", + "dependency": "Reliability qualification", + "ownerAndRequiredClosure": "Rules/API owners: original failure trace plus controlled causal reproduction and successor regression; passing retry alone insufficient", + "status": "Historical Rules 500 mechanism remains UNCONFIRMED", + "gates": { + "phase9": "historical causal mechanism UNCONFIRMED; not relabelled resolved", + "phase10": "candidate must preserve Rules recovery", + "production": "no complete reliability claim", + "debt": "unconfirmed historical observation" + } + }, + { + "id": "RD14", + "aliases": [], + "criterion": "Historical command/dialog focus incident remains UNCONFIRMED; settled drawer proof is a separate finite result", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 22 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium/High keyboard access", + "dependency": "Accessibility qualification", + "ownerAndRequiredClosure": "Shared UI owner: preserve original observations, reproduce affected modal transitions and actual reader/trap/return behavior", + "status": "Historical command/dialog focus incident remains UNCONFIRMED; settled drawer proof is a separate finite result", + "gates": { + "phase9": "historical causal mechanism UNCONFIRMED; human focus qualification", + "phase10": "candidate must preserve trap/return/error states", + "production": "applicable human checks open", + "debt": "unconfirmed historical observation" + } + }, + { + "id": "RD15", + "aliases": [], + "criterion": "Historical intermittent CV section expansion cause unproven", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 23 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: editing disrupted", + "dependency": "Reliability qualification", + "ownerAndRequiredClosure": "CV owner: retain failed observation and reproduce causally before closing; do not weaken expansion assertions", + "status": "Historical intermittent CV section expansion cause unproven", + "gates": { + "phase9": "historical cause UNCONFIRMED; no invented current defect", + "phase10": "candidate must preserve expansion state", + "production": "broader reliability qualification", + "debt": "unconfirmed historical observation" + } + }, + { + "id": "RD16", + "aliases": [], + "criterion": "Scoped company-error repair retained; wider reader/dialog/date contract PARTIAL", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 24 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: recovery/access", + "dependency": "Preservation qualification", + "ownerAndRequiredClosure": "Company/UI owners: native failed-save → retained draft → successful retry plus human dialogue checks", + "status": "Scoped company-error repair retained; wider reader/dialog/date contract PARTIAL", + "gates": { + "phase9": "scoped repair historical PASS; broader human contract open", + "phase10": "candidate-specific recovery proof", + "production": "human/provider qualification open", + "debt": "partial preserved contract" + } + }, + { + "id": "RD17", + "aliases": [], + "criterion": "Board remains O(N); 200/1,000-job and new bounded 250-job observations are finite", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 25 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: growing rendering cost", + "dependency": "Performance qualification", + "ownerAndRequiredClosure": "Jobs owner: agreed budget, bounded sustained profile and CPU/frame attribution before optimization; preserve full membership", + "status": "Board remains O(N); 200/1,000-job and new bounded 250-job observations are finite", + "gates": { + "phase9": "finite capacity evidence; fresh sustained lane pending", + "phase10": "measured bottleneck and full membership before optimization", + "production": "no production capacity/SLA claim", + "debt": "O(N) known design limit" + } + }, + { + "id": "RD18", + "aliases": [], + "criterion": "NOT TESTED: physical drag/drop/cancel/browser variants", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 26 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium access/workflow risk", + "dependency": "Human/device qualification", + "ownerAndRequiredClosure": "Input/device tester: real Board/CV selection and named alternatives, no hidden result cap", + "status": "NOT TESTED: physical drag/drop/cancel/browser variants", + "gates": { + "phase9": "manual carry-forward release qualification; physical behavior not passed", + "phase10": "retain accessible reorder alternatives", + "production": "BLOCKED physical input variants", + "debt": "open device qualification" + } + }, + { + "id": "RD19", + "aliases": [], + "criterion": "DEFERRED: reviewed `followMode` consumer", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 27 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium workflow limitation", + "dependency": "Deferred scope; not silently completed", + "ownerAndRequiredClosure": "Product/mail owner: separate explicit mode→review/action/fallback design; no auto-send or uncertain resend", + "status": "DEFERRED: reviewed `followMode` consumer", + "gates": { + "phase9": "accepted deferred reviewed consumer; no activation", + "phase10": "ineligible to remove metadata/paths", + "production": "separate activation gate", + "debt": "DEFERRED product scope" + } + }, + { + "id": "RD20", + "aliases": [], + "criterion": "Optional P5-05 quick preview DEFERRED; Phase 8 Dashboard scope was delivered separately", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 28 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Low optional scope", + "dependency": "Deferred scope", + "ownerAndRequiredClosure": "Product owner: explicit separate brief; retain existing full workspace and all routes", + "status": "Optional P5-05 quick preview DEFERRED; Phase 8 Dashboard scope was delivered separately", + "gates": { + "phase9": "optional preview DEFERRED; full workspace retained", + "phase10": "no deletion of full workspace/aliases", + "production": "no independent veto while optional scope remains deferred", + "debt": "DEFERRED optional scope" + } + }, + { + "id": "RD21", + "aliases": [], + "criterion": "OPEN: canonical Career/generic job revision contract and creation-intent idempotency", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 29 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + }, + { + "path": "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "kind": "historical superseding bounded provider evidence" + }, + { + "path": "docs/database/mariadb-standardisation/validation.json", + "kind": "historical raw result index" + } + ], + "severityAndImpact": "High: stale editor can overwrite acknowledged edits", + "dependency": "Data-integrity acceptance; production", + "ownerAndRequiredClosure": "Domain/API/UI owners: separate bounded contract issue covering both callers, server compare-and-swap/transaction semantics, conflict recovery and backward compatibility; characterization is not safety acceptance", + "status": "RESOLVED within qualified MariaDB 12.2.2 save/concurrency scope; current branch successor qualification pending root ledger; creation-intent idempotency remains separate OPEN debt", + "gates": { + "phase9": "bounded save/concurrency resolved historically; fresh full successor pending; creation idempotency separate", + "phase10": "no compatibility removal without all-caller/rollback proof", + "production": "BLOCKED deployment/rollback parity; no historical recovery claim", + "debt": "creation-intent idempotency OPEN, separate concern" + } + }, + { + "id": "RD22", + "aliases": [ + "F20" + ], + "criterion": "NOT TESTED: enabled-worker outage recovery/durability", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 30 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High: duplicate/lost async work", + "dependency": "Production / enabled producer", + "ownerAndRequiredClosure": "Worker owner: isolated enabled-producer failure/restart/recovery, no-loss/no-duplicate proof before activation", + "status": "NOT TESTED: enabled-worker outage recovery/durability", + "gates": { + "phase9": "isolated fixtures do not accept enabled producer", + "phase10": "retain stable IDs and recovery paths", + "production": "BLOCKED enabled-worker recovery", + "debt": "open operational qualification" + } + }, + { + "id": "RD23", + "aliases": [ + "F21" + ], + "criterion": "OPEN: actual calendar offset/DST/date-only semantics", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 31 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Medium: wrong event time", + "dependency": "Calendar qualification", + "ownerAndRequiredClosure": "Calendar owner: dedicated boundary/DST/provider proof in authorised sandbox before semantic changes", + "status": "OPEN: actual calendar offset/DST/date-only semantics", + "gates": { + "phase9": "actual offset/DST/date-only unqualified", + "phase10": "retain calendar semantics until dedicated proof", + "production": "BLOCKED calendar activation qualification", + "debt": "open provider semantics" + } + }, + { + "id": "RD24", + "aliases": [], + "criterion": "NOT TESTED: billing/deletion/retention/provider cleanup policy and configuration", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 32 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High privacy/lifecycle impact", + "dependency": "Production / lifecycle activation", + "ownerAndRequiredClosure": "Product/security/operator owners: approved policy, explicit destructive-action authority, isolated recovery/cleanup proof", + "status": "NOT TESTED: billing/deletion/retention/provider cleanup policy and configuration", + "gates": { + "phase9": "policy and destructive lifecycle outside functional proof", + "phase10": "no removal without approved lifecycle policy", + "production": "BLOCKED policy/restore/provider cleanup", + "debt": "open policy qualification" + } + }, + { + "id": "RD25", + "aliases": [], + "criterion": "PARTIAL: local SMTP/HTTP/provider contracts; actual OAuth/Turnstile/mail/calendar/model unavailable", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 33 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High identity/privacy/delivery impact", + "dependency": "Provider acceptance; production", + "ownerAndRequiredClosure": "Approved provider/human tester: sandbox consent/revoke/reconnect/origin/state/delivery/uncertain-attempt proof", + "status": "PARTIAL: local SMTP/HTTP/provider contracts; actual OAuth/Turnstile/mail/calendar/model unavailable", + "gates": { + "phase9": "sandbox/provider qualifications remain; fixtures do not pass them", + "phase10": "candidate must preserve auth/delivery contracts", + "production": "BLOCKED applicable real provider evidence", + "debt": "open provider qualification" + } + }, + { + "id": "RD26", + "aliases": [], + "criterion": "Legacy Job/Application cutover OPEN", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 34 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High compatibility/data loss if removed", + "dependency": "Phase 10 deletion eligibility; production", + "ownerAndRequiredClosure": "Migration owner: expand/verify/contract, restore/rollback and all readers/writers/aliases before removal", + "status": "Legacy Job/Application cutover OPEN", + "gates": { + "phase9": "no legacy cutover authorized", + "phase10": "BLOCKED deletion until expand/verify/contract and all readers/writers", + "production": "BLOCKED unqualified cutover", + "debt": "open migration scope" + } + }, + { + "id": "RD27", + "aliases": [], + "criterion": "NOT TESTED: actual monitoring/alert/recovery coverage", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 35 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High operational detection risk", + "dependency": "Production", + "ownerAndRequiredClosure": "Operations owner: effective sink, alert trigger, responder/runbook and recovery observations", + "status": "NOT TESTED: actual monitoring/alert/recovery coverage", + "gates": { + "phase9": "no independent veto of isolated functional QA", + "phase10": "candidate observability proof where affected", + "production": "BLOCKED actual alert/recovery", + "debt": "open operational qualification" + } + }, + { + "id": "RD28", + "aliases": [], + "criterion": "Ongoing evidence/provenance obligation", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 36 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "High if failures are misrepresented", + "dependency": "Every decision", + "ownerAndRequiredClosure": "QA owner: exact source hashes/counts, original failures, no retries/skips/assertion relaxation; separate characterization from safe behavior", + "status": "Ongoing evidence/provenance obligation", + "gates": { + "phase9": "fresh exact evidence and source binding required", + "phase10": "required exact candidate evidence", + "production": "required exact deployment evidence", + "debt": "ongoing obligation" + } + }, + { + "id": "P9-OPS-01", + "aliases": [], + "criterion": "Previously reported EXT4/Docker storage errors UNRECHECKED", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 37 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Critical if disk faults persist", + "dependency": "Production", + "ownerAndRequiredClosure": "Production operator only: independent storage-health/repair and recovery qualification under separate authority", + "status": "Previously reported EXT4/Docker storage errors UNRECHECKED", + "gates": { + "phase9": "not a standalone functional defect; retain stated qualification", + "phase10": "no permission to delete; affected-candidate proof", + "production": "BLOCKED until stated operator closure", + "debt": "retained gate" + } + }, + { + "id": "P9-SEC-01", + "aliases": [], + "criterion": "Live advisories NOT REFRESHED; inherited NuGet Pkcs high/moderate retained. Local dev-only GHSA-vfj7-8cjw-p6xm policy expires at2026-11-01 00:00UTC (after31October), verified in source23October", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 38 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + }, + { + "kind": "current root-reported authorized advisory review; final raw ledger pending", + "detail": "Root-reported live audits: System.Security.Cryptography.Pkcs8.0.1 transitively via MimeKit4.17.0, high/moderate advisories fixed8.0.2 (exact identifiers/raw audit pending final root ledger); Next16.3.8 now has three critical advisories, existing Sharp0.35.5 SVG mitigation covers one only and UI is statically exported; dev-transitive Zod4.5.4 GHSA-mrhx-c7xc-m3w5 fixed4.6.6." + }, + { + "kind": "current requalification observation, not a rewrite of inherited history", + "detail": "P9-REQUAL-SEC01–03 carry new stable IDs, original RED security-before-pins evidence and post-pin zero-findings audit paths; root will bind raw hashes in final validation." + }, + { + "kind": "fresh Python risk observation", + "detail": "P9-REQUAL-SEC04 retains locked Python critical/high provider labels and incomplete query coverage; post-pin NuGet/npm zero audits do not establish blanket security PASS." + } + ], + "severityAndImpact": "High dependency risk until assessed", + "dependency": "Production", + "ownerAndRequiredClosure": "Dependency owner: retain exact live audit paths/identifiers/severities and reachability analysis, minimally update compatible pins, run complete affected and full successors on frozen source, refresh raw advisories, retain actual residuals. Offline policy pass cannot clear live advisories or prove production repaired.", + "status": "Inherited advisory/review gate retained. Fresh live audit observations linked as P9-REQUAL-SEC01–03; compatible local pins and post-pin audits zero, full final-source successors pending. No production deployment or app-reachable exploit claimed. Fresh locked Python advisory finding P9-REQUAL-SEC04 is OPEN with INCOMPLETE coverage; no blanket security PASS.", + "gates": { + "phase9": "local dependency fixes and post-pin zero audits recorded; complete frozen successors pending", + "phase10": "testpass criterion pending final dependency source", + "production": "BLOCKED independent deployed versions, exposure and release gates; no production fix claimed", + "debt": "inherited live-advisory gate retained; three new observations independently tracked" + } + }, + { + "id": "P9-PUB-01", + "aliases": [], + "criterion": "Initial HTTP502 blockage recovered on23October; all checkpoint ancestors published in normal push; direct feature equality verified at `0fb108bd673ea91749f6fa057295e5b6d15d557f`", + "source": [ + { + "path": "docs/redesign/phase-9/RISKS.md", + "line": 39 + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical assessment" + } + ], + "severityAndImpact": "Resolved for published checkpoint; final commit still needs its own direct equality proof", + "dependency": "Final publication / handoff completeness", + "ownerAndRequiredClosure": "QA: retain failed attempts and verify each subsequent normal push; no force push", + "status": "Initial HTTP502 blockage recovered on23October; all checkpoint ancestors published in normal push; direct feature equality verified at `0fb108bd673ea91749f6fa057295e5b6d15d557f`", + "gates": { + "phase9": "not a standalone functional defect; retain stated qualification", + "phase10": "no permission to delete; affected-candidate proof", + "production": "BLOCKED until stated operator closure", + "debt": "retained gate" + } + }, + { + "id": "P9-T01", + "criterion": "Medium test reliability: parser descendant test could time out before it had a descendant", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-T01" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "Entry sidecar 55 pass/1 fail (missing PID); isolated run passes; explicit slow startup reproduces the race. Fixture now waits for its child PID before the unchanged 200 ms deadline. Real process-tree kill and HTTP 504 assertions retained. Focused green and full 56/56 successor. No parser product change." + } + ], + "severityAndImpact": "Medium test reliability: parser descendant test could time out before it had a descendant", + "dependency": "Resolved in tested Windows environment; Linux run remains separate.", + "ownerAndRequiredClosure": "QA; `.artifacts/phase9/sidecar-entry-failed.*`, `sidecar-fixture-red.*`, `sidecar-fixture-green.*`, `sidecar.xml`", + "status": "RESOLVED within historical tested scope; fresh successor pending", + "gates": { + "phase9": "fresh affected regression required", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Resolved in tested Windows environment; Linux run remains separate." + } + }, + { + "id": "P9-L01", + "criterion": "Low localisation defect: Admin grid vendor controls appear in English in Bokmål", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-L01" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "Sole DataGrid owner omitted localeText. New English desktop test passes while Bokmål fails to find “Rader per side:”. Reuse installed `nbNO` locale in AdminUsersPage. Focused 12/12 green; first integrated Jest919/104 and native desktop matrix green; final complete successors recorded in validation.json." + } + ], + "severityAndImpact": "Low localisation defect: Admin grid vendor controls appear in English in Bokmål", + "dependency": "Resolved in observed local integration; no authorisation, pagination or data contract change.", + "ownerAndRequiredClosure": "Frontend; `admin-users-page.test.tsx`, `AdminUsersPage.tsx`; retained RED/GREEN logs/JSON", + "status": "RESOLVED within historical tested scope; fresh successor pending", + "gates": { + "phase9": "fresh affected regression required", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Resolved in observed local integration; no authorisation, pagination or data contract change." + } + }, + { + "id": "P9-V01", + "criterion": "Medium visual defect: wrapped public h2 lines overlap at320px in EN/NB", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-V01" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "Four larger h2 owners inherited a fixed body line height. Original native geometry2/2 RED; explicit lineHeight1.4 now2/2 GREEN across16 width/theme/locale vectors; independent EN/light and NB/dark PNG inspection confirms separation. Intermediate1.2 still failed unchanged geometry assertions and was superseded." + } + ], + "severityAndImpact": "Medium visual defect: wrapped public h2 lines overlap at320px in EN/NB", + "dependency": "Bounded fix verified by native geometry/build; the complete final 362-case ordinary successor also passed.", + "ownerAndRequiredClosure": "Frontend; `LandingPage.tsx`, new `landing-presentation.spec.ts`; `landing-red`, `landing-qualified`, `landing-accepted` raw reports", + "status": "RESOLVED within historical tested scope; fresh successor pending", + "gates": { + "phase9": "fresh affected regression required", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Bounded fix verified by native geometry/build; the complete final 362-case ordinary successor also passed." + } + }, + { + "id": "P9-V02", + "criterion": "Wrapped bottom CTA title must keep separate readable lines across EN/NB, themes and narrow widths", + "source": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "line": 51, + "anchor": "P9-V02" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical separate bottom CTA repair and complete 362-case ordinary successor", + "detail": "Existing bottom CTA owner inherited fixed body line height; explicit1.4 repair retains exact translated CTA plus all four h2s in both native landing cases. Both languages failed before and passed after. Original-width inspection of all four320px green images retained." + } + ], + "severityAndImpact": "Medium visual defect: wrapped bottom CTA title lines overlapped", + "dependency": "LandingPage bottom CTA owner and landing-presentation.spec.ts; exact EN/NB, theme/width geometry and original image evidence", + "ownerAndRequiredClosure": "Frontend/QA: preserve existing LandingPage lineHeight1.4 and exact CTA+heading geometry assertions; qualify fresh complete landing and ordinary successors on frozen source, retain original RED/GREEN evidence and native-width images", + "status": "RESOLVED within historical tested scope; fresh successor pending", + "gates": { + "phase9": "fresh affected regression required", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "bounded CTA repair separate from P9-V01 four-h2 repair" + } + }, + { + "id": "P9-L02", + "criterion": "Low linguistic residual: stored event type `Created` appears in Bokmål job history/audit", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-L02" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "Rendered route comparison detects18 occurrences across the matrix; raw stored metadata is not a missing translation key. Do not translate authored/provider content indiscriminately." + } + ], + "severityAndImpact": "Low linguistic residual: stored event type `Created` appears in Bokmål job history/audit", + "dependency": "Retained nonblocking development qualification; no data mutation proposed.", + "ownerAndRequiredClosure": "UI/localisation owner; separately map known event enums with unknown-value fallback and history/audit tests; human wording review", + "status": "RETAINED low development debt", + "gates": { + "phase9": "nonblocking development debt with visible limit", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Retained nonblocking development qualification; no data mutation proposed." + } + }, + { + "id": "P9-T02", + "criterion": "Low test compatibility: existing Admin pagination fixture hard-coded the English vendor accessible name in Bokmål mode", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-T02" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "First native shard97pass/1fail: no button named “Go to next page” in NB. The installed locale exposes “Gå til neste side”. Locator now uses installed enUS/nbNO pagination names; the six original width/locale/theme, long-identity, page-change, focus/reachability and no-write assertions remain. Focused 1/1 green; the final isolated 98-case shard and complete 362-case successor passed." + } + ], + "severityAndImpact": "Low test compatibility: existing Admin pagination fixture hard-coded the English vendor accessible name in Bokmål mode", + "dependency": "Test-only repair; no product or authorisation change.", + "ownerAndRequiredClosure": "QA; `phase7-admin-users.spec.ts`; original shard report/trace and `admin-grid-green` retained. Other English-name callers belong to the separate English JobTable owner and remain unchanged.", + "status": "RESOLVED within historical tested scope; fresh successor pending", + "gates": { + "phase9": "fresh affected regression required", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Test-only repair; no product or authorisation change." + } + }, + { + "id": "P9-PERF-01", + "criterion": "Low duplicate report work: shell and Dashboard each initially read reminders", + "source": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "anchor": "P9-PERF-01" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-06/DEFECTS.md", + "kind": "historical defect/reproduction/closure record", + "detail": "Phase 8 source/network diagnosis retained. Phase 9 request-count evidence must distinguish initial duplicate reads from additional reads during editing." + } + ], + "severityAndImpact": "Low duplicate report work: shell and Dashboard each initially read reminders", + "dependency": "Accepted existing development debt; no Phase 10 implementation here.", + "ownerAndRequiredClosure": "Shared reminder read owner; measured benefit and independent shell/dashboard failure/loading tests before consolidation.", + "status": "RETAINED low development debt", + "gates": { + "phase9": "nonblocking development debt with visible limit", + "phase10": "candidate proof only; no cleanup authority", + "production": "does not clear independent release gates", + "debt": "Accepted existing development debt; no Phase 10 implementation here." + } + }, + { + "id": "P9-T03", + "criterion": "Provider-worker isolation must prevent server-originated NAV changes in preservation fixtures", + "source": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "anchor": "P9-T03" + }, + { + "path": "docs/redesign/phase-9/p9-00/worker-isolation-delta.json" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "kind": "historical 87 pass/1 fail then full corrected successor" + } + ], + "severityAndImpact": "High test isolation", + "dependency": "controlled native fixture; production worker unchanged", + "ownerAndRequiredClosure": "QA: retain failed run, unchanged no-write assertions, fixture config delta and fresh full successor", + "status": "RESOLVED historical fixture; fresh successor pending", + "gates": { + "phase9": "fresh exact fixture/case successor", + "phase10": "preserve isolation and assertions", + "production": "not enabled-worker acceptance", + "debt": "no product fix inferred" + } + }, + { + "id": "M09-01", + "criterion": "With NVDA + supported desktop browser, traverse login, Jobs, job details, Career, CV editor, Documents and Settings using headings/landmarks/forms. Repeat equivalent VoiceOver/Safari journeys.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-01 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Names, roles, values, selected state, headings, reading order and errors are understandable; retain reader/version and spoken observations. No hidden background content is announced.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-02", + "criterion": "Keyboard-only: skip link → navigation → commands → add/edit dialogs → job sections → CV preview/history. Open/close the mobile drawer, confirmation, select and menu repeatedly, including after errors.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-02 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Visible focus, logical order, genuine traps only while modal, Escape and focus restoration; no off-screen/hidden tab stops. Record any transition-specific failure.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-03", + "criterion": "Dashboard: hide/show, Earlier/Later, size, Cancel, Reset-confirm/cancel, failed Save, stale conflict/reload, saved empty layout recovery. Listen with a reader.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-03 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Each action/position/save/error announces once and agrees with visible DOM order; pointer drag has an equivalent keyboard route.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-04", + "criterion": "Inspect P9-AX-02/03 backgrounds in light/dark, focused/hover/disabled, open native select, scrolled editor and fixed chrome. Measure actual foreground/background paint.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-04 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Applicable normal text ≥4.5:1, large text ≥3:1 and necessary UI boundaries/focus ≥3:1. Record sampled colors/ratios/state. An axe incomplete is not sufficient to close the row.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-05", + "criterion": "Inspect zero badges and both open/settled-closed drawer states with the accessibility tree and actual reader.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-05 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Invisible zero badge is absent from announcements; live unread count remains meaningful; closed drawer is neither read nor tabbable. Runtime DOM checks cover only the tested states.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-06", + "criterion": "Use actual browser 100/200/400% zoom and text-only enlargement, increased text spacing and forced colors across all significant forms, grid pagination, job sections and CV controls.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-06 / accessibility tester" + } + ], + "evidence": [], + "severityAndImpact": "High accessibility qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "accessibility tester", + "status": "NOT TESTED", + "requiredClosure": "Essential controls remain reachable/readable, no lost content or focus; distinguish intentional table/document scrollers from root clipping. Preserve fixed A4/Letter geometry.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-07", + "criterion": "On actual phone/tablet in portrait/landscape, edit long text with software keyboard, open drawers/dialogs/selects, reorder Dashboard and Board via supported alternatives, scroll CV preview and download PDF.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-07 / product owner with physical devices" + } + ], + "evidence": [], + "severityAndImpact": "Medium/High human/provider/output qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "product owner with physical devices", + "status": "NOT TESTED", + "requiredClosure": "No keyboard-obscured primary action/data loss; reachable touch targets, no accidental destructive action; record device/input mode. Emulated touch does not close this.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-08", + "criterion": "Read registration/recovery, validation/errors, onboarding, Dashboard editing, Jobs/Board, Career/import, CV/library, documents/mail, notifications, Settings and Admin in Bokmål. Include long names, singular/plural, dates/numbers and accessible names.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-08 / Bokmål reviewer" + } + ], + "evidence": [], + "severityAndImpact": "Medium/High human/provider/output qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "Bokmål reviewer", + "status": "NOT TESTED", + "requiredClosure": "Natural professional Bokmål, consistent established terms, meaningful messages. Separate authored English content, technical names and provider strings from untranslated application copy.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-09", + "criterion": "Compare preview and downloaded one-/multi-page EN/NB CVs, long words, optional/photo sections and all supported templates on intended Linux/font environment and another supported browser; print representative PDFs.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-09 / document reviewer" + } + ], + "evidence": [], + "severityAndImpact": "Medium/High human/provider/output qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "document reviewer", + "status": "NOT TESTED", + "requiredClosure": "Legible fonts, intact glyphs/diacritics, margins, page boundaries, searchable text, photo/crop, correct language/date output and no missing/duplicated content. Retain original bytes, renderer/font versions and print observations.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "M09-10", + "criterion": "In authorised sandboxes test Google/Microsoft/Turnstile, verification/reset mail delivery, mailbox reconnect/revocation, uncertain send and actual calendar timezone/DST.", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/MANUAL_CHECKLIST.md", + "anchor": "M09-10 / approved provider tester" + } + ], + "evidence": [], + "severityAndImpact": "Medium/High human/provider/output qualification", + "dependency": "Human qualified tester; exact build/environment and synthetic data; see MANUAL_ACCEPTANCE.md", + "owner": "approved provider tester", + "status": "NOT TESTED", + "requiredClosure": "Correlated origin/state, explicit confirmation, no accidental resend, correct ownership/timezone. Local SMTP/HTTP fixtures do not close external-provider qualification.", + "gates": { + "phase9": "explicit carry-forward qualification under REQUEST §6; no human result inferred", + "phase10": "affected functionality proof required; no deletion authority", + "production": "BLOCKED until applicable genuine human/provider evidence", + "debt": "open qualification" + } + }, + { + "id": "P9-AX-01", + "criterion": "aria-hidden-focus: drawer/focus", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/inherited-axe-triage.json", + "anchor": "P9-AX-01" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-03/README.md", + "kind": "historical finite scans and original inherited triage", + "occurrences": 1 + } + ], + "severityAndImpact": "Accessibility qualification; incomplete is not a confirmed violation", + "dependency": "M09-01/02/04/05 as applicable", + "owner": "Accessibility tester", + "status": "Requires manual inspection", + "requiredClosure": "Shared Dashboard drawer settled predicate, Escape focus and24Tab proof pass. Original Analytics transition cause is not proven; human reader/transition qualification remains.", + "gates": { + "phase9": "carry exact applicable manual qualification; no violation or human PASS inferred", + "phase10": "retain accessible functionality; affected-candidate proof required", + "production": "applicable manual evidence required", + "debt": "human qualification; do not count repeated occurrences as unique defects" + } + }, + { + "id": "P9-AX-02", + "criterion": "color-contrast: dashboard size selector", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/inherited-axe-triage.json", + "anchor": "P9-AX-02" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-03/README.md", + "kind": "historical finite scans and original inherited triage", + "occurrences": 48 + } + ], + "severityAndImpact": "Accessibility qualification; incomplete is not a confirmed violation", + "dependency": "M09-01/02/04/05 as applicable", + "owner": "Accessibility tester", + "status": "Requires manual inspection", + "requiredClosure": "Contextual foreground/background measurement remains required.", + "gates": { + "phase9": "carry exact applicable manual qualification; no violation or human PASS inferred", + "phase10": "retain accessible functionality; affected-candidate proof required", + "production": "applicable manual evidence required", + "debt": "human qualification; do not count repeated occurrences as unique defects" + } + }, + { + "id": "P9-AX-03", + "criterion": "color-contrast: text/control with obscured background", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/inherited-axe-triage.json", + "anchor": "P9-AX-03" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-03/README.md", + "kind": "historical finite scans and original inherited triage", + "occurrences": 5 + } + ], + "severityAndImpact": "Accessibility qualification; incomplete is not a confirmed violation", + "dependency": "M09-01/02/04/05 as applicable", + "owner": "Accessibility tester", + "status": "Requires manual inspection", + "requiredClosure": "Contextual foreground/background measurement remains required.", + "gates": { + "phase9": "carry exact applicable manual qualification; no violation or human PASS inferred", + "phase10": "retain accessible functionality; affected-candidate proof required", + "production": "applicable manual evidence required", + "debt": "human qualification; do not count repeated occurrences as unique defects" + } + }, + { + "id": "P9-AX-04", + "criterion": "color-contrast: hidden badge", + "source": [ + { + "path": "docs/redesign/phase-9/p9-03/inherited-axe-triage.json", + "anchor": "P9-AX-04" + } + ], + "evidence": [ + { + "path": "docs/redesign/phase-9/p9-03/README.md", + "kind": "historical finite scans and original inherited triage", + "occurrences": 10 + } + ], + "severityAndImpact": "Accessibility qualification; incomplete is not a confirmed violation", + "dependency": "M09-05 actual reader/positive count", + "owner": "Accessibility tester", + "status": "Not applicable in tested settled hidden state", + "requiredClosure": "Four current native EN/NB theme vectors: aria-hidden=true and zero area. Actual reader/live unread-state remains separate.", + "gates": { + "phase9": "carry exact applicable manual qualification; no violation or human PASS inferred", + "phase10": "retain accessible functionality; affected-candidate proof required", + "production": "historical zero-state not applicable; live reader state still open", + "debt": "human qualification; do not count repeated occurrences as unique defects" + } + }, + { + "id": "P9-REQUAL-SEC01", + "reviewId": "P9-REQUAL-SEC01", + "criterion": "System.Security.Cryptography.Pkcs8.0.1 transitive lock via MimeKit4.17.0 contains published high/moderate advisories", + "source": [ + { + "path": ".artifacts/p9-requal-01/security-before-pins/", + "kind": "original RED live audit artifacts; exact report hashes owned by root validation ledger" + }, + { + "path": ".artifacts/p9-requal-01/security/nuget-advisories.log", + "kind": "actual post-pin audit; root verified, hashes pending final ledger" + } + ], + "evidence": [ + { + "path": ".artifacts/p9-requal-01/security/nuget-advisories.log", + "kind": "post-pin live NuGet audit: zero findings" + }, + { + "path": ".artifacts/p9-requal-01/security/frontend-audit.json", + "kind": "post-pin npm audit: zero vulnerabilities" + }, + { + "path": ".artifacts/p9-requal-01/security/npm-advisories.log", + "kind": "post-pin npm audit process log" + }, + { + "kind": "root-reported post-pin checks", + "detail": "Backend1123/1123, MariaDB32/32, build/types/lint pass. Frontend and full browser successors pending. Do not add repeated/focused counts or qualify final source with pre-pin frontend934." + } + ], + "severityAndImpact": "High GHSA-846f-f764-76mx SignedCms CPU exhaustion; Moderate GHSA-2fmv-rv2c-59x7 Windows EnvelopedCms behavior. Vulnerable package presence established; application reachability/exploit not claimed.", + "dependency": "compatible locked dependency correction plus complete affected/frozen-source successor qualification", + "ownerAndRequiredClosure": "Dependency/QA owner: Direct compatible package override System.Security.Cryptography.Pkcs8.0.2; retain MimeKit4.17.0 ownership. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent.", + "status": "LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED", + "gates": { + "phase9": "bounded dependency remediation observed locally; full frozen successor qualification pending", + "phase10": "testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority", + "production": "NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained", + "debt": "published vulnerable package version repaired locally; remaining evidence qualification" + } + }, + { + "id": "P9-REQUAL-SEC02", + "reviewId": "P9-REQUAL-SEC02", + "criterion": "Next16.3.8 locked package now has three published critical advisories", + "source": [ + { + "path": ".artifacts/p9-requal-01/security-before-pins/", + "kind": "original RED live audit artifacts; exact report hashes owned by root validation ledger" + }, + { + "path": ".artifacts/p9-requal-01/security/frontend-audit.json", + "kind": "actual post-pin audit; root verified, hashes pending final ledger" + } + ], + "evidence": [ + { + "path": ".artifacts/p9-requal-01/security/nuget-advisories.log", + "kind": "post-pin live NuGet audit: zero findings" + }, + { + "path": ".artifacts/p9-requal-01/security/frontend-audit.json", + "kind": "post-pin npm audit: zero vulnerabilities" + }, + { + "path": ".artifacts/p9-requal-01/security/npm-advisories.log", + "kind": "post-pin npm audit process log" + }, + { + "kind": "root-reported post-pin checks", + "detail": "Backend1123/1123, MariaDB32/32, build/types/lint pass. Frontend and full browser successors pending. Do not add repeated/focused counts or qualify final source with pre-pin frontend934." + } + ], + "severityAndImpact": "Critical package advisories GHSA-2464-fhr4-w9xw, GHSA-p3m5-59mp-jv5r and GHSA-673q-mjm6-r5xr. Vulnerable package presence is distinct from reachable deployed paths; no application exploit claimed.", + "dependency": "compatible locked dependency correction plus complete affected/frozen-source successor qualification", + "ownerAndRequiredClosure": "Dependency/QA owner: Pin Next and eslint-config-next exactly16.4.1. Existing static export, unoptimized images and Sharp0.35.5 mitigate the image-serving path; they do not close every package advisory. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent.", + "status": "LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED", + "gates": { + "phase9": "bounded dependency remediation observed locally; full frozen successor qualification pending", + "phase10": "testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority", + "production": "NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained", + "debt": "published vulnerable package version repaired locally; remaining evidence qualification" + } + }, + { + "id": "P9-REQUAL-SEC03", + "reviewId": "P9-REQUAL-SEC03", + "criterion": "Dev-transitive Zod4.5.4 via eslint-plugin-react-hooks is within a vulnerable published range", + "source": [ + { + "path": ".artifacts/p9-requal-01/security-before-pins/", + "kind": "original RED live audit artifacts; exact report hashes owned by root validation ledger" + }, + { + "path": ".artifacts/p9-requal-01/security/npm-advisories.log", + "kind": "actual post-pin audit; root verified, hashes pending final ledger" + } + ], + "evidence": [ + { + "path": ".artifacts/p9-requal-01/security/nuget-advisories.log", + "kind": "post-pin live NuGet audit: zero findings" + }, + { + "path": ".artifacts/p9-requal-01/security/frontend-audit.json", + "kind": "post-pin npm audit: zero vulnerabilities" + }, + { + "path": ".artifacts/p9-requal-01/security/npm-advisories.log", + "kind": "post-pin npm audit process log" + }, + { + "kind": "root-reported post-pin checks", + "detail": "Backend1123/1123, MariaDB32/32, build/types/lint pass. Frontend and full browser successors pending. Do not add repeated/focused counts or qualify final source with pre-pin frontend934." + } + ], + "severityAndImpact": "High GHSA-mrhx-c7xc-m3w5 in development dependency graph. No production application reachability/exploit claimed.", + "dependency": "compatible locked dependency correction plus complete affected/frozen-source successor qualification", + "ownerAndRequiredClosure": "Dependency/QA owner: Use compatible existing ^4 dependency range via Zod4.6.6 override; do not add runtime functionality. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent.", + "status": "LOCALLY REMEDIATED; post-pin audits zero; complete final-source successor validation PENDING; production NOT DEPLOYED", + "gates": { + "phase9": "bounded dependency remediation observed locally; full frozen successor qualification pending", + "phase10": "testpass and functionality-inventory criteria still require final complete evidence; no cleanup authority", + "production": "NOT DEPLOYED; no deployed fix or app-reachable exploit claim; independent release gates retained", + "debt": "published vulnerable package version repaired locally; remaining evidence qualification" + } + }, + { + "id": "P9-REQUAL-SEC04", + "reviewId": "P9-REQUAL-SEC04", + "criterion": "REQUEST §9 requires explicit review and disposition of live security/dependency risk; fresh locked Python sidecar advisory findings remain unclosed", + "source": [ + { + "path": "docs/redesign/phase-9/REQUEST.md", + "anchor": "9. Security and privacy" + }, + { + "path": ".artifacts/p9-requal-01/security/python-locked/", + "kind": "fresh exact locked Python provider query evidence; root/CI-owned tracked summary pending" + } + ], + "evidence": [ + { + "path": ".artifacts/p9-requal-01/security/python-locked/", + "kind": "root-reported fresh locked dependency queries", + "detail": "49 pins,98 provider queries,97 successful and1 PyPI404 for torch2.6.0+cpu; exact OSV lookup succeeds.249 provider records deduplicate into109 alias groups across8 packages:certifi,filelock,pillow,pypdf,setuptools,torch,transformers,urllib3. Critical/high among provider severity labels;109 alias groups are not109 independent CVEs. Exploitability/application reachability not assessed.", + "lockedFileSha256": "36f2912965d183e59f2d8320f3817ca8dd0fee6d76e05cfd63ac92defe6c6031" + }, + { + "kind": "pending tracked evidence packaging", + "detail": "CI agent preparing python-advisories.json and PYTHON_SECURITY.md; exact paths/final report hashes owned by root/CI ledger. No completed tracked summary claimed by this register." + } + ], + "severityAndImpact": "Critical/high provider-labelled advisories among locked packages; exploitability not assessed; coverage INCOMPLETE due one provider query404", + "dependency": "Security/sidecar review of exact locked versions, alias groups, applicability and provider query gap; separately validated scope for ML/parser dependency transition", + "ownerAndRequiredClosure": "Security/sidecar owners: preserve exact lock hash and raw provider records, resolve/document PyPI torch+cpu query gap while retaining successful exact OSV evidence, assess applicability/reachability and supported fixes, propose bounded separately validated ML/parser dependency transition with affected regression and model/parser compatibility evidence. No automatic dependency rewrite, model activation or production action.", + "status": "OPEN; locked Python advisory coverage INCOMPLETE; critical/high provider labels retained; exploitability NOT ASSESSED", + "gates": { + "phase9": "REQUEST §9 explicit security risk review required and NOT CLOSED; zero NuGet/npm findings cannot clear Python findings", + "phase10": "entry security uncertainty remains inherited and UNWAIVED; no cleanup authority", + "production": "RELEASE BLOCKER pending security/sidecar disposition and qualified remediation; no production fix/deployment claimed", + "debt": "open locked Python security findings and coverage gap; major ML/parser transition requires separate validated scope" + } + } + ] +} diff --git a/docs/redesign/phase-9/p9-requal-01/linux-run.py b/docs/redesign/phase-9/p9-requal-01/linux-run.py new file mode 100644 index 0000000..be77a7d --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/linux-run.py @@ -0,0 +1,141 @@ +"""Disposable local Linux renderer; no host daemon is exposed to the API container.""" +import datetime, json, os, re, subprocess, sys, time, urllib.request, uuid +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / '.artifacts/p9-requal-01/linux' +IMAGE = 'jobtracker-p9-requal-api:security-check' +DB = 'jobtracker-it-p9-requal-mariadb-test-1' +PIN = 'mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00' +VERSION = 'p9-requal-linux-780b9bc' + +def guard_schema(name): + if not re.fullmatch(r'jt_it_[0-9a-f]{32}', name): + raise ValueError('Only a generated qualification schema is allowed.') + return name + +def command(args, **kwargs): + return subprocess.run(['rtk', 'proxy', *args], check=True, capture_output=True, text=True, encoding='utf-8', **kwargs).stdout.strip() + +def sql(query): + return command(['docker', 'exec', '-e', 'MYSQL_PWD=jt-integration-only', DB, + 'mariadb', '-uroot', '--batch', '--skip-column-names', '-e', query]) + +def safe_error(error): + # CalledProcessError includes command arguments, including development-only credentials. + return str(error).replace('jt-integration-only','[test-password]').replace('E2ePassword123!','[test-password]').replace('e2e-only-key-at-least-thirty-two-characters-long','[test-key]') + +def main(): + if '--self-test' in sys.argv: + assert guard_schema('jt_it_'+'a'*32) + for name in ['jobtracker', 'jt_it_abc', 'jt_it_'+'a'*32+';DROP DATABASE x']: + try: guard_schema(name) + except ValueError: continue + raise AssertionError(name) + print('Linux qualification schema guards: PASS') + return + OUT.mkdir(parents=True, exist_ok=True) + if (OUT/'process.json').exists() or (OUT.parent/'linux-renderer.json').exists(): + raise ValueError('Retain prior evidence; select a fresh run directory.') + owned = json.loads(command(['docker','inspect',DB]))[0] + assert owned['Config']['Image'] == PIN + assert owned['Config']['Labels']['com.docker.compose.project'] == 'jobtracker-it-p9-requal' + assert owned['Config']['Labels']['com.docker.compose.service'] == 'mariadb-test' + assert '/var/lib/mysql' in owned['HostConfig'].get('Tmpfs',{}) + assert not owned['HostConfig'].get('Privileged') and owned['HostConfig'].get('NetworkMode')!='host' + assert owned['State']['Running'] and owned['State']['Health']['Status']=='healthy' + assert owned['HostConfig']['PortBindings']['3306/tcp'] == [{'HostIp':'127.0.0.1','HostPort':'33308'}] + actual = sql('SELECT VERSION()') + assert actual.startswith('12.2.2-MariaDB'), actual + name=guard_schema('jt_it_'+uuid.uuid4().hex) + suffix=uuid.uuid4().hex[:12] + api='jobtracker-p9-requal-linux-'+suffix + network='jobtracker-p9-requal-linux-'+suffix + record={'startedUtc':datetime.datetime.now(datetime.timezone.utc).isoformat(), 'schema':name, + 'serverVersion':actual,'imageTag':IMAGE,'apiContainer':api,'network':network,'cleanup':{},'exitCode':1} + created=attached=network_created=api_created=False + try: + assert sql(f"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='{name}'")=='0' + sql(f'CREATE DATABASE `{name}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci') + created=True + assert sql(f"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='{name}'")=='0' + record['imageId']=command(['docker','image','inspect','--format','{{.Id}}',IMAGE]) + record['chromium']=command(['docker','run','--rm','--network','none','--entrypoint','/usr/bin/chromium',IMAGE,'--version']) + record['runtime']=command(['docker','run','--rm','--network','none','--entrypoint','dotnet',IMAGE,'--info']) + command(['docker','network','create','--label','task=p9-requal-01',network]); network_created=True + command(['docker','network','connect','--alias','mariadb',network,DB]); attached=True + variables={ + 'ASPNETCORE_ENVIRONMENT':'Development','Database__Provider':'mariadb','Database__ServerVersion':'12.2.2', + 'ConnectionStrings__JobTracker':f'Server=mariadb;Port=3306;Database={name};User ID=root;Password=jt-integration-only;SslMode=None', + 'Auth__Require':'true','Auth__JwtKey':'e2e-only-key-at-least-thirty-two-characters-long', + 'Auth__AdminEmail':'e2e@example.test','Auth__AdminPassword':'E2ePassword123!', 'Auth__AllowRegistration':'false', + 'RateLimits__AuthLoginPermitLimit':'1000','Cors__Origins__0':'http://localhost:3300', + 'Workers__AiOperationsEnabled':'false','Workers__SavedJobSearchAlertsEnabled':'false', + 'HttpsRedirection__Enabled':'false','App__Version':VERSION,'App__CommitSha':'780b9bc', + 'Data__Root':'/data','Logging__LogLevel__Default':'Warning'} + args=['docker','create','--name',api,'--label','task=p9-requal-01','--network',network, + '-p','127.0.0.1:5302:8080','--tmpfs','/data:rw,nosuid,size=512m'] + for key,value in variables.items(): args+=['-e',key+'='+value] + command(args+[IMAGE]); api_created=True + assert command(['docker','inspect','--format','{{.Image}}',api])==record['imageId'] + command(['docker','start',api]) + deadline=time.monotonic()+120 + while True: + try: + with urllib.request.urlopen('http://localhost:5302/health',timeout=3) as response: + health=json.load(response) + assert health['version']==VERSION, health + with urllib.request.urlopen('http://localhost:5302/ready',timeout=3) as response: + assert json.load(response)['status']=='ready' + break + except Exception: + if time.monotonic()>=deadline: raise + time.sleep(1) + record['health']=health + record['migrationCount']=int(sql(f'SELECT COUNT(*) FROM `{name}`.`__EFMigrationsHistory`')) + assert record['migrationCount']>0 + env={**os.environ,'P9_REQUAL_LINUX_READY':VERSION,'PLAYWRIGHT_STATIC_EXPORT':'true', + 'PLAYWRIGHT_PREBUILT_EXPORT':'true','NEXT_PUBLIC_API_BASE_URL':'http://localhost:5302/api', + 'CV_FIDELITY_OUTPUT':str(OUT/'fidelity'),'CV_SETTINGS_FIDELITY_OUTPUT':str(OUT/'settings-fidelity'), + 'PLAYWRIGHT_JSON_OUTPUT_NAME':str(OUT.parent/'linux-renderer.json')} + test=['node','node_modules/@playwright/test/cli.js','test', + '--config=../docs/redesign/phase-9/p9-requal-01/linux/playwright.config.ts', + '--retries=0','--reporter=list,json','--output='+str(OUT/'test-results')] + with (OUT/'playwright.log').open('w',encoding='utf-8') as log: + record['browserExitCode']=subprocess.run(['rtk','proxy',*test],cwd=ROOT/'job-tracker-ui',env=env,stdout=log,stderr=subprocess.STDOUT).returncode + record['exitCode']=record['browserExitCode'] + record['migrationCountAfter']=int(sql(f'SELECT COUNT(*) FROM `{name}`.`__EFMigrationsHistory`')) + assert record['migrationCountAfter']==record['migrationCount'] + except Exception as error: + record['exitCode']=1 + record['error']=safe_error(error) + finally: + if api_created: + try: + (OUT/'api.log').write_text(safe_error(command(['docker','logs',api])),encoding='utf-8') + except Exception as error: record['cleanup']['logError']=safe_error(error) + try: + command(['docker','rm','--force',api]); record['cleanup']['apiRemoved']=True + except Exception as error: record['cleanup']['apiError']=str(error) + if attached: + try: command(['docker','network','disconnect',network,DB]); record['cleanup']['databaseDisconnected']=True + except Exception as error: record['cleanup']['disconnectError']=str(error) + if network_created: + try: command(['docker','network','rm',network]); record['cleanup']['networkRemoved']=True + except Exception as error: record['cleanup']['networkError']=str(error) + if created and (not api_created or record['cleanup'].get('apiRemoved')): + try: + guard_schema(name); sql(f'DROP DATABASE `{name}`') + assert sql(f"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='{name}'")=='0' + record['cleanup']['schemaRemoved']=True + except Exception as error: record['cleanup']['schemaError']=str(error) + elif created: + record['cleanup']['schemaError']='Schema retained because API removal was not confirmed.' + if any(key.endswith('Error') for key in record['cleanup']): record['exitCode']=1 + record['finishedUtc']=datetime.datetime.now(datetime.timezone.utc).isoformat() + (OUT/'process.json').write_text(json.dumps(record,indent=2)+'\n',encoding='utf-8') + (OUT.parent/'linux-renderer-exit.json').write_text(json.dumps(record,indent=2)+'\n',encoding='utf-8') + print(json.dumps(record)) + if record['exitCode'] or any(key.endswith('Error') for key in record['cleanup']): raise SystemExit(1) + +if __name__=='__main__': main() diff --git a/docs/redesign/phase-9/p9-requal-01/linux/playwright.config.ts b/docs/redesign/phase-9/p9-requal-01/linux/playwright.config.ts new file mode 100644 index 0000000..cd484f3 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/linux/playwright.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; +import base from '../../../../../job-tracker-ui/playwright.config'; +import path from 'node:path'; + +if (process.env.P9_REQUAL_LINUX_READY !== 'p9-requal-linux-780b9bc') { + throw new Error('Use the isolated Linux qualification runner and its verified API identity.'); +} +const servers = Array.isArray(base.webServer) ? base.webServer : [base.webServer!]; +export default defineConfig({ ...base, + testDir: path.resolve('e2e'), + testMatch: ['cv-readiness.spec.ts', 'cv-settings-presentation.spec.ts'], + grep: /native preview\/PDF fidelity corpus|document controls preserve settings/, + workers: 1, retries: 0, + // The runner starts and identifies the existing Linux renderer; only the UI is managed here. + webServer: [{ ...servers[1], reuseExistingServer: false }], + metadata: { linuxApiIdentity: process.env.P9_REQUAL_LINUX_READY, mariaDbVersion: '12.2.2' }, +}); diff --git a/docs/redesign/phase-9/p9-requal-01/mariadb-lane.py b/docs/redesign/phase-9/p9-requal-01/mariadb-lane.py new file mode 100644 index 0000000..b098cfa --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/mariadb-lane.py @@ -0,0 +1,229 @@ +"""Explicit isolated MariaDB browser lanes; self-check never touches a server.""" +import argparse +import base64 +import datetime +import hashlib +import json +import os +from pathlib import Path +import re +import socket +import subprocess +import sys +import time +import uuid + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / '.artifacts/p9-requal-01' +UI = ROOT / 'job-tracker-ui' +CLIENT = ROOT / '.artifacts/mariadb/runtime/mariadb-12.2.2-winx64/bin/mariadb.exe' +CONTAINER = 'jobtracker-it-p9-requal-mariadb-test-1' +IMAGE = 'mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00' +CONFIGS = { + 'mariadb-browser': ('playwright.mariadb.config.ts', 1), + 'mariadb-observations': ('../docs/redesign/phase-9/p9-requal-01/observations/playwright.config.ts', 2), + 'performance': ('../docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts', 1), +} + +def utc(): + return datetime.datetime.now(datetime.timezone.utc).isoformat() + +def scrub(value): + if isinstance(value, dict): + return {k: '[REDACTED]' if re.search(r'password|connectionstring', k, re.I) else scrub(v) for k, v in value.items()} + if isinstance(value, list): return [scrub(v) for v in value] + if not isinstance(value, str): return value + value = re.sub(r'Server=127\.0\.0\.1;Port=33308;Database=jt_it_[a-f0-9]{32};User ID=root;Password=[^;\r\n]+;SslMode=None;?', '[REDACTED CONNECTION]', value) + for secret in ('jt-integration-only', 'E2ePassword123!'): + value = value.replace(secret, '[REDACTED]') + return re.sub(r'(Password\s*=\s*)[^;\s]+', r'\1[REDACTED]', value, flags=re.I) + +def write(path, value): + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(scrub(value), indent=2) + '\n', encoding='utf-8') + +def schema_sql(schema, drop=False): + if not re.fullmatch(r'jt_it_[a-f0-9]{32}', schema): raise ValueError('Invalid generated schema') + return f'DROP DATABASE `{schema}`;' if drop else f'CREATE DATABASE `{schema}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;' + +def ownership(data): + labels = data['Config'].get('Labels', {}) + ports = data['NetworkSettings']['Ports'].get('3306/tcp', []) + if (data['Name'] != '/' + CONTAINER or not data['State']['Running'] or data['Config']['Image'] != IMAGE + or labels.get('com.docker.compose.project') != 'jobtracker-it-p9-requal' + or labels.get('com.docker.compose.service') != 'mariadb-test' + or ports != [{'HostIp': '127.0.0.1', 'HostPort': '33308'}] + or data['HostConfig'].get('Privileged') or data['HostConfig'].get('NetworkMode') == 'host' + or any(mount.get('Destination') == '/var/lib/mysql' and mount.get('Type') != 'tmpfs' for mount in data.get('Mounts', [])) + or '/var/lib/mysql' not in data['HostConfig'].get('Tmpfs', {})): + raise ValueError('Exact task-owned pinned loopback disposable container proof required') + return {'name': CONTAINER, 'id': data['Id'], 'imageReference': IMAGE, 'imageId': data['Image'], + 'project': labels['com.docker.compose.project'], 'service': 'mariadb-test', 'port': 33308, + 'bindHost': '127.0.0.1', 'disposableData': 'tmpfs', 'privileged': False} + +def cases(report): + result = [] + def walk(suite): + for spec in suite.get('specs', []): + for test in spec.get('tests', []): result.append(test) + for child in suite.get('suites', []): walk(child) + for suite in report.get('suites', []): walk(suite) + return result + +def extract_performance(report, process_code): + tests = cases(report) + attachments = [a for test in tests for run in test.get('results', []) for a in run.get('attachments', []) + if a.get('name') == 'p9-requal-01-mariadb-performance'] + if len(attachments) != 1: raise ValueError('Expected exactly one performance evidence attachment') + attachment = attachments[0] + if attachment.get('body'): + evidence = json.loads(base64.b64decode(attachment['body'])) + elif attachment.get('path'): + path = Path(attachment['path']) + if not path.is_absolute(): path = UI / path + path = path.resolve() + if not path.is_relative_to(OUT.resolve()): raise ValueError('Attachment outside task artifacts') + evidence = json.loads(path.read_text(encoding='utf-8')) + else: raise ValueError('Performance attachment has no body/path') + passed = process_code == 0 and len(tests) == 1 and not report.get('errors') and tests[0].get('status') == 'expected' + passed = passed and len(tests[0].get('results', [])) == 1 and tests[0]['results'][0].get('status') == 'passed' + passed = passed and evidence.get('phase') == 'complete' and evidence.get('actualDurationMs', 0) >= 900000 + return {**evidence, 'status': 'PASS' if passed else 'FAIL', 'processExitCode': process_code, + 'attachmentName': 'p9-requal-01-mariadb-performance'} + +def self_check(): + schema = 'jt_it_' + 'a' * 32 + assert schema_sql(schema, True) == f'DROP DATABASE `{schema}`;' + for bad in ('main', 'jt_it_' + 'a' * 31, schema + ';DROP DATABASE main'): + try: schema_sql(bad, True) + except ValueError: pass + else: raise AssertionError('Invalid schema accepted') + fixture = {'Name': '/' + CONTAINER, 'Id': 'test', 'Image': 'sha256:test', 'State': {'Running': True}, + 'Config': {'Image': IMAGE, 'Labels': {'com.docker.compose.project': 'jobtracker-it-p9-requal', 'com.docker.compose.service': 'mariadb-test'}}, + 'NetworkSettings': {'Ports': {'3306/tcp': [{'HostIp': '127.0.0.1', 'HostPort': '33308'}]}}, + 'HostConfig': {'Privileged': False, 'NetworkMode': 'bridge', 'Tmpfs': {'/var/lib/mysql': ''}}, 'Mounts': []} + assert ownership(fixture)['port'] == 33308 + fixture['HostConfig']['NetworkMode'] = 'host' + try: ownership(fixture) + except ValueError: pass + else: raise AssertionError('Host networking accepted') + fixture['HostConfig']['NetworkMode'] = 'bridge' + fixture['Config']['Image'] = 'mariadb:latest' + try: ownership(fixture) + except ValueError: pass + else: raise AssertionError('Unpinned image accepted') + fixture['Config']['Image'] = IMAGE + fixture['NetworkSettings']['Ports']['3306/tcp'][0]['HostIp'] = '0.0.0.0' + try: ownership(fixture) + except ValueError: pass + else: raise AssertionError('Public database binding accepted') + evidence = {'phase': 'complete', 'actualDurationMs': 900000} + result = {'status': 'passed', 'attachments': [{'name': 'p9-requal-01-mariadb-performance', 'body': base64.b64encode(json.dumps(evidence).encode()).decode()}]} + report = {'suites': [{'specs': [{'tests': [{'status': 'expected', 'results': [result]}]}]}]} + assert extract_performance(report, 0)['status'] == 'PASS' + assert extract_performance(report, 1)['status'] == 'FAIL' + assert 'jt-integration-only' not in scrub('Server=127.0.0.1;Port=33308;Database=' + schema + ';User ID=root;Password=jt-integration-only;SslMode=None') + print('PASS: schema ownership/drop guards, pinned container/network guards, performance extraction/status and redaction; no services touched') + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('mode', choices=list(CONFIGS) + ['self-check']) + args = parser.parse_args() + if args.mode == 'self-check': self_check(); return 0 + lane = args.mode + config, expected = CONFIGS[lane] + report_path = OUT / (lane + '.json') + exit_path = OUT / (lane + '-exit.json') + results_path = OUT / (lane + '-results') + if any(path.exists() for path in (report_path, exit_path, results_path)) or (lane == 'performance' and (OUT / 'performance/result.json').exists()): + raise ValueError('Existing evidence present; archive it explicitly before a new invocation') + OUT.mkdir(parents=True, exist_ok=True) + env = {**os.environ, 'MYSQL_PWD': 'jt-integration-only', 'DOTNET_ROOT': 'C:/Users/Connor/.dotnet', + 'DOTNET_HOST_PATH': 'C:/Users/Connor/.dotnet/dotnet.exe', 'PLAYWRIGHT_STATIC_EXPORT': 'true', + 'PLAYWRIGHT_PREBUILT_EXPORT': 'true', 'PLAYWRIGHT_REUSE_SERVERS': 'false', + 'PLAYWRIGHT_JSON_OUTPUT_NAME': str(report_path), 'JOBTRACKER_MARIADB_BROWSER_PORT': '33308', + 'JOBTRACKER_MARIADB_CLIENT': str(CLIENT), 'NEXT_PUBLIC_API_BASE_URL': 'http://localhost:5302/api', + 'SKIP_MODEL_LOAD': '1', 'AI_SERVICE_SKIP_MODEL_LOAD': '1', 'PYTHONIOENCODING': 'utf-8'} + schema = 'jt_it_' + uuid.uuid4().hex + created = False + process = None + record = {'lane': lane, 'startedUtc': utc(), 'generatedSchema': schema, 'commands': [], 'exitCode': 1, 'cleanup': {'attempted': False}} + started = time.monotonic() + def execute(command, name): + completed = subprocess.run(['rtk', 'proxy', *command], cwd=ROOT, env=env, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30) + log = OUT / (lane + '-' + name + '.log') + log.write_text(scrub(completed.stdout + completed.stderr), encoding='utf-8') + record['commands'].append({'operation': name, 'exitCode': completed.returncode, 'log': str(log.relative_to(ROOT))}) + if completed.returncode: raise RuntimeError(name + ' failed; inspect sanitized operation log') + return completed.stdout.strip() + def sql(query, name): + return execute([str(CLIENT), '--host=127.0.0.1', '--port=33308', '--user=root', '--batch', '--raw', '--skip-column-names', '--execute=' + query], name) + try: + for port in (5302, 3300): + for family, address in ((socket.AF_INET, '127.0.0.1'), (socket.AF_INET6, '::1')): + with socket.socket(family) as probe: + probe.settimeout(0.2) + if probe.connect_ex((address, port)) == 0: raise ValueError(f'Port {port} occupied; exclusive lane required') + # Inspect only this exact task container; full inspection stays in memory, never a report/log. + inspected = subprocess.run(['rtk', 'proxy', 'docker', 'inspect', CONTAINER], capture_output=True, text=True, timeout=20) + if inspected.returncode: raise ValueError('Task container inspection unavailable') + record['ownership'] = ownership(json.loads(inspected.stdout)[0]) + version = sql('SELECT VERSION();', 'version') + record['serverVersion'] = version + if not re.fullmatch(r'12\.2\.2-MariaDB(?:-[A-Za-z0-9.]+)?', version): raise ValueError('Unexpected actual server version') + sql(schema_sql(schema), 'create-schema') + created = True + env['JOBTRACKER_MARIADB_BROWSER_CONNECTION'] = f'Server=127.0.0.1;Port=33308;Database={schema};User ID=root;Password=jt-integration-only;SslMode=None' + command = ['node', 'node_modules/@playwright/test/cli.js', 'test', '--config=' + config, '--retries=0', '--reporter=list,json', '--output=' + str(results_path)] + record['command'] = command + with (OUT / (lane + '.log')).open('w', encoding='utf-8') as log: + process = subprocess.Popen(['rtk', 'proxy', *command], cwd=UI, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8', errors='replace') + record['processId'] = process.pid + for line in process.stdout: log.write(scrub(line)); log.flush() + record['exitCode'] = process.wait() + report = json.loads(report_path.read_text(encoding='utf-8')) + write(report_path, report) + tests = cases(report) + record['caseCount'] = len(tests) + if len(tests) != expected or any(test.get('status') != 'expected' or len(test.get('results', [])) != 1 or test['results'][0].get('status') != 'passed' for test in tests) or report.get('errors'): + record['exitCode'] = record['exitCode'] or 1 + if lane == 'performance': write(OUT / 'performance/result.json', extract_performance(report, record['exitCode'])) + except Exception as error: + record['error'] = scrub(type(error).__name__ + ': ' + str(error)) + record['exitCode'] = record['exitCode'] or 1 + if lane == 'performance' and not (OUT / 'performance/result.json').exists(): + write(OUT / 'performance/result.json', {'status': 'FAIL', 'reason': record['error'], 'processExitCode': record['exitCode']}) + finally: + # Stop only this invocation's process tree before dropping its schema after an interrupted run. + if process is not None and process.poll() is None: + stopped = subprocess.run(['rtk', 'proxy', 'taskkill', '/PID', str(process.pid), '/T', '/F'], capture_output=True, text=True, timeout=20) + record['processTreeStopExitCode'] = stopped.returncode + try: process.wait(timeout=20) + except subprocess.TimeoutExpired: + created = False + record['cleanup']['error'] = 'Owned process tree still running; schema retained for operator cleanup' + record['exitCode'] = record['exitCode'] or 1 + if created: + record['cleanup']['attempted'] = True + try: + sql(schema_sql(schema, True), 'drop-schema') + remaining = sql(f"SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='{schema}';", 'verify-drop') + if remaining != '0': raise ValueError('Generated schema remains after cleanup') + record['cleanup'].update(exitCode=0, schemaAbsent=True) + except Exception as error: + record['cleanup'].update(exitCode=1, error=scrub(str(error))) + record['exitCode'] = record['exitCode'] or 1 + record.update(finishedUtc=utc(), durationSeconds=time.monotonic() - started, + helperSha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest()) + if lane == 'performance' and (OUT / 'performance/result.json').exists(): + result = json.loads((OUT / 'performance/result.json').read_text()) + if record['exitCode']: result['status'] = 'FAIL' + result['cleanup'] = record['cleanup'] + write(OUT / 'performance/result.json', result) + write(exit_path, record) + print(json.dumps({'lane': lane, 'exitCode': record['exitCode'], 'processRecord': str(exit_path)})) + return record['exitCode'] + +if __name__ == '__main__': + try: sys.exit(main()) + except ValueError as error: raise SystemExit(scrub(str(error))) diff --git a/docs/redesign/phase-9/p9-requal-01/observations/persistence.spec.ts b/docs/redesign/phase-9/p9-requal-01/observations/persistence.spec.ts new file mode 100644 index 0000000..4144b18 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/observations/persistence.spec.ts @@ -0,0 +1,77 @@ +import { test, expect, type APIRequestContext } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; +import { sql } from '../performance/mariadb-proof.mjs'; + +const api='http://localhost:5302/api'; +const password='E2ePassword123!'; +async function login(request: APIRequestContext, email: string) { + expect((await request.post(`${api}/auth/login`,{data:{email,password}})).status()).toBe(200); + const me=await (await request.get(`${api}/auth/me`)).json(); + return {id:me.id as string, headers:{'X-CSRF-TOKEN':(await request.storageState()).cookies.find(c=>c.name==='XSRF-TOKEN')!.value, + 'X-Session-Context':me.sessionContext as string}}; +} +async function seed(admin: APIRequestContext, request: APIRequestContext) { + const administrator=await login(admin,'e2e@example.test'); + const email=`requal-observation-${Date.now()}@example.test`; + expect((await admin.post(`${api}/users`,{headers:administrator.headers,data:{email,password,roles:[]}})).status()).toBe(200); + const owner=await login(request,email); + const company=await request.post(`${api}/companies`,{headers:owner.headers,data:{name:'Requalification synthetic company'}}); + expect(company.status()).toBe(201); + return {owner,email,companyId:(await company.json()).id as number}; +} +async function stored(id: number) { + expect(Number.isSafeInteger(id)&&id>0).toBe(true); + return JSON.parse(await sql(`SELECT JSON_OBJECT('id',a.Id,'version',a.Version,'title',a.JobTitle,'notes',a.Notes, + 'opportunityTitle',j.JobTitle,'events',(SELECT COUNT(*) FROM JobEvents e WHERE e.JobApplicationId=a.Id)) + FROM JobApplications a JOIN Jobs j ON j.Id=a.JobId WHERE a.Id=${id}`)); +} + +test('MariaDB real HTTP job saves reject stale and unversioned drafts; independent SQL and a new session retain the acknowledged winner',async({playwright},info)=>{ + const contexts=await Promise.all(Array.from({length:4},()=>playwright.request.newContext())); + const [admin,first,second,fresh]=contexts; + try { + expect(await sql('SELECT VERSION()')).toMatch(/^12\.2\.2-MariaDB(?:-|$)/); + const {owner,email,companyId}=await seed(admin,first); + const otherSession=await login(second,email); + const created=await first.post(`${api}/jobapplications`,{headers:owner.headers,data:{companyId,jobTitle:'Original title',notes:'Original notes',status:'Prospect'}}); + expect(created.status()).toBe(201); + const id=(await created.json()).id as number; + const a=await (await first.get(`${api}/jobapplications/${id}`)).json(); + const b=await (await second.get(`${api}/jobapplications/${id}`)).json(); + expect(b).toEqual(a); + const saved=await first.put(`${api}/jobapplications/${id}`,{headers:owner.headers,data:{...a,jobTitle:'Acknowledged winner',expectedVersion:a.version}}); + expect(saved.status()).toBe(204); + const version=Number(saved.headers()['x-job-version']); + expect(version).toBe(a.version+1); + const acknowledged=await stored(id); + expect(acknowledged).toMatchObject({title:'Acknowledged winner',opportunityTitle:'Acknowledged winner',notes:'Original notes',version}); + expect((await second.put(`${api}/jobapplications/${id}`,{headers:otherSession.headers,data:{...b,notes:'Rejected stale notes',expectedVersion:b.version}})).status()).toBe(409); + expect(await stored(id)).toEqual(acknowledged); + expect((await second.put(`${api}/jobapplications/${id}`,{headers:otherSession.headers,data:{...b,notes:'Legacy unversioned draft'}})).status()).toBe(409); + expect(await stored(id)).toEqual(acknowledged); + await login(fresh,email); + expect(await (await fresh.get(`${api}/jobapplications/${id}`)).json()).toMatchObject({jobTitle:'Acknowledged winner',notes:'Original notes',version}); + const foreign=await seed(admin,admin); + expect((await admin.get(`${api}/jobapplications/${id}`)).status()).toBe(404); + expect((await admin.put(`${api}/jobapplications/${id}`,{headers:foreign.owner.headers,data:{...a,expectedVersion:version}})).status()).toBe(404); + expect(await stored(id)).toEqual(acknowledged); + await info.attach('durable-job-acknowledgement',{body:JSON.stringify({id,acknowledged,stale:409,missing:409,foreign:404,newSession:true}),contentType:'application/json'}); + } finally {await Promise.all(contexts.map(context=>context.dispose()));} +}); + +test('Characterization only: repeated creation bodies create separate persisted records; no creation-intent idempotency guarantee is claimed',async({playwright},info)=>{ + const admin=await playwright.request.newContext(); const request=await playwright.request.newContext(); + try { + expect(await sql('SELECT VERSION()')).toMatch(/^12\.2\.2-MariaDB(?:-|$)/); + const {owner,companyId}=await seed(admin,request); + const body={companyId,jobTitle:'Identical creation body',notes:'Synthetic intent ambiguity',status:'Prospect'}; + const first=await request.post(`${api}/jobapplications`,{headers:owner.headers,data:body}); + const second=await request.post(`${api}/jobapplications`,{headers:owner.headers,data:body}); + expect(first.status()).toBe(201); expect(second.status()).toBe(201); + const ids=[(await first.json()).id as number,(await second.json()).id as number]; + expect(ids[0]).not.toBe(ids[1]); + expect(await stored(ids[0])).toMatchObject({id:ids[0],title:body.jobTitle,notes:body.notes}); + expect(await stored(ids[1])).toMatchObject({id:ids[1],title:body.jobTitle,notes:body.notes}); + await info.attach('creation-intent-limit',{body:JSON.stringify({ids,statuses:[201,201],classification:'Characterization, not safety acceptance', + limit:'Identical JSON cannot distinguish two intentional creations from a retry after an unknown response. A separately specified creation-intent contract remains required; no silent deduplication was added.'}),contentType:'application/json'}); + } finally {await admin.dispose();await request.dispose();} +}); diff --git a/docs/redesign/phase-9/p9-requal-01/observations/playwright.config.ts b/docs/redesign/phase-9/p9-requal-01/observations/playwright.config.ts new file mode 100644 index 0000000..5f45683 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/observations/playwright.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; +import base from '../../../../../job-tracker-ui/playwright.mariadb.config'; + +export default defineConfig({ ...base, testDir: '.', testMatch: 'persistence.spec.ts', workers: 1, retries: 0 }); diff --git a/docs/redesign/phase-9/p9-requal-01/pdf-proof.py b/docs/redesign/phase-9/p9-requal-01/pdf-proof.py new file mode 100644 index 0000000..874df56 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/pdf-proof.py @@ -0,0 +1,91 @@ +"""Stage fresh PDF evidence and run the unchanged oracle after producers stop.""" +import argparse +import hashlib +import json +import shutil +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +ORACLE = ROOT / 'scripts/verify-cv-fidelity.py' + +def digest(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + +def merged_measurements(paths, expected): + records = [json.loads(path.read_text(encoding='utf-8-sig')) for path in paths] + versions = {record['browserVersion'] for record in records} + fixtures = [fixture for record in records for fixture in record['fixtures']] + names = [fixture['fixture'] for fixture in fixtures] + if len(versions) != 1 or len(fixtures) != expected or len(set(names)) != expected: + raise ValueError('Unexpected browser identity, fixture count or duplicate fixture names.') + if any(Path(name).name != name or name in ('.', '..') for name in names): + raise ValueError('Fixture name must identify one child directory.') + return {'browserVersion': versions.pop(), 'fixtures': fixtures} + +def stage(source, destination, measurements, hashes): + destination.mkdir() + for fixture in measurements['fixtures']: + name = fixture['fixture'] + files = [source / name / 'export.pdf', source / name / 'render.html'] + files += [source / name / f'preview-{page}.png' for page in range(1, fixture['previewPages'] + 1)] + (destination / name).mkdir() + for path in files: + hashes[str(path.resolve())] = digest(path) + shutil.copy2(path, destination / name / path.name) + (destination / 'measurements.json').write_text(json.dumps(measurements, ensure_ascii=False, indent=2), encoding='utf-8') + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--platform', choices=['windows', 'linux'], required=True) + parser.add_argument('--fidelity-root', type=Path, required=True) + parser.add_argument('--settings-root', type=Path, required=True) + parser.add_argument('--output', type=Path, required=True, help='New directory; never overwrites an earlier run.') + parser.add_argument('--record', type=Path, required=True, help='New native-pdf.json or linux-pdf.json record.') + args = parser.parse_args() + if args.output.exists() or args.record.exists(): + parser.error('Output directory and result record must both be new.') + inputs = [args.fidelity_root / 'measurements.json'] + settings = [args.settings_root / f'{theme}-{language}-measurements.json' + for theme in ['light', 'dark'] for language in ['en', 'nb']] + corpus = merged_measurements(inputs, 16) + setting_corpus = merged_measurements(settings, 8) + expected_settings = {f'{theme}-{language}-{phase}' for theme in ['light', 'dark'] + for language in ['en', 'nb'] for phase in ['before', 'after']} + if {fixture['fixture'] for fixture in setting_corpus['fixtures']} != expected_settings: + raise ValueError('Settings fixture membership differs from all eight required states.') + hashes = {str(path.resolve()): digest(path) for path in [ORACLE, *inputs, *settings]} + args.output.mkdir(parents=True) + record = {'status': 'FAIL', 'platform': args.platform, 'oracle': str(ORACLE), 'inputs': hashes, 'lanes': []} + try: + for name, source, measurements, count, pages in [ + ('fidelity', args.fidelity_root, corpus, 16, 36), + ('settings-fidelity', args.settings_root, setting_corpus, 8, 24)]: + destination = args.output / name + stage(source, destination, measurements, hashes) + command = [sys.executable, '-B', str(ORACLE), str(destination)] + process = subprocess.run(command, capture_output=True, text=True, encoding='utf-8', errors='replace') + (destination / 'oracle.log').write_text(process.stdout + process.stderr, encoding='utf-8') + report_path = destination / 'fidelity-results.json' + report = json.loads(report_path.read_text(encoding='utf-8')) if report_path.exists() else {} + native = report.get('fixtures', []) + passed = (process.returncode == 0 and report.get('passed') == count and report.get('total') == count + and len(native) == count and {row['fixture'] for row in native} == {row['fixture'] for row in measurements['fixtures']} + and all(row['pass'] and not row['failures'] for row in native) + and sum(row['pdfPages'] for row in native) == pages) + record['lanes'].append({'lane': name, 'status': 'PASS' if passed else 'FAIL', 'command': command, + 'exitCode': process.returncode, 'report': str(report_path), + 'reportSha256': digest(report_path) if report_path.exists() else None, + 'fixtures': len(native), 'pdfPages': sum(row['pdfPages'] for row in native)}) + record['inputDrift'] = [path for path, expected in hashes.items() if digest(Path(path)) != expected] + if not record['inputDrift'] and all(lane['status'] == 'PASS' for lane in record['lanes']): + record['status'] = 'PASS' + except Exception as error: + record['error'] = f'{type(error).__name__}: {error}' + args.record.write_text(json.dumps(record, ensure_ascii=False, indent=2) + '\n', encoding='utf-8') + print(json.dumps({'status': record['status'], 'record': str(args.record)})) + raise SystemExit(0 if record['status'] == 'PASS' else 1) + +if __name__ == '__main__': + main() diff --git a/docs/redesign/phase-9/p9-requal-01/performance/mariadb-proof.mjs b/docs/redesign/phase-9/p9-requal-01/performance/mariadb-proof.mjs new file mode 100644 index 0000000..2482712 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/performance/mariadb-proof.mjs @@ -0,0 +1,29 @@ +import { execFile } from 'node:child_process'; +import { promisify } from 'node:util'; +import { validateMariaDbBrowserConnection } from '../../../../../job-tracker-ui/scripts/mariadb-browser-connection.mjs'; + +const execute = promisify(execFile); +export async function sql(query) { + const port = process.env.JOBTRACKER_MARIADB_BROWSER_PORT; + const database = validateMariaDbBrowserConnection(process.env.JOBTRACKER_MARIADB_BROWSER_CONNECTION || '', port || ''); + if (port !== '33308' || !process.env.JOBTRACKER_MARIADB_CLIENT) throw new Error('Pinned MariaDB port and native client are required.'); + const { stdout } = await execute(process.env.JOBTRACKER_MARIADB_CLIENT, + ['--host=127.0.0.1', `--port=${port}`, '--user=root', `--database=${database}`, '--batch', '--raw', '--skip-column-names', + `--execute=SET TRANSACTION READ ONLY; START TRANSACTION; ${query}; COMMIT;`], + { encoding: 'utf8', timeout: 15000, maxBuffer: 4 * 1024 * 1024, env: { ...process.env, MYSQL_PWD: 'jt-integration-only' } }); + return stdout.trim(); +} + +export async function snapshot(owner) { + if (!/^[a-zA-Z0-9-]{1,64}$/.test(owner)) throw new Error('Invalid synthetic owner ID.'); + return JSON.parse(await sql(`SELECT JSON_OBJECT( + 'ids',(SELECT JSON_ARRAYAGG(Id ORDER BY Id) FROM JobApplications WHERE OwnerUserId='${owner}'), + 'ownerCount',(SELECT COUNT(*) FROM JobApplications WHERE OwnerUserId='${owner}'), + 'deletedCount',(SELECT COUNT(*) FROM JobApplications WHERE OwnerUserId='${owner}' AND IsDeleted=1), + 'tenantCounts',(SELECT JSON_ARRAYAGG(JSON_OBJECT('owner',OwnerUserId,'count',n) ORDER BY OwnerUserId) + FROM (SELECT OwnerUserId,COUNT(*) n FROM JobApplications GROUP BY OwnerUserId) counts), + 'profile',(SELECT ProfileJson FROM CareerProfiles WHERE OwnerUserId='${owner}'), + 'revision',(SELECT Version FROM CareerProfiles WHERE OwnerUserId='${owner}'), + 'projection',(SELECT ProfileCvStructureJson FROM AspNetUsers WHERE Id='${owner}'), + 'historyCount',(SELECT COUNT(*) FROM CareerProfileVersions WHERE OwnerUserId='${owner}'))`)); +} diff --git a/docs/redesign/phase-9/p9-requal-01/performance/metrics.mjs b/docs/redesign/phase-9/p9-requal-01/performance/metrics.mjs new file mode 100644 index 0000000..66ea9b9 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/performance/metrics.mjs @@ -0,0 +1,38 @@ +import assert from 'node:assert/strict'; +import { performance } from 'node:perf_hooks'; +import { setTimeout as sleep } from 'node:timers/promises'; + +export const durationMs = 15 * 60 * 1000; +export const paceMs = 500; + +export function summarize(rows) { + const values = rows.filter(row => !row.error && row.status === 200).map(row => row.ms).sort((a, b) => a - b); + const percentile = p => values.length ? values[Math.ceil(values.length * p) - 1] : null; + return { attempts: rows.length, failures: rows.filter(row => row.error || row.status !== 200).length, + p50Ms: percentile(.5), p95Ms: percentile(.95), p99Ms: percentile(.99), maxMs: values.at(-1) ?? null }; +} + +export async function waitUntil(target) { + while (performance.now() < target) await sleep(Math.min(1000, target - performance.now())); +} + +export function assertMembership(actual, expected) { + assert.equal(actual.length, 250); + assert.equal(new Set(actual).size, 250); + assert.deepEqual([...actual].sort((a, b) => a - b), [...expected].sort((a, b) => a - b)); +} + +if (process.argv.includes('--self-test')) { + assert.equal(durationMs, 900000); + assert.equal(paceMs, 500); + assert.deepEqual(summarize([]), { attempts: 0, failures: 0, p50Ms: null, p95Ms: null, p99Ms: null, maxMs: null }); + const rows = Array.from({ length: 100 }, (_, i) => ({ ms: i + 1, status: 200 })); + assert.deepEqual(summarize([...rows, { ms: 999, status: 500 }, { ms: 999, error: 'timeout' }]), + { attempts: 102, failures: 2, p50Ms: 50, p95Ms: 95, p99Ms: 99, maxMs: 100 }); + const ids = Array.from({ length: 250 }, (_, i) => i + 1); + assertMembership(ids.toReversed(), ids); + assert.throws(() => assertMembership([...ids.slice(0, 249), 1], ids)); + assert.throws(() => assertMembership([...ids.slice(0, 249), 999], ids)); + assert.throws(() => assertMembership(ids.slice(1), ids)); + console.log('performance metrics self-check passed'); +} diff --git a/docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts b/docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts new file mode 100644 index 0000000..1ad428c --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/performance/playwright.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; +import base from '../../../../../job-tracker-ui/playwright.mariadb.config'; +import path from 'node:path'; + +if (process.env.JOBTRACKER_MARIADB_BROWSER_PORT !== '33308') throw new Error('Requalification requires pinned loopback port 33308.'); +if (process.env.PLAYWRIGHT_STATIC_EXPORT !== 'true' || process.env.PLAYWRIGHT_PREBUILT_EXPORT !== 'true') { + throw new Error('Requalification requires a freshly built production static export.'); +} + +const artifacts = path.resolve('../.artifacts/p9-requal-01/performance'); +export default defineConfig({ ...base, testDir: '.', testMatch: 'sustained.spec.ts', workers: 1, retries: 0, + timeout: 18 * 60 * 1000, outputDir: path.join(artifacts, 'test-results'), + reporter: [['list'], ['json', { outputFile: path.join(artifacts, 'playwright-results.json') }]], +}); diff --git a/docs/redesign/phase-9/p9-requal-01/performance/sustained.spec.ts b/docs/redesign/phase-9/p9-requal-01/performance/sustained.spec.ts new file mode 100644 index 0000000..3ab19a2 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/performance/sustained.spec.ts @@ -0,0 +1,191 @@ +import { test, expect, type APIRequestContext } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; +import os from 'node:os'; +import { performance } from 'node:perf_hooks'; +import { durationMs, paceMs, waitUntil, summarize, assertMembership } from './metrics.mjs'; +import { snapshot, sql } from './mariadb-proof.mjs'; + +const api = 'http://localhost:5302/api'; +const password = 'E2ePassword123!'; +async function login(request: APIRequestContext, email: string) { + expect((await request.post(`${api}/auth/login`, { data: { email, password } })).status()).toBe(200); + const me = await (await request.get(`${api}/auth/me`)).json(); + return { id: me.id as string, headers: { 'X-CSRF-TOKEN': (await request.storageState()).cookies.find(c => c.name === 'XSRF-TOKEN')!.value, + 'X-Session-Context': me.sessionContext as string } }; +} + +test('P9-REQUAL-01 real MariaDB: 15 minutes, 250 applications, two paced readers and native workspaces', async ({ page, context, playwright }, info) => { + const admin = await playwright.request.newContext(); + const readers = await Promise.all([playwright.request.newContext(), playwright.request.newContext()]); + const cdp = await context.newCDPSession(page); + const latency: { worker: number; endpoint: string; ms: number; atMs: number; bytes?: number; status?: number; error?: string }[] = []; + const navigation: { index: number; route: string; atMs: number; readyMs: number; error?: string }[] = []; + const preflightNavigation: typeof navigation = []; + const telemetry: object[] = []; + const ids: number[] = []; + const evidence: Record = { fixtureJobs: 250, fixtureCareerRoles: 8, readConcurrency: 2, paceMs, requiredDurationMs: durationMs, + database: info.config.metadata.mariaDbDatabase, latency, navigation, preflightNavigation, telemetry, ids, phase: 'setup', + environment: { platform: os.platform(), cpus: os.cpus().length, totalMemoryBytes: os.totalmem(), browser: context.browser()?.version(), + databaseProvider: 'MariaDB', frontend: 'prebuilt production static export' }, + limits: 'Bounded local synthetic workload; no SLA, capacity, production, physical-device, model-inference or server CPU attribution claim. Host/Node/CDP telemetry is descriptive.' }; + try { + const server = await sql('SELECT VERSION()'); + expect(server).toMatch(/^12\.2\.2-MariaDB(?:-|$)/); + evidence.server = server; + const adminOwner = await login(admin, 'e2e@example.test'); + const email = `p9-requal-perf-${Date.now()}@example.test`; + // A free synthetic account excludes creation-time model inference from this database/UI workload. + expect((await admin.post(`${api}/users`, { headers: adminOwner.headers, data: { email, password, roles: [] } })).status()).toBe(200); + const owner = await login(page.request, email); + evidence.owner = owner.id; + const company = await page.request.post(`${api}/companies`, { headers: owner.headers, data: { name: 'P9 requalification synthetic workload' } }); + expect(company.status()).toBe(201); + const companyId = (await company.json()).id; + for (let index = 0; index < 250; index++) { + const response = await page.request.post(`${api}/jobapplications`, { headers: owner.headers, + data: { companyId, jobTitle: `P9 requalification role ${index}`, status: 'Applied', dateApplied: new Date().toISOString() } }); + expect(response.status(), `seed application ${index}`).toBe(201); + ids.push((await response.json()).id); + } + const profile = { version: '1', contact: { fullName: 'Åse Synthetic', email: 'synthetic@example.test' }, summary: ['Documented accessible workflows.'], + jobs: Array.from({ length: 8 }, (_, index) => ({ id: `p9-role-${index}`, title: `Platform engineer ${index}`, company: 'Nordlys synthetic', + start: '2017-01', end: '2025-12', bullets: Array.from({ length: 6 }, (_, bullet) => + `Evidence ${index}.${bullet}: ${'Documented reliable workflows. Dokumenterte pålitelige arbeidsflyter. '.repeat(3).trim()}`) })) }; + const initialProfile = await (await page.request.get(`${api}/career/profile`)).json(); + expect((await page.request.put(`${api}/career/profile`, { headers: owner.headers, + data: { expectedVersion: initialProfile.revision, profile } })).status()).toBe(200); + const savedProfile = (await (await page.request.get(`${api}/career/profile`)).json()).profile; + expect(savedProfile.jobs).toHaveLength(8); + expect(savedProfile.jobs.map((job: { start: string; end: string; bullets: string[] }) => ({ start: job.start, end: job.end, bullets: job.bullets }))) + .toEqual(profile.jobs.map(job => ({ start: job.start, end: job.end, bullets: job.bullets }))); + const cv = await page.request.post(`${api}/cv/variants`, { headers: owner.headers, + data: { name: 'P9 requalification long CV', settings: { themeId: 'minimal', language: 'nb' } } }); + expect(cv.status()).toBe(200); + const cvId = (await cv.json()).id; + const before = await snapshot(owner.id); + assertMembership(before.ids, ids); + expect(before.ownerCount).toBe(250); expect(before.deletedCount).toBe(0); + expect(JSON.parse(before.profile)).toEqual(savedProfile); + evidence.before = before; + await Promise.all(readers.map(reader => login(reader, email))); + await page.addInitScript(() => localStorage.setItem('uiLanguage', 'en')); + await context.route('**/*', route => { + const url = new URL(route.request().url()); + return ['localhost', '127.0.0.1'].includes(url.hostname) || ['data:', 'blob:', 'about:'].includes(url.protocol) ? route.continue() : route.abort(); + }); + await cdp.send('Performance.enable'); + const endpoints = ['/jobapplications/stats', '/jobapplications/board', '/career/profile', '/documents']; + const routes = ['/dashboard', '/jobs?view=table', '/jobs?view=board', `/career/builder/${cvId}`]; + evidence.phase = 'preflight'; + for (const endpoint of endpoints) { + const response = await page.request.get(`${api}${endpoint}`, { timeout: 10000 }); + try { + expect(response.status(), `preflight ${endpoint}`).toBe(200); + const body = await response.json(); + if (endpoint.endsWith('/board')) assertMembership(body.map((job: { id: number }) => job.id), ids); + else if (endpoint.endsWith('/profile')) expect(body.profile).toEqual(savedProfile); + else if (endpoint.endsWith('/stats')) expect(body.active).toBe(250); + else expect(Array.isArray(body.items)).toBe(true); + } finally { await response.dispose(); } + } + let started = performance.now(); + let deadline = 0; + const readWorker = async (worker: number) => { + let index = 0; + while (performance.now() < deadline) { + const endpoint = endpoints[index++ % endpoints.length]; + const begin = performance.now(); + const row: typeof latency[number] = { worker, endpoint, atMs: begin - started, ms: 0 }; + try { + const response = await readers[worker].get(`${api}${endpoint}`, { timeout: 10000 }); + try { + row.status = response.status(); row.bytes = (await response.body()).length; + expect(row.status, endpoint).toBe(200); + if (endpoint.endsWith('/board')) assertMembership((await response.json()).map((job: { id: number }) => job.id), ids); + if (endpoint.endsWith('/profile')) expect((await response.json()).profile).toEqual(savedProfile); + } finally { await response.dispose(); } + } catch (error) { row.error = String(error); } + row.ms = performance.now() - begin; + latency.push(row); + // Completion-to-start pacing avoids catch-up bursts after a slow response. + await waitUntil(Math.min(deadline, performance.now() + paceMs)); + } + }; + const interact = async (preflight = false) => { + for (let index = 0; index < (preflight ? 4 : 20); index++) { + if (!preflight) await waitUntil(started + index * durationMs / 20); + const route = routes[index % routes.length]; + const begin = performance.now(); + const row: typeof navigation[number] = { index, route, atMs: begin - started, readyMs: 0 }; + try { + await page.goto(route, { timeout: 20000 }); + if (route === '/dashboard') await expect(page.getByRole('link', { name: 'Tracked jobs: 250', exact: true })).toBeVisible(); + else if (route.endsWith('board')) { + await expect(page.locator('[data-kanban-card-id]')).toHaveCount(250); + assertMembership(await page.locator('[data-kanban-card-id]').evaluateAll(elements => elements.map(element => Number(element.getAttribute('data-kanban-card-id')))), ids); + } else if (route.endsWith('table')) await expect(page.locator('[data-job-row-id]').first()).toBeVisible(); + else { + await expect(page.getByRole('region', { name: 'Live preview', exact: true })).toHaveAttribute('aria-busy', 'false'); + const measured = await page.getByTitle('CV preview', { exact: true }).evaluate(element => { + const doc = (element as HTMLIFrameElement).contentDocument!; + const pages = Number(doc.documentElement.dataset.cvPreviewPages); + const width = Number(doc.documentElement.dataset.cvPreviewWidth); + const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT); + let node; let finalMarkerPage = 0; + while ((node = walker.nextNode())) { + const index = node.textContent?.indexOf('Evidence 7.5:') ?? -1; + if (index < 0) continue; + const range = doc.createRange(); range.setStart(node, index); range.setEnd(node, index + 'Evidence 7.5:'.length); + finalMarkerPage = Math.floor(range.getClientRects()[0].x / width) + 1; + } + return { pages, finalMarkerPage, ready: doc.documentElement.dataset.cvPreviewReady }; + }); + expect(measured.ready).toBe('true'); expect(measured.pages).toBeGreaterThan(1); + expect(measured.finalMarkerPage).toBe(measured.pages); + await expect(page.locator('[data-cv-page]')).toHaveCount(measured.pages); + await expect(page.getByTitle('CV preview page 1', { exact: true })).toBeVisible(); + } + telemetry.push({ phase: preflight ? 'preflight' : 'workload', atMs: performance.now() - started, metrics: (await cdp.send('Performance.getMetrics')).metrics, + domElements: await page.locator('*').count(), hostFreeMemoryBytes: os.freemem(), hostLoadAverage: os.loadavg(), + nodeMemoryBytes: process.memoryUsage(), nodeCpuMicroseconds: process.cpuUsage() }); + } catch (error) { row.error = String(error); } + row.readyMs = performance.now() - begin; + (preflight ? preflightNavigation : navigation).push(row); + if (preflight) expect(row.error, `preflight ${route}`).toBeUndefined(); + } + }; + await interact(true); + evidence.preflightPassed = true; + evidence.phase = 'workload'; + started = performance.now(); + deadline = started + durationMs; + evidence.startedUtc = new Date().toISOString(); + await Promise.all([readWorker(0), readWorker(1), interact()]); + evidence.actualDurationMs = performance.now() - started; + evidence.finishedUtc = new Date().toISOString(); + evidence.phase = 'preservation'; + expect(evidence.actualDurationMs).toBeGreaterThanOrEqual(durationMs); + const after = await snapshot(owner.id); + evidence.after = after; + assertMembership(after.ids, ids); + expect(after).toEqual(before); + const finalBoard = await page.request.get(`${api}/jobapplications/board`); + expect(finalBoard.status()).toBe(200); + assertMembership((await finalBoard.json()).map((job: { id: number }) => job.id), ids); + expect((await (await page.request.get(`${api}/career/profile`)).json()).profile).toEqual(savedProfile); + expect(summarize(latency).failures).toBe(0); + expect(navigation).toHaveLength(20); expect(navigation.filter(row => row.error)).toEqual([]); + for (const worker of [0, 1]) { + const rows = latency.filter(row => row.worker === worker); + expect(rows.length).toBeGreaterThan(0); + for (let index = 1; index < rows.length; index++) expect(rows[index].atMs - rows[index - 1].atMs).toBeGreaterThanOrEqual(paceMs); + expect(rows.at(-1)!.atMs).toBeGreaterThan(durationMs - 15000); + } + evidence.phase = 'complete'; + } finally { + evidence.summary = summarize(latency); + evidence.byEndpoint = Object.fromEntries([...new Set(latency.map(row => row.endpoint))].map(endpoint => [endpoint, summarize(latency.filter(row => row.endpoint === endpoint))])); + evidence.navigationFailures = navigation.filter(row => row.error).length; + await info.attach('p9-requal-01-mariadb-performance', { body: JSON.stringify(evidence, null, 2), contentType: 'application/json' }); + await cdp.detach(); await admin.dispose(); await Promise.all(readers.map(reader => reader.dispose())); + } +}); diff --git a/docs/redesign/phase-9/p9-requal-01/preservation.json b/docs/redesign/phase-9/p9-requal-01/preservation.json new file mode 100644 index 0000000..d55ae17 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/preservation.json @@ -0,0 +1,3818 @@ +{ + "schemaVersion": 1, + "baselineCommit": "549b2cba5a791862ba3f854312ea819a86dc42a0", + "counts": { + "groups": 57, + "partial": 56, + "deferred": 1, + "routes": 33 + }, + "policy": "Residual-specific retained statuses, not a blanket defect FAIL. Historical source is immutable; new evidence closes only mapped criteria. Fresh execution is owned by root validation.", + "groups": [ + { + "id": "PRES-E01", + "capability": "**PRES-E01** — Public product/plans; honest unavailable billing", + "owners": "LandingPage, planCatalog; AccountPlans", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "landing-presentation.spec.ts", + "title": "[P9 PRES-E01 E08] en wrapped landing headings keep separate text lines" + }, + { + "file": "landing-presentation.spec.ts", + "title": "[P9 PRES-E01 E08] nb wrapped landing headings keep separate text lines" + } + ], + "remaining": "Public-page complete mobile/keyboard review and actual billing availability; no invented prices", + "delta": "Finite full regression retained; human/provider/output qualifications remain. P9-V01/P9-V02 proportional heading and CTA fixes; two native cases retain16-vector geometry proof.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 0, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "LandingPage, planCatalog; AccountPlans", + "requiredClosure": "Public-page complete mobile/keyboard review and actual billing availability; no invented prices", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E02", + "capability": "**PRES-E02** — Local login/register/remember, challenge, reset and verification", + "owners": "LoginPage, TurnstileWidget, VerifyEmailPage; AuthController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Real mail/reset submit/Turnstile and token expiry/used-token cases; query loss is repaired for its tested scope", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 1, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "LoginPage, TurnstileWidget, VerifyEmailPage; AuthController", + "requiredClosure": "Real mail/reset submit/Turnstile and token expiry/used-token cases; query loss is repaired for its tested scope", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E03", + "capability": "**PRES-E03** — Google/Microsoft login, link, legacy relink and popup results", + "owners": "GoogleAuthCard, MicrosoftAuthCard, MicrosoftLegacyRelinkPage; token validators", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Actual consent/popups/revoked grants/relink; mailbox grants remain separate from sign-in", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 2, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "GoogleAuthCard, MicrosoftAuthCard, MicrosoftLegacyRelinkPage; token validators", + "requiredClosure": "Actual consent/popups/revoked grants/relink; mailbox grants remain separate from sign-in", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E04", + "capability": "**PRES-E04** — 2FA challenge/recovery/setup/disable; trusted-device revocation", + "owners": "TwoFactorSettingsCard, TwoFactorChallenge; TwoFactorController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E04 E08] failed 2FA status is read-only and deliberate retry restores the actual disabled state" + } + ], + "remaining": "Real authenticator/recovery and reader/trusted-device traversal; sensitive confirmations retained", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 3, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "TwoFactorSettingsCard, TwoFactorChallenge; TwoFactorController", + "requiredClosure": "Real authenticator/recovery and reader/trusted-device traversal; sensitive confirmations retained", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E05", + "capability": "**PRES-E05** — Session list/current device, revoke one/others, logout", + "owners": "SessionsSettingsCard, AppShell, auth; SessionsController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "account-isolation.spec.ts", + "title": "[P5-00 PRES-E05 E07 E08] account switch disposes open command, account and notification surfaces" + }, + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E05 E08 E09] native sessions cancel no-write, failed confirmed revoke stays in the dialog, retry revokes others and current logout disposes account" + } + ], + "remaining": "Native session-card refresh after remote revocation and complete device/AT acceptance", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 4, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "SessionsSettingsCard, AppShell, auth; SessionsController", + "requiredClosure": "Native session-card refresh after remote revocation and complete device/AT acceptance", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E06", + "capability": "**PRES-E06** — Avatar, account names/headline, email change and password", + "owners": "ProfilePage; AuthController, AvatarStorage", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E06 E08 E09 C01 C07] nb/dark 320px account identity save reload preserves canonical and sibling CVs" + }, + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E06 E08 E09 C01 C07] en/light 390px account identity save reload preserves canonical and sibling CVs" + }, + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E06 E08 E09 C01 C07] nb/light 768px account identity save reload preserves canonical and sibling CVs" + }, + { + "file": "phase7-account-security.spec.ts", + "title": "[P7-01 PRES-E06 E08 E09 C01 C07] en/dark 1440px account identity save reload preserves canonical and sibling CVs" + } + ], + "remaining": "Complete avatar/remove/password/email-change native flow; account identity remains distinct from career facts", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 5, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "ProfilePage; AuthController, AvatarStorage", + "requiredClosure": "Complete avatar/remove/password/email-change native flow; account identity remains distinct from career facts", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E07", + "capability": "**PRES-E07** — Desktop collapse/mobile drawer, active nav and command search/actions", + "owners": "AppShell, QuickCommandDialog; job/company search APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-E07 PRES-W01 PRES-J04] keyboard command navigation and legacy workspace entry preserve the selected job" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-A01 PRES-S04 PRES-E07] non-admin navigation cannot grant API privileges or unlock CV AI" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] light loaded status semantics, navigation and command focus" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] dark loaded status semantics, navigation and command focus" + }, + { + "file": "settings-page-layout.spec.ts", + "title": "[PRES-E07 E08 E09 S03 S04 S05 J05 J10 M06 W11] light/en Settings headings, reflow and retained actions" + }, + { + "file": "settings-page-layout.spec.ts", + "title": "[PRES-E07 E08 E09 S03 S04 S05 J05 J10 M06 W11] light/nb Settings headings, reflow and retained actions" + }, + { + "file": "settings-page-layout.spec.ts", + "title": "[PRES-E07 E08 E09 S03 S04 S05 J05 J10 M06 W11] dark/en Settings headings, reflow and retained actions" + }, + { + "file": "settings-page-layout.spec.ts", + "title": "[PRES-E07 E08 E09 S03 S04 S05 J05 J10 M06 W11] dark/nb Settings headings, reflow and retained actions" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E08 A03] light-en mobile labels, focus and admin reflow" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 J03 J08] light-en command list, keyboard and no-write actions" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-02 PRES-E07 E08 E09 S02] light-en utility search and notification states" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-01 PRES-E07 E08 A03] light-en grouped shell, rail menu and route focus" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E09 C06 S02 S03] light-en dirty editor survives shell utilities and cancel" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E08 A03] light-nb mobile labels, focus and admin reflow" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 J03 J08] light-nb command list, keyboard and no-write actions" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-02 PRES-E07 E08 E09 S02] light-nb utility search and notification states" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-01 PRES-E07 E08 A03] light-nb grouped shell, rail menu and route focus" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E08 A03] dark-en mobile labels, focus and admin reflow" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 J03 J08] dark-en command list, keyboard and no-write actions" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-02 PRES-E07 E08 E09 S02] dark-en utility search and notification states" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-01 PRES-E07 E08 A03] dark-en grouped shell, rail menu and route focus" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E08 A03] dark-nb mobile labels, focus and admin reflow" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 J03 J08] dark-nb command list, keyboard and no-write actions" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-02 PRES-E07 E08 E09 S02] dark-nb utility search and notification states" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-01 PRES-E07 E08 A03] dark-nb grouped shell, rail menu and route focus" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E07 E09 C06 S02 S03] dark-nb dirty editor survives shell utilities and cancel" + } + ], + "remaining": "Spoken names/live state, settled drawer AX-name triage and historical command/dialog timing; no route silently hidden", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 6, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "AppShell, QuickCommandDialog; job/company search APIs", + "requiredClosure": "Spoken names/live state, settled drawer AX-name triage and historical command/dialog timing; no route silently hidden", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E08", + "capability": "**PRES-E08** — Theme/system, EN/NB hydration, toast/confirm/prompt and errors", + "owners": "themePrefs, I18nProvider, confirm, prompt; auth preference", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/en preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/en preview keyboard, pagination and responsive state" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, dark)" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/en/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/en/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/nb/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/nb/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] light loaded status semantics, navigation and command focus" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/en/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/en/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/nb/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/nb/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] dark loaded status semantics, navigation and command focus" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E08 C06 S05] light-en real Tooltip contrast and open-toast action access" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E08 C06 S05] light-nb real Tooltip contrast and open-toast action access" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E08 C06 S05] dark-en real Tooltip contrast and open-toast action access" + }, + { + "file": "shell-readiness.spec.ts", + "title": "[P5-00 PRES-E08 C06 S05] dark-nb real Tooltip contrast and open-toast action access" + } + ], + "remaining": "Full OS/locale/state cross-product, contrast/incomplete axe, reader/reflow; save feedback is distinct from server500 root-cause repair", + "delta": "Finite full regression retained; human/provider/output qualifications remain. P9-L01 installed vendor locale and2new Jest cases.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 7, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "themePrefs, I18nProvider, confirm, prompt; auth preference", + "requiredClosure": "Full OS/locale/state cross-product, contrast/incomplete axe, reader/reflow; save feedback is distinct from server500 root-cause repair", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-E09", + "capability": "**PRES-E09** — Account-switch private-state disposal and stale request rejection", + "owners": "App, api, sessionBoundary; SessionContextMiddleware", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "analytics-auth-repair.spec.ts", + "title": "[P5-15-01R-03 PRES-E09] another protected section keeps its destination without bypassing ownership or unsafe-target validation" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, dark)" + }, + { + "file": "rules-draft-repair.spec.ts", + "title": "[P5-15-01R-02 PRES-E09] Rules API ignores forged owners and account switching disposes the previous draft" + } + ], + "remaining": "Broader BFCache/offline/old-bundle/deployed cases; presentation never becomes authorization", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 8, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "App, api, sessionBoundary; SessionContextMiddleware", + "requiredClosure": "Broader BFCache/offline/old-bundle/deployed cases; presentation never becomes authorization", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J01", + "capability": "**PRES-J01** — NAV discovery/filter/sort/source/deadline/details", + "owners": "JobDiscoveryPage; JobDiscoveryController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Live NAV availability/freshness and long-result keyboard/narrow traversal", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 9, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "JobDiscoveryPage; JobDiscoveryController", + "requiredClosure": "Live NAV availability/freshness and long-result keyboard/narrow traversal", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J02", + "capability": "**PRES-J02** — Saved searches, run/delete/alerts, result changes/dismissal", + "owners": "JobDiscoveryPage; saved-search/alert services", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Actual scheduler-to-owned-notification delivery, human/mobile delete acceptance and intended-provider qualification; deterministic runner is not live NAV", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 10, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "JobDiscoveryPage; saved-search/alert services", + "requiredClosure": "Actual scheduler-to-owned-notification delivery, human/mobile delete acceptance and intended-provider qualification; deterministic runner is not live NAV", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J03", + "capability": "**PRES-J03** — Reviewed manual/URL/paste job create, company/tags/dates, duplicates", + "owners": "AddJobModal; JobImportService, JobApplicationsController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Duplicate/company/date/interrupted creation and distinct creation-intent idempotency debt; preview/open is no-write", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 11, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "AddJobModal; JobImportService, JobApplicationsController", + "requiredClosure": "Duplicate/company/date/interrupted creation and distinct creation-intent idempotency debt; preview/open is no-write", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J04", + "capability": "**PRES-J04** — Extension/bookmarklet/share capture; post-create attachment/CV", + "owners": "App, captureUrl, QuickCaptureCard; job/CV APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-E07 PRES-W01 PRES-J04] keyboard command navigation and legacy workspace entry preserve the selected job" + } + ], + "remaining": "Installed extension/share/no-replay and attachment failure recovery; keep payload and safe-return contracts", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 12, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "App, captureUrl, QuickCaptureCard; job/CV APIs", + "requiredClosure": "Installed extension/share/no-replay and attachment failure recovery; keep payload and safe-return contracts", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J05", + "capability": "**PRES-J05** — Job filters/sort/page/columns, saved views and row/mobile actions", + "owners": "JobTable, SavedViewsMenu; JobApplicationsController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "board-presentation.spec.ts", + "title": "[PRES-J05 J07 E07 W01] legacy Board replaces history and preserves query, hash and route state; default Jobs stays Table" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] light loaded status semantics, navigation and command focus" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] dark loaded status semantics, navigation and command focus" + }, + { + "file": "table-density.spec.ts", + "title": "[PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities" + }, + { + "file": "table-density.spec.ts", + "title": "[PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities" + }, + { + "file": "table-density.spec.ts", + "title": "[PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities" + }, + { + "file": "table-density.spec.ts", + "title": "[PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities" + } + ], + "remaining": "Full saved-view CRUD/dirty page-size/history combinations and supported capacity; server query semantics unchanged", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 13, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "separate AI/model qualification; no activation" + ], + "owner": "JobTable, SavedViewsMenu; JobApplicationsController", + "requiredClosure": "Full saved-view CRUD/dirty page-size/history combinations and supported capacity; server query semantics unchanged", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J06", + "capability": "**PRES-J06** — Bulk status/delete, soft delete/trash/restore and job edit", + "owners": "JobTable, EditJobDialog; job lifecycle/controller", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Complete selected-scope/partial-failure/dirty/manual combinations; no hard-delete substitution", + "delta": "Finite full regression retained; human/provider/output qualifications remain. RD21 stale-write safety FAIL; see separate contract issue.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 14, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "JobTable, EditJobDialog; job lifecycle/controller", + "requiredClosure": "Complete selected-scope/partial-failure/dirty/manual combinations; no hard-delete substitution", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J07", + "capability": "**PRES-J07** — Kanban grouped statuses, pointer/keyboard move and precise menu", + "owners": "KanbanBoard, pipeline; status endpoint", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "board-presentation.spec.ts", + "title": "[PRES-J07 J05 W01 W02 E07 E08 E09] Board query membership matches Table and preserves moves, focus and route" + }, + { + "file": "board-presentation.spec.ts", + "title": "[PRES-J07 E08] Board loading, retryable error and fully empty columns" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] light loaded status semantics, navigation and command focus" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J05 PRES-J07] dark loaded status semantics, navigation and command focus" + } + ], + "remaining": "Physical drag/touch/browser variants and O(N) full-array capacity; no capped hidden results or pipeline redefinition", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 15, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "KanbanBoard, pipeline; status endpoint", + "requiredClosure": "Physical drag/touch/browser variants and O(N) full-array capacity; no capped hidden results or pipeline redefinition", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J08", + "capability": "**PRES-J08** — Company/contact edits, pipeline dates and linked-job history", + "owners": "CompaniesTable; company relationship APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/en/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/en/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/nb/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] light/nb/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/en/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/en/390 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/nb/1440 loading → error → retry → empty → populated" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-J08] dark/nb/390 loading → error → retry → empty → populated" + } + ], + "remaining": "Scoped in-modal failure proof follows P6 manifest; complete contact/date/source-link and human acceptance remain", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 16, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CompaniesTable; company relationship APIs", + "requiredClosure": "Scoped in-modal failure proof follows P6 manifest; complete contact/date/source-link and human acceptance remain", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J09", + "capability": "**PRES-J09** — Recorded offers/compensation/deadlines/notes and source links", + "owners": "OfferComparisonPage; job API", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Many-offer mobile/currency/date acceptance; no invented salary normalization", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 17, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "OfferComparisonPage; job API", + "requiredClosure": "Many-offer mobile/currency/date acceptance; no invented salary normalization", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-J10", + "capability": "**PRES-J10** — CSV/JSON export, JSON import and CSV-to-JSON conversion", + "owners": "ImportExportJobs; CSV/job controller", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Complete native roundtrip and target spreadsheet compatibility; job import is not account restore", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 18, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "ImportExportJobs; CSV/job controller", + "requiredClosure": "Complete native roundtrip and target spreadsheet compatibility; job import is not account restore", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W01", + "capability": "**PRES-W01** — Full workspace, sections, legacy links and optional reusable overlay", + "owners": "ApplicationWorkspacePage, jobWorkspaceRoute; workspace API", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "job-overview-presentation.spec.ts", + "title": "[PRES-W01 W02 W03 J05 E08 E09] native Job header/Overview retains actions, custom status, aliases and mobile progress keyboard access" + }, + { + "file": "job-overview-presentation.spec.ts", + "title": "[PRES-W01 W02 E08] Job Overview loading, failed read, retry and unavailable resource remain explicit" + }, + { + "file": "job-sections-presentation.spec.ts", + "title": "[PRES-W01 W08 M01 E08] Job section loading and partial read failures stay explicit and recover locally" + }, + { + "file": "job-sections-presentation.spec.ts", + "title": "[PRES-W01–W11 E08 E09] native Job sections retain drafts, frozen documents, tasks and history (en, light)" + }, + { + "file": "job-sections-presentation.spec.ts", + "title": "[PRES-W01–W11 E08 E09] native Job sections retain drafts, frozen documents, tasks and history (en, dark)" + }, + { + "file": "job-sections-presentation.spec.ts", + "title": "[PRES-W01–W11 E08 E09] native Job sections retain drafts, frozen documents, tasks and history (nb, light)" + }, + { + "file": "job-sections-presentation.spec.ts", + "title": "[PRES-W01–W11 E08 E09] native Job sections retain drafts, frozen documents, tasks and history (nb, dark)" + }, + { + "file": "phase7-application-forms.spec.ts", + "title": "[P7-06 PRES-W01 W04 W10] same-route job navigation waits for owned answers and preserves both jobs on save" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W05 PRES-W06 PRES-W07 PRES-W08] legacy workspace preserves frozen documents after current sources change" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-E07 PRES-W01 PRES-J04] keyboard command navigation and legacy workspace entry preserve the selected job" + } + ], + "remaining": "`followMode` metadata retained; compose consumer deferred. P5-05 optional preview lacks production host; full page remains", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 19, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "ApplicationWorkspacePage, jobWorkspaceRoute; workspace API", + "requiredClosure": "`followMode` metadata retained; compose consumer deferred. P5-05 optional preview lacks production host; full page remains", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "contains separately deferred scope, retain exact residual" + } + }, + { + "id": "PRES-W02", + "capability": "**PRES-W02** — Detail/status/progression, recruiter/dates/description/timeline", + "owners": "WorkspaceHeader, JobDetailsSection, ApplicationProgress/Timeline; workflow APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Stored-event localisation/timezones/status-reload combinations ; job stale-replacement contract repaired within qualified MariaDB 12.2.2 scope", + "delta": "Finite full regression retained; human/provider/output qualifications remain. RD21 stale-write safety FAIL; see separate contract issue.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 20, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "WorkspaceHeader, JobDetailsSection, ApplicationProgress/Timeline; workflow APIs", + "requiredClosure": "Stored-event localisation/timezones/status-reload combinations ; job stale-replacement contract repaired within qualified MariaDB 12.2.2 scope", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W03", + "capability": "**PRES-W03** — Analysis, match/gaps, strategy and reviewed status/workflow suggestions", + "owners": "ApplicationAnalysis/Match/StrategySnapshot/StatusSuggestion; intelligence/AI services", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Real-model truthfulness/freshness/cancel quality; route entry never auto-generates; unrelated AI survives C11 withholding", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 21, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "separate AI/model qualification; no activation" + ], + "owner": "ApplicationAnalysis/Match/StrategySnapshot/StatusSuggestion; intelligence/AI services", + "requiredClosure": "Real-model truthfulness/freshness/cancel quality; route entry never auto-generates; unrelated AI survives C11 withholding", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W04", + "capability": "**PRES-W04** — Checklist create/edit/complete/delete/order and next action", + "owners": "ApplicationChecklist; checklist service/controller", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, dark)" + } + ], + "remaining": "Mobile interruption/edit/delete/reader; item identity and keyboard alternatives retained; no invented due-date schema", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 22, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "ApplicationChecklist; checklist service/controller", + "requiredClosure": "Mobile interruption/edit/delete/reader; item identity and keyboard alternatives retained; no invented due-date schema", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W05", + "capability": "**PRES-W05** — Attach/select/create/tailor CV and source context", + "owners": "ApplicationCvSection/TailoringSection; ApplicationAssetsService", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W05 PRES-W06 PRES-W07 PRES-W08] legacy workspace preserves frozen documents after current sources change" + } + ], + "remaining": "**P2-D01 remains ordinary passing**; broader attach-render/model/deployed combinations remain; owner/job association unchanged", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 23, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification", + "separate AI/model qualification; no activation" + ], + "owner": "ApplicationCvSection/TailoringSection; ApplicationAssetsService", + "requiredClosure": "**P2-D01 remains ordinary passing**; broader attach-render/model/deployed combinations remain; owner/job association unchanged", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W06", + "capability": "**PRES-W06** — Cover-letter manual/AI review, versions/restore and dirty protection", + "owners": "ApplicationCoverLetterSection, CoverLetterAiAssistant; assets/history", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W05 PRES-W06 PRES-W07 PRES-W08] legacy workspace preserves frozen documents after current sources change" + } + ], + "remaining": "Complete native history/reject/reader/model combinations; no canonical mutation or auto-send", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 24, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "separate AI/model qualification; no activation" + ], + "owner": "ApplicationCoverLetterSection, CoverLetterAiAssistant; assets/history", + "requiredClosure": "Complete native history/reject/reader/model combinations; no canonical mutation or auto-send", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W07", + "capability": "**PRES-W07** — Application drafts and immutable submitted package/archived binaries", + "owners": "ApplicationPackageDraftsSection, SubmittedPackagesSection; package service/storage", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W05 PRES-W06 PRES-W07 PRES-W08] legacy workspace preserves frozen documents after current sources change" + } + ], + "remaining": "Actual production restore/rollback/all-storage combinations; current edits/delete cannot mutate frozen bytes; capture is not delivery", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 25, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25", + "independent output/storage/deployment qualification" + ], + "owner": "ApplicationPackageDraftsSection, SubmittedPackagesSection; package service/storage", + "requiredClosure": "Actual production restore/rollback/all-storage combinations; current edits/delete cannot mutate frozen bytes; capture is not delivery", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W08", + "capability": "**PRES-W08** — Attachments upload/category/name/AI consent/preview/download/delete", + "owners": "Attachments; AttachmentsController, AttachmentStorage", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W05 PRES-W06 PRES-W07 PRES-W08] legacy workspace preserves frozen documents after current sources change" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (en, dark)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, light)" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-W01 PRES-W04 PRES-W08 PRES-E08 PRES-E09] native workspace aliases, keyboard sections and history retain context (nb, dark)" + } + ], + "remaining": "Physical drop, full rename/download/reader and deployed storage; AI inclusion remains explicit", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 26, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "Attachments; AttachmentsController, AttachmentStorage", + "requiredClosure": "Physical drop, full rename/download/reader and deployed storage; AI inclusion remains explicit", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W09", + "capability": "**PRES-W09** — Interview questions/answers/ready/manual removal/AI review", + "owners": "InterviewPrep; interview persistence/AI endpoints", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Real-model and physical software-keyboard/reload/reader; preparation is not a scheduled interview", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 27, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "separate AI/model qualification; no activation" + ], + "owner": "InterviewPrep; interview persistence/AI endpoints", + "requiredClosure": "Real-model and physical software-keyboard/reload/reader; preparation is not a scheduled interview", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W10", + "capability": "**PRES-W10** — Debrief/follow-up draft/date/readiness", + "owners": "InterviewPrep; follow-up draft services", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Timezones/provider delivery; `followMode` reviewed compose UI remains deferred, no automatic send", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 28, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "InterviewPrep; follow-up draft services", + "requiredClosure": "Timezones/provider delivery; `followMode` reviewed compose UI remains deferred, no automatic send", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "contains separately deferred scope, retain exact residual" + } + }, + { + "id": "PRES-W11", + "capability": "**PRES-W11** — Reminder rules/actions/notifications, ICS and Google/Outlook events", + "owners": "RemindersView, RulesSettingsCard, ApplicationCalendarActions; calendar/rules APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-S03 PRES-W11] responsive settings navigation keeps rule edits and persists notification preferences" + } + ], + "remaining": "F21 DST/date-only/offsets, real provider events/scheduler delivery and historical unconfirmed Rules500 cause", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 29, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "RemindersView, RulesSettingsCard, ApplicationCalendarActions; calendar/rules APIs", + "requiredClosure": "F21 DST/date-only/offsets, real provider events/scheduler delivery and historical unconfirmed Rules500 cause", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-W12", + "capability": "**PRES-W12** — Async progress/failure/retry/cancel/notifications", + "owners": "OperationsPage, CareerProfilePage; operation store/worker", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Disconnect/reconnect and F20 enabled-worker fault recovery; stable operation IDs/no duplicate starts", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 30, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "OperationsPage, CareerProfilePage; operation store/worker", + "requiredClosure": "Disconnect/reconnect and F20 enabled-worker fault recovery; stable operation IDs/no duplicate starts", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C01", + "capability": "**PRES-C01** — Canonical structured career data and long-tail/custom sections", + "owners": "CareerProfilePage, career views; CareerProfileService/controller", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured and raw drafts survive English to Bokmål without canonical refetch or write" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] held save locks edits and duplicate writes; failed save retains its snapshot for explicit identical-body retry" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] actual validation400 retains draft and source; corrected explicit save persists once" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry nb/dark/320x844" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry en/light/360x800" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry nb/light/390x844" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry en/dark/768x1024" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry nb/dark/1024x768" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry en/light/1280x320" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry nb/light/1440x900" + }, + { + "file": "phase7-career-editor.spec.ts", + "title": "[P7-03 PRES-C01 C02 E08] structured editor headings, contextual actions and geometry en/dark/1920x1080" + }, + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C01 C02 C03 C04 C05 W07] explicit select/deselect acceptance uses stable IDs and preserves raw, CV siblings and frozen snapshots" + }, + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C01 C02 C04] discarding stored review retains dirty structured and CURRENT raw drafts without a source write" + }, + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C01 C02] version Restore appends a new structured version and preserves CURRENT raw text" + }, + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C01 C02 C04 E08] history read retry and settled review/history presentation across eight widths" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] nb/dark 320px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] en/light 360px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] nb/light 390px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] en/dark 768px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] nb/dark 1024px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] en/light 1280px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] nb/light 1440px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02 C04 C05 E08 E09] en/dark 1920px overview and factual evidence preserve canonical source and recent CV links" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C01 C02] existing raw source copy and history entry remain read-only" + }, + { + "file": "phase7-career-source-ids.spec.ts", + "title": "[P7-03 PRES-C01 C03 C06 C07 C10 W05 W06] unrelated canonical UI save preserves four source IDs, existing CV overrides, sibling and frozen package" + }, + { + "file": "phase7-career-source-ids.spec.ts", + "title": "[P7-03 PRES-C01 C03 E05 E09] real HTTP bounds canonical last-writer saves and structured-history recovery without claiming stale-write protection" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-C01 PRES-C06 PRES-C07 PRES-C10] mobile CV override persists without changing the canonical profile or sibling CV" + } + ], + "remaining": "Full long-tail mobile/human acceptance; canonical concurrency has bounded SQLite/MariaDB repair proof; singleton source distinct from identified variants", + "delta": "Finite full regression retained; human/provider/output qualifications remain. RD21 stale-write safety FAIL; see separate contract issue.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 31, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CareerProfilePage, career views; CareerProfileService/controller", + "requiredClosure": "Full long-tail mobile/human acceptance; canonical concurrency has bounded SQLite/MariaDB repair proof; singleton source distinct from identified variants", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C02", + "capability": "**PRES-C02** — Profile overview/completeness/import guidance/raw copy/history/restore", + "owners": "CareerWorkspacePage, CareerProfilePage; version service", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C02 C04 E09] stored reviews are owner scoped and foreign/anonymous review actions cannot mutate source" + }, + { + "file": "phase7-career-import-review.spec.ts", + "title": "[P7-03 PRES-C02 C04 E08] comparison GET failure has scoped retry and held loading without source mutation" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C02 E09] unavailable /career/profile stays unknown and retries its reads without writes or false first-run guidance" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C02 E09] unavailable /profile-cv/runs stays unknown and retries its reads without writes or false first-run guidance" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C02 E09] unavailable /cv/variants stays unknown and retries its reads without writes or false first-run guidance" + } + ], + "remaining": "Complete native historical restore/clipboard/avatar/reader; live inherited CVs may reflect later source changes", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 32, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md", + "docs/database/mariadb-standardisation/ACCEPTANCE.md", + "docs/redesign/phase-9/p9-requal-01/RD21_CLOSURE.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "CareerWorkspacePage, CareerProfilePage; version service", + "requiredClosure": "Complete native historical restore/clipboard/avatar/reader; live inherited CVs may reflect later source changes", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C03", + "capability": "**PRES-C03** — Upload/extract/rebuild/reprocess/diff/select/accept/discard/retry/cancel", + "owners": "CareerProfilePage; profile-CV/processing/diff services", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Scanned/OCR corpus and complete low-confidence/discard/native-reader flow; extracted proposal is not canonical truth", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 33, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CareerProfilePage; profile-CV/processing/diff services", + "requiredClosure": "Scanned/OCR corpus and complete low-confidence/discard/native-reader flow; extracted proposal is not canonical truth", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C04", + "capability": "**PRES-C04** — Evidence bank source/category/tags/add/list/delete", + "owners": "CareerEvidenceBank; CareerEvidenceController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C04 E09] real SQLite evidence list preserves owner boundaries and existing validation" + }, + { + "file": "phase7-career-overview.spec.ts", + "title": "[P7-02 PRES-C04 E09] evidence pending/failure/read retry and failed save preserve drafts across section changes, cancellation and actual deletion" + } + ], + "remaining": "Many-item/delete/keyboard/human acceptance; SQLite compatibility repaired with owner SQL preserved, full frontend/production acceptance remains qualified", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 34, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "CareerEvidenceBank; CareerEvidenceController", + "requiredClosure": "Many-item/delete/keyboard/human acceptance; SQLite compatibility repaired with owner SQL preserved, full frontend/production acceptance remains qualified", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C05", + "capability": "**PRES-C05** — CV library create/copy/delete/templates/share/publication/PDF", + "owners": "CvBuilderPage, thumbnails; CvVariantService/PublicCvController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "cv-editor-frame.spec.ts", + "title": "[PRES-C05 C06 C07 C10 W05 E08] light/en CV frame navigation, actions and pending editing" + }, + { + "file": "cv-editor-frame.spec.ts", + "title": "[PRES-C05 C06 C07 C10 W05 E08] dark/nb CV frame navigation, actions and pending editing" + }, + { + "file": "cv-editor-frame.spec.ts", + "title": "[PRES-C05 C06 C07 C10 W05 E08] light/nb CV frame navigation, actions and pending editing" + }, + { + "file": "cv-editor-frame.spec.ts", + "title": "[PRES-C05 C06 C07 C10 W05 E08] dark/en CV frame navigation, actions and pending editing" + }, + { + "file": "cv-responsive-workflow.spec.ts", + "title": "[PRES-C05 C06 C07 E08] emulated touch taps pane actions and the accessible entry-order alternative" + }, + { + "file": "cv-responsive-workflow.spec.ts", + "title": "[PRES-C05 C06 C07 C10 E08 E09] light/en responsive panes retain draft, source, pointer order and revision recovery" + }, + { + "file": "cv-responsive-workflow.spec.ts", + "title": "[PRES-C05 C06 C07 C10 E08 E09] dark/nb responsive panes retain draft, source, pointer order and revision recovery" + }, + { + "file": "cv-responsive-workflow.spec.ts", + "title": "[PRES-C05 C06 C07 C10 E08 E09] light/nb responsive panes retain draft, source, pointer order and revision recovery" + }, + { + "file": "cv-responsive-workflow.spec.ts", + "title": "[PRES-C05 C06 C07 C10 E08 E09] dark/en responsive panes retain draft, source, pointer order and revision recovery" + }, + { + "file": "cv-section-scope.spec.ts", + "title": "[PRES-C05 C07 C10 W05 E08] light/en CV field scope, source resets, entry order and custom content" + }, + { + "file": "cv-section-scope.spec.ts", + "title": "[PRES-C05 C07 C10 W05 E08] dark/nb CV field scope, source resets, entry order and custom content" + }, + { + "file": "cv-section-scope.spec.ts", + "title": "[PRES-C05 C07 C10 W05 E08] light/nb CV field scope, source resets, entry order and custom content" + }, + { + "file": "cv-section-scope.spec.ts", + "title": "[PRES-C05 C07 C10 W05 E08] dark/en CV field scope, source resets, entry order and custom content" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 E08] failed list has an explicit keyboard retry with held progress, stable focus and actual recovery" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C08 E08] locale-retained create draft locks during held failure and retries one identical snapshot" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C07 C10 W07] keyboard rename duplicate and delete persist without changing source, settings or frozen packages" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C10] concurrent rename receives ordinary409 and requires owner review before a new save" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C08 C12 A02] free gallery, private ownership and revoked public links retain server admission boundaries" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C12 E08] private PDF503 feedback does not retry or change the CV" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C12 E08] private PDF504 feedback does not retry or change the CV" + }, + { + "file": "phase7-cv-library.spec.ts", + "title": "[P7-04 PRES-C05 C08 E08] finite library and gallery width locale theme matrix keeps actions and real data reachable" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C05 C07 C12 A02] anonymous shared CV keeps sandbox noindex private denial and actual keyboard PDF download" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C05 C12] owner revocation removes anonymous view and PDF; republishing rotates the revoked link" + } + ], + "remaining": "Library migration not complete; publish/unpublish/old-slug revocation and every template combination required", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 35, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CvBuilderPage, thumbnails; CvVariantService/PublicCvController", + "requiredClosure": "Library migration not complete; publish/unpublish/old-slug revocation and every template combination required", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C06", + "capability": "**PRES-C06** — Studio tabs, preview debounce/pages/fit/save state/mobile panes", + "owners": "CvBuilderEditor, CvPreviewPane; preview API", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/en preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/en preview keyboard, pagination and responsive state" + }, + { + "file": "cv-pagination.spec.ts", + "title": "[PRES-C06 C09] pagination waits for image layout and publishes one settled measurement" + }, + { + "file": "cv-pagination.spec.ts", + "title": "[PRES-C06 C09] initially hidden default-modern preview waits for physical layout" + }, + { + "file": "cv-pagination.spec.ts", + "title": "[PRES-C06 C09] initially hidden long-en-minimal preview waits for physical layout" + }, + { + "file": "cv-preview-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] light/en native preview chrome, auto-fit, long pages and recovery" + }, + { + "file": "cv-preview-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] dark/nb native preview chrome, auto-fit, long pages and recovery" + }, + { + "file": "cv-readiness.spec.ts", + "title": "[PRES-C06 C08 C09 C12] native preview/PDF fidelity corpus records unchanged output at fixed settings" + }, + { + "file": "cv-readiness.spec.ts", + "title": "[PRES-C06 C10 E08] stale editor retains and downloads its draft; reviewed reload resumes versioned saves" + }, + { + "file": "cv-settings-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] light/en document controls preserve settings, source, history and native output" + }, + { + "file": "cv-settings-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] dark/nb document controls preserve settings, source, history and native output" + }, + { + "file": "cv-settings-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] light/nb document controls preserve settings, source, history and native output" + }, + { + "file": "cv-settings-presentation.spec.ts", + "title": "[PRES-C06 C08 C09 C10 C12 E08 E09] dark/en document controls preserve settings, source, history and native output" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-C01 PRES-C06 PRES-C07 PRES-C10] mobile CV override persists without changing the canonical profile or sibling CV" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "Physical keyboard/touch/AT and broader short-height/wrapped/deployed cases; one editor/save/preview owner", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 36, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "CvBuilderEditor, CvPreviewPane; preview API", + "requiredClosure": "Physical keyboard/touch/AT and broader short-height/wrapped/deployed cases; one editor/save/preview owner", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C07", + "capability": "**PRES-C07** — Visibility/order/custom sections and item/document overrides", + "owners": "CvBuilderEditor, CV controls/useDragReorder; resolver/settings", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/en preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/en preview keyboard, pagination and responsive state" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-C01 PRES-C06 PRES-C07 PRES-C10] mobile CV override persists without changing the canonical profile or sibling CV" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "Physical selection/drop/all-browser and exhaustive reset/inheritance combinations; sibling/canonical/frozen separation retained", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 37, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CvBuilderEditor, CV controls/useDragReorder; resolver/settings", + "requiredClosure": "Physical selection/drop/all-browser and exhaustive reset/inheritance combinations; sibling/canonical/frozen separation retained", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C08", + "capability": "**PRES-C08** — Capability-aware templates/typography/color/header/skills/sidebar/photo", + "owners": "CvCustomizeTab, registry; ThemedCvRenderer", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "Production fonts/portraits/wrapped lines/custom color/reader; schematic gallery is not final-photo qualification", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 38, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "CvCustomizeTab, registry; ThemedCvRenderer", + "requiredClosure": "Production fonts/portraits/wrapped lines/custom color/reader; schematic gallery is not final-photo qualification", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C09", + "capability": "**PRES-C09** — A4/Letter/density/margins/dates/document locale/section presentation", + "owners": "cvBuilder, CvCustomizeTab; settings normalization/render model", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "cv-pagination.spec.ts", + "title": "[PRES-C09 C12] original flowing/boundary fixtures retain native PDF page membership" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/en/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/nb/1440 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] light/nb/390 named controls, modal keyboard and retained draft" + }, + { + "file": "named-controls-modal-state.spec.ts", + "title": "[PRES-E07 PRES-E08 PRES-J08 PRES-C08 PRES-C09 PRES-W06 PRES-W08] dark/en/390 named controls, modal keyboard and retained draft" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "Advanced cross-product/manual print/deployed fonts; UI locale distinct from document locale; no print geometry styling change", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 39, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "cvBuilder, CvCustomizeTab; settings normalization/render model", + "requiredClosure": "Advanced cross-product/manual print/deployed fonts; UI locale distinct from document locale; no print geometry styling change", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C10", + "capability": "**PRES-C10** — Undo/redo, save queue, dirty guard, history restore/preview lifecycle", + "owners": "CvBuilderEditor; CvVariantService version history", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/en preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] light/nb preview keyboard, pagination and responsive state" + }, + { + "file": "builder-preview-keyboard.spec.ts", + "title": "[PRES-C06 PRES-C07 PRES-C10 PRES-E08] dark/en preview keyboard, pagination and responsive state" + }, + { + "file": "cv-readiness.spec.ts", + "title": "[PRES-C10 E05] independent authenticated clients cannot save or restore a stale CV revision" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-C01 PRES-C06 PRES-C07 PRES-C10] mobile CV override persists without changing the canonical profile or sibling CV" + } + ], + "remaining": "Long offline/history and IF-CV-UNSAVED-01 trace; settings history is not immutable historical profile/PDF; profile/job saves remain separate", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 40, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "CvBuilderEditor; CvVariantService version history", + "requiredClosure": "Long offline/history and IF-CV-UNSAVED-01 trace; settings history is not immutable historical profile/PDF; profile/job saves remain separate", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-C11", + "capability": "**PRES-C11** — Section and whole-document AI improve/translate/instruction/grammar review", + "owners": "AiSectionAssistant, DocumentAiTab; CV AI assist", + "entry": "DEFERRED", + "phase9": "DEFERRED", + "evidence": [ + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "**0/366 configured-target calls;0 human semantic reviews;review UI absent.** Production503 `cv_ai_unavailable`/no provider/no write remains; safe withholding is not generation acceptance", + "delta": "P5-13 remains withheld; real model/semantic qualification not executed.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 41, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "DEFERRED", + "currentStatus": "DEFERRED", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25", + "independent output/storage/deployment qualification", + "separate AI/model qualification; no activation" + ], + "owner": "AiSectionAssistant, DocumentAiTab; CV AI assist", + "requiredClosure": "**0/366 configured-target calls;0 human semantic reviews;review UI absent.** Production503 `cv_ai_unavailable`/no provider/no write remains; safe withholding is not generation acceptance", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "explicitly withheld model/product scope" + } + }, + { + "id": "PRES-C12", + "capability": "**PRES-C12** — Private PDF and published anonymous CV/PDF, long searchable pages", + "owners": "PublicCvPage, cvBuilder; HtmlPdfGenerator/shared admission", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12 E08] transient error retries by keyboard with held real read polite progress and stable H1 focus" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12 E08] initial held anonymous read announces loading without a document or download" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12 E08] unknown and numeric slugs use localized unavailable states without Retry or PDF controls" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12] same-document slug change removes prior HTML title and download before the next actual response" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12 E08] finite public width locale theme matrix preserves A4 white document and scaled wrapper boundaries" + }, + { + "file": "phase7-public-cv.spec.ts", + "title": "[P7-04 PRES-C12 C07] long public CV height remains reachable without shrinking A4 geometry or mutating source" + } + ], + "remaining": "Deployed Linux/font/photo/browser/manual-print qualification and complete revoke/busy-recovery cases; white print pages retained", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 42, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification" + ], + "owner": "PublicCvPage, cvBuilder; HtmlPdfGenerator/shared admission", + "requiredClosure": "Deployed Linux/font/photo/browser/manual-print qualification and complete revoke/busy-recovery cases; white print pages retained", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-M01", + "capability": "**PRES-M01** — Job-scoped manual correspondence/search/delete/paste import", + "owners": "Correspondence; CorrespondenceController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Full edit/delete/paste/reader native combinations; logging is not sending", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 43, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "Correspondence; CorrespondenceController", + "requiredClosure": "Full edit/delete/paste/reader native combinations; logging is not sending", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-M02", + "capability": "**PRES-M02** — Gmail candidate/thread import/refresh/sync/unlink/relink/move", + "owners": "Correspondence; GmailController/provider", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Actual provider threads/multi-account revoke/reconnect/sync failures; cross-job changes owner-bound", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 44, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "Correspondence; GmailController/provider", + "requiredClosure": "Actual provider threads/multi-account revoke/reconnect/sync failures; cross-job changes owner-bound", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-M03", + "capability": "**PRES-M03** — Global inbox filters/page/provider/link/direction/detail/source links", + "owners": "CorrespondenceInboxPage; EmailController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Large mailbox/native attachments/complete reader acceptance; global inbox remains Phase7 migration", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 45, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "CorrespondenceInboxPage; EmailController", + "requiredClosure": "Large mailbox/native attachments/complete reader acceptance; global inbox remains Phase7 migration", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-M04", + "capability": "**PRES-M04** — Compose/reply/provider/recipient/job; draft conflicts; confirm send/uncertainty", + "owners": "CorrespondenceInboxPage; EmailDrafts/Send/attempt store", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Sandbox delivery/reconnect/dirty interruption; no automatic uncertain resend; reviewed `followMode` UI deferred", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 46, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "CorrespondenceInboxPage; EmailDrafts/Send/attempt store", + "requiredClosure": "Sandbox delivery/reconnect/dirty interruption; no automatic uncertain resend; reviewed `followMode` UI deferred", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "contains separately deferred scope, retain exact residual" + } + }, + { + "id": "PRES-M05", + "capability": "**PRES-M05** — Review proposed jobs/link/reject/keep/notes/sync/create", + "owners": "GmailReviewPage, CorrespondenceInboxPage; Gmail review", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Real provider and complete proposed-job create flow; route opening is no-write", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 47, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "GmailReviewPage, CorrespondenceInboxPage; Gmail review", + "requiredClosure": "Real provider and complete proposed-job create flow; route opening is no-write", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-M06", + "capability": "**PRES-M06** — Gmail/Graph/IMAP connect/status/disconnect separate from sign-in", + "owners": "EmailProviderConnections; Google/Graph/IMAP controllers", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Real grants/revoke/token expiry/reconnect/IMAP safety; keep sign-in identity separate", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 48, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "EmailProviderConnections; Google/Graph/IMAP controllers", + "requiredClosure": "Real grants/revoke/token expiry/reconnect/IMAP safety; keep sign-in identity separate", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-S01", + "capability": "**PRES-S01** — Personal metrics/activity/funnel/company/skills/stage/salary/next actions", + "owners": "DashboardView; analytics/controllers", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "analytics-presentation.spec.ts", + "title": "[PRES-S01 S02 E07 E08 E09 J05 J09] Analytics native reports, direct entry, period, drill-down and owner isolation" + }, + { + "file": "analytics-presentation.spec.ts", + "title": "[PRES-S01 E08] Analytics independent loading and failure states never masquerade as empty reports" + }, + { + "file": "dashboard-presentation.spec.ts", + "title": "[PRES-S01 S02 E07 E08 E09] Dashboard native data, visibility and responsive presentation" + }, + { + "file": "dashboard-presentation.spec.ts", + "title": "[PRES-S01 E08] Dashboard loading and independent failed resources retain retry and exact values" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S01 S02 E08] failed Dashboard summary keeps first-job guidance unknown until its existing read owner retries" + } + ], + "remaining": "Exact cohort/timezone/sample/unsupported metrics and whole reader acceptance; no fabricated statistics or Analytics rebuild", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 49, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "DashboardView; analytics/controllers", + "requiredClosure": "Exact cohort/timezone/sample/unsupported metrics and whole reader acceptance; no fabricated statistics or Analytics rebuild", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-S02", + "capability": "**PRES-S02** — Owner-local five visibility preferences/onboarding dismiss/notifications", + "owners": "DashboardView, OnboardingChecklist, NotificationsPopover; notification APIs", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] nb/dark 320px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] en/light 360px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] nb/light 390px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] en/dark 768px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] nb/dark 1024px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] en/light 1280px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] nb/light 1440px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C01 C02 E09] en/dark 1920px setup counts saved manual career information without claiming CV import or email verification" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 E09] dismissal survives reload and remains isolated across actual A/B logout and login" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 E08] a failed mailbox read cannot invent setup progress and retry only reads" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 C02 E07] keyboard setup actions retain their four destinations and browser Back context" + }, + { + "file": "phase7-onboarding.spec.ts", + "title": "[P7-02 PRES-S02 E08] recovery to four complete setup steps removes guidance while retaining the next keyboard action" + } + ], + "remaining": "Historical500 causes unproved; full human/notification acceptance; order/resize/reset/cross-device design remains Phase8", + "delta": "Finite full regression retained; human/provider/output qualifications remain. Phase8 account-layout order/size/visibility/reset/conflict behaviour preserved.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 50, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09" + ], + "owner": "DashboardView, OnboardingChecklist, NotificationsPopover; notification APIs", + "requiredClosure": "Historical500 causes unproved; full human/notification acceptance; order/resize/reset/cross-device design remains Phase8", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-S03", + "capability": "**PRES-S03** — Rules/reminder/table/theme/language preferences and account links", + "owners": "SettingsView, RulesSettingsCard, theme/i18n; rules/notification/auth", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-S03 PRES-W11] responsive settings navigation keeps rule edits and persists notification preferences" + }, + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-S03] rule changes persist through the real API" + }, + { + "file": "rules-draft-repair.spec.ts", + "title": "[P5-15-01R-02 PRES-S03 W11] unsaved Rules draft survives an internal tab round trip without saving" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] light loaded CV tabs, selects and settings" + }, + { + "file": "semantic-foundations.spec.ts", + "title": "[PRES-E08 PRES-C06 PRES-C07 PRES-C08 PRES-C09 PRES-C11 PRES-S03] dark loaded CV tabs, selects and settings" + } + ], + "remaining": "Language failure visibility is separate from RD11 server cause; RD12 notification locking/RD13 Rules500 and human/provider acceptance retained", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 51, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "SettingsView, RulesSettingsCard, theme/i18n; rules/notification/auth", + "requiredClosure": "Language failure visibility is separate from RD11 server cause; RD12 notification locking/RD13 Rules500 and human/provider acceptance retained", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-S04", + "capability": "**PRES-S04** — AI privacy/usage/limits/Free-Pro/server entitlement/conditional billing", + "owners": "AiPrivacySettingsCard, AiUsageCard, AccountPlanProvider; billing/entitlement", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-A01 PRES-S04 PRES-E07] non-admin navigation cannot grant API privileges or unlock CV AI" + } + ], + "remaining": "Checkout/webhook/portal and provider delivery; temporary C11 withholding cannot disable unrelated AI or imply successful review", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 52, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25", + "separate AI/model qualification; no activation" + ], + "owner": "AiPrivacySettingsCard, AiUsageCard, AccountPlanProvider; billing/entitlement", + "requiredClosure": "Checkout/webhook/portal and provider delivery; temporary C11 withholding cannot disable unrelated AI or imply successful review", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-S05", + "capability": "**PRES-S05** — Account ZIP/encrypted backup/lifecycle/deletion confirmations", + "owners": "BackupCard; export/backup/deletion services", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Current complete backup/restore/keys/tombstones/rollback and deletion/provider policy; downloading backup is not restore proof", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 53, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "intended provider/operator sandbox evidence M09-10/RD22–25", + "independent output/storage/deployment qualification" + ], + "owner": "BackupCard; export/backup/deletion services", + "requiredClosure": "Current complete backup/restore/keys/tombstones/rollback and deletion/provider policy; downloading backup is not restore proof", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-A01", + "capability": "**PRES-A01** — Admin user/create/roles/reset/delete/last-admin/self guards", + "owners": "AdminUsersPage; UsersController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [ + { + "file": "redesign-preservation.spec.ts", + "title": "[PRES-A01 PRES-S04 PRES-E07] non-admin navigation cannot grant API privileges or unlock CV AI" + } + ], + "remaining": "Mounted-role revoke/full persisted mutations/reset delivery; hiding navigation never authorizes API calls", + "delta": "Finite full regression retained; human/provider/output qualifications remain. P9-L01 installed vendor locale and2new Jest cases.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 54, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "intended provider/operator sandbox evidence M09-10/RD22–25" + ], + "owner": "AdminUsersPage; UsersController", + "requiredClosure": "Mounted-role revoke/full persisted mutations/reset delivery; hiding navigation never authorizes API calls", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-A02", + "capability": "**PRES-A02** — Audit list/detail/supported undo/job restore", + "owners": "AdminAuditPage; AdminAuditController", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Native successful persisted undo/restore and unsupported-action denial; no generic undo semantics", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 55, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification", + "separate AI/model qualification; no activation" + ], + "owner": "AdminAuditPage; AdminAuditController", + "requiredClosure": "Native successful persisted undo/restore and unsupported-action denial; no generic undo semantics", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + }, + { + "id": "PRES-A03", + "capability": "**PRES-A03** — System/build/DB/AI/mail/SMTP/test/probe/benchmark/maintenance", + "owners": "AdminSystemPage; AdminSystemController/maintenance/benchmark", + "entry": "PARTIAL", + "phase9": "PARTIAL", + "evidence": [], + "remaining": "Actual guarded diagnostic/SMTP/model/maintenance and sensitive-output qualification; no production jobs launched", + "delta": "Finite full regression retained; human/provider/output qualifications remain.", + "criterionSource": { + "path": "docs/redesign/phase-9/preservation.json", + "index": 56, + "originalCriteria": "docs/redesign/phase-2/PRESERVATION_MATRIX.md", + "laterResidual": "docs/redesign/phase-7/PRESERVATION.md" + }, + "baselineStatus": "PARTIAL", + "currentStatus": "PARTIAL", + "sourceEvidence": [ + "docs/redesign/phase-9/p9-07/FINAL_ACCEPTANCE.md", + "docs/redesign/phase-9/rd21-remediation/PRESERVATION.md" + ], + "execution": "historical baseline evidence; fresh root-owned qualification pending", + "severity": "capability qualification; see linked RD/P9 finding for defect severity", + "dependency": [ + "applicable human rows M09-01–09", + "independent output/storage/deployment qualification", + "separate AI/model qualification; no activation" + ], + "owner": "AdminSystemPage; AdminSystemController/maintenance/benchmark", + "requiredClosure": "Actual guarded diagnostic/SMTP/model/maintenance and sensitive-output qualification; no production jobs launched", + "gates": { + "phase9": "assess exact workflow residual; no PARTIAL→PASS without complete evidence", + "phase10": "no affected deletion until unused-route proof + tests pass + functionality inventory satisfied", + "production": "applicable human/provider/output/operator gates remain independent", + "debt": "remaining qualification; not automatically a defect" + } + } + ], + "routes": [ + { + "route": "/", + "owners": [ + "Navigate", + "LandingPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "Navigate, LandingPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/dashboard", + "owners": [ + "DashboardView" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "DashboardView", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/analytics", + "owners": [ + "AnalyticsPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "AnalyticsPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/discover", + "owners": [ + "JobDiscoveryPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "JobDiscoveryPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/jobs", + "owners": [ + "JobTable" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "JobTable", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/jobs/:id", + "owners": [ + "ApplicationWorkspacePage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "ApplicationWorkspacePage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/reminders", + "owners": [ + "RemindersView" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "RemindersView", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/operations", + "owners": [ + "OperationsPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "OperationsPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/kanban", + "owners": [ + "LegacyBoardRedirect" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "LegacyBoardRedirect", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/companies", + "owners": [ + "CompaniesTable" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "CompaniesTable", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/offers", + "owners": [ + "OfferComparisonPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "OfferComparisonPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/correspondence", + "owners": [ + "CorrespondenceInboxPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "CorrespondenceInboxPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/correspondence/review", + "owners": [ + "LegacyCorrespondenceReviewRedirect" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "LegacyCorrespondenceReviewRedirect", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/profile", + "owners": [ + "ProfilePage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "ProfilePage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/applications/:id", + "owners": [ + "LegacyApplicationRedirect" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "LegacyApplicationRedirect", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/career", + "owners": [ + "CareerWorkspacePage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "CareerWorkspacePage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/career/builder", + "owners": [ + "CvBuilderPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "CvBuilderPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/career/builder/:id", + "owners": [ + "CvBuilderEditor" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "CvBuilderEditor", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/documents", + "owners": [ + "DocumentsPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "DocumentsPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/admin/audit", + "owners": [ + "AdminAuditPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "AdminAuditPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/admin/users", + "owners": [ + "AdminUsersPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "AdminUsersPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/admin/system", + "owners": [ + "AdminSystemPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "AdminSystemPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/trash", + "owners": [ + "JobTable" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "JobTable", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/settings", + "owners": [ + "SettingsView" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "SettingsView", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/settings/connected-accounts", + "owners": [ + "ConnectedAccountsPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "ConnectedAccountsPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/login", + "owners": [ + "LoginPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "LoginPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/register", + "owners": [ + "LoginPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "LoginPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/forgot-password", + "owners": [ + "ForgotPasswordPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "ForgotPasswordPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/reset-password", + "owners": [ + "ResetPasswordPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "ResetPasswordPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/verify-email", + "owners": [ + "VerifyEmailPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "VerifyEmailPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/confirm-email-change", + "owners": [ + "VerifyEmailPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "VerifyEmailPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/microsoft-legacy-relink", + "owners": [ + "MicrosoftLegacyRelinkPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "MicrosoftLegacyRelinkPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + }, + { + "route": "/cv/:slug", + "owners": [ + "PublicCvPage" + ], + "criterionSource": "job-tracker-ui/src/App.tsx:420-524", + "baselineSource": "docs/redesign/phase-9/p9-00/inventory.json", + "status": "PRESENT in source census; historical automated coverage, no new human acceptance", + "evidence": "docs/redesign/phase-9/p9-01/ordinary-cases.json and docs/redesign/phase-9/p9-02/README.md (historical; exact fresh root result pending)", + "severity": "route preservation obligation", + "dependency": "retain authenticated/public/legacy identity, query/hash and section semantics", + "owner": "PublicCvPage", + "requiredClosure": "fresh route membership reconciliation plus affected connected workflow evidence; human checks remain distinct", + "gates": { + "phase9": "source presence is not complete usability acceptance", + "phase10": "route still used: no unused-route deletion proof", + "production": "deployment identity and applicable release gates independent", + "debt": "no deletion authority" + } + } + ] +} diff --git a/docs/redesign/phase-9/p9-requal-01/python-advisories.json b/docs/redesign/phase-9/p9-requal-01/python-advisories.json new file mode 100644 index 0000000..acba781 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/python-advisories.json @@ -0,0 +1,365 @@ +{ + "schemaVersion": 1, + "gate": "OPEN", + "coverage": "INCOMPLETE", + "startedUtc": "2026-10-24T07:27:05.547836+00:00", + "finishedUtc": "2026-10-24T07:27:13.317497+00:00", + "lockPath": "tools/summarizer/requirements-linux.lock", + "lockSha256": "36f2912965d183e59f2d8320f3817ca8dd0fee6d76e05cfd63ac92defe6c6031", + "rawDirectory": ".artifacts/p9-requal-01/security/python-locked", + "rawManifestSha256": "3dac31a50d803e4c4a27c43e683dcf7ee7f2587a122cfb8c38fc5276fb7233ec", + "rawSummarySha256": "31fe495d72a9b11564c8e78943be7901610e023a8606b5aeb53710871092ca20", + "exactPins": [ + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "cachetools", + "version": "5.5.2" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "charset-normalizer", + "version": "3.5.1" + }, + { + "name": "click", + "version": "8.5.0" + }, + { + "name": "fastapi", + "version": "0.141.1" + }, + { + "name": "filelock", + "version": "3.32.4" + }, + { + "name": "fsspec", + "version": "2026.7.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httptools", + "version": "0.8.0" + }, + { + "name": "huggingface-hub", + "version": "0.36.2" + }, + { + "name": "idna", + "version": "3.19" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "lxml", + "version": "6.1.2" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "networkx", + "version": "3.6.1" + }, + { + "name": "numpy", + "version": "2.4.6" + }, + { + "name": "packaging", + "version": "26.3" + }, + { + "name": "pillow", + "version": "12.3.0" + }, + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "pydantic-core", + "version": "2.27.2" + }, + { + "name": "pymupdf", + "version": "1.25.5" + }, + { + "name": "pypdf", + "version": "6.16.2" + }, + { + "name": "pytesseract", + "version": "0.3.13" + }, + { + "name": "python-docx", + "version": "1.1.2" + }, + { + "name": "python-dotenv", + "version": "1.2.3" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setuptools", + "version": "84.0.0" + }, + { + "name": "starlette", + "version": "1.6.0" + }, + { + "name": "sympy", + "version": "1.13.1" + }, + { + "name": "tokenizers", + "version": "0.21.4" + }, + { + "name": "torch", + "version": "2.6.0+cpu" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "4.48.3" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.4" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.34.0" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "watchfiles", + "version": "1.2.0" + }, + { + "name": "websockets", + "version": "17.1" + } + ], + "counts": { + "exactPins": 49, + "queries": 98, + "successfulQueries": 97, + "queryErrors": 1, + "providerRecords": 249, + "osvRecords": 137, + "pypiRecords": 112, + "aliasGroups": 109, + "packagesWithAdvisories": 8 + }, + "errors": [ + { + "package": "torch", + "version": "2.6.0+cpu", + "provider": "pypi", + "httpStatus": 404, + "error": "HTTPError" + } + ], + "groupsPerPackage": { + "certifi": 1, + "filelock": 3, + "pillow": 41, + "pypdf": 19, + "setuptools": 1, + "torch": 19, + "transformers": 22, + "urllib3": 3 + }, + "limits": [ + "Public exact locked-version advisory metadata only; no installation, resolution or package changes.", + "OSV performs upstream version matching; query results are not independently reproduced vulnerabilities.", + "PyPI exact torch 2.6.0+cpu release returns 404; no substitute version queried; OSV exact query succeeds.", + "249 provider records overlap; 109 groups use published alias equivalence only and are not 109 independent CVEs.", + "All returned groups retained; none had withdrawn metadata in this snapshot.", + "Severity labels reproduce provider database_specific.severity only; no score inferred or normalized.", + "Fixed-version events reproduce upstream data and can differ by branch; they are not compatible upgrade recommendations.", + "No exploitability, production package identity, deployed state or provider security acceptance established.", + "Static sidecar call sites are documented separately; individual advisory reachability is not adjudicated.", + "Audit covers 49 Python lock pins only, excluding OS/native/image packages and unpinned Docker bootstrap upgrades.", + "No model load/inference, malicious documents, deployment inspection or runtime dependency changes performed.", + "NuGet/npm remediation is separate; Python advisories remain OPEN and coverage incomplete." + ], + "advisoryGroups": [ + {"package":"certifi","lockedVersion":"2026.7.22","identifiers":["GHSA-6q48-6c7w-9gw2","PYSEC-2026-4320"],"primaryLinks":["https://github.com/advisories/GHSA-6q48-6c7w-9gw2"],"publishedFixedVersionEvents":["2026.10.19"],"providerRecordCount":4,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"filelock","lockedVersion":"3.32.4","identifiers":["CVE-2026-112940","GHSA-v4x8-3wr5-3wq8"],"primaryLinks":["https://github.com/advisories/GHSA-v4x8-3wr5-3wq8"],"publishedFixedVersionEvents":["4.2.1"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"filelock","lockedVersion":"3.32.4","identifiers":["CVE-2026-112913","GHSA-9vhv-jxww-xfm5"],"primaryLinks":["https://github.com/advisories/GHSA-9vhv-jxww-xfm5"],"publishedFixedVersionEvents":["4.2.1"],"providerRecordCount":2,"publishedSeverityLabels":["LOW"]}, + {"package":"filelock","lockedVersion":"3.32.4","identifiers":["CVE-2026-112907","GHSA-567q-5qvw-pf92"],"primaryLinks":["https://github.com/advisories/GHSA-567q-5qvw-pf92"],"publishedFixedVersionEvents":["4.2.1"],"providerRecordCount":2,"publishedSeverityLabels":["LOW"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112394","GHSA-4558-3h8r-v8xp"],"primaryLinks":["https://github.com/advisories/GHSA-4558-3h8r-v8xp"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":1,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112403","GHSA-8g5g-8vmr-9782"],"primaryLinks":["https://github.com/advisories/GHSA-8g5g-8vmr-9782"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":1,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112898","GHSA-rfgq-q3w2-pmv2"],"primaryLinks":["https://github.com/advisories/GHSA-rfgq-q3w2-pmv2"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":1,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112902","GHSA-xvh5-g6gv-559v"],"primaryLinks":["https://github.com/advisories/GHSA-xvh5-g6gv-559v"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":1,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112895","GHSA-p4wg-p73j-c528"],"primaryLinks":["https://github.com/advisories/GHSA-p4wg-p73j-c528"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112400","GHSA-65qm-jvmh-6pqg"],"primaryLinks":["https://github.com/advisories/GHSA-65qm-jvmh-6pqg"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112397","GHSA-58r4-6rv3-gfh8"],"primaryLinks":["https://github.com/advisories/GHSA-58r4-6rv3-gfh8"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112896","GHSA-pchr-8j38-3x4p"],"primaryLinks":["https://github.com/advisories/GHSA-pchr-8j38-3x4p"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112897","GHSA-q45j-58j2-45rg"],"primaryLinks":["https://github.com/advisories/GHSA-q45j-58j2-45rg"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112395","GHSA-462x-pgg6-55fp"],"primaryLinks":["https://github.com/advisories/GHSA-462x-pgg6-55fp"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112404","GHSA-c6hw-5grf-ff96"],"primaryLinks":["https://github.com/advisories/GHSA-c6hw-5grf-ff96"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112899","GHSA-vx6w-vv9f-6gvg"],"primaryLinks":["https://github.com/advisories/GHSA-vx6w-vv9f-6gvg"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112402","GHSA-7mwm-ghpf-9vrm"],"primaryLinks":["https://github.com/advisories/GHSA-7mwm-ghpf-9vrm"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112900","GHSA-w889-685w-c8fh"],"primaryLinks":["https://github.com/advisories/GHSA-w889-685w-c8fh"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112893","GHSA-j4m9-6w36-pw47"],"primaryLinks":["https://github.com/advisories/GHSA-j4m9-6w36-pw47"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112392","GHSA-27h8-gf7j-v5hc"],"primaryLinks":["https://github.com/advisories/GHSA-27h8-gf7j-v5hc"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112891","GHSA-fc9g-5qg7-mf45"],"primaryLinks":["https://github.com/advisories/GHSA-fc9g-5qg7-mf45"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112405","GHSA-cp9v-662q-vvx9"],"primaryLinks":["https://github.com/advisories/GHSA-cp9v-662q-vvx9"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112390","GHSA-22hg-r758-rrw9"],"primaryLinks":["https://github.com/advisories/GHSA-22hg-r758-rrw9"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112401","GHSA-74r2-7ff9-mjj2"],"primaryLinks":["https://github.com/advisories/GHSA-74r2-7ff9-mjj2"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112901","GHSA-xgh8-jp6q-p5x8"],"primaryLinks":["https://github.com/advisories/GHSA-xgh8-jp6q-p5x8"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112391","GHSA-254f-3936-288h"],"primaryLinks":["https://github.com/advisories/GHSA-254f-3936-288h"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112894","GHSA-jg86-v3jv-hrpm"],"primaryLinks":["https://github.com/advisories/GHSA-jg86-v3jv-hrpm"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112406","GHSA-f2g6-542v-9j58"],"primaryLinks":["https://github.com/advisories/GHSA-f2g6-542v-9j58"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112399","GHSA-5xm2-6676-qcp9"],"primaryLinks":["https://github.com/advisories/GHSA-5xm2-6676-qcp9"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112892","GHSA-gg2r-wvfm-q9rx"],"primaryLinks":["https://github.com/advisories/GHSA-gg2r-wvfm-q9rx"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112393","GHSA-332p-7hrc-92wf"],"primaryLinks":["https://github.com/advisories/GHSA-332p-7hrc-92wf"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112396","GHSA-4rr5-89j8-mwwm"],"primaryLinks":["https://github.com/advisories/GHSA-4rr5-89j8-mwwm"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96638","GHSA-24rc-8hj2-v98c"],"primaryLinks":["https://github.com/advisories/GHSA-24rc-8hj2-v98c"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96641","GHSA-4rm8-3hmm-39fg"],"primaryLinks":["https://github.com/advisories/GHSA-4rm8-3hmm-39fg"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96640","GHSA-mrfp-p49p-3hf2"],"primaryLinks":["https://github.com/advisories/GHSA-mrfp-p49p-3hf2"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96642","GHSA-3j72-p6qg-6xp7"],"primaryLinks":["https://github.com/advisories/GHSA-3j72-p6qg-6xp7"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96639","GHSA-v9pv-5gc8-w2m6"],"primaryLinks":["https://github.com/advisories/GHSA-v9pv-5gc8-w2m6"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96643","GHSA-g4qv-2jxx-769h"],"primaryLinks":["https://github.com/advisories/GHSA-g4qv-2jxx-769h"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96637","GHSA-g842-9rc4-69pw"],"primaryLinks":["https://github.com/advisories/GHSA-g842-9rc4-69pw"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96644","GHSA-9v9v-9qvf-h2hj"],"primaryLinks":["https://github.com/advisories/GHSA-9v9v-9qvf-h2hj"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96778","GHSA-g7cr-3p24-7wf7"],"primaryLinks":["https://github.com/advisories/GHSA-g7cr-3p24-7wf7"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-96636","GHSA-p8hx-v2p6-rp84"],"primaryLinks":["https://github.com/advisories/GHSA-p8hx-v2p6-rp84"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["GHSA-78g4-xqwv-q3g8"],"primaryLinks":["https://github.com/advisories/GHSA-78g4-xqwv-q3g8"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-114501","GHSA-654x-cwwv-5j9c"],"primaryLinks":["https://github.com/advisories/GHSA-654x-cwwv-5j9c"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pillow","lockedVersion":"12.3.0","identifiers":["CVE-2026-112398","GHSA-5x8w-8jj5-q52h"],"primaryLinks":["https://github.com/advisories/GHSA-5x8w-8jj5-q52h"],"publishedFixedVersionEvents":["13.0.0"],"providerRecordCount":2,"publishedSeverityLabels":["CRITICAL"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102994","GHSA-5jq2-8x83-x246","PYSEC-2026-4153"],"primaryLinks":["https://github.com/advisories/GHSA-5jq2-8x83-x246"],"publishedFixedVersionEvents":["6.18.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102995","GHSA-fp3h-c4fm-7vvf","PYSEC-2026-4154"],"primaryLinks":["https://github.com/advisories/GHSA-fp3h-c4fm-7vvf"],"publishedFixedVersionEvents":["6.18.1"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-103000","GHSA-w23x-9jrw-r45c","PYSEC-2026-4160"],"primaryLinks":["https://github.com/advisories/GHSA-w23x-9jrw-r45c"],"publishedFixedVersionEvents":["6.19.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102999","GHSA-v247-6f48-mgcj","PYSEC-2026-4159"],"primaryLinks":["https://github.com/advisories/GHSA-v247-6f48-mgcj"],"publishedFixedVersionEvents":["6.19.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102997","GHSA-jw7q-gvrg-4vj3","PYSEC-2026-4156"],"primaryLinks":["https://github.com/advisories/GHSA-jw7q-gvrg-4vj3"],"publishedFixedVersionEvents":["6.18.1"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102996","GHSA-g9cg-prrw-2r8q","PYSEC-2026-4155"],"primaryLinks":["https://github.com/advisories/GHSA-g9cg-prrw-2r8q"],"publishedFixedVersionEvents":["6.18.1"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102993","GHSA-qv6h-rv94-w285","PYSEC-2026-4158"],"primaryLinks":["https://github.com/advisories/GHSA-qv6h-rv94-w285"],"publishedFixedVersionEvents":["6.17.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-102998","GHSA-php9-fj8v-98fj","PYSEC-2026-4157"],"primaryLinks":["https://github.com/advisories/GHSA-php9-fj8v-98fj"],"publishedFixedVersionEvents":["6.19.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113792","GHSA-qfv9-64jg-mh7p"],"primaryLinks":["https://github.com/advisories/GHSA-qfv9-64jg-mh7p"],"publishedFixedVersionEvents":["6.20.1"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113795","GHSA-7mh2-4gg2-979f"],"primaryLinks":["https://github.com/advisories/GHSA-7mh2-4gg2-979f"],"publishedFixedVersionEvents":["6.20.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113793","GHSA-9mx8-4j7g-633p"],"primaryLinks":["https://github.com/advisories/GHSA-9mx8-4j7g-633p"],"publishedFixedVersionEvents":["6.20.1"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113794","GHSA-39mj-jf6j-2qj3"],"primaryLinks":["https://github.com/advisories/GHSA-39mj-jf6j-2qj3"],"publishedFixedVersionEvents":["6.20.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113786","GHSA-5hx5-vpf9-5wcv"],"primaryLinks":["https://github.com/advisories/GHSA-5hx5-vpf9-5wcv"],"publishedFixedVersionEvents":["6.21.1"],"providerRecordCount":2,"publishedSeverityLabels":["LOW"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113791","GHSA-cgf9-327m-v77c"],"primaryLinks":["https://github.com/advisories/GHSA-cgf9-327m-v77c"],"publishedFixedVersionEvents":["6.21.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113790","GHSA-f54x-cmq8-qg57"],"primaryLinks":["https://github.com/advisories/GHSA-f54x-cmq8-qg57"],"publishedFixedVersionEvents":["6.21.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-113789","GHSA-6vvc-x485-93v7"],"primaryLinks":["https://github.com/advisories/GHSA-6vvc-x485-93v7"],"publishedFixedVersionEvents":["6.21.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-115572","GHSA-6c7f-9265-g8fw"],"primaryLinks":["https://github.com/advisories/GHSA-6c7f-9265-g8fw"],"publishedFixedVersionEvents":["6.21.2"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-115585","GHSA-jr96-gvgh-j3r4"],"primaryLinks":["https://github.com/advisories/GHSA-jr96-gvgh-j3r4"],"publishedFixedVersionEvents":["6.21.2"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"pypdf","lockedVersion":"6.16.2","identifiers":["CVE-2026-115580","GHSA-gmh7-3g9r-mjh5"],"primaryLinks":["https://github.com/advisories/GHSA-gmh7-3g9r-mjh5"],"publishedFixedVersionEvents":["6.21.2"],"providerRecordCount":2,"publishedSeverityLabels":["HIGH"]}, + {"package":"setuptools","lockedVersion":"84.0.0","identifiers":["GHSA-xmj3-9gf7-h52w"],"primaryLinks":["https://github.com/advisories/GHSA-xmj3-9gf7-h52w"],"publishedFixedVersionEvents":["84.1.0"],"providerRecordCount":2,"publishedSeverityLabels":["LOW"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-3001","CVE-2025-3001","GHSA-qfhq-4f3w-5fph","PYSEC-2025-195"],"primaryLinks":["https://github.com/advisories/GHSA-qfhq-4f3w-5fph"],"publishedFixedVersionEvents":["2.10.0"],"providerRecordCount":1,"publishedSeverityLabels":["LOW"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-3000","CVE-2025-3000","GHSA-rrmf-rvhw-rf47","PYSEC-2025-194"],"primaryLinks":["https://github.com/advisories/GHSA-rrmf-rvhw-rf47"],"publishedFixedVersionEvents":["2.13.0"],"providerRecordCount":1,"publishedSeverityLabels":["LOW"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-2999","CVE-2025-2999","GHSA-vgrw-7cvw-pwgx","PYSEC-2025-193"],"primaryLinks":["https://github.com/advisories/GHSA-vgrw-7cvw-pwgx"],"publishedFixedVersionEvents":["2.9.1"],"providerRecordCount":1,"publishedSeverityLabels":["MODERATE"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-2953","CVE-2025-2953","GHSA-3749-ghw9-m3mg","PYSEC-2025-191"],"primaryLinks":["https://github.com/advisories/GHSA-3749-ghw9-m3mg"],"publishedFixedVersionEvents":["2.7.1-rc1"],"providerRecordCount":2,"publishedSeverityLabels":["LOW"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-46148","CVE-2025-46148","PYSEC-2025-198"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151198"],"publishedFixedVersionEvents":["2.7.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-46149","CVE-2025-46149","PYSEC-2025-199"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/147848"],"publishedFixedVersionEvents":["2.7.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-46150","CVE-2025-46150","PYSEC-2025-200"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/141538"],"publishedFixedVersionEvents":["2.7.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-46152","CVE-2025-46152","PYSEC-2025-201"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/143555"],"publishedFixedVersionEvents":["2.7.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-46153","CVE-2025-46153","PYSEC-2025-202"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/142853"],"publishedFixedVersionEvents":["2.7.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55551","CVE-2025-55551","PYSEC-2025-203"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151401"],"publishedFixedVersionEvents":["2.9.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55552","CVE-2025-55552","PYSEC-2025-204"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/147847"],"publishedFixedVersionEvents":["2.9.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55553","CVE-2025-55553","PYSEC-2025-205"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151432"],"publishedFixedVersionEvents":["2.7.1"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55554","CVE-2025-55554","PYSEC-2025-206"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151510"],"publishedFixedVersionEvents":["2.9.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55557","CVE-2025-55557","PYSEC-2025-207"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151738"],"publishedFixedVersionEvents":["2.7.1"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55558","CVE-2025-55558","PYSEC-2025-208"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151523"],"publishedFixedVersionEvents":["2.7.1"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-55560","CVE-2025-55560","PYSEC-2025-209"],"primaryLinks":["https://github.com/pytorch/pytorch/issues/151522"],"publishedFixedVersionEvents":["2.7.1"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2026-4538","CVE-2026-4538","PYSEC-2026-139"],"primaryLinks":["https://github.com/pytorch/pytorch/pull/176791"],"publishedFixedVersionEvents":[],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2025-3730","CVE-2025-3730","GHSA-887c-mr87-cxwp","PYSEC-2026-1970"],"primaryLinks":["https://github.com/advisories/GHSA-887c-mr87-cxwp"],"publishedFixedVersionEvents":["2.8.0"],"providerRecordCount":2,"publishedSeverityLabels":["MODERATE"]}, + {"package":"torch","lockedVersion":"2.6.0+cpu","identifiers":["BIT-pytorch-2026-24747","CVE-2026-24747","GHSA-63cw-57p8-fm3p","PYSEC-2026-1856","PYSEC-2026-2286"],"primaryLinks":["https://github.com/advisories/GHSA-63cw-57p8-fm3p"],"publishedFixedVersionEvents":["2.10.0"],"providerRecordCount":1,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14929","PYSEC-2025-217"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-217"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-2099","GHSA-qq3j-4f4f-9583","PYSEC-2025-40"],"primaryLinks":["https://github.com/advisories/GHSA-qq3j-4f4f-9583"],"publishedFixedVersionEvents":["4.49.0","4.50.0","8cb522b4190bd556ce51be04942720650b1a3e57"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14926","PYSEC-2025-214"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-214"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14930","PYSEC-2025-218"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-218"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14920","PYSEC-2025-211"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-211"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14921","PYSEC-2025-212"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-212"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14924","PYSEC-2025-213"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-213"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14927","PYSEC-2025-215"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-215"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-14928","PYSEC-2025-216"],"primaryLinks":["https://osv.dev/vulnerability/PYSEC-2025-216"],"publishedFixedVersionEvents":[],"providerRecordCount":2,"publishedSeverityLabels":[]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-3933","GHSA-37mw-44qp-f5jm","PYSEC-2026-1977"],"primaryLinks":["https://github.com/advisories/GHSA-37mw-44qp-f5jm"],"publishedFixedVersionEvents":["4.52.1"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-6638","GHSA-59p9-h35m-wg4g","PYSEC-2026-1981"],"primaryLinks":["https://github.com/advisories/GHSA-59p9-h35m-wg4g"],"publishedFixedVersionEvents":["4.53.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-3264","GHSA-jjph-296x-mrcr","PYSEC-2026-1985"],"primaryLinks":["https://github.com/advisories/GHSA-jjph-296x-mrcr"],"publishedFixedVersionEvents":["4.51.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-1194","GHSA-fpwr-67px-3qhx","PYSEC-2026-1984"],"primaryLinks":["https://github.com/advisories/GHSA-fpwr-67px-3qhx"],"publishedFixedVersionEvents":["4.50.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-3777","GHSA-phhr-52qp-3mj4","PYSEC-2026-1986"],"primaryLinks":["https://github.com/advisories/GHSA-phhr-52qp-3mj4"],"publishedFixedVersionEvents":["4.52.1"],"providerRecordCount":4,"publishedSeverityLabels":["LOW"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-6051","GHSA-rcv9-qm8p-9p6j","PYSEC-2026-1988"],"primaryLinks":["https://github.com/advisories/GHSA-rcv9-qm8p-9p6j"],"publishedFixedVersionEvents":["4.53.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-6921","GHSA-4w7r-h757-3r74","PYSEC-2026-1980"],"primaryLinks":["https://github.com/advisories/GHSA-4w7r-h757-3r74"],"publishedFixedVersionEvents":["4.53.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-3263","GHSA-q2wp-rjmx-x6x9","PYSEC-2026-1987"],"primaryLinks":["https://github.com/advisories/GHSA-q2wp-rjmx-x6x9"],"publishedFixedVersionEvents":["4.51.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2025-5197","GHSA-9356-575x-2w9m","PYSEC-2026-1983"],"primaryLinks":["https://github.com/advisories/GHSA-9356-575x-2w9m"],"publishedFixedVersionEvents":["4.53.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2026-1839","GHSA-69w3-r845-3855","PYSEC-2026-2288"],"primaryLinks":["https://github.com/advisories/GHSA-69w3-r845-3855"],"publishedFixedVersionEvents":["5.0.0","5.0.0rc3"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2026-4372","GHSA-29pf-2h5f-8g72","PYSEC-2026-2289"],"primaryLinks":["https://github.com/advisories/GHSA-29pf-2h5f-8g72"],"publishedFixedVersionEvents":["5.3.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2026-5241","GHSA-fgcw-684q-jj6r","PYSEC-2026-2290"],"primaryLinks":["https://github.com/advisories/GHSA-fgcw-684q-jj6r"],"publishedFixedVersionEvents":["5.5.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"transformers","lockedVersion":"4.48.3","identifiers":["CVE-2026-9856","GHSA-xrqw-3rrv-vx5w","PYSEC-2026-3929"],"primaryLinks":["https://github.com/advisories/GHSA-xrqw-3rrv-vx5w"],"publishedFixedVersionEvents":["5.10.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"urllib3","lockedVersion":"2.7.0","identifiers":["CVE-2026-97689","GHSA-vxq7-64xx-v4gw","PYSEC-2026-4177"],"primaryLinks":["https://github.com/advisories/GHSA-vxq7-64xx-v4gw"],"publishedFixedVersionEvents":["2.8.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]}, + {"package":"urllib3","lockedVersion":"2.7.0","identifiers":["CVE-2026-97688","GHSA-gh4c-6fx4-qh6g","PYSEC-2026-4176"],"primaryLinks":["https://github.com/advisories/GHSA-gh4c-6fx4-qh6g"],"publishedFixedVersionEvents":["2.8.0"],"providerRecordCount":4,"publishedSeverityLabels":["MODERATE"]}, + {"package":"urllib3","lockedVersion":"2.7.0","identifiers":["CVE-2026-97687","GHSA-8988-9cw3-xx77","PYSEC-2026-4175"],"primaryLinks":["https://github.com/advisories/GHSA-8988-9cw3-xx77"],"publishedFixedVersionEvents":["2.8.0"],"providerRecordCount":4,"publishedSeverityLabels":["HIGH"]} + ] +} diff --git a/docs/redesign/phase-9/p9-requal-01/reconcile.py b/docs/redesign/phase-9/p9-requal-01/reconcile.py new file mode 100644 index 0000000..ee1ee13 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/reconcile.py @@ -0,0 +1,187 @@ +"""Record actual requalification outcomes; reject incomplete or overlapping browser proof.""" +import hashlib +import json +import sys +from pathlib import Path +import xml.etree.ElementTree as ET +from collections import Counter + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[3] +RAW = ROOT / '.artifacts/p9-requal-01' + +def load(path): + data = path.read_bytes() + return json.loads(data.decode('utf-16' if data.startswith(b'\xff\xfe') else 'utf-8-sig')) + +def identity(path): + return {'path': path.relative_to(ROOT).as_posix(), 'sha256': hashlib.sha256(path.read_bytes()).hexdigest()} + +def specs(report): + for suite in report.get('suites', []): + yield from suite.get('specs', []) + yield from specs(suite) + +def browser_results(report, exit_code, expected_count=None): + if exit_code != 0 or report.get('errors'): raise ValueError('Browser process or run-level failure.') + cases = [] + for spec in specs(report): + for test in spec['tests']: + results = test.get('results', []) + if test.get('expectedStatus') != 'passed' or len(results) != 1: + raise ValueError('Missing, repeated or expected-failure execution.') + result = results[0] + if result.get('status') != 'passed' or result.get('retry', 0) != 0: + raise ValueError('Failed, skipped or retried browser execution.') + cases.append({'id': spec['id'] + ':' + test['projectName'], 'title': spec['title'], + 'outcome': result['status'], 'durationMs': result['duration'] if 'duration' in result else None}) + if len({c['id'] for c in cases}) != len(cases): raise ValueError('Duplicate browser case IDs.') + if expected_count is not None and len(cases) != expected_count: raise ValueError('Browser membership count mismatch.') + return cases + +def reconcile_ordinary(discovery, shards): + expected = [s['id'] + ':' + t['projectName'] for s in specs(discovery) for t in s['tests']] + actual = [case for shard in shards for case in shard] + ids = [case['id'] for case in actual] + if discovery.get('errors') or len(expected) != len(set(expected)) or len(ids) != len(set(ids)) or set(ids) != set(expected): + raise ValueError('Ordinary discovery and actual shard membership differ or overlap.') + return actual + +def require_complete(results): + incomplete=[name for name,result in results.items() if result.get('status')!='PASS'] + if incomplete: raise ValueError('Required automation incomplete or failing: '+', '.join(incomplete)) + +def sidecar_results(root, expected): + cases=list(root.iter('testcase')) + identities=[(case.get('classname'),case.get('name')) for case in cases] + if len(cases)!=expected or len(set(identities))!=expected or any(not name for _,name in identities): + raise ValueError('Missing or duplicate sidecar cases.') + if any(case.find(tag) is not None for case in cases for tag in ['failure','error','skipped']): + raise ValueError('Failed or skipped sidecar cases.') + return [{'classname':group,'name':name,'outcome':'passed'} for group,name in identities] + +def jest_results(report, baseline, exit_code, expected): + def rows(value): + return [(suite['name'].replace('\\','/'),case) for suite in value['testResults'] for case in suite['assertionResults']] + actual, reference=rows(report), rows(baseline) + # test.each can legitimately generate identical labels; preserve their exact multiplicity. + membership=lambda items: Counter((file,case['fullName']) for file,case in items) + if exit_code!=0 or len(actual)!=expected or membership(actual)!=membership(reference): + raise ValueError('Frontend native case membership differs from unchanged-source reference.') + if any(case['status']!='passed' or case.get('invocations',1)!=1 or case.get('retryReasons') for _,case in actual): + raise ValueError('Failed, skipped or retried frontend case.') + return [{'file':file,'nativeOrdinal':index,'name':case['fullName'],'outcome':case['status']} for index,(file,case) in enumerate(actual)] + +def security_results(commands, npm, nuget): + expected={'supply-chain','evaluator','browser-runtime','ingress','secrets','sbom','node-guards','extension', + 'database-runner','browser-database-boundary','nuget-advisories','npm-advisories'} + if len(commands)!=len(expected) or {command['name'] for command in commands}!=expected: + raise ValueError('Missing or duplicate security command evidence.') + projects=nuget.get('projects',[]) + if len(projects)!=1 or not projects[0].get('path','').replace('\\','/').endswith('/JobTrackerApi/JobTrackerApi.csproj'): + raise ValueError('Missing or unexpected NuGet project evidence.') + if nuget.get('problems') or nuget.get('errors') or any(project.get('errors') for project in projects): + raise ValueError('NuGet audit errors.') + vulnerabilities=[package for project in projects for framework in project.get('frameworks',[]) for key in ['topLevelPackages','transitivePackages'] for package in framework.get(key,[]) if package.get('vulnerabilities')] + passed=all(command['exitCode']==0 for command in commands) and npm['metadata']['vulnerabilities']['total']==0 and not vulnerabilities + return passed,vulnerabilities + +def python_security_status(record): + if record['advisoryGroups']: return 'FINDINGS' + return 'INCOMPLETE' if record['errors'] else 'PASS' + +def collect_browser(name, count=None): + report_path, process_path = RAW / (name + '.json'), RAW / (name + '-exit.json') + result = {'lane': name} + try: + report, process = load(report_path), load(process_path) + result.update(report=identity(report_path), processEvidence=identity(process_path), process=process) + result['cases'] = browser_results(report, process['exitCode'], count) + result.update(status='PASS', passed=len(result['cases']), stats=report.get('stats')) + except FileNotFoundError as error: result.update(status='NOT_RUN', reason=str(error)) + except (ValueError, KeyError) as error: result.update(status='FAIL', reason=str(error)) + return result + +def collect_trx(name, file, expected): + result = {'lane': name} + try: + path = RAW / file + root = ET.parse(path).getroot() + counters = next(e.attrib for e in root.iter() if e.tag.endswith('Counters')) + cases = [e.attrib for e in root.iter() if e.tag.endswith('UnitTestResult')] + process = load(RAW / (name + '-exit.json')) + passed = process['exitCode'] == 0 and int(counters['passed']) == expected and int(counters['total']) == expected and len(cases) == expected + passed = passed and len({(c['testId'],c['testName']) for c in cases}) == expected and len({c['executionId'] for c in cases}) == expected + passed = passed and all(c['outcome'] == 'Passed' for c in cases) + result.update(status='PASS' if passed else 'FAIL', report=identity(path), counters=counters, process=process, + cases=[{'testId':c['testId'],'executionId':c['executionId'],'name':c['testName'], 'outcome':c['outcome']} for c in cases]) + except FileNotFoundError as error: result.update(status='NOT_RUN', reason=str(error)) + return result + +def main(): + results = {'backend':collect_trx('backend','backend/backend.trx',1123), + 'mariadb':collect_trx('mariadb','mariadb/mariadb.trx',32)} + for index in range(1,5): results[f'ordinary-{index}'] = collect_browser(f'ordinary-{index}') + try: + if not all(results[f'ordinary-{i}']['status']=='PASS' for i in range(1,5)): raise ValueError('Incomplete ordinary shards.') + actual=reconcile_ordinary(load(RAW/'discovery.json'),[results[f'ordinary-{i}']['cases'] for i in range(1,5)]) + if len(actual)!=362: raise ValueError('Unexpected ordinary discovery count.') + results['ordinary']={'status':'PASS','passed':len(actual),'discovery':identity(RAW/'discovery.json')} + except (FileNotFoundError,ValueError) as error: results['ordinary']={'status':'NOT_COMPLETE','reason':str(error)} + for name,count in {'ai':2,'auth':2,'rate':9,'ingress':6,'pdf-admission':1,'preferences':3, + 'rd21':6,'diagnostics':18,'volume':3,'rd21-volume':3,'mariadb-browser':1,'mariadb-observations':2,'linux-renderer':5}.items(): + results[name]=collect_browser(name,count) + try: + path=RAW/'frontend.json'; data=load(path); process=load(RAW/'frontend-exit.json') + cases=jest_results(data,load(RAW/'frontend-before-security.json'),process['exitCode'],934) + passed=process['exitCode']==0 and data['numPassedTests']==934 and data['numTotalTests']==934 and data['numPendingTests']==0 and data['numTodoTests']==0 and data['numFailedTests']==0 + results['frontend']={'status':'PASS' if passed else 'FAIL','passed':data['numPassedTests'], + 'suites':data['numPassedTestSuites'],'report':identity(path),'process':process, + 'cases':cases,'membershipReference':identity(RAW/'frontend-before-security.json')} + except FileNotFoundError as error: results['frontend']={'status':'NOT_RUN','reason':str(error)} + except ValueError as error: results['frontend']={'status':'FAIL','reason':str(error)} + for name in ['types','lint','build','sidecar']: + try: + process=load(RAW/(name+'-exit.json')) + results[name]={'status':'PASS' if process['exitCode']==0 else 'FAIL','process':process,'log':identity(RAW/(name+'.log'))} + if name=='sidecar': + try: results[name]['cases']=sidecar_results(ET.parse(RAW/'sidecar.xml').getroot(),56) + except ValueError as error: results[name].update(status='FAIL',reason=str(error)) + results[name]['report']=identity(RAW/'sidecar.xml') + except FileNotFoundError as error: results[name]={'status':'NOT_RUN','reason':str(error)} + for name,file in [('performance','performance/result.json'),('native-pdf','native-pdf.json'),('linux-pdf','linux-pdf.json')]: + try: + data=load(RAW/file) + results[name]={'status':data['status'],'record':data,'evidence':identity(RAW/file)} + except FileNotFoundError: results[name]={'status':'NOT_RUN'} + try: + path=RAW/'security/commands.json'; commands=load(path) + npm=load(RAW/'security/frontend-audit.json') + nuget=load(RAW/'security/nuget-advisories.log') + passed,vulnerabilities=security_results(commands,npm,nuget) + results['security']={'status':'PASS' if passed else 'FAIL','commands':commands,'evidence':identity(path),'npmAudit':identity(RAW/'security/frontend-audit.json'),'nugetAudit':identity(RAW/'security/nuget-advisories.log'),'nugetVulnerabilities':vulnerabilities,'npmVulnerabilities':npm['metadata']['vulnerabilities']} + except FileNotFoundError: results['security']={'status':'NOT_RUN'} + except ValueError as error: results['security']={'status':'FAIL','reason':str(error)} + try: + path=HERE/'python-advisories.json'; data=load(path) + if data['lockSha256']!=identity(ROOT/data['lockPath'])['sha256']: + raise ValueError('Python lock changed after advisory queries.') + results['python-advisories']={'status':python_security_status(data),'coverage':data['coverage'], + 'counts':data['counts'],'errors':data['errors'],'evidence':identity(path)} + except FileNotFoundError: results['python-advisories']={'status':'NOT_RUN'} + except ValueError as error: results['python-advisories']={'status':'FAIL','reason':str(error)} + manifest=RAW/'source-freeze.json' + source=load(manifest) + drift=[name for name,expected in source['inputs'].items() if not (ROOT/name).is_file() or hashlib.sha256((ROOT/name).read_bytes()).hexdigest()!=expected] + record={'schemaVersion':1,'baselineCommit':'549b2cba5a791862ba3f854312ea819a86dc42a0', + 'branch':'fix/p9-ci-and-requalification','countPolicy':'Separate lanes; discovery-only skips and overlapping reruns never enter executed totals.', + 'sourceIdentity':identity(manifest),'frozenInputCount':len(source['inputs']),'runtimeDrift':drift,'results':results} + record['automationComplete']=not drift and all(value.get('status')=='PASS' for value in results.values()) + (HERE/'validation.json').write_text(json.dumps(record,indent=2)+'\n',encoding='utf-8') + print(json.dumps({name:data.get('status','RECORDED') for name,data in results.items()})) + if drift: raise SystemExit('Runtime source changed: '+str(drift)) + if '--collect-only' not in sys.argv: + try: require_complete(results) + except ValueError as error: raise SystemExit(str(error)) + +if __name__=='__main__': main() diff --git a/docs/redesign/phase-9/p9-requal-01/test-linux-run.py b/docs/redesign/phase-9/p9-requal-01/test-linux-run.py new file mode 100644 index 0000000..9df02fa --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/test-linux-run.py @@ -0,0 +1,59 @@ +"""Offline failure-path checks; these do not qualify a database or renderer.""" +import contextlib +import importlib.util +import io +import json +import tempfile +import unittest +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import patch + +spec = importlib.util.spec_from_file_location('linux_run', Path(__file__).with_name('linux-run.py')) +runner = importlib.util.module_from_spec(spec) +spec.loader.exec_module(runner) + +class CleanupTests(unittest.TestCase): + def exercise(self, *, sql_failure=False, log_failure=False): + calls=[] + migration_reads=0 + def command(args, **kwargs): + calls.append(args) + if args==['docker','inspect',runner.DB]: + return json.dumps([{'Config':{'Image':runner.PIN,'Labels':{'com.docker.compose.project':'jobtracker-it-p9-requal','com.docker.compose.service':'mariadb-test'}}, + 'State':{'Running':True,'Health':{'Status':'healthy'}}, + 'HostConfig':{'Tmpfs':{'/var/lib/mysql':''},'PortBindings':{'3306/tcp':[{'HostIp':'127.0.0.1','HostPort':'33308'}]}}}]) + if args[:2]==['docker','logs'] and log_failure: raise OSError('Synthetic log capture failure') + return 'synthetic identity' + def sql(query): + nonlocal migration_reads + if query=='SELECT VERSION()': return '12.2.2-MariaDB-test' + if '__EFMigrationsHistory' in query: + migration_reads+=1 + if migration_reads==2 and sql_failure: raise OSError('Synthetic post-run SQL failure') + return '1' + return '0' + def urlopen(url, **kwargs): + return io.BytesIO(json.dumps({'version':runner.VERSION} if url.endswith('/health') else {'status':'ready'}).encode()) + with tempfile.TemporaryDirectory(prefix='p9-linux-guard-') as directory: + out=Path(directory)/'linux' + with patch.object(runner,'OUT',out), patch.object(runner,'command',command), patch.object(runner,'sql',sql), \ + patch.object(runner.urllib.request,'urlopen',urlopen), patch.object(runner.subprocess,'run',return_value=SimpleNamespace(returncode=0)), \ + patch.object(runner.sys,'argv',['linux-run.py']), contextlib.redirect_stdout(io.StringIO()): + with self.assertRaises(SystemExit) as failure: runner.main() + self.assertEqual(failure.exception.code,1) + record=json.loads((out/'process.json').read_text(encoding='utf-8')) + self.assertEqual(record['browserExitCode'],0) + self.assertEqual(record['exitCode'],1) + self.assertTrue(record['cleanup']['apiRemoved']) + self.assertTrue(record['cleanup']['schemaRemoved']) + self.assertTrue(any(args[:3]==['docker','rm','--force'] for args in calls)) + self.assertEqual(json.loads((out.parent/'linux-renderer-exit.json').read_text())['exitCode'],1) + + def test_post_run_sql_failure_cannot_pass(self): + self.exercise(sql_failure=True) + + def test_log_failure_does_not_suppress_removal(self): + self.exercise(log_failure=True) + +if __name__=='__main__': unittest.main() diff --git a/docs/redesign/phase-9/p9-requal-01/test-project-advisories.json b/docs/redesign/phase-9/p9-requal-01/test-project-advisories.json new file mode 100644 index 0000000..e227e2a --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/test-project-advisories.json @@ -0,0 +1,20 @@ +{ + "observedUtc": "2026-10-24T11:08:20.616748+00:00", + "status": "PASS", + "projects": [ + { + "project": "JobTrackerApi.Tests", + "exitCode": 0, + "report": ".artifacts/p9-requal-01/security/JobTrackerApi.Tests-audit.json", + "sha256": "7083e801175539d0f1a00f0c24fe5577275485445f06e6daadb87c528f278b00", + "vulnerabilities": [] + }, + { + "project": "JobTrackerApi.MariaDb.Tests", + "exitCode": 0, + "report": ".artifacts/p9-requal-01/security/JobTrackerApi.MariaDb.Tests-audit.json", + "sha256": "14505f7f80a7d470bbc75806784e5dbfea1a89c6f605f47eaa5551eb9c6461a6", + "vulnerabilities": [] + } + ] +} diff --git a/docs/redesign/phase-9/p9-requal-01/test-reconcile.py b/docs/redesign/phase-9/p9-requal-01/test-reconcile.py new file mode 100644 index 0000000..b2c01d4 --- /dev/null +++ b/docs/redesign/phase-9/p9-requal-01/test-reconcile.py @@ -0,0 +1,82 @@ +"""Offline fail-closed checks for the requalification result ledger.""" +import copy +import importlib.util +from pathlib import Path +import unittest +import xml.etree.ElementTree as ET + +spec = importlib.util.spec_from_file_location('requalification', Path(__file__).with_name('reconcile.py')) +ledger = importlib.util.module_from_spec(spec) +spec.loader.exec_module(ledger) + +def report(identifier='one'): + return {'errors': [], 'suites': [{'specs': [{'id': identifier, 'title': identifier, + 'tests': [{'projectName': 'chromium', 'expectedStatus': 'passed', + 'results': [{'status': 'passed', 'retry': 0}]}]}]}]} + +class EvidenceGuards(unittest.TestCase): + def test_accepts_completed_native_case(self): + self.assertEqual(len(ledger.browser_results(report(), 0, 1)), 1) + + def test_failed_process_cannot_be_qualified_by_passing_cases(self): + with self.assertRaises(ValueError): ledger.browser_results(report(), 1, 1) + + def test_rejects_skips_retries_and_missing_results(self): + for results in [[{'status':'skipped','retry':0}], [{'status':'passed','retry':1}], []]: + value=report(); value['suites'][0]['specs'][0]['tests'][0]['results']=results + with self.assertRaises(ValueError): ledger.browser_results(value, 0, 1) + + def test_rejects_expected_failure_and_run_errors(self): + value=report(); value['suites'][0]['specs'][0]['tests'][0]['expectedStatus']='failed' + with self.assertRaises(ValueError): ledger.browser_results(value, 0, 1) + value=report(); value['errors']=[{'message':'web server failed'}] + with self.assertRaises(ValueError): ledger.browser_results(value, 0, 1) + + def test_rejects_count_mismatch_and_duplicate_cases(self): + with self.assertRaises(ValueError): ledger.browser_results(report(), 0, 2) + value=report(); value['suites']*=2 + with self.assertRaises(ValueError): ledger.browser_results(value, 0) + + def test_discovery_only_skip_status_is_not_runtime_skip_evidence(self): + discovery=report(); discovery['suites'][0]['specs'][0]['tests'][0]['results']=[] + discovery['stats']={'skipped':1,'expected':0} + self.assertEqual(len(ledger.reconcile_ordinary(discovery, [ledger.browser_results(report(),0)])),1) + + def test_shards_cannot_overlap_or_omit_discovery_members(self): + cases=ledger.browser_results(report(),0) + with self.assertRaises(ValueError): ledger.reconcile_ordinary(report(), [cases,cases]) + with self.assertRaises(ValueError): ledger.reconcile_ordinary(report('different'), [cases]) + + def test_final_gate_cannot_succeed_with_incomplete_or_failed_lanes(self): + ledger.require_complete({'one': {'status': 'PASS'}}) + for status in ['FAIL', 'NOT_RUN', 'NOT_COMPLETE', 'BLOCKED', 'FINDINGS', 'INCOMPLETE']: + with self.assertRaises(ValueError): ledger.require_complete({'one': {'status':'PASS'}, 'two': {'status':status}}) + + def test_sidecar_requires_unique_successful_native_cases(self): + value=ET.fromstring('') + self.assertEqual(len(ledger.sidecar_results(value,2)),2) + duplicate=ET.fromstring('') + with self.assertRaises(ValueError): ledger.sidecar_results(duplicate,2) + failed=ET.fromstring('') + with self.assertRaises(ValueError): ledger.sidecar_results(failed,1) + + def test_jest_parameterized_labels_require_exact_baseline_multiset(self): + value={'testResults':[{'name':'suite.ts','assertionResults':[ + {'fullName':'same label','status':'passed','invocations':1}, + {'fullName':'same label','status':'passed','invocations':1}]}]} + self.assertEqual(len(ledger.jest_results(value,value,0,2)),2) + extra=copy.deepcopy(value); extra['testResults'][0]['assertionResults'].append(extra['testResults'][0]['assertionResults'][0]) + with self.assertRaises(ValueError): ledger.jest_results(extra,value,0,3) + retried=copy.deepcopy(value); retried['testResults'][0]['assertionResults'][0]['invocations']=2 + with self.assertRaises(ValueError): ledger.jest_results(retried,value,0,2) + + def test_security_rejects_missing_commands_and_empty_project_evidence(self): + with self.assertRaises(ValueError): ledger.security_results([],{'metadata':{'vulnerabilities':{'total':0}}},{'projects':[]}) + + def test_known_python_advisories_cannot_be_a_clean_security_gate(self): + value={'advisoryGroups':[{'identifiers':['one']}],'errors':[{'httpStatus':404}]} + self.assertEqual(ledger.python_security_status(value),'FINDINGS') + self.assertEqual(ledger.python_security_status({'advisoryGroups':[],'errors':[{}]}),'INCOMPLETE') + self.assertEqual(ledger.python_security_status({'advisoryGroups':[],'errors':[]}),'PASS') + +if __name__ == '__main__': unittest.main()