P5-09 readiness — CV integrity and rendering evidence
Successor: CV pagination-fidelity repair preserves this original evidence and revision boundary, replaces screen break estimation with native fragmentation, and measures all 16 fixtures within the original tolerances. This record's NO-GO and six failures below describe checkpoint 046dc304; the successor owns the current rendering decision.
P5-09: NO-GO. G-CV-REV passes locally; G-CV-RENDER fails materially. This bounded checkpoint starts at ac6d78289d487c5ceae3e59db435f7ede24bb6f2. It adds revision protection, deterministic native evidence and three small rendering corrections necessary to obtain a useful baseline. It does not implement the CV redesign, P5-09–14 or B07. The inherited baseline is 936 backend / 418 frontend / 93 actual browser cases; P2-D01 is an ordinary passing case.
Contract established before measurements
PDF exported through the real authenticated endpoint and existing Chromium CLI exporter is final output truth. Compare the same saved variant settings and canonical source, without an intervening write. Application theme and viewport must not alter document geometry.
The following tolerances are fixed before collecting results; failures remain failures rather than widening these thresholds:
- Physical page dimensions: within 0.5 mm of A4 (210 × 297 mm) or Letter (215.9 × 279.4 mm).
- Page count and marker-to-page membership: exact agreement. No unexpected blank page, missing/duplicated fixture content or hidden-section leakage.
- Matching text/section anchors: horizontal and vertical positions within 2 mm after converting CSS px at 96 dpi and PDF points at 72 dpi; page index must agree. Glyph bounding boxes differ from CSS line boxes, so compare text baselines/line starts where possible, recording extraction limits.
- Repeated effective top/bottom safe area: PDF text must remain within the renderer's density-adjusted margin, allowing 1 mm for glyph metrics. Template-owned horizontal padding is measured independently rather than assuming one uniform horizontal margin for sidebar layouts.
- Font size: within 0.5 pt for representative text. Wrapped-line membership and line count must agree for deterministic marker paragraphs; no clipping or misleading one-page fit.
- Accent and semantic document colour: same configured RGB source in both render paths; PDF vector/text colour components within 1/255 where extractable. Anti-aliasing is not a colour mismatch.
- Section order, visibility, source/override content and user text: exact agreement in the applicable main/sidebar column. Across two independent columns, record column order rather than impose a fictitious global reading order.
Use every catalogued template at default settings and a deterministic risk-based corpus: short EN/NB, multi-page entries/bullets, long words, skills/projects, hidden/reordered sections, A4/Letter, 8/28 mm margins, compact/roomy density, photo/icons, grid/bubbles and content near page breaks. This does not certify every Cartesian setting combination or production font environment.
Preservation scope
Direct: PRES-C05–C10/C12 (variant lifecycle, editor, overrides, templates/settings, history, PDF); PRES-C01/C02 (canonical source boundary); PRES-W05/W07 (selected and frozen submitted CV); PRES-E05/E08/E09 (account isolation, keyboard, responsive/localisation). PRES-C11 AI review is regression-only, not redesigned.
Revision history is currently append-only settings, not a snapshot of the Career Profile or a historical rendered PDF. Restoring re-saves old settings as a new current version against the current canonical profile. Submitted packages separately freeze rendered content and capture variant/version metadata. Do not change that domain distinction to make the gate pass.
Actual model and preservation invariants
| Repository concept | Ownership / data contract | Evidence and consequence for later redesign |
|---|---|---|
Career Profile / StructuredCvProfile |
Owner-scoped canonical source with stable job/education/project item IDs; its own history is separate | CareerProfileService, resolver and existing profile tests; CV writes never save this profile |
CvVariant |
Named current lens; owner, optional job reference, share slug, visibility, SettingsJson, integer Version |
Each successful settings/name save appends history and advances the current version. Duplication creates a separate lens/slug. No second canonical CV document model is introduced |
CvVariantSettings |
CV-only headline/item/section overrides, custom content, hidden items/sections, ordering, template, colour, fonts, density, margins, spacing, layout, locale | Null override uses current source; an explicit empty list is deliberately empty. Reset removes the override rather than changing the source |
CvVariantVersion |
Append-only settings JSON, version number, source and time | Does not snapshot profile/name/publication state or PDF bytes. Restore appends old settings as a new current version and retains the current CV name. History remains readable through the existing list/restore workflow; there is no independent immutable historical-PDF endpoint |
| Editor undo/redo | In-memory settings snapshots of the mounted editor | Existing session undo/redo stays separate from persisted revision history. Autosave remains debounced at 800 ms; preview at 300 ms; manual Save uses the same queue |
| Rendering model / HTML | Derived from current canonical profile + current lens + person/photo + template | It is neither an immutable career snapshot nor the submitted document. Current published CVs likewise use current source; publication does not freeze them |
| Job tailoring / selected CV | Existing job association and CV-specific/source-grounded overrides | Existing attachment/tailoring owners and APIs remain. No new many-to-many association, tailoring or AI workflow |
SubmittedApplicationPackage |
Separate frozen capture: CV ID/name/version/theme/settings, canonical snapshot, rendered HTML, letter/material and copied attachments | Native P2-D01 and package/ZIP fixtures revalidate that later live CV/profile/letter/file changes do not replace captured content or version metadata |
Historical lens state and historical submitted content are deliberately different contracts. An inherited source field can change when an old lens is restored against a newer Career Profile. The historical settings JSON itself remains unchanged; explicit overrides remain historical values. Changing this to full profile snapshots would be a new domain decision, not a readiness repair.
Previously frozen HTML/files are not regenerated to adopt the CSS/export corrections. They retain their original captured bytes, including any historical rendering limitation. Newly rendered current CVs use the corrected existing rules; that does not replace a prior submitted capture.
Section order/visibility and every document setting are stored in the same versioned JSON. The SQLite revision fixture restores that exact JSON, checks hidden/order/template/margin/density/override state, edits again and checks both older rows remain unchanged. Generated PDFs are derived exports; current preview/export geometry is a separate failed gate, not proof of corrupt settings history.
Revision defect, boundary and recovery
Before the fix, SaveAsync owner-loaded a CV and blindly incremented its version. Restore called that same method. Two independently loaded contexts could replace newer settings with an older draft; both original stale-save and stale-restore regression cases failed with “no exception thrown.” A browser-local queue could not protect another tab/session/client.
The smallest shared boundary now requires the client's last acknowledged expectedVersion for both save and restore, compares it with owner-loaded current state, and marks the existing integer Version column as an EF concurrency token. The SQL update compares the loaded version atomically; a race after initial validation also fails. Current-state update and appended history use the existing relational SaveChanges transaction, so a rejected race does not leave a phantom history row. The EF snapshot contains the metadata annotation only: no schema migration, new column or data rewrite.
| Request condition | Safe HTTP result |
|---|---|
| Foreign/unknown save or restore target | Existing 404, before version validation; no resource existence disclosure. History lists retain their existing empty-list convention |
| Missing, zero or negative expected version | 428, cv_revision_required; old bundles cannot silently write |
| Stale expected version or atomic SQL conflict | 409, cv_revision_conflict; request not applied; no latest CV contents returned |
| Current expected version | Existing successful save/restore response with new version |
Ownership still comes from the authenticated principal, with B02 session/CSRF validation retained. Body user IDs do not select ownership. Public/private download, entitlement and shared B03 admission paths remain. Generic job/profile concurrency and creation idempotency are still separate contracts.
The editor supplies the acknowledged server version when a queued save executes, consumes the returned version, and never applies save responses over a newer local draft. Applying a fetched/restored state invalidates older queued work. A revision conflict blocks further saves, retains settings/name/undo and the dirty navigation guard, and offers:
- Download unsaved copy: user-triggered JSON of this draft/name/expected version; a recovery record, not a new persistent draft or import subsystem.
- Reload saved CV: explicit discard confirmation; Cancel keeps the draft. Edits made while reload is in flight are retained. Restoring history also retains edits made while its request is in flight and requires conflict recovery.
There is no force overwrite, automatic merge or silent retry with a fabricated latest version. Other network failures retain the existing Retry behavior. Library rename reads the variant and supplies its version, so it shares the same boundary. Server and client must ship together; cached older clients fail closed with 428 and require refresh. Rolling back the server to the former blind-save behavior would reopen the integrity defect and is not a safe conflict-resolution strategy.
Rendering paths and root causes
Both paths start with CvVariantResolver / ThemedCvRenderer and the same normalized settings. Preview renders server HTML in sandboxed same-origin iframes, adds screen-only physical-page padding and a keep-together script, crops/translates one flowing screen document per page and derives page count from scroll height. Export uses the real authenticated PDF endpoint, PlaywrightCvPdfExporter, Chromium CLI --print-to-pdf, CSS @page and native print fragmentation. PDF is final output truth. B03 bounds the expensive process through its existing admission/lifetime owner.
Three small root corrections were necessary before fidelity measurements were useful:
- A C# verbatim CSS string emitted
content:";for a bubble marker. That unterminated CSS string caused Chromium to discard later template/print rules, including@page. Correct escaping now emitscontent:"";. This restores the existing intended rules rather than redesigning templates. - Chromium CLI inserted browser date/file-URL headers/footers.
--no-pdf-header-footerremoves that unsolicited browser chrome; it is not a new CV footer feature. - Preview used the raw margin while PDF used density-adjusted margin. Preview now uses the existing renderer factors: compact 0.82, balanced 1, roomy 1.18. Raw 8 mm compact → 6.56 mm; raw 28 mm roomy → 33.04 mm. The meaning of stored settings is unchanged.
Before these changes all 16 measured fixtures failed; short A4 previews could produce two-page Letter PDFs, with browser chrome and displaced template geometry. Original results and a representative comparison are preserved separately. After correction all nine default-template fixtures and the grid/bubble fixture pass the implemented measurements. Six long fixtures still fail.
Measured corpus and results
The permanent native browser fixture creates deterministic canonical inputs and variants, loads the actual editor iframe, exports the actual PDF bytes, checks no intervening variant/profile change, records DOM text ranges/computed styles and captures the actual page iframe HTML at its physical viewport. It does not mock the renderer, export or admission layer. Separate PDFium rasterization and pdfplumber text/font/colour extraction avoid treating another browser screenshot as the PDF oracle.
| Fixture | Meaningful path/settings | Preview pages | PDF pages | Measured verdict |
|---|---|---|---|---|
| default-modern | Short source, header band | 1 | 1 | Pass |
| default-minimal | Short single-column source | 1 | 1 | Pass |
| default-executive | Executive typography/layout | 1 | 1 | Pass |
| default-technical | Technical sidebar/type | 1 | 1 | Pass |
| default-ats-classic | ATS/default type | 1 | 1 | Pass |
| default-nordic | Nordic layout | 1 | 1 | Pass |
| default-elegant | Serif typography | 1 | 1 | Pass |
| default-creative | Creative template/layout | 1 | 1 | Pass |
| default-code | Monospaced/numbered-heading path | 1 | 1 | Pass |
| long-en-minimal | Six multi-bullet experiences, multiple education, projects/skills, long EN | 3 | 4 | Fail |
| long-nb-code | Long NB, extended education/title text | 3 | 4 | Fail |
| compact-8mm-letter | Letter, compact, 6.56 mm effective margin, smaller gaps | 3 | 4 | Fail |
| roomy-28mm-nb | A4, 33.04 mm effective margin, line height 1.6 | 4 | 5 | Fail |
| grid-and-bubbles | Reordered projects/skills, grid/bubbles, hidden interests, accent #126b55 | 1 | 1 | Pass |
| long-sidebar-nb | Technical sidebar 68 mm, grouped skills, long NB | 4 | 5 | Fail |
| unbreakable-and-boundary | Long unbreakable text/custom paragraphs at page boundaries | 4 | 4 | Fail despite equal counts |
The risk fixtures cover long flowing bullets/entries, section starts, repeated margins and text near page boundaries. Five show one fewer preview page than exported PDF. The sixth shows materially displaced anchors/page membership even though total counts agree. First-page positions can agree while later-page anchors differ by tens of millimetres; page count alone is insufficient.
Across the ten measured passing fixtures, maximum anchor differences are x < 0.001 mm, y 1.462 mm, font size 0.0051 pt, and extractable RGB component 0.000046. The complete corpus has 31 preview pages versus 36 PDF pages. long-en-minimal has a 72.60 mm same-page vertical displacement as well as markers E05/B13/B14 moving from preview page 2 to PDF page 3. These are measured document-placement failures, not just anti-aliasing or screenshot scale differences.
Remaining root cause: screen cropping does not reproduce native repeated print margins and fragmentation for long .entry-flow / .item-flow content. The existing script skips indivisible blocks taller than printable space, while Chromium can split long text and moves subsequent content using actual print boundaries. No new paginator, PDF viewer, renderer replacement or typography shrink workaround is added here. A dedicated bounded repair must preserve PDF truth and rerun this corpus before P5-09.
Measurement coverage and limits
Implemented numerical checks are physical page dimensions, exact count/marker membership, every captured marker's x/y/font size and extractable RGB, PDF vertical safe area, no blank pages, marker presence/duplicates and hidden-interest leakage. Computed main/sidebar/header boxes, full extracted text, section order and font names are recorded for review. Only the implemented checks determine each table verdict; this is not proof that every pixel, phrase or template/control combination is correct.
The stronger contract above also requires complete wrapped-line/section fragmentation and clipping qualification. It is not yet a complete automated line-by-line oracle. Photo, all alternate font overrides, icon on/off combinations, arbitrary section combinations, zoom and every template's long form are not measured in this 16-fixture corpus. Default contact icons are exercised. These remain explicit follow-up qualifications; no omitted capability is counted as a fidelity pass. The failed multi-page gate already blocks progression, without widening tolerances after measurement.
Rendered review also shows a decorative difference in the short sidebar templates: the preview stretches the sidebar surface down the page, while PDF stops it at the content height. Text positions/counts pass in those fixtures; their surface extent is not certified by the numerical pass. This remains a preview presentation/geometry qualification for the repair, alongside long-page cropping. The grid-and-bubbles fixture exercises the saved hints with one project and the template's existing skills style; it does not prove every multi-entry grid or all bubble/tag combinations.
Configured font stacks include Segoe UI/Roboto/Arial, Helvetica families, Georgia/Times and Code's monospaced utility stack; allowed overrides include Poppins. No bundled web font is supplied by the document renderer. Chromium embeds available selected/substituted subsets in the local PDFs; extracted font names are retained. Preview and PDF use the same local machine/browser family here. The production Debian image installs Chromium, not this Windows font environment. Cross-host metrics/production substitutions are unverified; there is no font redistribution or production-font certification. Rerun the same corpus against the deployment-equivalent image after geometry repair.
DateFormat is already a frontend display hint; the server uses source date strings. ShowPageNumbers is stored but has no renderer implementation. Removing browser-generated page counters does not implement that setting. These existing controls/semantics are documented for P5-12; do not invent behavior or silently remove the settings now. Optional page-break editing controls do not currently exist.
Regression and preservation trace
| PRES contracts | Existing invariant → readiness change | Permanent proof / remaining limit |
|---|---|---|
| C01/C02, C07 | Canonical source versus lens/reset → no source writes | New SQLite source/update/reset/history fixture; existing resolver/item/section/profile tests; native corpus compares source before/after |
| C05/C06/C10 | Create/current/history/rename/autosave/restore/undo → version precondition and recoverable conflict | Five new backend cases, four new editor cases, two native API/editor cases; existing library/dirty/undo/redo/preview error tests |
| C07/C08/C09 | Order/hidden/override/template/margin/density remain versioned → same normalized settings | Exact original history JSON before/after restore/edit; native 16-fixture output record; partial fidelity fails explicitly |
| C12, E05 | Private/public export and owner/session boundary → no bypass | Existing public/private PDF and account-isolation cases; new SQLite foreign history/save/restore case, concurrent same-account API test; rate/ingress/PDF suites retained |
| W05/W07 | Selected lens versus exact frozen capture → no capture changes | Ordinary P2-D01 plus native package/ZIP fixtures and existing capture/owner tests after final changes; package models/services untouched |
| E08/E09, C06/C10 | Named editor/preview, history actions, keyboard/mobile state → minimal names only | Named editor region/tablist/version-specific Restore, unit assertion and inherited P4-03 four theme/locale keyboard cases; human screen-reader remains open |
| C11 | AI explicit grounded review/accept/reject → unchanged | Existing whole-document/section review and invalid-response tests, full regression run; no provider factual acceptance claimed |
IDs above use the stable PRES- prefix. Other contracts are regression-only; this does not claim exhaustive behavior across all 57 groups.
New backend cases live in CvRevisionReadinessTests: stale save and stale restore with independently tracked SQLite contexts (2), stale fresh request (1), source/lens/history/reset/settings (1), foreign ownership (1). The relational token test checks the winning revision and exact history count after failure, rather than accepting a rejection with partial persistence.
Four new editor cases cover acknowledged save versions/new draft retention, recoverable conflict with Cancel/confirmed reload, edits during reload, and edits during restore with named history controls. Three native cases cover real 16-fixture acquisition, independent authenticated current/stale API requests (including 428 and concurrent 200/409), and an actual stale editor download/cancel/reload/review/save workflow. A successful acquisition case does not mean the fidelity gate passed; the independent measurement command exits 1 on six failures.
Accessibility and rendered review
The existing frame gains a named CV editing controls region, a named CV studio sections tablist, and version-specific Restore names. Existing preview region, iframe titles, focus-visible treatment, responsive pane selection and polite saving status remain. Conflict uses an existing MUI warning Alert with textual state/recovery actions; it is not colour-only. No new layout, tab sequence, keyboard shortcuts or focusable decorative region is introduced.
P4-03's actual keyboard cases remain the native proof for Tab entry/exit, PageDown/Home/End, focused pane resize preservation, preview failure/Retry, undo/redo and source/sibling separation in EN/NB × light/dark at 390/768/899/900/1024/1440 px. Automated axe assertions retain their original rules. Incomplete axe findings are not passes; spoken accessible names and live announcements have not been manually verified with a screen reader. P5-02's human acceptance item remains mandatory for P5-15.
The seven-case evidence rerun retains 16 scoped axe scans with zero reported violations. They also contain 32 aria-prohibited-attr node occurrences (existing Undo/Redo tooltip wrapper spans in EN/NB) and 237 color-contrast node occurrences (overlapping/partly obscured editor elements and short badge text). These are repeated occurrences across scans, not counts of unique defects. They remain incomplete/manual qualifications, not automated accessibility passes. This checkpoint does not modify those unrelated wrapper/contrast owners.
Visual review covers one final document comparison for each of the 16 fixtures, the original default-modern comparison, eight actual editor/phone captures across all four theme/language combinations, and the retained conflict draft/recovery state. The editor focus captures are scrolled preview states, not a full-frame visual acceptance for the later redesign. Phone fit-to-page is a document overview; existing zoom remains necessary to read small document text. Four multi-page end captures are retained without individual visual sign-off.
Evidence uses synthetic fixtures only. The visual manifest records every retained screenshot's hash and whether it was individually inspected. The fidelity results, original numerical results, browser baseline summary, supplemental browser results and accessibility summary keep measurements and incomplete checks separate. Representative images: short modern comparison, failed multi-page comparison, Bokmål/dark phone preview, and conflict draft retained. Authentication storage, raw traces and credentials are not part of this evidence package.
Changed files and bounded rationale
Application: CvVariantService.cs / CvVariantController.cs enforce the common write boundary; JobTrackerContext.cs and its model snapshot mark the existing column; cvBuilder.ts, CvBuilderEditor.tsx and CvBuilderPage.tsx carry versions/recovery through every client caller; translations.ts adds EN/NB recovery/accessibility names. ThemedCvRenderer.cs fixes one malformed CSS string and PlaywrightCvPdfExporter.cs adds one CLI switch. All are direct readiness owners.
Tests: new CvRevisionReadinessTests.cs and e2e/cv-readiness.spec.ts; existing CvBuilderTests.cs, editor unit tests and three existing browser fixtures supply versions for legitimate writes. The original forged foreign writes remain rejected; assertions were not weakened. scripts/verify-cv-fidelity.py is a local measurement tool, using available PDF libraries without adding a dependency to the app.
Documentation/evidence: this record, current Phase 5 gate/index/blocker links, Phase 2 traceability and roadmap status. No route table, component library, schema migration, dependency, CI, package script, production configuration, AI flow or Job workspace implementation change.
Final validation
All commands use rtk proxy; npm runs inside job-tracker-ui. Browser suites run sequentially because they share the API port. Final application code is unchanged throughout the complete run and rendered review. No failing fidelity fixture is included in the ordinary passing-suite count. F04 remains open; no deployed topology or credentials were inspected.
| Command | Final result |
|---|---|
C:/Users/Connor/.dotnet/dotnet.exe test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj -c Release --no-restore --logger 'console;verbosity=minimal' |
941/941, zero failed/skipped; +5 cases described above |
npm.cmd test -- --runInBand --silent --json --outputFile=../.artifacts/p5-09-readiness-jest.json |
422/422, 80 suites, zero failures; +4 editor cases |
npm.cmd run test:e2e -- --reporter=line,json |
96/96 actual passes, 15.0 minutes, +3 native cases; no expected-failure annotation, skips or failures |
npm.cmd run typecheck / npm.cmd run lint |
Passed; no TS2571 or lint suppression introduced |
npm.cmd exec tsc -- --project ../.artifacts/p5-09-readiness-e2e-tsconfig.json --noEmit --incremental false |
All permanent browser fixtures passed TypeScript using existing project types |
npm.cmd run build with NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api |
Production static export passed |
C:/Users/Connor/.dotnet/dotnet.exe build JobTrackerApi/JobTrackerApi.csproj -c Release --no-restore -warnaserror |
Passed, zero warnings/errors |
npm.cmd run test:rate-limits -- --reporter=line |
9 passed; principal/IP/session partition behavior retained |
npm.cmd exec playwright test -- --config=playwright.ingress.config.ts --output=../.artifacts/p5-09-readiness/ingress --reporter=line |
6 passed; application-level proxy/host/scheme/CORS behavior, never deployed ingress proof |
npm.cmd run test:pdf-admission -- --output=../.artifacts/p5-09-readiness/pdf-admission --reporter=line |
1 passed; actual cross-route capacity and recovery retained |
python scripts/test-ingress.py |
3 configuration/Compose checks passed |
python scripts/test-supply-chain.py / python scripts/test-ollama-evaluation.py / node browser-extension/tests/capture-url.test.mjs |
3 / 5 / 3 passed; local fixtures, not provider certification |
Bundled Python scripts/verify-cv-fidelity.py .artifacts/p5-09-readiness/final |
Exit 1: 10/16 pass, 6 fail, same predeclared tolerances; failed readiness gate explicitly retained |
python scripts/supply-chain.py scan-secrets |
Passed against tracked/staged candidate; no high-confidence credential patterns found |
git diff --check / git diff --cached --check |
Working and staged checks passed |
python .artifacts/p4-04-check-doc-links.py |
Final repeat: 144 current/root Markdown files, zero missing local targets; archive excluded |
Native browser environment: DOTNET_ROOT=C:/Users/Connor/.dotnet, DOTNET_HOST_PATH=C:/Users/Connor/.dotnet/dotnet.exe, PLAYWRIGHT_STATIC_EXPORT=true, PLAYWRIGHT_PREBUILT_EXPORT=true, CV_FIDELITY_OUTPUT=../.artifacts/p5-09-readiness/final, PLAYWRIGHT_JSON_OUTPUT_NAME=test-results/p5-09-readiness-final.json. The corpus uses local Chromium 151.0.7922.34; no public internet or external AI provider.
To rerun only native readiness acquisition: npm.cmd run test:e2e -- cv-readiness.spec.ts --reporter=line with the same environment after Release/static builds. Then run the measurement tool at the repository root with Python containing pdfplumber, PDFium and Pillow. Here that is C:/Users/Connor/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe -X utf8 scripts/verify-cv-fidelity.py .artifacts/p5-09-readiness/final. Exit 1 is the current expected failure of the prerequisite, not a renamed passing test. A future repair must make it exit 0 without weakening the oracle.
The initial new backend harness lacked using Xunit; that compile error was fixed before the deliberate before-fix stale-write failures were observed. One new unit recovery test initially raced dialog exit; it now waits for actual removal while retaining all draft/cancel/reload assertions. These fixture corrections do not hide a product regression or change the inherited cases.
The first evidence-copy helper encountered a missing main JSON file because the subsequent rate suite had cleaned Playwright's shared test-results directory. The completed 96 passed / exit 0 command result remains observed, and the separate final fidelity files were preserved. Seven CV/native/keyboard cases were rerun solely to retain detailed screenshots/axe/results in an independent ignored directory, without code or assertion changes: 7/7 passed in 3.3 minutes, zero skips, expected failures or retries. Their count is not added to the 96-case baseline. Exact supplemental command: npm.cmd run test:e2e -- builder-preview-keyboard.spec.ts cv-readiness.spec.ts --output=../.artifacts/p5-09-readiness/browser-evidence --reporter=line,json, JSON output ../.artifacts/p5-09-readiness/browser-evidence.json and corpus output ../.artifacts/p5-09-readiness/supplemental.
Decision and next boundary
G-CV-REV: locally satisfied, preserving the actual lens/history/source/frozen-package distinction. G-CV-RENDER: NOT satisfied. P5-09: NO-GO. Do not begin P5-09–14, force long documents into one page, narrow the corpus or weaken the measured thresholds to continue.
Recommended next instruction: authorise a separate CV pagination-fidelity repair checkpoint at the existing preview/print owner, starting from the failing deterministic fixtures and retaining PDF output truth. It must reproduce repeated margins/flow/page membership, extend clipping/wrapping/photo/font qualification and rerun the full baseline. If doing this correctly requires replacing the rendering subsystem or changing document semantics, stop for that architecture decision. P5-11 preview presentation and P5-12 controls remain later UI work, not substitutes for this gate.
F04, human screen-reader acceptance, Dashboard preference-save 500, Board scaling/native touch, incomplete accessibility/manual checks and deferred followMode compose UI remain separate open items. P2-D01 remains closed/passing.