test(i18n): qualify CV singular captions and preserved editor behavior

This commit is contained in:
cesnimda
2026-11-04 13:21:23 +01:00
parent 122956b6a3
commit e70c7098cd
93 changed files with 2341 additions and 7 deletions
+2
View File
@@ -1,5 +1,7 @@
# A3-IM10 Cross-application qualification
4 November CV-count source **122956b6a38f4dc06b461383f31fdaa2658a6fdb**:81 native cases/two suites, types/full lint/export build and36 configurations/72 caption states PASSED,zero writes/errors/axe violations. V23 one-entry/page captions corrected, no new dynamic calls; pagination, source content, settings and revision behavior preserved. See visual-correction/CV_COUNTS_REVIEW.md for retained failures and exact scope. Preceding CV journey7e2bf201 remains local-only pending publication; last successful remote8fef819c. No production/renderer/security/owner acceptance inferred.
4 November Profile→CV creation/edit/preview/download client journey on unchanged **9bfc51b067c4da4164b84578f5dacf452125ba62**:8 representative390/1440×EN/NB×theme journeys/40 states PASSED,16 intercepted creates/renames and8 revision-checked export/download events. No unexpected writes/errors/axe violations;8 company and8 template-preview reads unavailable. Selected contact/summary inheritance request and unchanged settings at rename checked; backend Profile rendering/physical PDF NOT RUN. Synthetic download bytes explicitly are not a PDF. See visual-correction/CV_JOURNEY_REVIEW.md. Matching-count receipt **8fef819c4e5a17eee65c8707d014155dea8a6322** published/readback-verified with1,256 integrity checks. Remaining application→follow-up/import/error/native/owner/security/recovery/release gates stay OPEN.
4 November matching-count source **9bfc51b067c4da4164b84578f5dacf452125ba62**:48 selected native cases/four suites, types/full lint/export build and36 configurations/72 table/board states PASSED,zero writes/unavailable reads/page errors/axe violations. V22 singular text resolved in EN/NB, no new dynamic translation call; existing locale-triggered active-view reload preserved. See visual-correction/MATCHING_COUNT_REVIEW.md for retained RED/path failures and exact superseded counts. Viewer24 families/864 actual bindings/28 frozen references;48 artifact selections passed separately. Discovery receipt **ed4ce4cc3a0fffecfa406793a60680e490fa6674** published and independently verified after one ordinary retry of a remote unpack checksum rejection;1,287 integrity checks matched. No infrastructure change. Remaining IM10/route/workflow/owner/native/European/security/recovery/release gates remain OPEN.
@@ -0,0 +1,13 @@
# CV section and page count localisation
4 November 2026. Source `122956b6a38f4dc06b461383f31fdaa2658a6fdb`, after local CV-journey receipt7e2bf201 (publication was blocked by HTTP502 at that checkpoint). V23 was reproduced in the actual Bokmål/dark editor and confirmed at the section/page caption callers.
Add paired singular section-entry and page-count keys, selected only for1 with literal translator calls. Keep existing0/2+ text and English page wording. The section-count formula is unchanged for custom, structured entries and inherited/editable items. Do not change pagination, measured HTML, preview readiness, settings, inheritance, undo/save/history, source content or UI/output-language ownership. No new dynamic translation call, dependency or data migration.
RED:6 failed/10 passed new cases,62 older cases filtered. The initial native frame setup fired load before debounced preview HTML was ready; its failure is retained. Corrected tests wait for HTML and explicitly simulate ready/page metadata; this tests captions, not physical page measurement. Typecheck/build caught an unsupported test selector option; removed it and retained failed receipts. Final81-case run below was executed after that correction and supersedes earlier runs, without additive counting.
PASSED:81 native cases/two suites (78 CV deep-link/edit/revision/AI-contract cases including16 new count cases, three catalogue cases), types, full lint, scoped harness/test lint and static export build. New cases cover Profile/custom0/1/2 entries and1/2-page captions in EN/NB, live locale switches and no settings writes. Existing native AI tests use mocks; no live model runs.
PASSED:36 configurations/72 actual section/page-caption scans and captures across all nine widths, languages and themes. Zero mutations, unexpected writes, page exceptions or axe violations. The count scope leaves creation, save, import and export NOT RUN; the preceding8/40 connected client journey stays source-bound to9bfc/7e2 and is not repeated for text. Browser preview uses36 synthetic HTML responses;36 company reads are unavailable fixtures. Template-preview service is not exercised by this scope. No new physical PDF, canonical backend rendering or semantic-quality acceptance.
Rollback reverts paired catalogue entries/count selections and related tests; no data rollback. Full A3/Phase10/European/native/owner/integrated security/recovery/release acceptance remain OPEN. Next independent work: application status→follow-up scheduling and remaining permission/error/recovery route states.
File diff suppressed because it is too large Load Diff
@@ -30,7 +30,7 @@ Owner correction: 3 November 2026. This register extends IM10 and the original 3
| V20 | Shared feedback | ToastProvider outside the application theme produced failing information-toast contrast3.85:1 | Fixed provider order in a84a97cb;70 native cases and36 configurations/252 Settings states passed, toast visible during contrast analysis | Other feedback/workflow and human/native acceptance remain separate; failed scan retained |
| V21 | Administration hierarchy | Repeated generic route/page headings remain after opening section surfaces | OPEN minor visual discrepancy from rendered review | Review current route heading ownership and focus/test contracts before removing repetition |
| V22 | Application localisation | One result renders `1 matching jobs` / `1 jobber samsvarer` | RESOLVED in9bfc51b0:48 native cases and36 configurations/72 focused table/board count states passed,zero writes | Existing active-view locale reload/loading/error suppression retained; owner/native/European acceptance separate |
| V23 | CV localisation | One section item renders `1 entries` / `1 oppføringer`; one-page Bokmål caption uses `1 sider` | OPEN reproduced in connected CV screenshot and confirmed at section-entry/page-count callers | Add paired singular labels with0/1/2/current-locale regression; preserve document content, UI/output-language ownership, paging and revision behavior |
| V23 | CV localisation | One section item renders `1 entries` / `1 oppføringer`; one-page Bokmål caption uses `1 sider` | RESOLVED in122956b6:81 native cases and36 configurations/72 focused caption states passed,zero writes | Entry-count formula and physical pagination unchanged; full native/European/owner acceptance separate |
The owner-approved design foundation remains original A1 dashboard, D1 visual system, B1 tracking, editor left / preview right, application context right, desktop sidebar and hybrid mobile navigation. No controls, imports, revisions, permissions or provider rights may be removed to obtain visual simplicity.
@@ -198,8 +198,8 @@
"CvBuilderEditor"
],
"visualStatus": "OPEN_SURFACES_SCOPED_REVIEW_FULL_ACCEPTANCE_OPEN",
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed; representative source-selection/create/edit/preview/download transport8/40 passed; physical PDF/backend/template services NOT RUN",
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md; CV_JOURNEY_REVIEW.md; evidence/cv-journey/BROWSER.json",
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed; representative source-selection/create/edit/preview/download transport8/40 passed; physical PDF/backend/template services NOT RUN; singular-caption successor36/72 passed,zero writes; original physical metrics untouched",
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md; CV_JOURNEY_REVIEW.md; evidence/cv-journey/BROWSER.json; CV_COUNTS_REVIEW.md; evidence/cv-counts/BROWSER.json",
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion"
},
{
@@ -0,0 +1,921 @@
{
"screens": [
{
"width": 320,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 320,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 360,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 390,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 430,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 768,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1024,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1280,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1440,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "en",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "en",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "en",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "en",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "nb",
"mode": "light",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "nb",
"mode": "light",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "nb",
"mode": "dark",
"state": "section-count",
"capture": "targeted viewport",
"violations": []
},
{
"width": 1920,
"language": "nb",
"mode": "dark",
"state": "page-count",
"capture": "targeted viewport",
"violations": []
}
],
"journeys": [
{
"width": 320,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 320,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 320,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 320,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 360,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 360,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 360,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 360,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 390,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 390,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 390,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 390,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 430,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 430,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 430,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 430,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 768,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 768,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 768,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 768,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1024,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1024,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1024,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1024,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1280,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1280,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1280,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1280,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1440,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1440,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1440,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1440,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1920,
"language": "en",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1920,
"language": "en",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1920,
"language": "nb",
"mode": "light",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
},
{
"width": 1920,
"language": "nb",
"mode": "dark",
"singularEntryAndPageCount": "PASS",
"creationSaveImportExport": "NOT RUN"
}
],
"errors": [],
"unexpectedWrites": [],
"mockedWrites": [],
"exportRequests": [],
"downloads": [],
"renderReads": 36,
"unavailableReads": [
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies",
"/api/companies"
],
"blockedExternal": [
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com",
"https://fonts.googleapis.com"
],
"limits": [
"All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.",
"Legacy import comparison and selection only; no parser, model, import acceptance or source mutation.",
"No native device, screen reader, provider, integrated security, deployment or release acceptance."
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

@@ -0,0 +1,19 @@
{
"checks": [
{
"width": 390,
"language": "nb",
"theme": "dark",
"selections": 26,
"errors": []
},
{
"width": 1440,
"language": "en",
"theme": "light",
"selections": 26,
"errors": []
}
],
"scope": "Static comparison artifact only, not application acceptance."
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

@@ -8,6 +8,7 @@ body{margin:24px;font:16px/1.5 system-ui,sans-serif;color:#302744;background:#f5
</style>
<h1>A3: approved reference and real application</h1>
<p><a href="CV_JOURNEY_REVIEW.md">Connected Profile-to-CV creation, edit, preview and download review</a> covers eight representative phone/desktop configurations. Its synthetic download transport is not physical PDF qualification.</p>
<p>The connected CV captures retain their historical labels. Select CV section/page counts below for the singular-text correction at source122956b6.</p>
<p>Development evidence, not final acceptance. References are unchanged PNG bytes from approved A3 commit237c79b8. They include workshop controls and different synthetic content. Compare hierarchy, spacing, borders, navigation and available actions rather than whole-image pixels. Reference text is English/light; the real capture follows the controls below. Human, device, native-language and final security/release qualifications remain separate.</p>
<nav aria-label="Review controls">
<label>Screen<select id="screen"></select></label>
@@ -32,6 +33,8 @@ const screens = [
{name:'Matching count board',reference:'applications',folder:'matching-count',state:'board',source:'9bfc51b0',scope:'The same single-count rule in Board; real count/membership retained. Mutation/detail qualification is not repeated.'},
{name:'Career overview',reference:'career',folder:'career',state:'overview',source:'b31ce617',scope:'Open overview sections and all14 edit actions. Scoped216-state qualification passed; company/preview reads remain unavailable.'},
{name:'Career evidence',reference:'career',folder:'career-evidence',state:'populated',source:'a84a97cb',scope:'Evidence form/record boundaries retained intentionally. Unsaved drafts, cancelled deletion and error/retry qualified with synthetic data; no evidence mutations.'},
{name:'CV section counts',reference:'cv',folder:'cv-counts',state:'section-count',source:'122956b6',scope:'Singular section-entry label successor; inherited/custom0/1/2 and live-locale native regression. No settings writes.'},
{name:'CV page counts',reference:'cv',folder:'cv-counts',state:'page-count',source:'122956b6',scope:'Correct one-page Bokmål caption. Synthetic HTML; original physical renderer/page metrics untouched and not requalified.'},
{name:'Calendar agenda',reference:'calendar',folder:'calendar',state:'agenda',source:'b31ce617',scope:'Recorded deadlines/follow-ups only. Scoped108-state qualification passed; no invented interview appointments or original timezone precision.'},
{name:'Document results',reference:'documents',folder:'documents-inbox',state:'document-filtered',source:'b31ce617',scope:'Targeted result viewport; filters, downloads and source links remain. Scoped document/mail216-state qualification passed.'},
{name:'Opened mail message',reference:'correspondence',folder:'mail-flat',state:'message',source:'a9208ab4',scope:'Source-bound context/workflow capture. Its singular label text is corrected in cd116ab8; select Mail label counts to see that successor.'},
+14 -4
View File
@@ -10,14 +10,16 @@ const { translations } = await import(`data:text/javascript;base64,${Buffer.from
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
const evidenceOnly = process.env.A3_EVIDENCE_REVIEW === '1';
const cvJourney = process.env.A3_CV_JOURNEY === '1';
const countOnly = process.env.A3_CV_COUNTS === '1';
assert.ok(!countOnly || !(cvJourney || evidenceOnly || process.env.A3_BOUNDARY), 'CV count presentation is a separate read-only scope.');
assert.ok(!cvJourney || !(evidenceOnly || visualMatrix || process.env.A3_BOUNDARY), 'CV journey is a separate representative workflow scope.');
assert.ok(!evidenceOnly || !process.env.A3_BOUNDARY, 'Evidence review does not repeat editor boundary qualification.');
const out = path.resolve(import.meta.dirname, cvJourney ? '../../docs/ui-modernisation/visual-correction/evidence/cv-journey' : evidenceOnly ? '../../docs/ui-modernisation/visual-correction/evidence/career-evidence' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/career' : '../../docs/ui-modernisation/evidence/career/browser');
const out = path.resolve(import.meta.dirname, countOnly ? '../../docs/ui-modernisation/visual-correction/evidence/cv-counts' : cvJourney ? '../../docs/ui-modernisation/visual-correction/evidence/cv-journey' : evidenceOnly ? '../../docs/ui-modernisation/visual-correction/evidence/career-evidence' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/career' : '../../docs/ui-modernisation/evidence/career/browser');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], exportRequests: [], downloads: [], renderReads: 0, unavailableReads: [], blockedExternal: [] };
const browser = await chromium.launch();
try {
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? (cvJourney ? [[390, 'en', 'light'], [1440, 'en', 'light']] : evidenceOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[320, 'en', 'light']]) : (cvJourney ? [390, 1440] : visualMatrix || evidenceOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? (cvJourney ? [[390, 'en', 'light'], [1440, 'en', 'light']] : evidenceOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[320, 'en', 'light']]) : (cvJourney ? [390, 1440] : visualMatrix || evidenceOnly || countOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
for (const [width, language, mode] of configurations) {
console.log(`Checking ${width}/${language}/${mode}`);
const t = key => { assert.ok(translations[language][key], key); return translations[language][key]; };
@@ -39,12 +41,13 @@ try {
const evidenceItems = [{ id: 1, category: 'achievement', title: 'Recorded nurse mentoring', statement: 'Mentored new colleagues in a synthetic training scenario.', tags: ['Training', 'Communication'], sourceReference: 'Synthetic review' }, { id: 2, category: 'project', title: 'Recorded electrician project', statement: 'Documented a synthetic installation handover.', tags: ['Safety'], sourceReference: 'Synthetic project notes' }];
await page.route('**/*', route => {
const req = route.request(), url = new URL(req.url()), p = url.pathname;
if ((evidenceOnly || cvJourney) && url.origin !== 'http://localhost:4338' && !(url.origin === 'http://localhost:5202' && p.startsWith('/api/'))) { report.blockedExternal.push(url.origin); return route.abort(); }
if ((evidenceOnly || cvJourney || countOnly) && url.origin !== 'http://localhost:4338' && !(url.origin === 'http://localhost:5202' && p.startsWith('/api/'))) { report.blockedExternal.push(url.origin); return route.abort(); }
if (!['localhost', '127.0.0.1'].includes(url.hostname)) { report.blockedExternal.push(url.origin); return route.abort(); }
if (!p.startsWith('/api/')) return route.continue();
const answer = data => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(data) });
const note = action => report.mockedWrites.push({ width, language, mode, action });
if (evidenceOnly && req.method() !== 'GET') { report.unexpectedWrites.push(p); return route.abort(); }
if (countOnly && req.method() !== 'GET' && !(req.method() === 'POST' && p === '/api/cv/preview')) { report.unexpectedWrites.push(p); return route.abort(); }
if (evidenceOnly && p === '/api/career/evidence') return evidenceState === 'error' ? route.fulfill({ status: 503, contentType: 'application/json', body: '{}' }) : answer(evidenceState === 'empty' ? [] : evidenceItems);
if (cvJourney && req.method() === 'POST' && p === '/api/cv/variants') {
const body = req.postDataJSON(); assert.equal(created, false); assert.equal(body.name, 'Teacher career CV'); assert.equal(body.settings.includeProfileContact, true); assert.equal(body.settings.sectionsExplicit, true); assert.deepEqual(body.settings.sections, [{ key: 'summary' }]);
@@ -99,6 +102,13 @@ try {
if (width >= 600) await page.getByRole('tab', { name: t(key), exact: true }).click();
else { await page.getByRole('combobox', { name: t('careerWorkspaceNavigation'), exact: true }).click(); await page.getByRole('option', { name: t(key), exact: true }).click(); }
};
if (countOnly) {
await page.goto('http://localhost:4338/career/builder/3'); await expect(page.getByRole('region', { name: t('cvEditorEditingRegion'), exact: true })).toBeVisible();
const caption = page.getByText(language === 'en' ? /\b1 entry\b/ : /\b1 oppføring\b/); await expect(caption).toBeVisible(); await scan('section-count', caption);
if (width < 768) await page.getByRole('button', { name: t('cvEditorPreview'), exact: true }).click();
const preview = page.getByRole('region', { name: t('cvEditorLivePreview'), exact: true }); await expect(preview).toBeVisible(); await expect(page.getByText(language === 'en' ? '1-page CV' : 'CV på 1 side', { exact: true })).toBeVisible(); await scan('page-count', preview);
report.journeys.push({ width, language, mode, singularEntryAndPageCount: 'PASS', creationSaveImportExport: 'NOT RUN' }); await context.close(); continue;
}
if (cvJourney) {
await page.goto('http://localhost:4338/career/builder'); await expect(page.getByRole('button', { name: t('cvDashboardNewCv'), exact: true })).toBeEnabled(); await scan('library');
await page.getByRole('button', { name: t('cvDashboardNewCv'), exact: true }).click();
@@ -174,7 +184,7 @@ try {
report.journeys.push({ width, language, mode, all14KeyboardEditTargets: 'PASS', canonicalSaveStableIds: 'PASS', legacyImportComparisonSelectionNoApply: 'PASS', libraryKeyboardOpen: 'PASS', cvResponsiveRename: 'PASS', letterResponsiveManualSave: 'PASS' });
await context.close();
}
assert.equal(report.screens.length, configurations.length * (cvJourney ? 5 : 6)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, evidenceOnly ? 0 : configurations.length * (cvJourney ? 2 : 3)); assert.equal(report.exportRequests.length, cvJourney ? configurations.length : 0); assert.equal(report.downloads.length, cvJourney ? configurations.length : 0);
assert.equal(report.screens.length, configurations.length * (countOnly ? 2 : cvJourney ? 5 : 6)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, evidenceOnly || countOnly ? 0 : configurations.length * (cvJourney ? 2 : 3)); assert.equal(report.exportRequests.length, cvJourney ? configurations.length : 0); assert.equal(report.downloads.length, cvJourney ? configurations.length : 0);
assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
console.log(`PASS:${report.journeys.length} controlled journeys,${report.screens.length} axe scans/captures,${report.mockedWrites.length} fixture mutations.`);
} finally {