P5-13 — CV AI grounding readiness
This records the explicitly authorized grounding and stale-apply prerequisite. It does not accept the P5-13 presentation migration or start P5-14, P5-15 or B07. Contract enforcement and model factual accuracy are separate acceptance categories.
Starting checkpoint: d8d262e4d1a6223f4b6c5fa52b8419013a929d35 on codex/ui-redesign-phase4. Scope is existing CV section and whole-document suggestions, authoritative source selection, factual assessment, explicit acceptance and existing variant save/history. No new model, provider, schema, profile write, global AI panel or review-layout redesign is introduced.
Why this prerequisite exists
The original local characterization used synthetic source Built reliable APIs and a mocked provider result Managed 50 engineers at Microsoft and increased revenue 300%.
| Original proof | Observation at the starting checkpoint | What the proof establishes |
|---|---|---|
| Section assistant: unsupported provider output | Explicit Apply passed the invented employer, responsibility and metrics to the callback unchanged | Existing review UI did not enforce support; this was not a real model factuality measurement |
| Section assistant: source changed during pending generation | The source changed to Newer user content; the old response arrived and could still be applied |
Existing pending-response handling did not require current source review |
| Direct backend controller action | Mocked provider output was returned unchanged with HTTP 200; no master-profile change or variant/PDF call occurred | The suggestion endpoint accepted unvalidated output. Direct invocation bypassed middleware and did not prove entitlement, persistence or user acceptance |
The two frontend characterization checks passed because they reproduced unsafe behavior. They were not P5-13 acceptance passes. Historical, ignored local evidence remains in the characterization record, frontend proof source, backend harness description and backend result. These links are local investigation artifacts, not committed portable evidence. The harness linked the controller at execution time; rerunning it against the repaired tree is not a reproduction of the original checkpoint.
The Phase 3 AI interaction contract already required stale-source rejection and known-source factual evaluations, while assigning structured claim references and unsupported-claim validation to a separate API/evaluation contract. A prompt, source chip or check-facts notice cannot supply that contract. An exact-copy restriction would also remove legitimate rewriting and translation.
Approved architecture extension
The existing AI architecture and accepted ADR-004 place authorization and usage policy in .NET and configured provider routing inside the private sidecar. Inspection found no runtime factual evaluator before this checkpoint. The existing offline evaluation harness uses case-folded mustContain/mustNotContain checks and optional JSON keys; it remains unchanged and is not a runtime semantic grounding authority.
The extension follows the existing path:
owned saved CV source → existing rewrite generation → separate factual assessment
→ strict server assessment validation → protected proposal
→ explicit Apply → source recheck → existing versioned CV save
This boundary covers the CV Builder's section and whole-document suggestion consumers. Legacy profile-CV rewriting and Job Application package/narrative generation retain their existing controllers/validators and are not migrated by this checkpoint. Sharing ISummarizerService is not evidence that those separate content domains now have protected CV proposals. No application-wide factuality certification follows from this bounded repair.
ISummarizerService.EvaluateCvRewriteAsync accepts (candidateSource, proposal, contextOnly, cancellationToken) and returns nullable AiGenerationResult, with assessment JSON in Text. Its default implementation returns null so older implementations cannot approve an unevaluated rewrite. MeteredSummarizerService uses the ordinary synchronous usage gate for this additional call; generation and review are separate metered operations.
The private sidecar route, /cv/evaluate-rewrite, accepts exactly the candidate source, proposal and requirements-only context used by the API. It uses the existing cv-rewrite task policy, shared service-token protection, configured local-first routing and external-processing privacy gate. It does not add unrelated profile context, choose a new model or bypass consent on fallback. Combined input is bounded to 20,000 characters and context to 6,000 characters; the CV suggestion service further bounds submitted context to 4,000. Oversized review input fails closed rather than truncating evidence or a proposal.
The evaluator is independent of the generation request, but uses the existing configured provider/model route. It is not an independently verified factual oracle or a separate model architecture.
Typed document-format correction
Review reproduced an existing conflicting provider contract: the controller requested a JSON block array for document actions, but /cv/rewrite unconditionally requested plain text and “No JSON”. The new strict shape gate would safely reject that output, but valid document generation still needed a compatible transport. AiGenerationOutputMode.CvBlocksJson now explicitly selects the sidecar's block-array format through the existing provider abstraction and usage owner. Text remains the default for existing section/legacy calls; older providers without typed document support fail closed. Cache keys include the output mode, so a text response cannot be reused as document JSON. No model, renderer, template or document-language mutation is introduced by this format correction.
The transport and sidecar format tests exercise both modes, missing/default text mode and invalid modes. The real HTTP proof additionally checks that a document action transmits output_mode: cv_blocks_json, returns the original IDs, and applies through the same owned revision save. Actual configured-model JSON compliance and language accuracy remain live-provider qualifications.
Authoritative source and assessment contract
CvAiSuggestionService loads the authenticated owner's saved variant and canonical Career Profile through the existing read-only owner path, then resolves the existing render model. Client text is only a consistency check against the selected saved source; it is never a substitute for authoritative source data.
- Section requests require a typed
targetIdidentifying the headline, standard section, entry or custom section. Generation receives the selected item's text; assessment receives its selected block values, including the corresponding title/subtitle. An explicitly selected omitted section or entry remains editable, with only that selected block as evidence. - Whole-document requests have no
targetIdand usedocument-translate,document-improveordocument-grammar. The source is the included editable block array; omitted rows stay excluded. The current block representation containsid, optionaltitle/subtitleanditems. Contact and date metadata outside these fields are not rewritten by this route. - Grouped Skills are outside the existing whole-document editable block representation; this checkpoint does not invent a rewrite/apply mapping for that rendering form. Explicit section actions keep their original editable section items. Whole-document AI must not be advertised as rewriting every field or every presentation.
- Job/role/context text describes requirements or the requested task. It cannot establish candidate employment, skill, qualification or other factual support. No unrelated account/resource context is added.
- UI language and target document language remain separate. Existing section and document language controls retain English and Norwegian Bokmål; semantic review must permit faithful translation, paraphrase and shortening.
The assessment JSON has exactly this structure:
{
"verdict": "supported",
"coverageComplete": true,
"claims": [
{
"text": "Developed dependable APIs.",
"verdict": "supported",
"sourceQuotes": ["Built reliable APIs."]
}
]
}
Each verdict is supported, unsupported or unknown. The evaluator must assess every factual assertion within each complete nonempty trimmed proposal line, or within each complete nonempty JSON title/subtitle/items value. IDs are routing data and cannot provide candidate evidence. One entry may contain several assertions; all must be supported for that entry to receive supported.
CvAiGrounding.IsSupported accepts only the exact supported schema, coverageComplete: true, one supported entry for every proposal value and at least one nonempty exact candidate-source excerpt per entry. Quotes must occur within a candidate source line or decoded source value. Missing, extra or duplicate schema properties, malformed JSON, missing/duplicate/wrong proposal coverage, invalid quotes, unsupported or unknown entries and mixed output reject the entire proposal. Whole-document structure separately requires every original known ID exactly once and valid original fields/types.
The deterministic numeric guard rejects introduced numeric tokens even if the reviewer claims support, including the original invented 50/300% case, new dates/salary and a quantity changed into a percentage. IDs cannot license numeric claims. This is a conservative token guard, not dimensional analysis or universal handling of number words, every locale format or semantic quantity changes. Semantic support for employers, skills, responsibilities and other claims remains the evaluator's judgment.
Final review found another trust-boundary weakness in whole-document assessments: a quote or numeric token from entry A could license a claim under entry B. Two failing regressions reproduced this before repair. The validator now retains each decoded value's block ID and restricts evidence/numeric tokens for entry:* values to that same entry. It still permits a summary to consolidate known candidate facts and permits repeated grounded wording in distinct entries; two additional positive regressions protect those legitimate transformations. Quote matching checks source membership within the permitted scope; it still does not replace semantic entailment evaluation.
Protected acceptance and freshness
The controller contract retains authenticated owner access and the existing Pro policy. POST /api/cv/ai/assist requires variantId and expectedVersion, with targetId for section scope. Successful generation returns { original, result, proposalToken }; generation/review do not change career content, variant settings or CV history. Operational usage accounting still occurs.
The existing data-protection key ring protects the proposal capability. It binds owner, variant, version, a SHA-256 fingerprint of persisted canonical profile plus saved variant settings, scope, action, requirements context, original source and reviewed result. A client cannot replace a protected result or assert its own source. POST /api/cv/variants/{id}/ai/apply accepts that capability and an optional edited result. A changed result is structurally checked and independently reassessed before acceptance; a failed reassessment writes no CV change.
Freshness is checked before generation, after provider/reviewer work and before Apply. Apply clears tracked state and reads the source again inside a serializable relational transaction; the final canonical fingerprint/version check and ordinary versioned variant save occur in that same transaction. This covers canonical source changes that do not increment a CV variant version. Only scoped variant settings and the existing append-only CV history are changed; the canonical profile and sibling CVs remain outside the mutation boundary. Accepted saves use existing ai:<action> history provenance. Replay after the accepted version advances fails freshness checks.
Ordinary authored-content saves retain the existing version contract. The controller trims the submitted source before rejecting the reserved case-insensitive ai: prefix, so whitespace cannot forge AI provenance. Users may still author and save arbitrary manual content outside this AI capability path. This checkpoint neither certifies the truth of all user-authored source facts nor treats ordinary autosave as reviewed AI output.
| Failure | API behavior |
|---|---|
| Missing variant/version precondition | 428, cv_revision_required |
| Saved variant or canonical source changed | 409, cv_ai_source_changed; ordinary save concurrency retains cv_revision_conflict |
| Malformed/unsupported whole-document shape | 422, cv_ai_proposal_invalid |
| Missing, malformed, unsupported, unknown or incomplete assessment | 422, cv_ai_grounding_unproven |
| Invalid protected capability | 400, cv_ai_proposal_invalid |
| Capability belongs to another owner/variant | 404, cv_ai_proposal_unavailable |
| Ordinary save asserts reserved AI provenance | 400, cv_ai_proposal_required |
| Provider/reviewer unavailable | Existing safe unavailable response; no invented fallback output |
Provider/reviewer exceptions become 502, cv_ai_unavailable at the controller. These machine-readable results use existing frontend error surfaces; refined grounding/stale guidance and diff presentation remain P5-13 work.
Deployment must release the API and private sidecar together. An older sidecar without the review route or typed document mode cannot silently approve content: the request fails closed through the existing unavailable/invalid response path. The existing data-protection key-ring lifecycle remains authoritative; unavailable keys make a pending capability unusable rather than permitting an unverified Apply. This checkpoint does not deploy production or change provider configuration.
Existing frontend integration
CvBuilderEditor flushes the existing save queue before generating or applying a suggestion, sends the persisted server version and accepts only the server-returned saved variant. Generation is invalidated if the editor epoch or local revision changes. Apply is serialized with ordinary saves; a local edit arriving while Apply is in flight enters a conflict state instead of silently overwriting that local draft.
AiSectionAssistant discards an open or pending proposal when selected text, target, document language or AI availability changes. Request identity also invalidates Reject/Close and older completions. Whole-document review similarly invalidates when its resolved source/settings scope changes. Edited acceptance keeps the original protected proposal and sends the edited value to the server. Reject, Close and generation failure do not apply content. Client invalidation improves review behavior; server source checks remain the authority when canonical data or another session changes.
The typed frontend API, section/document tests and builder integration tests cover these boundaries. This is prerequisite wiring in existing surfaces, not the P5-13 diff/review presentation redesign or a complete native responsive/accessibility acceptance claim.
Flushing a dirty editor before generation may persist an ordinary user edit through the existing autosave queue. That is distinct from recording an unaccepted proposal: a clean generation/rejection creates no content history, and only server acceptance writes ai:<action> history. No second undo/save/concurrency owner is introduced.
Files and preservation impact
| Owner / files | Why required by this checkpoint |
|---|---|
CvVariantController.cs, Program.cs, new CvAiSuggestionService.cs |
Owned source selection, protected proposal/apply route, final transactional freshness, existing versioned save and DI; reserved AI provenance cannot be client asserted |
New CvAiGrounding.cs |
Strict assessment/coverage/evidence validation and independent introduced-numeric rejection |
SummarizerService.cs, MeteredSummarizerService.cs, tools/summarizer/app.py |
Extend the approved private provider path with factual review and typed document output while preserving privacy, metering and text defaults |
cvBuilder.ts, AiSectionAssistant.tsx, CvBuilderEditor.tsx |
Minimal necessary protected-proposal plumbing, saved-source flush, late-result rejection and acceptance through the server; existing visual composition retained |
CvAiReadinessTests.cs, CvAiGroundingTests.cs, CvAiEvaluationTests.cs, corpus, metering/entitlement tests, sidecar tests |
Permanent source, evaluation, transaction, transport, privacy, limits and provenance evidence |
Existing section/editor Jest tests; new ai-tests/cv-ai-readiness.spec.ts, playwright.cv-ai.config.ts, scripts/cv-ai-provider-fixture.mjs |
Behavioral client proof and isolated real HTTP/auth/SQLite/provider-transport proof; no production provider or normal browser-harness configuration change |
e2e/cv-settings-presentation.spec.ts, e2e/smoke.spec.ts |
Narrow inherited fixture stabilization after the first complete browser run exposed moving pointer targets during long-preview reflow; existing application controls and export assertions remain unchanged |
e2e/semantic-foundations.spec.ts |
Reuse its existing finite-transition/contrast boundary before checking settled command Tab focus; the entry callback otherwise returns focus to the input during the assertion |
No application file outside these readiness owners changes. Package/lock files, CI, database schema, renderer, templates, preview geometry, routing and review-layout styling remain unchanged.
The first complete browser run recorded 110 passes and two failures: light/Bokmål margin reset did not issue its save after reload, and the long Code-template Experience disclosure did not activate by pointer. Existing preview/PDF oracles passed, and the failures were retained in .artifacts/p5-13-readiness/browser.json. The settings fixture now waits for the existing aria-busy=false and data-cv-preview-ready=true layout signals before the same pointer activation. The Code fixture uses its named disclosure's keyboard activation, matching its existing Education keyboard step. No sleep, retry, skip, export assertion removal, or application fix was added. These corrections do not qualify all pointer/reflow interaction; that separate debt remains open. A second run was interrupted for the cross-entry repair and is not an acceptance result.
The next complete run recorded 111 passes and one failure in browser-accepted.json: inherited dark command focus timing. Tab briefly focused the first command before the unchanged MUI Dialog onEntered callback focused the input. The captured failure shows the input ring; the trace records command focus about 250 ms after Ctrl+K, during entry. The loaded-state fixture now reuses its existing finite-transition/contrast boundary before keyboard traversal; its command focus and 3px outline assertions are retained. No command application code changes. This only accepts settled-dialog behavior. Very early keyboard interaction during entry remains an explicit inherited timing qualification, not a repaired product behavior. The final post-fixture run and repeated fidelity oracles use distinct browser-verified, fidelity-verified and settings-fidelity-verified paths.
The final complete post-fixture run passes 112/112 in 27.7 minutes, with zero skipped, expected-failure or flaky cases. Earlier failed/incomplete runs remain investigation evidence, not acceptance passes. The final fidelity outputs again pass 16/16 (36 = 36 pages) and 8/8 settings exports (24 = 24 pages) with the original oracle and tolerances.
| PRES contract | Readiness requirement → implementation → evidence |
|---|---|
| PRES-C01 | Canonical Career Profile isolation and freshness → read-only owner source, full persisted-source fingerprint, no profile writes → SQLite and real HTTP canonical/history readback, source-change conflict |
| PRES-C06 | Existing editor/save/preview lifecycle → queue flush and server-returned variant only → editor Jest, inherited native frame/preview checks |
| PRES-C07 | Scoped overrides, custom/omitted content and unrelated settings retained → typed target and known-block-only application → omitted/whole-document SQLite tests, section/editor Jest |
| PRES-C10 | Revision/undo/conflict → existing versioned save, serializable final source check and undo owner → accepted/replayed/stale/edited-review history checks, five revision-safety tests |
| PRES-C11 | Grounded generation/review/accept/reject/language → strict evaluator gate, protected proposal, typed JSON output and client invalidation → 26-case EN/NB corpus, parser/service/sidecar checks, focused Jest, real HTTP proof |
| PRES-S04 | Existing entitlement/privacy/usage → same Pro policies, meter and private local-first/consent route → added Apply policy/meter tests, existing privacy tests, sidecar fallback checks |
| PRES-E09 | Owner/current-session and stale private state → existing session boundary plus owner/CV-bound capability → real cookie/CSRF/session-context owner negative case and full account-isolation regressions |
| PRES-E08 | Existing localized errors/control availability/focus → reuse current error/review surfaces → full Jest/browser theme/locale/keyboard baseline; manual screen reader remains open |
| PRES-C05/C08/C09/C12, PRES-W05 — regression boundary | Library/template/document/export/frozen capture unaffected → no renderer/domain changes → retained native frame/settings/PDF/package cases and fidelity/revision suites; no exhaustive all-template/provider claim |
Routes remain /career/builder/:id and existing CV/profile routes. The added POST /api/cv/variants/{id}/ai/apply is a protected content-acceptance API within the existing workflow, not a new production user journey or UI destination.
Synthetic evaluation corpus and evidence limits
The grounding corpus contains only synthetic source/proposal pairs and controlled assessment verdicts. Expected results are:
| Cases | Expected result |
|---|---|
| English paraphrase and shortening | Supported wording retained without requiring exact-copy output |
| Bokmål paraphrase and shortening | Supported wording retained without requiring exact-copy output |
| English → Bokmål and Bokmål → English | Faithful translated candidate claims accepted |
30 percent → 30% translation |
Existing quantity and percentage preserved |
| New employer/work history, title, responsibility, skill or technology | Unsupported proposal rejected |
| New education, qualification, certification, achievement or project | Unsupported proposal rejected |
| New language proficiency, personal detail or experience duration | Unsupported proposal rejected |
| Invented metric, date or salary with an erroneous supported verdict | Deterministic numeric guard rejects |
| Unknown/mixed output | Entire proposal rejected |
| Job requirement or injected context presented as candidate ability | Context supplies no candidate evidence; unsupported proposal rejected |
Parser/corpus tests, private-service tests, usage-gate tests, native SQLite suggestion tests and mocked sidecar tests separate contract enforcement, ownership/freshness, persistence, limits and privacy routing. Local evaluator artifacts are under .artifacts/p5-13-grounding-backend. Final root validation will record its exact revision, complete baseline, counts and any additional evidence below.
| Required behavioral boundary | Permanent evidence |
|---|---|
| Grounded paraphrase/shortening and English/Bokmål transformations | Seven positive corpus cases; Grounded_rewriting_is_applied_only_on_accept_and_uses_normal_history; frontend language/accept tests |
| Invented skill, employer/title, qualification/certification, responsibility, project, language, date and metric | Nineteen negative/unknown corpus cases; fabricated/mixed service cases; independent numeric and cross-entry validator negatives |
| Job requirements cannot become candidate evidence | Job_requirements_are_context_not_candidate_evidence; requirement/injection corpus negatives; exact candidate-quote validation |
| Provider fabrication rejected by the API | Confirmed_provider_fabrication_reproduction_is_now_an_API_rejection; isolated real HTTP fabricated-provider case |
| Newer CV/canonical source rejects old Apply | Pending_proposal_cannot_overwrite_newer_CV_or_canonical_source; both isolated HTTP conflicts; no content/history/profile mutation |
| Changes during generation or edited-result evaluation | Source_change_during_generation_does_not_issue_a_stale_proposal; Canonical_change_during_edited_proposal_review_is_checked_again_before_save |
| Rejected/unknown/unavailable/tampered/edited unsupported output creates no content revision | Native SQLite unchanged-state assertions; HTTP readback; section/editor reject/error/late-result regressions |
| Accepted result uses ordinary version/history and stays in the CV | Native SQLite and HTTP version increment, ai:<action> history and unchanged canonical/history readback; editor queue/undo tests |
| Account, CV and target identity cannot be client-selected at Apply | Protected_proposal_is_bound_to_owner_and_intended_CV; tampered-token test; foreign-owner HTTP 404 and unchanged owned state |
| Generation/regeneration remain pending; Reject does not apply | Section/editor proposal tests and HTTP generation readback; no standalone suggestion history or new regeneration workflow |
Native integration and resource boundary
The permanent isolated suite runs the actual Release API against a disposable SQLite database with normal cookie authentication, CSRF, session-context and Pro authorization. The loopback Node fixture implements only synthetic rewrite/review responses through the real private-service HTTP transport. It is a test provider, not a configured production model. The single case exercises section and typed whole-document generation/acceptance, foreign-owner rejection, fabricated output rejection and CV/canonical freshness conflicts, reading variant/history/profile/history after each boundary. It records five rewrite and five assessment requests; no external service is called.
Normal generation adds one factual-review request after one rewrite request. An unchanged protected Apply performs no new provider request; an edited result adds one review request. Review is metered using the existing usage policy. Source snapshots and the final save have short serializable database transactions; provider latency is outside those transactions. No proposal table, worker, background retry, new cache or alternative revision store is added. The 20,000-character combined evaluation bound may reject a long document even when generation alone fits; the API cannot treat truncated or unreviewed output as safe. Large-document chunked semantic evaluation is not invented here. Live-model latency, quality and additional usage cost are not measured by the deterministic fixtures.
The independent semantic evaluator is model judgment. Controlled corpus verdicts and mocks prove enforcement of the assessment contract, not real evaluator accuracy or universal no-fabrication. Exact quotes prove source membership, not semantic entailment. A model can mistakenly mark an unsupported nonnumeric claim supported or cite an irrelevant source quote. Prompt-injection resistance and model quality are not established by delimiter/prompt assertions. No live local or external provider evaluation was run for this implementation. Production factuality, configured-model accuracy and live-provider quality remain qualified; no “hallucination-proof” or universal factual certification is claimed.
Final root validation
| Gate | Final evidence/count |
|---|---|
| Final Release build | API/test Release builds pass, zero warnings/errors with -warnaserror; production frontend build passes |
| Backend baseline and grounding/ownership/freshness checks | 1,021/1,021, zero skipped; 106/106 focused AI/meter/privacy checks; 5/5 revision-safety cases |
| Frontend baseline and type/lint/build | 455/455 in 81 suites; standalone TypeScript, added API-proof/e2e TypeScript, lint and production build pass |
| Sidecar and offline-harness regressions | 49/49 sidecar; 5/5 offline harness; 3/3 supply-chain script checks; 3/3 capture-extension checks |
| Isolated real HTTP contract | 1/1, actual authenticated API/SQLite/private transport with synthetic provider; not a Chromium or live-model factuality case |
| Original preview/PDF fidelity | 16/16, 36 preview = 36 PDF pages, unchanged declared tolerances |
| Settings preview/PDF exports | 8/8, 24 preview = 24 PDF pages across light/dark × English/Bokmål, unchanged declared tolerances |
| Complete inherited Chromium evidence | 112/112 actual passes, no skipped/expected-failure/flaky cases; P2-D01 ordinary pass |
| Security/configuration | 9/9 rate-limit, 6/6 ingress, 1/1 PDF admission, 3/3 configuration; local regressions do not close F04 production evidence |
| Final source/diff/doc-link review | Scoped staged review and secret/whitespace scan pass; 150 current/root Markdown documents, zero missing local targets; no app file outside the documented readiness owners |
| Bounded prerequisite decision | CONDITIONAL GO; configured-model semantic qualification remains open |
Backend growth is 941 → 1,021 (+80): 45 new grounding/corpus/schema/scope cases, 27 new suggestion/SQLite/controller cases, five private evaluation/typed-format cases, two metering cases and one Pro policy case. Frontend growth is 440 → 455 (+15): eight added section-assistant cases and seven editor integration cases. The previous focused section/editor baseline of 40 becomes 55. No inherited case was removed. Sidecar growth is 37 → 49 (+12): eight review-boundary cases and four typed-format cases. The separate native HTTP proof adds one integration case; it does not inflate the inherited 112 Chromium count. P2-D01 remains an ordinary passing case and is not an expected failure or open debt.
The portable validation summary records result counts extracted from final TRX/Jest/Playwright/JUnit and fidelity reports. Member-data rows are counted from executed results, rather than unique TRX method definitions; the 26 corpus rows contribute 26 cases. The source checkpoint identifies the parent; the final checkpoint hash is supplied by Git after committing. Raw local outputs remain under .artifacts/p5-13-readiness/.
Reproduction commands
Run shell commands through rtk proxy and Git through rtk git. The installed SDK is C:/Users/Connor/.dotnet/dotnet.exe; the sidecar's test environment is tools/summarizer/.venv/Scripts/python.exe. The bundled Python with the existing PDF libraries is C:/Users/Connor/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe. No dependency, package lock or CI configuration changes are needed.
Root commands (replace executable names with those installed paths):
dotnet build JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-incremental -warnaserror
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-build --logger "trx;LogFileName=final.trx" --results-directory .artifacts/p5-13-readiness/backend
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-build --filter "FullyQualifiedName~CvAi|FullyQualifiedName~AiWorkspace|FullyQualifiedName~AiPrivacyPolicy|FullyQualifiedName~MeteredSummarizerService" --logger "trx;LogFileName=ai-final.trx" --results-directory .artifacts/p5-13-readiness/backend
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-build --filter FullyQualifiedName~CvRevisionReadinessTests --logger "trx;LogFileName=revision-final.trx" --results-directory .artifacts/p5-13-readiness/revision
tools/summarizer/.venv/Scripts/python.exe -m pytest tools/summarizer/tests -q --junitxml=.artifacts/p5-13-readiness/sidecar-final.xml
python -X utf8 scripts/verify-cv-fidelity.py .artifacts/p5-13-readiness/fidelity-verified
python -c "import json; from pathlib import Path; p=Path('.artifacts/p5-13-readiness/settings-fidelity-verified'); r=[json.loads(f.read_text(encoding='utf-8')) for f in sorted(p.glob('*-measurements.json'))]; assert len(r)==4 and len({x['browserVersion'] for x in r})==1; fixtures=[f for x in r for f in x['fixtures']]; assert len(fixtures)==8 and len({f['fixture'] for f in fixtures})==8; (p/'measurements.json').write_text(json.dumps({'browserVersion':r[0]['browserVersion'],'fixtures':fixtures},ensure_ascii=False,indent=2)+'\n',encoding='utf-8')"
python -X utf8 scripts/verify-cv-fidelity.py .artifacts/p5-13-readiness/settings-fidelity-verified
python scripts/test-ingress.py
python scripts/test-supply-chain.py
python scripts/test-ollama-evaluation.py
node browser-extension/tests/capture-url.test.mjs
python scripts/supply-chain.py scan-secrets
python .artifacts/p4-04-check-doc-links.py
git diff --check
git diff --cached --check
From job-tracker-ui:
npm test -- --runInBand --silent --json --outputFile=../.artifacts/p5-13-readiness/jest-final.json
npm run typecheck
npm exec tsc -- --project ../.artifacts/p5-13-readiness/e2e-tsconfig.json --noEmit --incremental false
npm run lint
npm run build
npm exec playwright test -- --config=playwright.cv-ai.config.ts --output=../.artifacts/p5-13-readiness/native-api-final --reporter=line
npm run test:e2e -- --output=../.artifacts/p5-13-readiness/browser-verified --reporter=line,json
npm run test:rate-limits -- --output=../.artifacts/p5-13-readiness/rate-limits --reporter=line
npm exec playwright test -- --config=playwright.ingress.config.ts --output=../.artifacts/p5-13-readiness/ingress --reporter=line
npm run test:pdf-admission -- --output=../.artifacts/p5-13-readiness/pdf-admission --reporter=line
Build with NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api. Set 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, CV_FIDELITY_OUTPUT=../.artifacts/p5-13-readiness/fidelity-verified, CV_SETTINGS_FIDELITY_OUTPUT=../.artifacts/p5-13-readiness/settings-fidelity-verified and PLAYWRIGHT_JSON_OUTPUT_NAME=../.artifacts/p5-13-readiness/browser-verified.json for the inherited browser run. Specialized suites share port 5302 and run sequentially; the isolated API contract uses 15313/18133. Avoid overlapping .NET builds. Tests use disposable local databases; no production database, credentials, provider request or deployment is involved. Scan staged new files before committing. Raw traces, cookies and authentication state remain ignored; portable evidence contains only synthetic corpus definitions and validation counts.
The additional local typecheck config at .artifacts/p5-13-readiness/e2e-tsconfig.json is reproducible with:
{
"extends": "../../job-tracker-ui/tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"],
"typeRoots": ["../../job-tracker-ui/node_modules/@types"]
},
"include": [
"../../job-tracker-ui/e2e/**/*.ts",
"../../job-tracker-ui/ai-tests/**/*.ts",
"../../job-tracker-ui/playwright.cv-ai.config.ts"
],
"exclude": ["../../job-tracker-ui/node_modules"]
}
Browser and accessibility evidence boundary
Actual captured rendering was reviewed for the retained focused preview at 390px light/English and 768px dark/English, and the retained editor/white document at desktop light/Bokmål and dark/Bokmål. Page boundaries, inclusion labels, source-scope text and focused-pane outlines remain visible. These screenshots are regression evidence of the unchanged frame, not P5-13 AI-review design approval. The inherited native browser fixtures cover the four theme/language pairs, mobile pane transitions, undo/settings/history, populated/error/retry states and ordinary keyboard workflows; the new actual-HTTP case proves the authoritative protocol without a browser UI.
Scoped automated axe assertions and keyboard outcomes are distinct from manual screen-reader acceptance. Full scan attachments retain incomplete findings; a passing contrast-only fixture does not accept unrelated naming/semantics rules or incomplete nodes. No human screen-reader, physical touch or production font/photo acceptance was performed. The screenshot files remain in the ignored browser output; no raw authentication state or extra personal/source content is added to the documentation package.
P5-13 readiness decision and remaining qualification
CONDITIONAL GO for P5-13, subject to configured-model semantic qualification. The authoritative owner/source/version/assessment/capability boundary is implemented; recognized unsupported/unknown/mixed output and stale acceptance fail closed. The deterministic contract corpus, real SQLite writes and real HTTP integration establish those boundaries. They do not establish that the configured model correctly recognizes every unsupported factual assertion.
Before treating factual grounding as fully accepted, qualify the existing configured evaluation route with the synthetic corpus: submit its source, proposal and optional contextOnly as candidate_source, proposal and context_only to the private review route in an isolated test environment using the existing privacy/routing policy. Record model/version/route, all 26 outcomes, schema/coverage/exact-source-quote validity, false approvals and false rejections; keep credentials and hidden prompts out of evidence. The seven supported transformations must remain usable, and the nineteen prohibited/unknown cases must be inapplicable at the API validator. Include the job-requirement/injection and cross-entry fixtures when qualifying the actual route. No new external-processing consent, provider/model selection or production user content follows from this procedure. A failed configured-model case requires a separately reviewed correction and remains a blocker; do not weaken corpus expectations or replace the current server enforcement with UI review.
Until that proof is obtained, there is no unqualified no-fabrication acceptance or production factuality certification. P5-13 presentation has not begun. Stale-apply protection is locally accepted independently: both variant-version and canonical-fingerprint changes reject with conflict and preserve newer content/history. Broader screen-reader, pointer/early-entry timing, production/font/photo and other carried qualifications remain separate; this checkpoint does not close them.
Remaining scope and open debt
The P5-12 acceptance limits, Phase 5 blocker register, readiness gates and known issues remain authoritative. This checkpoint closes no unrelated row and erases no historical observation.
Preserve human screen-reader/spoken-name/state-announcement acceptance, incomplete axe/manual contrast/hidden-focus/table checks, broader pointer/reflow/sticky-boundary coverage, 200%/400% zoom, forced colours/text spacing, physical touch/software keyboard/mobile screen reader, production Linux/font/photo/all-template/other-browser qualification, F04 production ingress, protected-main runner/release evidence, Dashboard preference-save 500, Board scaling/native touch, deferred followMode compose UI, P5-10-O01 nested drag/drop ownership and inherited timing/focus observations. Profile/job revision work, creation idempotency, calendar/DST, enabled worker containment, startup-provider safety, backup/restore/schema cutover, paid deletion/retention and live mail/AI/calendar delivery remain with their existing owners.
P5-13 presentation, P5-14 complete responsive workflow and P5-15 representative acceptance require their own scope and evidence after the bounded prerequisite decision. No B07, production deployment or new provider authorization follows from this checkpoint.