Files
jobtrackingapp/docs/cv-integration-qa/ARCHITECTURE_AND_COVERAGE.md
T

87 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```mermaid
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.