134aac7bcf
Add a content-free usage ledger with legacy backfill. Reserve Workspace and durable Strategy/CV work before execution so deleted history or duplicate admission cannot reset limits.
45 lines
4.6 KiB
Markdown
45 lines
4.6 KiB
Markdown
# AI-003 Strategy Snapshot durable operation
|
|
|
|
Updated: 2026-08-09
|
|
|
|
Status: `IMPLEMENTED — NOT VERIFIED`. Repository implementation and automated tests pass; browser, selected local model, MariaDB, restart canary and production rollout are not verified.
|
|
|
|
## Revalidated execution path and root cause
|
|
|
|
The Overview button in `JobDetailsDialog.tsx` called candidate fit and `GET /api/jobapplications/{id}/focus-plan` concurrently. Opening the Focus Plan tab or pressing Regenerate called the same GET. `JobApplicationsController.GetFocusPlan` loaded owner-filtered job/profile/attachments, then performed four sequential model requests and wrote one `AiWorkspaceNote` before returning. Authorization and owner filters were present, but the browser request owned the complete workload: proxy/transport timeout or application restart lost the request, there was no stable operation ID, and refresh/double-click/cancel/retry had no durable contract. Live reproduction remains blocked; this is a confirmed code execution path, not a claimed browser reproduction.
|
|
|
|
## Implemented contract
|
|
|
|
- `GET /api/jobapplications/{jobId}/focus-plan` is read-only and returns only the stable cached result or `404 strategy_not_generated`.
|
|
- `POST /api/jobapplications/{jobId}/focus-plan/operations` validates the owner-scoped job, profile and up to four selected attachments, applies centralized Pro/privacy/capacity admission and returns `202` with the existing safe operation DTO/status URL.
|
|
- `GET .../focus-plan/operation` resumes the latest operation for the exact job/attachment context after navigation or refresh.
|
|
- Task `strategy.snapshot` stores only `jobId|attachmentIds`; job text, CV, notes, attachment text and prompts are rehydrated in the worker's owner scope and never copied into `UserOperations`.
|
|
- An active operation is reused. The next successful regeneration key includes the current cached-result timestamp; failed/cancelled work uses the existing safe retry API. A crash/retry overwrites the same unique `AiWorkspaceNote`, not a second output row.
|
|
- The handler makes one bounded structured generation request, validates the entire JSON shape before publishing, passes worker cancellation, records actual provider/model/route metadata and rejects embedded source instructions. Job text, profile text, structured profile and extracted attachment context have explicit ceilings.
|
|
- UI states cover queued, local processing, retry wait, approved-fallback wait, completed, failed, cancelled and cancellation requested, with cancel/retry actions. A request-version guard prevents a stale resume lookup from erasing a newly queued operation.
|
|
- The existing generic terminal notification is produced transactionally by the operation store. No email is sent.
|
|
- Admission creates one content-free usage reservation in the same transaction as the operation. Duplicate clicks reuse it, and successful execution replaces the conservative 12,000-token reservation with the measured input/output character estimate.
|
|
|
|
`strategy.snapshot` is not in the external fallback allowlist, so it remains local-only even when a user has external consent. The worker switch remains off by default pending the production canary.
|
|
|
|
## Automated evidence
|
|
|
|
- Focused backend Strategy/cache/queue/policy tests: 34/34.
|
|
- Strategy UI focused suite: 6/6.
|
|
- Full backend: 592/592.
|
|
- Full frontend: 47/47 suites, 160/160 tests.
|
|
- Frontend production build and `git diff --check`: pass; line-ending notices only.
|
|
- Tests use SQLite and fake model output. They cover 202/idempotent duplicate click, typed handler success/provenance, one stable result, malformed response/retry state/no partial output, owner isolation, queued/cancelled/failed/retry UI states and cached-result refresh.
|
|
|
|
## Remaining gates
|
|
|
|
- Browser refresh, navigation, back/forward, mobile, light/dark and keyboard checks are blocked by localhost browser policy.
|
|
- No Ollama model, external provider, private CV, production service or paid API was called.
|
|
- Worker/model restart and lease recovery are proven generically by AI-001 tests but not run with a real Strategy model.
|
|
- MariaDB execution, production queue telemetry, selected-model timeout/quality benchmarks, notification navigation and deployment rollback remain unverified.
|
|
- The Strategy operation now participates in the central monthly usage ledger. Older synchronous AI endpoints outside this workflow remain a separate POL-001 completion item.
|
|
|
|
## Rollback
|
|
|
|
Keep `Workers:AiOperationsEnabled=false`, revert commit `a621226`, and retain the additive operation/note tables. No dependency, schema or migration changed. Any already queued `strategy.snapshot` rows should be cancelled or drained before removing the handler.
|