155 lines
21 KiB
Markdown
155 lines
21 KiB
Markdown
# 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](../p5-09-readiness/README.md#measured-corpus-and-results) 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 `.page` CSS. 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-margin` CSS token, including template/default margin and density. The duplicate frontend density/margin calculation is removed.
|
||
- Existing `@media print` declarations are reused in the screen fragmentainer. Header/main/sidebar padding, min-height, borders, fonts and content remain renderer-owned.
|
||
- Existing computed `avoid-page` break decisions are applied as `avoid-column` in 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](evidence/fidelity/fidelity-results.json), [source measurements](evidence/fidelity/measurements.json) 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](evidence/performance.json) preserve each sample. The [native ruler results](evidence/native-ruler/results.json) 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](evidence/visual-manifest.json) 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](evidence/one-page-light-en.png), [dark/Bokmål desktop](evidence/multipage-end-dark-nb.png), [light/Bokmål phone](evidence/preview-390-light-nb.png), [dark/English phone](evidence/preview-390-dark-en.png). 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](evidence/accessibility-summary.json) 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](evidence/browser-summary.json) |
|
||
| `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.
|