21 KiB
CV pagination-fidelity repair checkpoint
Source: 046dc304aa68d67e15a019057f9bdec0c89bf475. This checkpoint repairs only the live document's fragmentation and measurement lifecycle. No P5-09 UI redesign, template/export change, revision change, AI workflow, responsive redesign or B07.
The final decision and executed baseline are recorded below. The original 16-fixture evidence remains unchanged; its six failures are not removed or reclassified as passes.
Root cause and per-fixture diagnosis
The former screen preview added padding to a tall continuous .page, estimated keep-together gaps for selected blocks and cropped every physical page by a vertical transform. It explicitly skipped blocks taller than the usable page. That meant flowing entries/list items received neither native line fragmentation nor repeated page margins. Padding an entire section could not implement widows, orphans, keep-with-next or margin treatment at a fragment boundary. Font readiness was also absent from the parent page-count callback.
All six failures share this mechanism. The sixth is not stale data, reordered DOM or hidden content: it reproduces offline from the identical saved HTML, with stable fonts and no API writes. Its E03/B07 markers appeared on preview page 1 instead of PDF page 2; later S09/R09/R10 positions differed by approximately 21 mm despite equal overall counts.
| Original failing fixture | Original divergence | Repair proof |
|---|---|---|
| long-en-minimal | 3 vs 4 pages; E05/B13/B14 stayed on page 2 instead of 3; later vertical error up to 72.60 mm | Native flow fragmentation, repeated usable height and unchanged print keep rules |
| long-nb-code | 3 vs 4 pages; E03/B07 wrongly on page 1; accumulated subsequent-page displacement | Same native flow; monospaced headings and Segoe body metrics preserved |
| compact-8mm-letter | 3 vs 4 pages; compact flow and page-boundary splitting | Native fragmentation and print fragmentainer pixel rounding, independently demonstrated with a native ruler |
| roomy-28mm-nb | 4 vs 5 pages; large repeated safe area absent from long flow; displacement over 200 mm | Renderer margin 33.04 mm retained on every fragment |
| long-sidebar-nb | 4 vs 5 pages; main/sidebar fragmentation and subsequent-page offsets diverged | Existing grid/column layout fragments natively; no sidebar/template rewrite |
| unbreakable-and-boundary | 4 vs 4 pages, but markers assigned to wrong pages and custom-section anchors displaced | Same source and native keep/flow rules; focused marker-membership regression plus positional oracle |
An offline probe reusing actual server HTML and native PDFs corrected all counts and 15/16 positional results with browser column fragmentation. Compact Letter still misplaced later anchors by roughly 10.9 mm when given a fractional fragmentainer height. Rounding each margin separately produced a different wrong result: the Languages section incorrectly fit on page 3. Neither workaround was shipped.
A separate Chromium CLI 1px native ruler, with the same page and margin rules, establishes the correct physical rounding:
| Page / effective margin | Calculated usable CSS height | Native first-page 1px rows | Preview fragmentainer |
|---|---|---|---|
| A4 / 16 mm | 1001.574803 px | 1002 | 1002 px |
| Letter / 6.56 mm | 1006.412598 px | 1007 | 1007 px |
| A4 / 33.04 mm | 872.768504 px | 873 | 873 px |
The repair uses ceil(physicalHeight − 2 × effectiveMarginPx), matching these measured print fragmentainers. It is at most one CSS pixel (0.2646 mm) of platform quantization, not an arbitrary content buffer, a changed margin or a widened tolerance.
Renderer and geometry contract
Generated PDF remains authoritative. ThemedCvRenderer, PlaywrightCvPdfExporter, their CSS/CLI flags, admission and submitted/frozen content are unchanged in this checkpoint.
cvPreview.ts replaces the former estimation function with native CSS column fragmentation. Each column has one page's physical width and usable height; selecting a page translates horizontally by that width inside the existing physical-page iframe. The application still presents the same vertically stacked page previews, zoom, scrolling and named keyboard region.
- Physical width/height come from the actual renderer's
.pageCSS. The existing selected-page height is only a fallback. A4 and Letter keep their existing dimensions. - Effective top/bottom margin comes from the existing
--cv-page-marginCSS token, including template/default margin and density. The duplicate frontend density/margin calculation is removed. - Existing
@media printdeclarations are reused in the screen fragmentainer. Header/main/sidebar padding, min-height, borders, fonts and content remain renderer-owned. - Existing computed
avoid-pagebreak decisions are applied asavoid-columnin the preview. Automatic flow, line height,widows/orphans, list/paragraph/section spacing and native element splitting stay with the browser engine. - Print rules supply no separate CV footer/header space. No browser chrome, PDF margin, PDF pagination, font or document setting changes.
- The hidden measurement iframe loses its default border, so its content viewport agrees with visible borderless document frames. This is a measurement correction, not editor layout work.
The original failures had matching horizontal anchors and font sizes (within approximately 0.006 pt) while vertical/page membership diverged. The retained CSS confirms the same family/fallback chain, weight, line-height, letter spacing, paragraph/list gaps, entry/section gaps, box sizing and template borders. There is no font-specific shrink, substituted document font, generic safety padding or forced one-page fit.
Measurement lifecycle and fonts
Each document waits for document.fonts.ready and image decode, applies the existing print decisions, then waits for two animation frames to settle layout. It publishes a single cv-preview-ready event and page/geometry metadata. The parent consumes that settled measurement, rejects an obsolete frame/document callback and does not count the previous continuous scroll height. No arbitrary sleep or continuous resize/mutation re-pagination loop is added.
The fidelity fixture waits for this explicit readiness signal, including standalone document captures. Horizontal columns are normalized into the same physical-page coordinate system used by the unchanged PDF oracle: column index from x; local x within that page; local y plus page index × physical height. Raw x/y and page membership are retained. This representation change does not change tolerance, expected marker membership or the PDF data.
Font families/fallbacks remain those documented in the original readiness record. Local preview/CLI use the same Chromium family; native PDFs retain their embedded selected/substituted font subsets. No font files are added, exposed or redistributed. Production Debian/font substitution and other browser engines still require deployment qualification; local evidence is not production font certification. New layout readiness waits do not claim to supply missing fonts.
Final evidence integrity checks confirm 16/16 server HTML inputs are byte-identical to the original readiness corpus, 16/16 PDFs have identical extracted page text, and all PDFs retain the same normalized embedded font names and page counts. PDF file-byte identity is not asserted because generated metadata can vary. All retained screenshot manifest hashes resolve correctly; no authentication state or raw browser traces are committed.
Fidelity acceptance and evidence
The original numerical oracle is unchanged: page size ±0.5 mm; exact page count/marker membership; anchor position ±2 mm; font size ±0.5 pt; extractable RGB component ±1/255; repeated vertical safe area ±1 mm; no blank pages, missing/extra markers or hidden-interest leakage. All original 16 fixtures remain. Full wrapped-line/photo/all-font/all-template-long-form qualification is not implied by a numerical pass.
Both the repaired real-editor/native-export focused run and the subsequent complete browser run measured 16/16 passing, exit 0, at the original tolerances. The final numerical results, source measurements and synthetic source HTML/native PDFs/page comparisons are retained under evidence/fidelity/.
| Fixture | Before preview pages | PDF pages | After preview pages | Measured result |
|---|---|---|---|---|
| default-modern | 1 | 1 | 1 | Pass |
| default-minimal | 1 | 1 | 1 | Pass |
| default-executive | 1 | 1 | 1 | Pass |
| default-technical | 1 | 1 | 1 | Pass |
| default-ats-classic | 1 | 1 | 1 | Pass |
| default-nordic | 1 | 1 | 1 | Pass |
| default-elegant | 1 | 1 | 1 | Pass |
| default-creative | 1 | 1 | 1 | Pass |
| default-code | 1 | 1 | 1 | Pass |
| long-en-minimal | 3 | 4 | 4 | Pass |
| long-nb-code | 3 | 4 | 4 | Pass |
| compact-8mm-letter | 3 | 4 | 4 | Pass |
| roomy-28mm-nb | 4 | 5 | 5 | Pass |
| grid-and-bubbles | 1 | 1 | 1 | Pass |
| long-sidebar-nb | 4 | 5 | 5 | Pass |
| unbreakable-and-boundary | 4 | 4 | 4 | Pass, including corrected marker placement |
Total: 31 → 36 preview pages, matching the unchanged 36 PDF pages. Final-run maxima: x 0.0000037 mm, y 1.493055 mm, font 0.005026 pt, extractable RGB component 0.0000451. No count, marker membership, hidden-content, blank-page or vertical-safe-area failure is waived. These values do not claim pixel identity or exhaustive complete wrapped-line qualification.
Rendered comparisons show corrected continuation/bullet/section placement in all six former failures, including the compact Letter Languages section on page 4. Native short-sidebar surface height now agrees with print instead of being stretched to the screen page height. Small rasterization/glyph-box differences remain within the declared contract.
The PDF's existing long-entry keep rules can leave an entry heading plus company at the bottom of a page with bullets continuing next page (visible in the roomy fixture). Preview now represents that faithfully. Improving that native print-quality policy would change output semantics and is deliberately deferred; it is not hidden by a preview-only workaround.
Preservation and changed owners
| PRES IDs | Invariant | Evidence |
|---|---|---|
| C06, E08/E09 | Same editor/preview panes, zoom/scroll, accessible name, focus entry/exit and responsive visibility | Inherited four P4-03 EN/NB × light/dark keyboard cases; rendered editor evidence |
| C07/C08/C09 | Override/source, hidden/order, template/settings and physical document geometry | All 16 unchanged source/settings fixtures; exact marker/content/page comparisons |
| C10, C01/C02 | Revision protection, canonical source separation, undo/redo | Existing 941 backend / editor conflict/history cases and native stale-write proof; owners untouched |
| C12 | Native PDF truth/content and admission | Unchanged native export endpoint/renderer; existing PDF and security suites |
| W05/W07, E05 | Selected versus frozen submitted CV and account ownership | Ordinary P2-D01/native package proof and account-isolation cases retained |
| C11 | Grounded AI review/accept/reject | Existing regressions retained; AI owners untouched |
Production files: new small src/cvPreview.ts isolates the existing document-preview owner for native behavioural testing; CvBuilderEditor.tsx consumes it and its settled measurements. No editor-frame/navigation/control redesign. Test files: e2e/cv-pagination.spec.ts adds two behaviours (six original failure memberships; delayed-image readiness), and e2e/cv-readiness.spec.ts records the new coordinate representation/readiness/performance without weakening the existing oracle.
Performance
An offline benchmark uses the same saved HTML and Chromium, three runs of every fixture per implementation: 48 samples each. Document setup through settled font/layout frames: median 48.75 → 52.28 ms, p95 59.19 → 62.84 ms. This small local change is not production latency or a universal performance guarantee; scheduling/frame waits are included.
The benchmark measurements preserve each sample. The native ruler results retain the independent page-capacity observation, with its three synthetic HTML inputs and generated PDFs. These are local probes, not new runtime dependencies or CI services.
The existing 300 ms preview debounce/API boundary remains. Pagination runs once per newly rendered document. Break-style reads are collected before writes to avoid an unnecessary alternating read/write loop. The existing architecture still loads the document into a measurement frame and each visible page frame; corrected page counts naturally add one frame to five formerly undercounted fixtures. Long-document DOM duplication remains an existing scaling limitation, not a newly introduced PDF request on each edit. No premature caching/virtualization platform is introduced.
Visual and accessibility review
All 36 final comparison pages were reviewed as six contact-sheet overviews; selected template, continuation, final-page and boundary comparisons were also inspected at full resolution. This review finds matching document sequence, continued text, margins and sidebar fragment surfaces, including Languages on compact Letter page 4 and the corrected custom section on boundary page 4. The visual manifest records hashes and review method; unreviewed standalone raster files are not labelled as individually inspected. Source HTML/native PDF/preview/PDF raster/comparison pairs remain available for every fixture.
The existing keyboard suite exercises EN/Bokmål × light/dark, named editor/preview regions, preview entry/exit, focus retention, zoom/scroll and phone pane visibility. It does not certify human screen-reader speech. Mounted-page visual and axe results from the final run are recorded below; incomplete findings remain incomplete. No editor/preview controls, layout, routes, reduced-motion rules or focus owners are redesigned.
All twelve retained mounted-editor screenshots were individually reviewed: one-page, multipage end and 390 px phone preview, each in EN/Bokmål × light/dark. Examples: light/English desktop, dark/Bokmål desktop, light/Bokmål phone, dark/English phone. Preview focus remains visible and document scrolling/page gaps remain usable. The deliberately unchanged fit-to-width phone rendering can have small document text; interaction/presentation improvements belong to later CV slices.
The sixteen scoped axe scans have zero violations, but retain 32 aria-prohibited-attr incomplete nodes and 252 color-contrast incomplete nodes, each rule appearing in all 16 scans. Those are not passes or human acceptance. Earlier scans had fewer incomplete contrast nodes; the retained multipage DOM/visibility changes alter scanned node population, not proof of contrast compliance. Template-card descriptions and their localisation/disabled appearance remain existing controls debt, not part of this repair.
Final validation and decision
Executed against the final code/test candidate on 2026-10-07. Commands use the repository-required rtk prefix (rtk proxy for unfiltered runners); below, prefixes are omitted for readability. Root commands run in the checkout, npm.cmd commands in job-tracker-ui. Browser runs set DOTNET_ROOT=C:/Users/Connor/.dotnet and DOTNET_HOST_PATH=C:/Users/Connor/.dotnet/dotnet.exe. Complete browser acquisition uses the production export with PLAYWRIGHT_STATIC_EXPORT=true, PLAYWRIGHT_PREBUILT_EXPORT=true, CV_FIDELITY_OUTPUT=../.artifacts/p5-09-pagination/final, and PLAYWRIGHT_JSON_OUTPUT_NAME=../.artifacts/p5-09-pagination/final-browser.json. Specialized suites run sequentially because they share the disposable API port.
| Exact command / check | Final result |
|---|---|
C:/Users/Connor/.dotnet/dotnet.exe test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj -c Release --no-restore --logger 'console;verbosity=minimal' |
941/941 passed, zero failures/skips; unchanged count. Includes revision/atomic writes, source/override, frozen package/ownership, import/CSV/PDF/security regressions |
npm.cmd test -- --runInBand --silent --json --outputFile=../.artifacts/p5-09-pagination-jest.json |
422/422 passed, 80 suites; unchanged count. Editor history/conflict/undo/recovery owners retained |
npm.cmd run test:e2e -- --output=../.artifacts/p5-09-pagination/final-browser --reporter=line,json |
98/98 actual passes, 15.9 minutes, zero failures/skips/flaky/expected-failure cases; safe case summary |
npm.cmd run typecheck / npm.cmd run lint |
Both passed; no suppression or CI/dependency change |
npm.cmd exec tsc -- --project ../.artifacts/p5-09-readiness-e2e-tsconfig.json --noEmit --incremental false |
All permanent browser fixtures type-check; ignored local config extends existing project types |
npm.cmd run build with NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api |
Frontend production static export passed |
C:/Users/Connor/.dotnet/dotnet.exe build JobTrackerApi/JobTrackerApi.csproj -c Release --no-restore -warnaserror |
API Release passed, zero warnings/errors |
npm.cmd run test:rate-limits -- --reporter=line |
9/9 passed, trusted principal/IP/session and forwarding-spoof boundaries retained |
npm.cmd exec playwright test -- --config=playwright.ingress.config.ts --output=../.artifacts/p5-09-pagination/ingress --reporter=line |
6/6 passed; local application behavior, not deployed production proof |
npm.cmd run test:pdf-admission -- --output=../.artifacts/p5-09-pagination/pdf-admission --reporter=line |
1/1 passed, actual cross-route capacity/recovery |
python scripts/test-ingress.py |
3/3 passed, configuration/Compose checks |
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, no provider certification |
Bundled Python -X utf8 scripts/verify-cv-fidelity.py .artifacts/p5-09-pagination/final |
16/16 pass, exit 0; unchanged oracle/tolerances; all 36 pages retained |
python scripts/supply-chain.py scan-secrets |
Passed against the staged/tracked candidate; no high-confidence credential patterns |
git diff --check / git diff --cached --check |
Passed |
python .artifacts/p4-04-check-doc-links.py |
145 current/root Markdown documents, zero missing local targets; historical archive excluded |
The bundled PDF Python executable is C:/Users/Connor/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe; it uses already available PDF extraction/rasterization libraries. No application dependency is added.
Count reconciliation: 941 backend and 422 frontend are unchanged. Browser 96 → 98 adds only the two permanent cv-pagination.spec.ts behaviours: original six failing fixtures' exact native membership, and image-gated one-time settled measurement. The existing corpus case still contains all 16 numerical fixtures. Four inherited P4-03 preview keyboard cases, native stale-write recovery and frozen-package/P2-D01 cases pass normally. P2-D01 has no expected-failure annotation.
The initial focused run had 8/9 passing: the corpus readiness poll dereferenced documentElement during the iframe's initial document transition. The final fixture uses a null-safe poll for the explicit readiness signal; the native three-case rerun passed, followed by the complete 98/98 run above. No test expectation, fixture, oracle threshold or difficult content was removed.
P5-09: GO. G-CV-REV remains accepted and regression-green. G-CV-RENDER is satisfied by the retained corpus: exact page counts/membership, no missing content/blank-page/hidden-section/safe-area failures, positional/typographic/color results within the original tolerances, and matching reviewed page boundaries. P4-03 keyboard behavior remains green. This is a local measured gate, not certification of every possible CV, browser, font or deployment environment.
Remaining qualifications: production Linux/font substitution, other browser engines, complete wrapped-line/photo/all-font/all-template-long-form comparisons, existing native heading/bullet keep policy and later template/control presentation. The synthetic delayed-image test proves measurement readiness, not photo/PDF equivalence. These are explicit limits of the accepted fixture contract; no remaining fixture has a material count/placement/clipping mismatch. Further qualification must retain PDF truth rather than weaken this oracle.
F04, P5-02 human screen-reader acceptance, incomplete accessibility/manual checks, Dashboard preference-save 500, Board scaling/native touch and deferred followMode UI remain separate. No unrelated debt is closed by this repair. No backend/schema/export/package/CI/provider changes occurred. Stop before P5-09 and B07; the next authorised slice would be P5-09 editor frame/navigation using these unchanged output/revision contracts.