11 KiB
CV-QA-00 architecture and baseline coverage
26 October 2026. Baseline ef425c288b38ae0e91dcc216a5c8b6c02c433ab5; branch test/cv-integration-acceptance, containing CV-UX 4a0af62. Clean local/fetched import HEAD matched. All 84 CV-import indexed evidence hashes matched. Fresh isolated MariaDB entry run: 70/70, no skips (.artifacts/cv-integration-qa/entry-mariadb-01), not production.
Authority: docs/architecture/current.md → overview.md; CV-UX/CV-import ACCEPTANCE reports and CV-QA handoff; RD21 SAVE_CONTRACT; latest P9-SEC-02 addendum/verdicts; Phase 9 preservation inventory/Phase10 handoff. Historical RD21/provider blocks were superseded by actual provider qualification. P9-SEC-02 records RD21 RESOLVED and narrow trained-BART/cache compatibility PASS, with Python security CONDITIONAL PASS (vendor PyPI query gap), hosted MariaDB BLOCKED/isolation UNVERIFIED. That is not qualification of the new CV Ollama adapter or production. Original Phase10 deletion eligibility requires candidate-specific caller/route/inventory/test proof; production-only gates do not automatically block separately scoped development.
Lifecycle and owners
flowchart LR
U[CareerProfilePage upload] --> V[ProfileCvController.Import validation]
V --> A[CvUploadArtifact + CvExtractionRun]
A --> Q[cv.process operation / worker lease]
Q --> S[SummarizerService → FastAPI app.py]
S --> P[bounded parser_child.py / Docling native]
P --> B[ordered id/text/kind/page blocks]
B --> I[CvDocumentInterpreter]
I --> G[CvDocumentReview.Ground]
G --> R[CvImportReview / owned source endpoint]
R --> T[apply-reviewed / expectedVersion / ExecuteAtomicAsync]
T --> C[CareerProfileService + Mapper + children/history/Identity]
C --> E[CvBuilderEditor / resolver / variant overrides]
E --> D[template physical renderer / preview / revisioned PDF]
D --> J[ApplicationAssetsService / frozen application package]
Historical entry findings (before remediation): CvDocumentReview/CvImportReview exposed only nonempty incoming typed leaves. add meant accepting an emitted field; it could not create missing fields/records. New extracted records were already appended, but missing-record authoring, explicit target selection and source assignment were absent. CvDocumentInterpreter handled positional pipe rows and section lists; later undelimited lines could be wrongly attached to the last global record. Transport discarded Docling hierarchy/geometry/table cells, so the order of two unlabeled text lines could not prove employer versus title. Ground selected the first document-wide substring, losing repeated-occurrence association. Current remediations and remaining limits are documented in CAREER_PROFILE_MAPPING.md and EXTRACTION_ACCURACY.md; the entry matrix below remains historical rather than being silently rewritten.
Canonical writes remain CareerProfileService.ExecuteAtomicAsync/SaveVersionAsync, CareerProfileMapper and CareerProfileValidator. CV documents/settings/overrides/history retain CvVariantService, existing resolver/editor and physical renderers. Letter/application revisions remain JobApplication.Version/ApplicationAssetsService. No second profile, queue, revision or renderer is proposed.
Field-level entry matrix
Each row follows source → interpreted field → generic emitted-field review → canonical destination → existing atomic persistence → CV Editor output. CvDocumentImportTests covers grounding/selected fields/provenance/duplicates; CvImportReviewedPersistenceTests covers durable transactional apply. CvBuilderTests and native document suites cover output owners, but do not by themselves prove imported-field integration. Statuses below are entry evidence, not final decisions.
| Source / extracted canonical field | Review control at entry | Destination / editor output | Entry classification and existing evidence |
|---|---|---|---|
| Labelled name → contact.fullName | emitted string correction | contact / CV header | Supported with incomplete evidence: real import journeys |
| Email → contact.email | emitted string correction | contact / header | Supported with incomplete evidence: parser + import journeys |
| Phone → contact.phone | emitted string correction | contact / header | Supported with incomplete evidence: labelled parser, PDF fixture |
| Title → contact.headline | emitted string correction | contact / header | Partially implemented: labelled only |
| Location → contact.location | emitted string correction | contact / header | Partially implemented: labelled only |
| Website/LinkedIn/GitHub → contact.website/linkedIn/gitHub | emitted string correction | contact / links | Supported with incomplete evidence: links regression; missing values cannot be authored |
| Portfolio/other links → contact.links[].label/url | emitted leaves | contact / labelled links | Partially implemented: existing link preservation tested, missing creation absent |
| Summary/specialisms → summary[] | emitted item correction | long-tail summary / summary | Supported with incomplete evidence: real PDF journey |
| Role/employer → jobs[].title/company | emitted leaves | work children / experience | Partially implemented: pipe grammar, extracted-add tests; missing authoring absent |
| Employment start/end → jobs[].start/end | emitted leaves | work children / original date strings | Partially implemented: partial-date/current tests; multiline dates unresolved |
| Current employment → jobs[].isCurrent | emitted true only | work children / current-date output | Partially implemented: cannot author false/missing field |
| Job location → jobs[].location | absent unless emitted | work children / experience | Missing deterministic mapping/review authoring |
| Responsibilities/achievements → jobs[].bullets[] | emitted item correction | work children / bullets | Partially implemented: list merge/provenance tested, next-record misattribution gap |
| Explicit job technologies → jobs[].skills[] | absent unless emitted | work children / skills | Missing deterministic mapping/review authoring |
| Institution/qualification → education[].institution/qualification | emitted leaves | education children / education | Partially implemented: pipe grammar; missing authoring absent |
| Qualification level → education[].qualificationLevel | absent unless emitted | education children / education | Missing stated-level mapping/review authoring; must not infer |
| Study dates → education[].start/end | emitted leaves | education children / dates | Partially implemented: partial dates supported, multiline segmentation absent |
| Education location/details → education[].location/details[] | emitted details only | education children / details | Partially implemented: location missing, continuation unsafe |
| Skills/frameworks/tools → skills[] | emitted scalar correction | skills long-tail / skills | Supported with incomplete evidence: normalized source indices tested; no schema for categories/proficiency |
| Language/proficiency/notes → languages[].name/level/notes | nonempty emitted leaves | languages long-tail / languages | Partially implemented: missing level stays unknown, missing authoring absent |
| Certification → certifications[].name/issuer/location/date/details[] | emitted name/issuer/date | certification children / certifications | Partially implemented: PDF table association defect, location/details missing |
| Project → projects[].name/role/location/start/end/bullets[]/skills[] | emitted name/role/bullets | project children / projects | Partially implemented: other fields/missing-record authoring absent |
| Awards → awards[] | emitted items | long-tail / awards | Supported with incomplete end-to-end evidence |
| Publications → publications[] | emitted items | long-tail / publications | Supported with incomplete end-to-end evidence |
| Organisations → organisations[] | emitted items | long-tail / organisations | Supported with incomplete end-to-end evidence |
| Interests → interests[] | emitted items | long-tail / interests | Supported with incomplete end-to-end evidence |
| References → references[] | emitted items | long-tail / references | Supported with incomplete end-to-end evidence |
| Courses/custom → otherSections[].title/items[] | emitted items | long-tail / custom sections | Partially implemented: retained source; cannot reclassify missing typed records |
| Stable IDs, normalized sorting dates, metadata/version | no caller authoring | canonical owner-generated/internal | Unsupported by design as extracted facts; source date precision retained |
| Experience duration, new skill-category/proficiency entities | none | no corresponding canonical contract | Unsupported by design; preserve source in custom/detail instead |
| AI interpretations / OCR/layout model results | none active | disabled/disconnected seam | Blocked by external qualification; no real CV-model evidence |
Current supported-document boundary (27 October addendum)
Pinned extraction remains docling-slim==2.142.1, docling-core==2.104.0, docling-parse==7.23.0 in the isolated hash-locked import runtime; no new dependency/model download was required for QA. Real document conversion is separate from generative interpretation.
| Input | Qualified behavior and limit |
|---|---|
| Text PDF, single/multi-page | Actual local text/block/page extraction. Explicit semantic labels and supported pipe grammar can form records; complex columns/tables can require source mapping. Full arbitrary-layout semantic accuracy is not qualified. |
| DOCX paragraphs/headings/lists/header-defined tables | Actual structured extraction and deterministic labelled records; page numbers remain unknown and excerpts are shown. Frozen labelled cases passed; headerless relationships can remain unresolved. |
| Genuinely ambiguous employer/title or institution/qualification | Preserve visible source; user chooses fields and new/existing destination. No relationship guessed from capitalization or employer dictionaries. Legacy headerless pipe order remains an explicit compatibility limitation. |
| Scanned/image-only PDF | OCR disabled in qualified import configuration; unsupported/unreadable outcome is explicit. No scan-accuracy claim. |
| Active/malformed/oversized/archive-bomb documents | Reject under bounded security rules rather than claim extraction support. |
| Other legacy file types | Existing older importer retains its supported path; this QA does not qualify them as Docling PDF/DOCX workflow. |
No real CV-model inference was run. Model adapter contracts/synthetic responses establish integration seams only. Partial deterministic recall and open human/device/security/release qualifications remain independent.
Preservation impact
All 57 groups / 33 routes remain in scope; no historical status is upgraded by this audit. Direct changes: PRES-C01/C02/C03 (canonical/import), C05–C10/C12 (consumption/overrides/history/rendering), W05/W06/W07/W12 (associations/letters/frozen/progress), E05/E07/E08/E09 (draft/keyboard/access/ownership), S04/S05 (privacy/portability). Other groups remain regression coverage. No route removal or cleanup. See the dated Phase 9 preservation addendum and final checkpoint reconciliation.