# AI-004 durable CV processing

Updated: 2026-08-09

Status: `IMPLEMENTED — NOT VERIFIED`. The repository queue migration and automated tests pass. Parser dependency/isolation work, browser checks, selected-model execution, MariaDB, restart canary and production rollout remain blocked or unverified.

## Revalidated execution path and root cause

CV upload previously saved an artifact and held the HTTP request while extraction, reconstruction, classification, normalization, structured parsing and model-capable work completed. Reprocess, rebuild and improve returned 202, but woke an unbounded process-local channel. A hosted service separately scanned queued/running extraction rows at startup. The persistent `CvExtractionRun` protected the review result, but the execution path had no shared admission, lease, deadline, retry, cancellation, provider provenance or persistent notification contract. A proxy/backend restart could therefore lose the wakeup or present a 504 even when later work completed. Live 504 reproduction remains blocked; this is confirmed source-path evidence, not a claimed browser reproduction.

## Implemented contract

- Upload now saves the owner-scoped artifact and queued extraction run, enqueues typed `cv.process` work, and returns 202 with the existing safe operation DTO/status URL. It does not parse inside the request.
- Reprocess, rebuild and improve use the same producer. The old channel and `CvProcessingHostedService` are removed; AI-001 is the only scheduler/worker.
- Operations store only subject type `cv_extraction_run` and the numeric run ID. Raw CV text, filenames, prompts and parser output are not copied into `UserOperations`.
- The worker re-enters the operation owner scope, rechecks live Pro/AI policy, and only loads an extraction run owned by that scope. The handler reports provider/model/route metadata when available.
- Sequential duplicate uploads with the same content and active rebuild/improve/reprocess requests reuse one active run/operation. The duplicate temporary upload copy is deleted before it is added to the database.
- Retryable provider failures leave the extraction run queued while the operation owns retry timing. Final/non-retryable failures become failed. Running cancellation and timeout state are synchronized; generic operation state is embedded in extraction-history responses so refresh resumes queued/retry/cancel/failure UI.
- Upload/reprocess reopen the stored owner artifact in the worker. Rebuild/improve pass the worker cancellation token to the metadata-capable generation call.
- Successful processing stops at `pending_review`. It does not update profile text/structure/current-version pointers until the existing accept endpoint is called. Discard remains available.
- The UI shows queued, local processing, retry wait, approved-fallback wait, failed, cancelled and cancellation-requested states with cancel/retry actions. The upload spinner now ends after admission and reports the queued run rather than false extraction success.

No dependency, schema, migration, proxy timeout or production switch changed. `Workers:AiOperationsEnabled` remains false by default.

## Automated evidence

- Focused CV/queue/SQLite tests: 40/40 after the final failure-path addition; synthetic files and fake providers only.
- Full backend: 594/594.
- Focused Career Profile UI: 10/10.
- Full frontend: 47/47 suites and 161/161 tests.
- Backend build, frontend production build and `git diff --check`: pass; line-ending notices only.
- Integration coverage uses real SQLite operation/run/artifact/notification rows and proves 202, active duplicate reuse, no raw CV payload in operation state, owner-scoped execution, provider-failure retry state, one terminal notification and the unchanged human review gate.

## Remaining gates and known limits

- SEC-006/007 still own fixed parser versions, page/pixel/decompression/memory/process isolation and complete parser-child cancellation/cleanup. Legacy structured parsing calls are not all cancellation-aware. No malicious file was executed.
- Cancellation of an operation before a worker claims it is authoritative in `UserOperation` and shown correctly after refresh; the underlying extraction row is reconciled when retried/processed, but immediate terminal synchronization of that dormant row remains follow-up cleanup work.
- Browser localhost is denied by administrator policy. No real browser/mobile/theme/keyboard/refresh/back-forward workflow or screenshot is claimed.
- The authorized private CV was not used. Synthetic input must pass the SEC-006/007 gates before that local-only check.
- The generic lease tests cover restart recovery, but no CV parser/model process was interrupted and resumed in a runtime canary.
- MariaDB, selected Ollama model, worker telemetry, production activation and rollback canary remain unverified. The worker stays default-off.

## Rollback

Keep `Workers:AiOperationsEnabled=false`, revert `c3c5af8`, and retain the additive operation/extraction tables. Cancel or drain queued `cv.process` operations before removing the handler. No database downgrade or artifact rewrite is required; existing extraction runs remain readable.
