feat/Update_Controllers_to_Allow_for_Premium_Membership

This commit is contained in:
cesnimda
2026-08-03 09:17:28 +02:00
parent de937d25dc
commit c3f4a57195
187 changed files with 26062 additions and 991 deletions
+281
View File
@@ -0,0 +1,281 @@
# JobTracker programme decisions and assumptions
## DEC-001 — Programme source paths
- **Date:** 2026-08-02
- **Decision:** The source files are exactly `docs/todo/work.md` and `docs/todo/ollama.md`; no fallback path search was needed.
- **Reason/evidence:** Both exact files exist and were read completely (922 and 825 lines respectively).
- **Alternatives considered:** `docs/work-programmes/` content-based discovery, required only if names differed.
- **Consequences:** Original references in the master plan use these paths and line ranges.
- **User approval required:** No; factual discovery.
- **Reversible:** Yes, update paths if the sources move.
## DEC-002 — One authoritative plan, compatibility pointer only
- **Date:** 2026-08-02
- **Decision:** `docs/work-programmes/master-work-plan.md` is authoritative. The older requested `docs/plans/post-audit-ux-reliability-program.md` will point to it instead of duplicating the checklist.
- **Reason/evidence:** The current request explicitly requires one authoritative record; `work.md:46-59` requires the older plan path, and `docs/plans/` did not exist.
- **Alternatives considered:** duplicate both full plans; rejected because they would drift.
- **Consequences:** Legacy references remain valid without a second status source.
- **User approval required:** No; directly reconciles both instructions.
- **Reversible:** Yes.
## DEC-003 — Canonical origin precedes identity recovery
- **Date:** 2026-08-02
- **Decision:** SEC-001/SEC-002 precede Microsoft legacy relinking and email change/recovery.
- **Reason/evidence:** JT-002 security URLs currently fall back to request Host; recovery built first could send attacker-controlled links.
- **Alternatives considered:** follow the suggested identity-first order; rejected as unsafe.
- **Consequences:** SEC-001 is the first implementation package.
- **User approval required:** No; safer dependency ordering was requested.
- **Reversible:** No practical reason to reverse.
## DEC-004 — Scoped production authority
- **Date:** 2026-08-02
- **Decision:** Production mutation authority applies only to the production-local-AI inventory/benchmark/install/configuration/rollout described in `ollama.md`, and only after its backup/rollback gates. Other production deployment still requires explicit instruction.
- **Reason/evidence:** `work.md:15` prohibits production deploy; `ollama.md:3` and the current request authorize scoped AI work.
- **Alternatives considered:** treat either instruction as globally overriding the other; rejected as over-broad.
- **Consequences:** repository work continues; PROD items remain blocked without documented access.
- **User approval required:** No; this is the narrow intersection of explicit instructions.
- **Reversible:** Yes with new authority.
## DEC-005 — ADR-004 is superseded for the scoped local-first programme
- **Date:** 2026-08-02
- **Decision:** Implement one central local-first routing policy with controlled external fallback, while retaining existing models/configuration for rollback.
- **Reason/evidence:** ADR-004 and current architecture choose one deployment provider; `ollama.md:398-451,574-608` explicitly requires ordered routing/fallback and the user asked to execute it.
- **Alternatives considered:** keep one provider and ignore the new programme; scatter fallback in callers; both rejected.
- **Consequences:** ADR-004 must later be superseded/updated in its own cohesive package. No provider change occurs before privacy/entitlement/queue controls.
- **User approval required:** Already supplied by the programme request.
- **Reversible:** Yes; old provider path/config remains for rollback.
## DEC-006 — Free means no AI in the target policy
- **Date:** 2026-08-02
- **Decision:** The target external plan model is Free (no AI, core non-AI tracking) and Pro (defined AI capabilities). Preserve existing user data and internal `Premium` compatibility while migrating behavior.
- **Reason/evidence:** `work.md:636-719` is explicit; current roadmap/code instead permits limited Free AI and uses `Premium`.
- **Alternatives considered:** retain existing limited Free AI; rejected because it contradicts the new programme.
- **Consequences:** POL-001 requires a deliberate server-side policy/compatibility package; copy changes cannot precede enforcement.
- **User approval required:** Already supplied.
- **Reversible:** Product policy is reversible later; data migration should remain additive.
## DEC-007 — One durable operation foundation
- **Date:** 2026-08-02
- **Decision:** Strategy Snapshot, CV processing and other long AI work share OPS-001/AI-001; feature packages supply handlers/results/UI only.
- **Reason/evidence:** Both programmes specify the same state, idempotency, retry, notification and restart requirements and explicitly warn against duplicate implementations.
- **Alternatives considered:** separate CV and Strategy queues; rejected as duplicated infrastructure and inconsistent behavior.
- **Consequences:** AI-003/AI-004 depend on the common foundation.
- **User approval required:** No; explicitly requested.
- **Reversible:** The model can be extended; duplicate queues should not be introduced.
## DEC-008 — New-table ownership is unresolved until provider-safe design
- **Date:** 2026-08-02
- **Decision:** Do not create operation/deletion tables until their package selects one schema owner and proves fresh/upgrade SQLite and MariaDB behavior.
- **Reason/evidence:** `docs/infrastructure/database-ownership.md` mandates reconciler DDL for current cross-provider tables, while audit JT-019 identifies dual schema ownership as a risk and the Phase 0 identity design prefers a real EF migration.
- **Alternatives considered:** silently follow either document; rejected because the conflict is material.
- **Consequences:** no migration is created in SEC-001; OPS-001 records the eventual choice and rollback evidence.
- **User approval required:** No now; ask only if the evidence leaves materially different safe choices.
- **Reversible:** Yes before schema deployment.
## DEC-009 — Production access is currently blocked, not guessed
- **Date:** 2026-08-02
- **Decision:** Mark production inventory/benchmark/rollout blocked while continuing safe repository work.
- **Reason/evidence:** existing backup/verification docs say this environment has no route or production credentials; only CI secret names and `/opt/job-tracker/app` are documented.
- **Alternatives considered:** guess SSH host/user or scan; explicitly prohibited.
- **Consequences:** PROD-001/003/004 and REL-001 cannot be `DONE`; sanitized templates/harnesses can still be built.
- **User approval required:** No.
- **Reversible:** Immediately when documented access is provided.
## DEC-010 — One canonical origin replaces provider callback overrides
- **Date:** 2026-08-02
- **Decision:** `App:PublicBaseUrl` now builds Gmail and Microsoft Graph callback URLs; the old provider-specific redirect variables are removed from Compose and the example environment.
- **Reason/evidence:** Independent callback origins contradicted SEC-001's single-origin trust boundary and allowed configuration drift. Provider registrations must use the documented paths under the canonical origin.
- **Alternatives considered:** Accept overrides only after equality validation; rejected because it preserves duplicate configuration with no supported separate-origin use case.
- **Consequences:** Operators with legacy redirect variables must register/use `<APP_PUBLIC_BASE_URL>/api/gmail/oauth/callback` and `/api/microsoft-graph/oauth/callback`. Existing variables no longer affect the application.
- **User approval required:** No; this implements the approved canonical-origin prerequisite.
- **Reversible:** Yes by restoring validated overrides, but only if a real separate-origin requirement is established.
## DEC-011 — Dedicated one-hop nginx trust network
- **Date:** 2026-08-02
- **Decision:** Nginx and backend share a dedicated internal `WEB_PROXY_SUBNET`; forwarded headers are accepted for one hop only from that configured CIDR. Production Compose has no host-bound app or Ollama ports; development port bindings require `docker-compose.dev.yml` explicitly.
- **Reason/evidence:** Docker's dynamic/default/shared networks cannot safely identify nginx as the trusted hop, and the old auto-loaded override disabled proxy trust while exposing ports.
- **Alternatives considered:** clear all known proxy collections; trust the external shared network; assign a single static container IP. The first two trust too much, while a dedicated CIDR tolerates container replacement without pinning one container address.
- **Consequences:** production must inventory Docker networks and set a non-overlapping `WEB_PROXY_SUBNET` before deploy. External Traefik still requires separate operator verification.
- **User approval required:** No; this is the scoped security prerequisite.
- **Reversible:** Yes via version rollback and previous environment, but rollback must not reopen host ports unintentionally.
## DEC-012 — Nginx Host is derived, not separately configured
- **Date:** 2026-08-02
- **Decision:** The frontend container derives nginx's exact server name at startup from `APP_PUBLIC_BASE_URL`; no second host setting exists. Unknown Hosts receive nginx 444 except `/health`.
- **Reason/evidence:** Hard-coding the current domain or introducing an independent nginx-host variable would violate the single canonical-origin contract and create drift.
- **Alternatives considered:** application-only Host rejection; separate `APP_EXTERNAL_HOST`; operator-only Traefik filtering. Each leaves one repository boundary weak or duplicates authority.
- **Consequences:** the frontend container fails fast on malformed/unsupported origins; IPv6 host literals are currently outside the deploy preflight contract.
- **User approval required:** No.
- **Reversible:** Yes; broaden only with matching parser, nginx and deployment tests.
## DEC-013 — Microsoft sign-in has one tenant-qualified trust path
- **Date:** 2026-08-02
- **Decision:** Microsoft ID tokens are accepted only by the exchange/link validator, which requires the configured account mode plus exact GUID `tid`/`oid` and issuer agreement. The raw Microsoft bearer scheme is removed. Email-like claims are metadata, not verified ownership.
- **Reason/evidence:** The UI already exchanges Microsoft tokens for local sessions; maintaining a second issuer-disabled API bearer path duplicated and weakened the trust decision. `oid` alone is tenant-scoped.
- **Alternatives considered:** harden both bearer and exchange paths; retain `common` implicitly in Production; use `sub` or email as identity. Each adds duplicated policy or preserves the audited ambiguity.
- **Consequences:** undocumented raw-token API clients stop working; Production must choose a tenant mode. Legacy identity ownership remains unresolved until SEC-004 and Microsoft must not be enabled there first.
- **User approval required:** No; this is the validated P0-1A contract.
- **Reversible:** The account mode is configurable; raw bearer support should return only with a documented requirement and the same policy/tests.
## DEC-014 — Split email ownership from session revocation
- **Date:** 2026-08-02
- **Decision:** Split the original SEC-005 into SEC-005A (session/recovery revocation) and SEC-005B (registration/pending email plus migration/UI).
- **Reason/evidence:** The revocation work uses the existing schema and is independently testable/rollbackable; pending email requires a coordinated database and frontend contract. Keeping both under one active item violated the requested small-package cycle.
- **Alternatives considered:** keep one broad item; rejected because its status could not accurately distinguish verified security behavior from an unstarted migration/UI flow.
- **Consequences:** SEC-004 depends on both children. Original source/audit references remain on each, so no requirement was lost.
- **User approval required:** No; this is tracking granularity within approved scope.
- **Reversible:** Yes by presenting them as one release, but their verification remains separate.
## DEC-015 — Pending email uses Identity tokens and one provider-aware EF migration
- **Date:** 2026-08-02
- **Decision:** Store only the proposed address and request time, rotate the Identity security stamp for each replacement request, and use the built-in change-email token. Add both fields through one EF migration whose SQLite and MariaDB column types are explicit; do not duplicate these Identity columns in the startup reconciler.
- **Reason/evidence:** The active email must remain authoritative until proof. Identity already binds tokens to user, new email, purpose and security stamp; stamp rotation makes the latest request win without another token table. Dry-run SQL showed SQLite-scaffolded types were unsafe for MariaDB until the migration branched by provider. Audit/schema decision P0-4B assigns these Identity fields to EF.
- **Alternatives considered:** immediately replace `Email`; store plaintext confirmation tokens; add a request table/nonce abstraction; add the same columns to startup reconciliation. The first two are unsafe, and the latter two add duplicate state/ownership without a demonstrated need.
- **Consequences:** deployment must run `20260802205800_AddPendingEmailChange` before the new API version. SQLite uses `TEXT`; MariaDB uses `varchar(320)` and `datetime(6)`. Rolling-version and MariaDB execution still require verification.
- **User approval required:** No; this is the smallest implementation of the approved ownership contract.
- **Reversible:** Yes via the migration `Down` before data relies on pending requests; active email data is unchanged.
## DEC-016 — SEC-005B remains short of local browser verification
- **Date:** 2026-08-02
- **Decision:** Mark SEC-005B `IMPLEMENTED — NOT VERIFIED`, not `VERIFIED LOCALLY` or `DONE`.
- **Reason/evidence:** all automated suites and an isolated API runtime pass, but the in-app browser denied localhost because its administrator policy check could not be verified. SMTP and MariaDB execution are also unavailable.
- **Alternatives considered:** infer browser behavior from component tests or claim the existing Docker UI; rejected because the running containers are old images and the programme forbids inferred test claims.
- **Consequences:** SEC-004 repository work can proceed, but SEC-005B retains explicit browser/provider/production acceptance checks.
- **User approval required:** No; truthful status accounting is required.
- **Reversible:** Yes immediately after the blocked checks pass.
## DEC-017 — Canonical Microsoft ownership never backfills legacy evidence
- **Date:** 2026-08-02
- **Decision:** Add nullable bounded `MicrosoftTenantId`/`MicrosoftObjectId` with one unique composite index, use only that pair for ownership, and leave every legacy subject/email row null-canonical until explicit dual-proof relinking.
- **Reason/evidence:** `oid` is tenant-scoped, legacy subjects may be `oid` or `sub`, and provider email is mutable metadata. A disposable migration rehearsal preserved duplicate legacy values and enforced unique proven pairs. The recovery ceremony requires both a purpose-bound token delivered to the confirmed app email and a fresh Microsoft token for the same pair.
- **Alternatives considered:** backfill from `common`, legacy subject, email or next-seen token; retain email fallback; add a general identity-provider framework. Each would merge unproven identities or add unrelated abstraction.
- **Consequences:** ambiguous/unconfirmed legacy users require operator assistance; production needs a counts-only inventory and relink window. Link/unlink revoke sessions, and passwordless unlink is refused until a safe provider reauthentication path exists.
- **User approval required:** No; this implements the approved JT-001 safety contract.
- **Reversible:** Additive schema is reversible before canonical data is relied upon. Application rollback must never restore email auto-linking.
## DEC-018 — Keep MariaDB date work in SQL and bound SQLite fallback by owner/job
- **Date:** 2026-08-02
- **Decision:** Branch only at the affected `DateTimeOffset` query roots: SQLite materializes owner/job-scoped rows before ordering or range comparison; MariaDB keeps server-side ordering, filtering, aggregation and pagination.
- **Reason/evidence:** the real SQLite provider throws before execution, while Pomelo generates the required SQL. Changing all timestamp storage would require a risky migration and editing response endpoints individually would leave CV cleanup/reprocess siblings broken. Real-provider tests and fresh HTTP rehearsal pass.
- **Alternatives considered:** global timestamp conversion/schema rewrite; always materialize on every provider; modify historical migrations; catch-and-retry translation exceptions. These add migration risk, production performance cost or hide separate JT-019 ownership drift.
- **Consequences:** SQLite work is bounded by tenant/job and current entitlement limits but still happens in memory; production MariaDB behavior is unchanged. If per-user AI history grows materially, a later UTC scalar column/index migration may be measured and designed.
- **User approval required:** No; this is the smallest root-cause correction within CORE-001.
- **Reversible:** Yes; revert the provider branches and relational test, with no data rollback.
## DEC-019 — Keep the editable interview board canonical and move the generated brief
- **Date:** 2026-08-02
- **Decision:** Keep `GET /interview-prep` for the durable editable `InterviewPrepItem` board, move the distinct cached/generated `InterviewPrepNote` response to `GET /interview-prep/brief`, and delete the unused flat timeline action so the grouped/filterable timeline remains canonical.
- **Reason/evidence:** both interview representations have active repository UI callers and incompatible DTOs, while only the newer timeline has a caller. Overloading by query parameter or deleting one live feature would preserve ambiguity or break behavior. Reflection and isolated HTTP tests now show one action per method/path with owner 200, other user 404 and anonymous 401.
- **Alternatives considered:** delete either interview feature; retain the old path with a discriminator; rename the editable board; merge DTOs. Each creates unnecessary compatibility state or breaks the current workspace contract.
- **Consequences:** undocumented direct consumers of the generated brief must adopt `/brief`; repository clients/docs are updated. No data or schema changes.
- **User approval required:** No; this is the smallest cohesive repair of confirmed JT-004.
- **Reversible:** Yes by restoring the route/client and flat action, but rollback also restores the exploitable availability defect and is not recommended.
## DEC-020 — Attachment final paths are the durable operation identity
- **Date:** 2026-08-02
- **Decision:** Represent recoverable attachment mutations as `<final>.uploading` and `<final>.deleting`; do not add a separate JSON journal, schema or periodic worker. Reconcile once after database initialization and preserve unknown plain files.
- **Reason/evidence:** every final path is already generated, unique and root-bounded. The suffix plus row existence encodes every required recovery decision, and real-SQLite failure injection proves upload promotion, delete restore/purge and idempotent restart behavior. A second journal would introduce dual durable state and another crash-ordering problem.
- **Alternatives considered:** JSON operation journal; database operation table; object-store abstraction; periodic/multi-replica reconciler. None is required for the current single-filesystem deployment and each adds coordination or migration cost.
- **Consequences:** recovery retries on safe restart rather than a timer; persistent failures remain observable until restart/operator action. Multi-replica or high-volume deployments must first add a lease and measured periodic reconciliation. SEC-009 must reuse these root/quarantine rules.
- **User approval required:** No; this is the smallest implementation of the approved JT-010 recovery contract.
- **Reversible:** Yes after draining/reviewing all suffix markers. No schema rollback exists; unknown plain orphans must never be guessed away.
## DEC-021 — Worker enumeration bypasses filters once, then re-enters owner scope
- **Date:** 2026-08-02
- **Decision:** `BackgroundTenantRunner` may ignore tenant filters only to enumerate non-empty job owners. Each owner is processed sequentially in a new scope whose live `CurrentUserService` restores all normal query filters. Rules, reminders, daily export and enrichment receive separate default-false switches.
- **Reason/evidence:** hosted scopes have no HTTP identity and therefore returned zero rows. Leaving services on while fixing that root cause would unexpectedly start status mutations, file exports, email and AI calls. Real-SQLite tests prove owner filtering, per-owner settings, failure isolation and fake-only side effects.
- **Alternatives considered:** unfiltered queries throughout each worker; a privileged DbContext; automatic activation under legacy settings; a distributed scheduler. These enlarge the trust boundary, create rollout risk or solve unmeasured scale.
- **Consequences:** workers remain inert until explicitly enabled after OPS/POL prerequisites. Execution is sequential/single-instance; leasing and durable operations are the next package. Existing backup, probe and CV-run handling remain unchanged.
- **User approval required:** No; this is the requested safe foundation and does not activate production work.
- **Reversible:** Yes by keeping switches false and reverting the runner/service changes. Already-generated exports or user-visible mutations require separate reviewed rollback.
## DEC-022 — Durable operations are EF-owned and store references, not payloads
- **Date:** 2026-08-02
- **Decision:** Split OPS-001 into independently reviewable OPS-001A state/schema, OPS-001B notifications and OPS-001C APIs/UI. `UserOperations` is owned only by a provider-conditional EF migration; the startup reconciler does not create or alter it. The row stores bounded policy/subject references and no generic raw payload.
- **Reason/evidence:** a manually branched migration produces correct SQLite and bounded MariaDB DDL, avoiding the repository's old SQLite-type failure while reducing JT-019 dual ownership. CV/Strategy inputs already have durable domain IDs; copying private text into a queue row is unnecessary. Concurrent SQLite tests prove one idempotent row and one lease winner.
- **Alternatives considered:** extend `CvExtractionRun`; reconciler plus no-op migration; generic JSON payload; external queue/Redis; one large schema/UI package. These duplicate feature state, preserve dual ownership, increase private-data copies/infrastructure, or prevent small rollbackable review.
- **Consequences:** feature producers reference domain rows and must re-check entitlement/privacy before work. Notifications/API/UI follow without changing the operation identity. MariaDB execution remains a deployment gate.
- **User approval required:** No; this resolves the recorded DEC-008 conflict using repository evidence and the requested smallest reliable design.
- **Reversible:** Yes before consumers rely on rows; stop producers/drain rows before `Down`. Additive table may remain during application rollback.
## DEC-023 — One current generic notification is atomic with terminal operation state
- **Date:** 2026-08-02
- **Decision:** Store one owner-scoped `UserNotification` per current terminal operation outcome, committed in the same relational transaction. Use generic bounded text, no email delivery and no private operation/failure content. A manual retry removes the prior notification so the next terminal outcome can replace it.
- **Reason/evidence:** a unique nullable operation foreign key supplies database idempotency; a forced notification-write failure proves the terminal update rolls back. This reuses OPS-001A rather than introducing an outbox framework or a second queue.
- **Alternatives considered:** transient frontend notifications; email outbox; multiple immutable notifications per retry attempt; generic event bus. Transient state fails restart recovery, email is not authorized, and the latter two add delivery/history machinery not required by either programme.
- **Consequences:** OPS-001C can expose stable read/dismiss state without creating another notification model. Historical retry-attempt notifications are not retained; operation attempt/failure fields remain the technical state. MariaDB execution remains a deployment gate.
- **User approval required:** No; this implements the approved persistent-notification prerequisite without external side effects.
- **Reversible:** Yes before API/UI consumers rely on it. Older application versions tolerate the additive table; schema `Down` deletes notification state.
## DEC-024 — Operation APIs expose state, not worker internals
- **Date:** 2026-08-02
- **Decision:** Expose authenticated owner list/detail/cancel/retry and notification list/count/read/dismiss APIs, but no generic operation-create endpoint. Return only bounded user-facing state; omit idempotency keys, lease tokens, provider/model fields, raw failure text and result references. Use bounded polling rather than realtime infrastructure.
- **Reason/evidence:** feature producers must enforce entitlement/privacy and durable subject references before admission, so a generic create endpoint would bypass later policy. Existing Axios, MUI and browser events cover the UI without a dependency. Two-user HTTP checks prove copied identifiers return 404.
- **Alternatives considered:** WebSockets/SignalR; a generic JSON task API; exposing the full entity; merging reminders and operation notifications. These add infrastructure, unsafe authority or misleading counts without a current need.
- **Consequences:** AI-003/004 own feature admission and result navigation. The operation page polls every 15 seconds while mounted; the shell polls unread count every 60 seconds. Realtime delivery can be reconsidered only if measured UX/load requires it.
- **User approval required:** No; this is the smallest implementation of both programmes' stable status and notification contract.
- **Reversible:** Yes. UI/API removal leaves durable operation/notification data intact; application rollback can retain additive tables.
## DEC-025 — Public Pro policy uses live roles while retaining legacy billing identifiers
- **Date:** 2026-08-02
- **Decision:** Expose only `free` and `pro`; make Free AI entitlement and limits zero; authorize explicit AI actions with one live database-role policy; recheck queued/background work at execution; preserve the internal `Premium` Identity role and `Stripe:PricePremium` configuration key for billing/data compatibility.
- **Reason/evidence:** the new programme supersedes the old limited-Free-AI model. Claim-only authorization would let an already-issued session retain AI after downgrade, while renaming the persisted role/config now adds migration and rollback risk without changing user-visible behavior. Core job create/detail and deterministic enrichment were traced separately because they must still work when their optional model call is skipped.
- **Alternatives considered:** static `RequireRole`; guards copied into every controller; renaming the Identity role/config; wrapping every summarizer call in a new provider abstraction; blocking whole controllers. These leave stale-claim/worker bypasses, add scattered checks, create needless migration risk, pre-empt POL-002/AI-002, or hide existing non-AI data.
- **Consequences:** explicit locked APIs return stable `pro_required`; Admin maps to Pro; UI receives `ai`/`proThemes`; existing AI history and non-AI editing remain accessible. Usage accounting outside AI Workspace remains incomplete and blocks provider rollout/full POL-001 verification. PRODUCT-001 still owns removal of invented landing-page price/tier claims.
- **User approval required:** No; the programme explicitly requires Free=no-AI and centralized enforcement.
- **Reversible:** Yes as one repository-only policy/UI change with no schema update. Workers must remain off while rolling back to avoid restoring an entitlement bypass.
## DEC-026 — Classify synthetic AI workloads before finalizing privacy routing
- **Date:** 2026-08-02
- **Decision:** Advance PROD-002 immediately after POL-001 and before POL-002, even though the recommended list placed the general privacy policy first.
- **Reason/evidence:** POL-002 explicitly depends on task type, privacy class, payload shape, latency and fallback suitability. POL-001 produced the reachable-call inventory, and PROD-002 can safely classify it and create synthetic fixtures without production access or provider calls. Writing policy first would either duplicate this inventory or invent categories without fixtures.
- **Alternatives considered:** keep POL-002 next and revise it later; perform PROD-001 hardware inventory first; start queue implementation. The first creates churn, while the latter two are blocked by production access or need the privacy contract.
- **Consequences:** PROD-002 is the sole in-progress item; POL-002 follows with evidence-backed classes. No production/provider action is introduced.
- **User approval required:** No; the user directed dependency-aware reordering and conflict recording.
- **Reversible:** Yes; documentation/fixtures can be revised before routing code depends on them.
## DEC-027 — External AI needs two administrator/user gates and defaults to local
- **Date:** 2026-08-03
- **Decision:** Persist `AiEnabled` and `ExternalAiProcessingAllowed` per user; preserve AI-enabled behaviour for existing accounts, default external consent to false, and permit an external `/cv/*` request only when backend and sidecar administrator gates, a supported configured provider, live Pro entitlement, AI-enabled preference and explicit user consent all agree. Background calls without an authenticated request fail safe to local.
- **Reason/evidence:** the existing global sidecar `AI_PROVIDER` could route full CV data externally without a user decision. One backend policy plus a sidecar permission header closes that execution path without deleting rollback provider configuration or inventing the final AI-002 router.
- **Alternatives considered:** remove Gemini/Groq; rely on UI/local storage consent; trust one environment flag; refactor every AI interface now; silently use external when configured. These either break rollback compatibility, are bypassable, or prematurely duplicate AI-001/002.
- **Consequences:** disabling AI is enforced from live database state; external processing is off by default and needs deliberate two-sided configuration. True local-first fallback triggers, operation policy snapshots, provider/reason persistence, payload minimization and cost controls remain explicit AI-001/002 gates, so POL-002 is not overstated as fully verified.
- **User approval required:** No; this is the smallest safe implementation of the programme's explicit privacy controls and preserves provider configurations.
- **Reversible:** Yes. Application rollback should leave the additive preference columns in place; turning both administrator gates off immediately restores local-only processing without data loss.
## DEC-028 — Durable AI work extends UserOperations with a default-off typed worker
- **Date:** 2026-08-03
- **Decision:** Reuse OPS-001A/B/C for every long AI task. Add one task-handler worker and one admission service; expose no generic create endpoint. Admission stores only a domain subject reference and policy snapshot, enforces Pro/privacy/capacity/idempotency/deadline, and returns the existing stable status URL. Start at one worker and keep it disabled until real handlers and rollout checks pass.
- **Reason/evidence:** the existing operation store already supplies persistent states, atomic claims, leases, retries, cancellation, restart recovery, notifications and owner APIs/UI. A second CV/Strategy queue or Redis would duplicate proven state. A generic create API would let callers bypass task-specific ownership and payload validation.
- **Alternatives considered:** separate in-memory channel; Redis/Hangfire; one worker per feature; synchronous provider calls; generic public task creation; unbounded hosted-service parallelism. These lose restart state, duplicate infrastructure, expand authority or fail the congestion requirement.
- **Consequences:** AI-003/004 only add typed handlers/producers. Current capacity serialization is process-local for the documented single-backend deployment; database reservation is required before multiple backend replicas. Provider/model semaphores and circuit/provenance remain AI-002 responsibilities.
- **User approval required:** No; this follows both programmes' explicit instruction to reuse the smallest reliable existing infrastructure.
- **Reversible:** Yes. Keep the worker switch false, remove admission/worker registrations, and retain operation rows/API history. No new schema was added in this slice.
+42
View File
@@ -0,0 +1,42 @@
# JobTracker master programme progress
Updated: 2026-08-03
- **Overall programme status:** Active. Six packages are locally verified; eleven packages including POL-001/002 and AI-001 are implemented with automated/runtime evidence but blocked from later browser/provider/production gates; AI-002 is now in progress.
- **Current work package:** `AI-002` — Ollama adapter and local-first provider routing (`IN PROGRESS`), extending the POL-002 boundary and AI-001 execution context.
- **Completed work packages:** None are `DONE`; all repository security packages still have applicable browser, provider and/or production gates.
- **Locally verified work:** SEC-001, SEC-002, SEC-003, SEC-005A, CORE-001 and PROD-002 (`VERIFIED LOCALLY`).
- **Implemented, verification incomplete:** SEC-004, SEC-005B, SEC-008, CORE-002, BG-001, OPS-001A/B/C, POL-001/002 and AI-001 (`IMPLEMENTED — NOT VERIFIED`): foundations through durable bounded AI execution pass local checks; real handlers, browser, provider, accounting and production gates remain.
- **Production-verified work:** None.
- **Blocked work:** SEC-006 requires explicit internet/package-index permission; PROD-001/003/004 and REL-001 require documented production access and unfinished dependencies. Browser access was denied by the browser admin policy check; SMTP/MariaDB environments are unavailable.
- **Deferred work:** None. Conditional large abstractions, model deletion, multi-replica coordination and unrelated production changes remain outside current packages.
- **Next five work packages:** AI-002 Ollama adapter/routing; AI-003 Strategy Snapshot queue migration; AI-004 CV processing queue migration; UX-001 authentication/theme corrections; QA-001 job-analysis/keyword quality. SEC-006/007 resume after package-index permission.
- **Status counts:** 6 `VERIFIED LOCALLY`; 11 `IMPLEMENTED — NOT VERIFIED`; 1 `IN PROGRESS`; 16 `NOT STARTED`; 5 `BLOCKED`; 0 `DONE`; 0 `DEFERRED`.
- **Test status:** backend 581/581; AI-001 focused queue/state/API 17/17; frontend 47/47 suites and 158/158 tests plus build; Python sidecar 18/18. Prior POL/PROD/OPS/BG/SEC/CORE evidence remains green.
- **Deployment status:** No deployment performed. No production migrations were run.
- **Production status:** Unchanged and unverified. Pre-existing Docker development services on 3000/5202 were observed and left untouched.
- **Known regressions:** No known regression from the implemented packages. POL-002 preserves local AI behaviour and defaults external consent off. Direct clean EF-only SQLite migration still hits the pre-existing historical blank-chain defect before the new migration; normal startup owns reconciliation. Complete usage/provider provenance remains a known pre-rollout gap.
- **Outstanding security findings:** JT-001 repository ownership is implemented but remains High deployment risk until migration/inventory/provider checks; production portion of JT-002; JT-006, JT-009 and associated JT-011/JT-012/JT-022 prerequisites. JT-005 owner foundation is implemented but workers remain off until persistent notification, entitlement and privacy gates. JT-007/JT-008/JT-010 repository behavior is not fully browser/provider/production verified.
## Current evidence
- `docs/audits/audit-remediation-backlog.md`
- `docs/audits/verification-log.md`
- `docs/verification/sec-001-canonical-origin.md`
- `docs/verification/sec-002-ingress-compose.md`
- `docs/verification/sec-003-microsoft-tenant.md`
- `docs/verification/sec-004-microsoft-identity.md`
- `docs/verification/sec-005a-session-revocation.md`
- `docs/verification/sec-005b-email-ownership.md`
- `docs/verification/core-001-sqlite-provider-parity.md`
- `docs/verification/core-002-route-uniqueness.md`
- `docs/verification/sec-008-attachment-consistency.md`
- `docs/verification/bg-001-tenant-workers.md`
- `docs/verification/ops-001a-durable-operations.md`
- `docs/verification/ops-001b-notifications.md`
- `docs/verification/ops-001c-operation-ui.md`
- `docs/verification/pol-001-free-pro-entitlements.md`
- `docs/verification/pol-002-ai-privacy.md`
- `docs/verification/ai-001-durable-ai-queue.md`
- `docs/verification/prod-002-ai-evaluation.md`
- `docs/work-programmes/master-work-plan.md`
+775
View File
@@ -0,0 +1,775 @@
# JobTracker master work plan
Prepared: 2026-08-02
Authoritative sources:
- `docs/todo/work.md` (UX/reliability programme, lines 1-922)
- `docs/todo/ollama.md` (production local-AI programme, lines 1-825)
- `docs/audits/audit-remediation-backlog.md` (validated security and reliability prerequisites)
This file is the authoritative merged implementation plan. It avoids duplicate implementations: Strategy Snapshot, CV processing, durable operations, notifications, entitlement, AI privacy, provider routing, tenant-safe workers and restart recovery are each represented once and retain references to both source programmes.
## Status and completion rules
Allowed statuses are `NOT STARTED`, `IN PROGRESS`, `IMPLEMENTED — NOT VERIFIED`, `VERIFIED LOCALLY`, `DEPLOYED — NOT VERIFIED`, `DONE`, `BLOCKED`, and `DEFERRED`.
`DONE` requires every applicable acceptance criterion, focused and regression tests, browser/accessibility/theme/mobile checks, tenant and entitlement checks, documentation, migration/rollback evidence, and production verification. Repository-only work that still requires production is at most `VERIFIED LOCALLY`.
Exactly one implementation item may be `IN PROGRESS`. As of this revision it is **AI-002**.
## Consolidated dependency order
```text
SEC-001 -> SEC-002 -> SEC-003 -> SEC-004
| | \-> SEC-005A -> SEC-005B
| \--------------> BG-001
|
+-> SEC-006 -> SEC-007 -> AI-004
+-> SEC-008 ----------------> SEC-009
CORE-001 -> CORE-002 -> BG-001 -> OPS-001A -> OPS-001B -> OPS-001C
OPS-001A -> POL-001 -> POL-002 -> AI-001 -> AI-002
PROD-002 -> POL-002 -> AI-001
PROD-002 -> PROD-003
PROD-001 -> PROD-003 -> PROD-004
AI-001 + AI-002 -> AI-003 and AI-004
UX-001/UX-002/QA-001 may proceed after their security prerequisites.
CAREER-001 -> CAREER-002; MAIL-001, JOBS-001, JOBS-002, UX-003 and PRODUCT-001 follow foundations.
All implemented surfaces -> VER-001 -> REL-001.
```
Ordering differences from the suggested list:
- SEC-001 canonical origin precedes Microsoft legacy relinking and email recovery because those links cannot prove ownership while request Host can influence their origin.
- SEC-006/SEC-007 parser hardening precedes the CV queue migration; moving an unsafe parser into a queue does not make it safe.
- SEC-008 attachment consistency precedes complete account deletion.
- The synthetic workload inventory/evaluation set (PROD-002) can proceed without production access and should inform routing and benchmarks early.
- Production inventory, benchmark and rollout remain independent blockers; repository-side queue, policy and UX work continues without them.
## Requirement coverage index
| Source section | Covered by |
|---|---|
| Work Phase 1 baseline/plan (36-61) | This master plan, the progress/handoff/decisions files, compatibility pointer under `docs/plans/`, VER-001 |
| Work Phase 2 authentication (63-100) | UX-001, SEC-003, SEC-004, SEC-005 |
| Work Phase 3 theme (102-133) | UX-002 |
| Work Phase 4 job search (135-172) | JOBS-001 |
| Work Phase 5 keyword quality (174-263) | QA-001, PROD-002 |
| Work Phase 6 Career Workspace (265-307) | CAREER-001 |
| Work Phase 7 CV 504 (309-386) | SEC-006, SEC-007, OPS-001A/B/C, AI-001, AI-004 |
| Work Phase 8 CV Builder/FlowCV (388-452) | CAREER-002 |
| Work Phase 9 consolidated email (454-527) | MAIL-001, POL-001, POL-002 |
| Work Phase 10 Kanban dark mode (529-560) | UX-003 |
| Work Phase 11 application table/workspace (562-634) | CORE-002, JOBS-002, AI-003, MAIL-001 |
| Work Phases 12-13 Free/Pro (636-721) | POL-001, PRODUCT-001 |
| Work Phase 14 Strategy Snapshot (723-777) | CORE-001, CORE-002, OPS-001A/B/C, POL-001, POL-002, AI-001, AI-003 |
| Work Phase 15 action verification (779-855) | VER-001 |
| Work quality/browser/completion (857-922) | Every UI package, VER-001, REL-001 |
| Ollama Phases 1-2 inventory/safety (58-176) | PROD-001 |
| Ollama Phase 3 workloads/evaluation (177-258) | PROD-002 |
| Ollama Phases 4-6 candidate/tuning/decision (259-397) | PROD-003 |
| Ollama Phase 7 routing/privacy (398-451) | POL-001, POL-002, AI-002 |
| Ollama Phases 8-9 queue/backpressure (452-573) | BG-001, OPS-001A/B/C, AI-001 |
| Ollama Phase 10 fallback (574-608) | POL-002, AI-002, PROD-004 |
| Ollama Phase 11 frontend states (609-639) | OPS-001C, AI-003, AI-004 |
| Ollama Phases 12-14 observability/rollout/validation (640-775) | PROD-004, REL-001 |
| Ollama tests/report (776-825) | Every AI package, VER-001, REL-001 |
## Work items
### SEC-001 — Canonical external origin and application Host guard
- **Source programme:** shared security prerequisite; Work 17-34; Ollama 26-56; audit P0-2A/JT-002.
- **Original requirement references:** `work.md:17-34`; `ollama.md:26-56`; `audit-remediation-backlog.md` P0-2A.
- **Related findings:** JT-002.
- **Priority:** P0 security prerequisite.
- **Dependencies:** confirmed canonical production URL; none in code.
- **Affected components:** ASP.NET startup/configuration, security-link/OAuth/billing/reminder URL builders, cookie policy, config tests, environment/deploy preflight docs.
- **Acceptance criteria:** Production requires one canonical HTTPS origin; request/forwarded Host never changes an external URL; unknown production Host is rejected; local Development/Test remains explicit and working.
- **Required tests:** origin parser/startup; every URL caller; hostile Host/forwarded headers; Unicode/ports/paths; secure-cookie behavior; relevant backend regression suite.
- **Required browser verification:** local login/reset/verification navigation when a local email sink is available; no visual redesign.
- **Required production verification:** canonical and hostile Host smoke after SEC-002; not required to claim local verification.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** production/ingress verification depends on SEC-002; a live local Production-mode process launch was rejected by the execution policy before starting, so it is not claimed.
- **Evidence:** `docs/verification/sec-001-canonical-origin.md`; `ExternalOriginTests`; focused security/controller slice 79/79; full backend 474/474; Release build; Compose config; normalized deploy-shell syntax.
- **Commit:** none.
- **Remaining work:** verify canonical and hostile Host behavior through the complete proxy path in SEC-002; exercise reset/verification navigation with a safe local email sink; deploy and verify before `DONE`.
### SEC-002 — Production ingress, forwarded headers and Compose separation
- **Source programme:** shared production/security prerequisite; Work 17-34; Ollama 123-176; audit P0-2B/JT-002.
- **Original requirement references:** `work.md:17-34`; `ollama.md:123-176`; audit P0-2B.
- **Related findings:** JT-002, JT-013, JT-020.
- **Priority:** P0.
- **Dependencies:** SEC-001; actual proxy network/IP supplied by operator for production verification.
- **Affected components:** production/development Compose selection, nginx forwarded headers, explicit known proxy/network config, deploy script/runbook, CI deployment invocation.
- **Acceptance criteria:** dev override is never auto-loaded in production; no direct production application ports; exact-host ingress contract; sanitized two-hop forwarding; rollback command documented.
- **Required tests:** merged Compose assertions, production config tests, nginx/proxy integration, deploy shell checks.
- **Required browser verification:** canonical public/API navigation through local proxy.
- **Required production verification:** exact Traefik route, closed ports, correct HTTPS/client IP/cookies.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** external Traefik topology, production CIDR/network inventory, firewall state and provider routes are unavailable for production verification; the pinned nginx base image was not installed locally and was not pulled without internet permission.
- **Evidence:** `docs/verification/sec-002-ingress-compose.md`; production Compose has no published frontend/backend/Ollama ports; dev Compose publishes only 3000/5202/11434; proxy parser tests; nginx syntax/substitution checks; frontend build; backend 476/476.
- **Commit:** none.
- **Remaining work:** inventory/set the non-overlapping production CIDR; verify operator Traefik exact-host/header replacement and firewall; build the pinned image in approved CI; run local/prod proxy and hostile-Host smoke before `DONE`.
### SEC-003 — Microsoft tenant and issuer trust policy
- **Source programme:** Work authentication/audit prerequisite.
- **Original requirement references:** `work.md:91-100`; audit P0-1A/JT-001.
- **Related findings:** JT-001.
- **Priority:** P0.
- **Dependencies:** supported single/multitenant mode configured.
- **Affected components:** Microsoft token validator, smart auth scheme, sign-in configuration, mocked validator tests.
- **Acceptance criteria:** exact issuer/`tid`; (`tid`,`oid`) returned; invalid/missing/mismatched tenant rejected; unused raw bearer trust path removed or proven necessary and hardened.
- **Required tests:** all tenant modes, issuer/audience/signature/lifetime, personal/organizational, same `oid` across tenants.
- **Required browser verification:** mocked Microsoft success/failure/cancel only; real provider later if safely configured.
- **Required production verification:** configured tenant mode and synthetic/provider smoke without exposing tokens.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** none for validator implementation; real Microsoft smoke needs provider configuration.
- **Evidence:** `docs/verification/sec-003-microsoft-tenant.md`; tenant/issuer validator matrix; raw bearer branch removed; focused 42/42 and full backend 491/491; Compose and deploy-shell config checks.
- **Commit:** none.
- **Remaining work:** production inventory/configuration and mocked/real safe provider smoke; SEC-004 canonical pair persistence/relinking must complete before JT-001 closes or Microsoft is enabled in production.
### SEC-004 — Canonical Microsoft links and safe legacy relinking
- **Source programme:** Work authentication/audit prerequisite.
- **Original requirement references:** `work.md:91-100`; audit P0-1B/JT-001.
- **Related findings:** JT-001.
- **Priority:** P0.
- **Dependencies:** SEC-001, SEC-003, SEC-005A and SEC-005B recent reauthentication/email proof.
- **Affected components:** `ApplicationUser`, EF model/migration, auth exchange/link/unlink/recovery UI and APIs.
- **Acceptance criteria:** composite tenant/object key is unique owner; no email auto-link; no silent legacy backfill/merge; legitimate legacy users have explicit non-locking recovery.
- **Required tests:** fresh/legacy SQLite+MariaDB migration, collisions, two tenants/same email, last-credential guard, 2FA, mocked relink.
- **Required browser verification:** local mocked new sign-in and legacy relink.
- **Required production verification:** anonymized legacy inventory before migration; monitored relink window.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** real Microsoft/browser/SMTP and disposable MariaDB checks are unavailable; production legacy inventory is unknown.
- **Evidence:** `docs/verification/sec-004-microsoft-identity.md`; focused auth 34/34; backend 507/507; frontend 152/152 and build; dual-provider SQL; disposable SQLite legacy/unique-index rehearsal.
- **Commit:** none.
- **Remaining work:** real mocked-browser Microsoft popup/relink flow with an SMTP sink; disposable MariaDB migration; production counts-only legacy inventory, rolling-version smoke and monitored relink window before `DONE`.
### SEC-005A — Session and recovery revocation
- **Source programme:** Work auth constraints; shared recovery prerequisite.
- **Original requirement references:** `work.md:17-34,63-100`; audit P0-4A/P0-4B, JT-007/JT-008.
- **Related findings:** JT-007, JT-008.
- **Priority:** P0.
- **Dependencies:** SEC-001; coordinates with SEC-004.
- **Affected components:** logout, password reset/change, local session validation, trusted devices, pending 2FA challenges and auth tests.
- **Acceptance criteria:** logout revokes the exact copied `sid`; reset revokes all sessions/devices without disabling 2FA; password change rotates the current session, revokes others and preserves only the current trusted device; session validation binds `sid` to user; stale pending 2FA fails after a security-stamp change.
- **Required tests:** valid/expired logout cookie; copied session; reset across users/devices; password rotation; trusted-device retention/removal; `sid`/user mismatch; pending 2FA stamp.
- **Required browser verification:** logout in two tabs; password change/reset with a local email sink; 2FA recovery.
- **Required production verification:** copied-cookie/reset/change smoke without logging token values.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** browser and production checks require safe running environments.
- **Evidence:** `docs/verification/sec-005a-session-revocation.md`; focused 48/48; full backend 497/497.
- **Commit:** none.
- **Remaining work:** browser/runtime and production verification before `DONE`; SEC-005B owns email state.
### SEC-005B — Verified registration and pending-email transitions
- **Source programme:** Work auth constraints; shared identity/recovery prerequisite.
- **Original requirement references:** `work.md:17-34,63-100`; audit P0-4B, JT-007/JT-008.
- **Related findings:** JT-007, JT-008.
- **Priority:** P0.
- **Dependencies:** SEC-001, SEC-005A; coordinates with SEC-004.
- **Affected components:** registration, verification/resend, profile DTOs, pending-email request/confirm/cancel APIs, `ApplicationUser`, one additive EF migration/snapshot, auth/profile UI and tests.
- **Acceptance criteria:** verification-required registration creates no session and returns typed 202; active email never changes before proof; latest pending request wins; confirmation uses Identity change-email semantics, conditionally updates username, clears pending state and revokes all sessions/devices.
- **Required tests:** registration/no-cookie transition; verify then login; enumeration-resistant resend; duplicate/latest/mismatched/expired/replayed pending email; username preservation; passwordless/provider users; SQLite and MariaDB migration paths.
- **Required browser verification:** mocked/local-sink register/resend/verify and request/cancel/confirm email at desktop/mobile with keyboard access.
- **Required production verification:** safe SMTP link/origin and version-skew smoke; no real personal address.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** in-app browser localhost access was denied by its admin policy check; no safe SMTP sink, disposable MariaDB, or production environment is available.
- **Evidence:** `docs/verification/sec-005b-email-ownership.md`; focused backend 35/35; full backend 501/501; frontend 151/151 and build; SQLite upgrade and dual-provider migration scripts; isolated API 202/no-cookie and 403/no-cookie checks.
- **Commit:** none.
- **Remaining work:** real-browser desktop/mobile/keyboard flows with a local email sink; expired/replayed token and custom-username integration checks; disposable MariaDB migration execution; production SMTP/origin/version-skew verification before `DONE`.
### SEC-006 — Compatible document-parser dependency update
- **Source programme:** Work CV 504; Ollama parser prerequisite; audit P0-3A.
- **Original requirement references:** `work.md:309-386`; `ollama.md:44-56,177-258`; audit JT-006.
- **Related findings:** JT-006, JT-017.
- **Priority:** P0.
- **Dependencies:** approved package-index access during implementation; synthetic benign corpus.
- **Affected components:** Python requirements/lock/hash, parser tests and image build.
- **Acceptance criteria:** compatible fixed versions; no unaccepted reachable High/Critical parser advisory; clean reproducible install; benign extraction parity.
- **Required tests:** dependency resolution/audit, Python suite, generated benign corpus.
- **Required browser verification:** none for dependency-only package.
- **Required production verification:** image digest and smoke before activation.
- **Status:** `BLOCKED`.
- **Blocker:** repository instructions prohibit internet/package resolution without explicit permission; fixed-version compatibility cannot be resolved or verified offline.
- **Evidence:** audit lists reachable Pillow/pypdf/multipart/Starlette advisories and compatibility conflict.
- **Commit:** none.
- **Remaining work:** explicit package-index permission, compatible fixed-version resolution, lock/hash refresh, audit, benign corpus parity and image smoke; do not execute malicious files.
### SEC-007 — Bounded isolated document processing
- **Source programme:** Work CV 504; Ollama privacy/queue; audit P0-3B/P0-3C.
- **Original requirement references:** `work.md:309-386`; `ollama.md:177-258,452-573`; audit JT-006/JT-011.
- **Related findings:** JT-006, JT-011.
- **Priority:** P0.
- **Dependencies:** SEC-006.
- **Affected components:** backend upload/fallback, FastAPI parser child, queue backpressure, container non-root/resource/tmp cleanup.
- **Acceptance criteria:** bounded file/page/pixel/decompression/memory/time work; child/process group killed; no binary backend fallback; safe cleanup/errors; private tokenized service remains.
- **Required tests:** generated boundary/corrupt fixtures, harmless sleeping child, cancellation/restart cleanup, outage/no-fallback, container assertions.
- **Required browser verification:** synthetic CV upload status/failure; authorized private CV local-only only after safeguards.
- **Required production verification:** measured memory/CPU limits and canary synthetic extraction.
- **Status:** `NOT STARTED`.
- **Blocker:** follows dependency update; production sizing requires access.
- **Evidence:** audit parser call path and limits design.
- **Commit:** none.
- **Remaining work:** split behavioral and container commits if needed.
### SEC-008 — Recoverable attachment mutations
- **Source programme:** audit prerequisite for account lifecycle and workspace files.
- **Original requirement references:** Work 17-34 and file/application requirements; audit P0-5/JT-010.
- **Related findings:** JT-010.
- **Priority:** P0 data integrity.
- **Dependencies:** coordinate file-root/journal format with SEC-009.
- **Affected components:** attachment controller/file helper/reconciler/tests.
- **Acceptance criteria:** every DB/filesystem failure converges to committed or durable retryable state; no silent orphan/missing file; rename is metadata-only; owner/path isolation.
- **Required tests:** invalid later file, cancellation, DB/move/delete failure, restart stages, traversal/symlink, two users.
- **Required browser verification:** upload/rename/delete/refresh with synthetic files.
- **Required production verification:** report-only orphan inventory and monitored journal counters.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** in-app browser localhost is policy-blocked; no production report-only inventory/monitoring or MariaDB environment is available. This host denied disposable symlink creation, so that branch is code-inspected only.
- **Evidence:** audit JT-010 execution path; `docs/verification/sec-008-attachment-consistency.md`; 20/20 focused and 525/525 full backend tests; isolated User A/User B upload/download/rename/delete HTTP rehearsal.
- **Commit:** none.
- **Remaining work:** browser upload/rename/delete/refresh; executable symlink test on a capable host; production report-only orphan inventory and counters; MariaDB runtime; reconcile suffix markers before any rollback.
### SEC-009 — Complete readable export and account deletion lifecycle
- **Source programme:** Work audit constraint; Ollama private-data lifecycle; audit P0-6A/P0-6B.
- **Original requirement references:** `work.md:17-34`; `ollama.md:17-22,427-450`; audit JT-009.
- **Related findings:** JT-009, JT-013, JT-022.
- **Priority:** P0 data lifecycle.
- **Dependencies:** SEC-005 revoke-all, SEC-008, owner inventory, backup-retention/tombstone decision.
- **Affected components:** domain inventory/export ZIP, owner-scoped files/caches/queues, deletion saga, provider tokens, migrations, backup restore/runbooks/UI.
- **Acceptance criteria:** readable complete redacted export; idempotent live deletion across rows/files/tokens/queue/cache; no other tenant impact; backup retention truthful; restore tombstones prevent resurrection.
- **Required tests:** two users/every entity, manifest/checksums/redaction, fault/restart/idempotence, provider failures, disposable restore replay.
- **Required browser verification:** disposable self/admin export/delete and confirmations.
- **Required production verification:** backup retention/tombstone rehearsal before self-service enablement.
- **Status:** `NOT STARTED`.
- **Blocker:** legal/operator retention and production restore decisions; repository work can proceed to disabled/dark launch.
- **Evidence:** audit JT-009 inventory/design.
- **Commit:** none.
- **Remaining work:** owner inventory/export first, deletion second.
### CORE-001 — Restore default SQLite/MariaDB behavior parity
- **Source programme:** Work Strategy/Career failures; audit P1-1.
- **Original requirement references:** `work.md:723-777`; audit JT-003.
- **Related findings:** JT-003.
- **Priority:** P0 broken default workflow.
- **Dependencies:** none.
- **Affected components:** Career/Application workspace date-order/filter queries and provider matrix tests.
- **Acceptance criteria:** variants/runs/history/workspace return correct owner/empty/non-owner results on both supported providers.
- **Required tests:** fresh/seeded HTTP provider matrix, date/month/timezone boundaries.
- **Required browser verification:** SQLite Career/Application workspace after API tests.
- **Required production verification:** MariaDB smoke after deployment.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** production MariaDB execution and browser checks remain unavailable; direct blank-file EF-only migration is separate JT-019 schema-ownership debt while fresh application startup passes.
- **Evidence:** audit runtime reproduction JT-003; `docs/verification/core-001-sqlite-provider-parity.md`; 3/3 real-provider tests; 509/509 backend regression; isolated fresh-SQLite owner/empty/non-owner HTTP matrix.
- **Commit:** none.
- **Remaining work:** browser Career/Application workspace verification and executable MariaDB smoke after safe provider/deployment access; address EF-only blank-chain drift under JT-019 rather than editing already-applied historical migrations here.
### CORE-002 — Remove ambiguous application-workspace routes
- **Source programme:** Work Strategy and embedded workspace; audit P1-2.
- **Original requirement references:** `work.md:562-634,723-777`; audit JT-004.
- **Related findings:** JT-004.
- **Priority:** P0 broken core route.
- **Dependencies:** CORE-001; inventory frontend/API consumers.
- **Affected components:** workspace/timeline/interview controllers, API clients/tests/docs.
- **Acceptance criteria:** one action per verb/path; owner 200, non-owner 404, anonymous 401; UI panels load.
- **Required tests:** route-table uniqueness, HTTP ownership, frontend panel tests.
- **Required browser verification:** direct/deep-link workspace panels and Back/Forward.
- **Required production verification:** authenticated workspace smoke.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** in-app browser localhost is policy-blocked; no production/MariaDB HTTP environment is available.
- **Evidence:** audit runtime ambiguous route reproduction; `docs/verification/core-002-route-uniqueness.md`; reflection route regression; 31/31 focused and 511/511 full backend; 153/153 frontend and build; owner 200/non-owner 404/anonymous 401 HTTP matrix.
- **Commit:** none.
- **Remaining work:** browser direct/deep-link, Back/Forward and rendered-panel verification; production authenticated smoke before `DONE`.
### BG-001 — Tenant-safe hosted-worker foundation
- **Source programme:** both; shared prerequisite.
- **Original requirement references:** `work.md:17-34,723-777`; `ollama.md:44-56,452-529`; audit JT-005.
- **Related findings:** JT-005, JT-012, JT-022.
- **Priority:** P0/P1.
- **Dependencies:** CORE-001/CORE-002; do not activate workers before OPS-001B, POL-001 and POL-002.
- **Affected components:** rules/reminders/export/enrichment/CV/AI hosted services, owner context, worker kill switches and tests.
- **Acceptance criteria:** explicit owner selection, deny-on-null avoided safely, idempotent results, structured failures, no cross-owner work, disabled workers remain off.
- **Required tests:** two-owner/no-HttpContext, enable/disable, restart/retry/clock, fake email/AI.
- **Required browser verification:** notification/result surfaces only after OPS-001C.
- **Required production verification:** one-worker canary and owner-safe metrics.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** activation blocked until policy/notification prerequisites; foundation code is not blocked.
- **Evidence:** audit JT-005 service inspection; `docs/verification/bg-001-tenant-workers.md`; real-SQLite two-owner worker suite with fake email/AI; full backend 532/532; Compose validation; isolated default-off startup/health/no-export check.
- **Commit:** none.
- **Remaining work:** OPS-001B persistent notification/idempotency before reminders/rules; POL-001/002 and durable AI queue before enrichment; restart/clock tests; browser result surfaces; monitored single-worker production canary. Keep all four switches false.
### OPS-001A — Durable operation record and lease state machine
- **Source programme:** both; shared CV/Strategy/AI operation foundation.
- **Original requirement references:** `work.md:360-386,761-777`; `ollama.md:452-529`.
- **Related findings:** JT-005, JT-013, JT-014, JT-022.
- **Priority:** P1 foundation.
- **Dependencies:** BG-001; explicit schema ownership.
- **Affected components:** `UserOperation` entity, owner/idempotency/claim indexes, state/lease store, provider-aware EF migration and tests.
- **Acceptance criteria:** stable owner-scoped ID; atomic idempotent create/claim; bounded states/retries/leases/deadlines/cancellation; restart recovery; no raw private payload field.
- **Required tests:** concurrent create/claim, two tenants, transition guards, lease expiry/final attempt, cancellation, retry delay, deadlines, migration up/down/provider SQL.
- **Required browser verification:** not applicable until OPS-001C exposes owner APIs.
- **Required production verification:** executable MariaDB upgrade/down rehearsal and monitored schema rollout.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** no disposable MariaDB or production environment; application consumers deliberately not migrated yet.
- **Evidence:** `docs/verification/ops-001a-durable-operations.md`; 7/7 focused and 539/539 full backend tests; SQLite upgrade/down/up and fresh startup; dual-provider scripts.
- **Commit:** none.
- **Remaining work:** MariaDB execution/production rollout; task-specific producers must validate references/policies and use OPS-001B/C rather than storing private payloads.
### OPS-001B — Persistent operation notifications and terminal outbox
- **Source programme:** both; shared completion/failure visibility and reminder safety.
- **Original requirement references:** `work.md:360-386,761-777`; `ollama.md:512-529,609-639`.
- **Related findings:** JT-005, JT-012, JT-014, JT-022.
- **Priority:** P1 foundation.
- **Dependencies:** OPS-001A; keep real SMTP/AI workers disabled.
- **Affected components:** owner notification entity/store, operation terminal transactions, unread/dismiss state, provider-safe schema and tests.
- **Acceptance criteria:** success/failure/cancellation notification is committed atomically with terminal state; owner isolation; idempotent single notification; no private content; retained across restart.
- **Required tests:** every terminal state, duplicate completion, DB failure rollback, two owners, unread/read/dismiss, migration provider scripts.
- **Required browser verification:** deferred to OPS-001C.
- **Required production verification:** schema rollout and synthetic notification canary only.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** MariaDB execution unavailable; repository implementation can continue.
- **Evidence:** `docs/verification/ops-001b-notifications.md`; 9/9 focused and 541/541 full backend tests; forced transaction rollback; SQLite upgrade/down/up; current model snapshot; generated SQLite/MariaDB up/down SQL.
- **Commit:** none.
- **Remaining work:** execute the migration on MariaDB; expose owner APIs/UI in OPS-001C; complete browser and production canaries. No email delivery is part of this package.
### OPS-001C — Owner operation/notification APIs and frontend queue client
- **Source programme:** both; shared queued-operation UX.
- **Original requirement references:** `work.md:360-386,761-777`; `ollama.md:499-510,609-639`.
- **Related findings:** JT-014, JT-015, JT-022.
- **Priority:** P1 foundation.
- **Dependencies:** OPS-001A/B; POL-001 locked-state admission precedes AI producers.
- **Affected components:** status/list/cancel/retry APIs, notification read/dismiss APIs, frontend polling/status/notification client and shell badge.
- **Acceptance criteria:** stable status URL, owner-only list/detail/cancel/retry; refresh/navigation recovery; honest states/errors; completion badge/read/dismiss; no duplicate submission or private diagnostics.
- **Required tests:** two-user API, refresh/poll/retry/cancel, invalid/expired IDs, component/keyboard/accessibility states.
- **Required browser verification:** queued/refresh/navigate/retry/cancel/completion notification with synthetic handler at 375/768/1440 and light/dark.
- **Required production verification:** authenticated synthetic polling/notification smoke.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** browser localhost remains policy-blocked, but repository/API/component work can continue.
- **Evidence:** `docs/verification/ops-001c-operation-ui.md`; 12/12 focused backend, 544/544 backend, 3/3 focused UI, 156/156 frontend and production build; isolated two-user HTTP owner/cross-owner matrix.
- **Commit:** none.
- **Remaining work:** real browser responsive/theme/keyboard/refresh checks, MariaDB/production smoke and feature-specific producers in AI-003/004. No generic create API is exposed.
### POL-001 — Canonical Free/Pro entitlement policy
- **Source programme:** Work Free/Pro and Ollama entitlement enforcement.
- **Original requirement references:** `work.md:636-721`; `ollama.md:17-22,412-449,501-529,638`.
- **Related findings:** JT-012, JT-022.
- **Priority:** P1 security/business policy.
- **Dependencies:** OPS-001A operation admission contract.
- **Affected components:** role/subscription capability service, API authorization, worker admission/recheck, usage accounting, auth DTO, frontend locked states.
- **Acceptance criteria:** exactly Free and Pro externally; Free has no AI; server rejects direct/batch/background bypass; Pro/expired/downgraded/admin behavior consistent; non-AI data remains accessible.
- **Required tests:** endpoint inventory for Free/Pro/expired/downgraded/admin, worker recheck, usage, direct requests and two tenants.
- **Required browser verification:** locked state/upgrade action/dismissal and Pro execution; mobile/theme/accessibility.
- **Required production verification:** configured Stripe/role mapping only when operator activation is approved.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** browser localhost is denied; Stripe/MariaDB/production are unavailable. Usage accounting is complete only for AI Workspace, so provider rollout remains blocked until durable execution centralizes it.
- **Evidence:** `docs/verification/pol-001-free-pro-entitlements.md`; focused backend 74/74; full backend 568/568; focused frontend 22/22; full frontend 47 suites/157 tests; production build.
- **Commit:** none.
- **Remaining work:** browser locked/Pro state checks; mocked Stripe expiry/downgrade lifecycle; central all-task usage accounting through AI-001/002; production role/config smoke. PRODUCT-001 separately removes the known landing-page price/third-tier/unlimited claims.
### POL-002 — AI privacy, consent and external-fallback policy
- **Source programme:** both.
- **Original requirement references:** `work.md:17-34,495-505,723-777`; `ollama.md:398-451,574-608`.
- **Related findings:** JT-012, JT-022, JT-025.
- **Priority:** P1 privacy/security.
- **Dependencies:** POL-001, PROD-002 task/privacy classification.
- **Affected components:** persistent settings, operation policy snapshot, payload minimization, admin diagnostics, fallback audit, UI privacy explanation.
- **Acceptance criteria:** local-only/default/fallback policy enforced server-side; private categories never leave without permission; minimum payload; provider/reason recorded; opt-out never overridden; no browser secrets.
- **Required tests:** task/privacy matrix, consent changes, payload capture/redaction, fallback allowed/prohibited, entitlement, two tenants.
- **Required browser verification:** user/admin controls and disclosure/locked/failure states.
- **Required production verification:** external egress capture with synthetic data only; no real private CV/email.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** browser localhost is denied; MariaDB/production/external-provider verification is unavailable. Final fallback triggers and provenance depend on AI-001/002.
- **Evidence:** `docs/verification/pol-002-ai-privacy.md`; focused backend 72/72 and final policy 28/28; sidecar 18/18; focused frontend 8/8; full backend 576/576; full frontend 47 suites/158 tests; production build; config and migration script checks.
- **Commit:** none.
- **Remaining work:** browser user/admin disclosure checks; MariaDB and production synthetic egress proof; AI-001 policy snapshot/recheck; AI-002 provider provenance, payload minimization, cost controls and bounded local-first fallback. Background CV calls currently fail safe to local.
### AI-001 — Durable AI queue, backpressure and operation APIs
- **Source programme:** both.
- **Original requirement references:** `work.md:360-386,761-777`; `ollama.md:452-573,609-639`.
- **Related findings:** JT-005, JT-011, JT-013, JT-014.
- **Priority:** P1.
- **Dependencies:** BG-001, OPS-001A/B/C, POL-001, POL-002.
- **Affected components:** AI operation handlers/worker, priority/concurrency/capacity/deadline/circuit, API polling/retry/cancel, frontend shared queue UI.
- **Acceptance criteria:** HTTP returns 202/stable URL; bounded priority queue protects Ollama; exact state transitions; no duplicate billing/output; refresh/restart recovery; scheduled jobs cannot starve interactive work.
- **Required tests:** queue capacity/priority, atomic claim, circuit, timeout/retry/jitter, duplicate click/idempotency, cancellation, shutdown/restart, tenant and policy recheck.
- **Required browser verification:** synthetic operation status across refresh/nav/double-click/offline/retry/cancel.
- **Required production verification:** queue depth/age, one-worker canary, Ollama offline/restart and app/worker restart.
- **Status:** `IMPLEMENTED — NOT VERIFIED`.
- **Blocker:** real 202 producers/browser verification depend on AI-003/004; provider/model circuit and provenance depend on AI-002; MariaDB/production are unavailable and the worker remains off.
- **Evidence:** `docs/verification/ai-001-durable-ai-queue.md`; focused queue/state/API tests 17/17; full backend 581/581; Compose config and diff checks.
- **Commit:** none.
- **Remaining work:** AI-002 provider/model controls; AI-003/004 task handlers and 202 endpoints; browser refresh/double-click/cancel/retry; MariaDB and monitored single-worker production canary. Do not create a second CV- or Strategy-specific queue.
### AI-002 — Ollama adapter and local-first provider routing
- **Source programme:** Ollama local-first; Work privacy/Pro constraints.
- **Original requirement references:** `ollama.md:398-451,574-608`; `work.md:17-34,723-777`.
- **Related findings:** JT-012, JT-017, JT-022.
- **Priority:** P1.
- **Dependencies:** PROD-002, POL-001, POL-002, AI-001.
- **Affected components:** central task routing policy, Ollama/external adapters, sidecar/backend provider boundary, circuit/health, provider diagnostics/config.
- **Acceptance criteria:** deterministic then primary local then optional local then permitted external then clear failure; one policy considers task/privacy/entitlement/health/deadline/cost; no simultaneous duplicate completion.
- **Required tests:** routing matrix, Ollama adapter, schema failure, local circuit, fallback allowed/prohibited/unavailable, cost limits and deduplication.
- **Required browser verification:** provider-agnostic queued states and appropriate fallback disclosure.
- **Required production verification:** actual selected local model and controlled synthetic fallback.
- **Status:** `IN PROGRESS`.
- **Blocker:** actual model/config depends on PROD-003; adapter/policy can use fakes first.
- **Evidence:** new programme explicitly supersedes ADR-004's single-provider decision for this scope.
- **Commit:** none.
- **Remaining work:** design smallest central policy; preserve old provider config for rollback.
### PROD-001 — Read-only production AI inventory and rollout safety
- **Source programme:** Ollama Phases 1-2.
- **Original requirement references:** `ollama.md:58-176`.
- **Related findings:** JT-013, JT-017, JT-020, JT-021.
- **Priority:** P1 production gate.
- **Dependencies:** documented/configured production access; none for repository report templates.
- **Affected components:** production hardware assessment, current Ollama/app/network/config inventory, backup and rollout/rollback report.
- **Acceptance criteria:** sanitized measured OS/CPU/RAM/GPU/storage/Ollama/deployment inventory; no public Ollama; config/backup/restart/interruption/rollback recorded before mutation.
- **Required tests:** read-only commands only; backup mechanism evidence; no secrets/content in reports.
- **Required browser verification:** none.
- **Required production verification:** this item is itself production read-only verification.
- **Status:** `BLOCKED`.
- **Blocker:** repository docs state the local environment has no production route and CI SSH secrets are unavailable; no documented callable host/credential is present.
- **Evidence:** `docs/deployment/backup-restore.md` and `docs/operations/production-backup-verification.md` explicitly record the access gap.
- **Commit:** none.
- **Remaining work:** create sanitized report template locally; operator/documented access required for measured completion.
### PROD-002 — AI workload inventory and synthetic evaluation set
- **Source programme:** Ollama Phase 3; Work keyword/AI/CV/email features.
- **Original requirement references:** `ollama.md:177-258`; `work.md:174-263,309-386,454-527,723-777`.
- **Related findings:** JT-012, JT-022.
- **Priority:** P1.
- **Dependencies:** code inventory; no production access.
- **Affected components:** workload catalog, synthetic/redacted fixtures, deterministic-versus-AI and privacy/latency/output classifications.
- **Acceptance criteria:** every AI task has input/size/output/language/latency/quality/privacy/fallback/interactive/entitlement/current-provider classification; evaluation set covers every listed English/Norwegian/noisy/adversarial/long/invalid case without real data.
- **Required tests:** fixture validity, deterministic expected signals, strict JSON schemas, prompt-injection containment inputs.
- **Required browser verification:** none; fixtures later drive UI packages.
- **Required production verification:** none until benchmark.
- **Status:** `VERIFIED LOCALLY`.
- **Blocker:** none; authorized private CV is optional local-only and never committed/external.
- **Evidence:** `docs/verification/prod-002-ai-evaluation.md`; `docs/ai/workload-inventory.md`; fixture validation 1/1; full backend 569/569; frontend 47 suites/157 tests and build.
- **Commit:** none.
- **Remaining work:** PROD-003 later executes model benchmarks and sets measured thresholds. Revise classifications if POL-002 route tracing finds an omitted payload; no production/provider work is required for this package.
### PROD-003 — Production model benchmarks and model decision
- **Source programme:** Ollama Phases 4-6.
- **Original requirement references:** `ollama.md:259-397`.
- **Related findings:** JT-021.
- **Priority:** P1 production gate.
- **Dependencies:** PROD-001 measured hardware, PROD-002 evaluation set.
- **Affected components:** benchmark harness/evidence and `ollama-model-benchmark.md`.
- **Acceptance criteria:** exact candidate tags/license/version/quantization/resources/latency/throughput/quality/JSON/Norwegian/injection/failure/repeat results; measured context/tuning; primary/optional/deterministic/external decision.
- **Required tests:** repeated synthetic benchmark at 4K/8K and 16K only if safe; one inference initially; no very large/cloud model.
- **Required browser verification:** none.
- **Required production verification:** measured on actual machine; local workstation results are labeled separately.
- **Status:** `BLOCKED`.
- **Blocker:** PROD-001 production access/hardware inventory.
- **Evidence:** none yet.
- **Commit:** none.
- **Remaining work:** repository harness can be prepared after PROD-002.
### PROD-004 — Local-model rollout, fallback, observability and operations
- **Source programme:** Ollama Phases 9-14.
- **Original requirement references:** `ollama.md:531-775`.
- **Related findings:** JT-005, JT-013, JT-017, JT-021, JT-022.
- **Priority:** P1 production deployment.
- **Dependencies:** AI-001, AI-002, PROD-001/003, verified backup/rollback.
- **Affected components:** Ollama limits/model install, app config/migrations/worker, telemetry/health/runbook, validation matrix.
- **Acceptance criteria:** selected digest installed without deleting old model; bounded Ollama/app queues; local-first default; safe fallback; privacy-safe metrics/health; drain/restart/rollback; full production validation matrix.
- **Required tests:** offline/timeout/restart/congestion/concurrent/fallback/free/pro/two-tenant/notification matrix.
- **Required browser verification:** queued AI journeys in production using synthetic data.
- **Required production verification:** mandatory; no `DONE` without actual deploy, resource observation and restart recovery.
- **Status:** `BLOCKED`.
- **Blocker:** production access plus all dependencies.
- **Evidence:** none yet.
- **Commit:** none.
- **Remaining work:** repository runbooks/config only after measured values; no guessed limits/model.
### AI-003 — Strategy Snapshot durable-operation migration
- **Source programme:** both; one consolidated implementation.
- **Original requirement references:** `work.md:723-777`; `ollama.md:609-639,730-765`.
- **Related findings:** JT-003, JT-004, JT-005, JT-012, JT-014, JT-022.
- **Priority:** P1 broken user workflow.
- **Dependencies:** CORE-001/002, AI-001/002, POL-001/002.
- **Affected components:** Strategy button/API/operation handler/result persistence/UI status/notification.
- **Acceptance criteria:** root timeout reproduced; enqueue returns 202; stable result; success/failure/timeout/cancel/retry/idempotent double-click/refresh/restart; no duplicate usage/output.
- **Required tests:** endpoint/handler/provider fakes, all required states, entitlement/privacy/tenant checks, E2E.
- **Required browser verification:** complete queue/status/error/retry/cancel/refresh/back-forward/mobile/theme flow.
- **Required production verification:** local model success, timeout and restart recovery.
- **Status:** `NOT STARTED`.
- **Blocker:** dependencies.
- **Evidence:** reported timeout not yet reproduced in this programme.
- **Commit:** none.
- **Remaining work:** do not build a Strategy-specific queue.
### AI-004 — CV-processing 504 and durable-operation migration
- **Source programme:** both; one consolidated implementation.
- **Original requirement references:** `work.md:309-386`; `ollama.md:609-639,730-765`.
- **Related findings:** JT-006, JT-011, JT-014.
- **Priority:** P1 broken user workflow/security.
- **Dependencies:** SEC-006/007, OPS-001A/B/C, AI-001; authorized private file optional only after safe fixture reproduction.
- **Affected components:** browser upload/API/proxy/artifact/parser/normalization/result polling/recovery/UI queue states.
- **Acceptance criteria:** 504 origin established; enqueue/persist/progress/result; bounded processing/retry/cancel/cleanup; restart recovery; no timeout inflation; review gate preserved.
- **Required tests:** safe synthetic PDFs/DOCX/images, proxy/backend/parser/provider failure, duplicate/refresh/restart, E2E.
- **Required browser verification:** synthetic CV first; authorized private file via temporary local copy only, never logged/committed/external.
- **Required production verification:** synthetic/local-only canary, no external payload, restart recovery.
- **Status:** `NOT STARTED`.
- **Blocker:** security/queue dependencies; source file availability is not required for synthetic root-path work.
- **Evidence:** audit parser path; reported private-file 504 not yet reproduced.
- **Commit:** none.
- **Remaining work:** trace current response duration before migration.
### UX-001 — Unified authentication page
- **Source programme:** Work Phase 2.
- **Original requirement references:** `work.md:63-100`.
- **Related findings:** JT-001, JT-007, JT-008, JT-015.
- **Priority:** P2 after auth safety.
- **Dependencies:** SEC-003/004/005 behavior contracts.
- **Affected components:** login/register UI, Microsoft/Google buttons, error/cancel/return handling, translations/tests.
- **Acceptance criteria:** one username/password card, `or`, normal Google/Microsoft alternatives, recovery/register links; prohibited provider-status clutter removed; no linking implication.
- **Required tests:** invalid credentials/provider failure/cancel/return, focus/order/labels.
- **Required browser verification:** 375/768/1440, light/dark, keyboard/focus, logged-out/provider mocks.
- **Required production verification:** real provider smoke only with authorized accounts.
- **Status:** `NOT STARTED`.
- **Blocker:** security dependencies; provider production checks external.
- **Evidence:** source requirement.
- **Commit:** none.
- **Remaining work:** keep visual change separate from identity migration.
### UX-002 — Deterministic theme state
- **Source programme:** Work Phase 3.
- **Original requirement references:** `work.md:102-133`.
- **Related findings:** JT-015.
- **Priority:** P2.
- **Dependencies:** inspect all theme sources.
- **Affected components:** theme provider/bootstrap/local/profile/cross-tab state and tests.
- **Acceptance criteria:** saved user > anonymous local > system only in System > default; no unexpected route/nav changes or startup flash; loop-free tab sync.
- **Required tests:** Light/Dark/System, login/logout/refresh/navigation/storage/preference listeners/tabs.
- **Required browser verification:** 375/768/1440, light/dark/system, refresh/navigation/two tabs/reduced motion.
- **Required production verification:** normal browser smoke after deploy.
- **Status:** `NOT STARTED`.
- **Blocker:** none.
- **Evidence:** reported behavior not yet reproduced.
- **Commit:** none.
- **Remaining work:** trace root precedence before changing UI.
### QA-001 — Job-analysis and keyword quality
- **Source programme:** Work Phase 5; Ollama deterministic workload rule.
- **Original requirement references:** `work.md:174-263`; `ollama.md:177-223`.
- **Related findings:** JT-021 (measurement), AI quality.
- **Priority:** P2.
- **Dependencies:** PROD-002 fixtures; current pipeline/caching version inventory.
- **Affected components:** import cleanup/language/token/stop words/phrases/skills/scoring/prompt/postprocess/storage/UI label.
- **Acceptance criteria:** function/filler/chrome suppressed generically; technologies/punctuation/multiword phrases preserved; contextual generic terms; honest label; versioned regeneration behavior.
- **Required tests:** seven specified Norwegian/English/mixed/short/noisy/tech/filler fixtures.
- **Required browser verification:** result presentation/empty/error/long Norwegian text at three widths/themes.
- **Required production verification:** synthetic analysis comparison; no silent historical rewrite.
- **Status:** `NOT STARTED`.
- **Blocker:** none.
- **Evidence:** reported examples not yet reproduced.
- **Commit:** none.
- **Remaining work:** deterministic fix before considering model help.
### CAREER-001 — Career Workspace action-oriented redesign
- **Source programme:** Work Phase 6.
- **Original requirement references:** `work.md:265-307`.
- **Related findings:** JT-003, JT-015.
- **Priority:** P2.
- **Dependencies:** CORE-001 and AI-004 status contract.
- **Affected components:** Career Workspace hierarchy/empty/onboarding/import review/completeness/recent docs/status UI.
- **Acceptance criteria:** concise actions for profile/import/review/resume/builder/general/job CV/recent/completeness/errors; long paragraph removed; approval gate preserved.
- **Required tests:** first/returning/incomplete/processing/failure state and navigation.
- **Required browser verification:** three widths, light/dark, keyboard/focus/loading/empty/error/Norwegian.
- **Required production verification:** synthetic account smoke.
- **Status:** `NOT STARTED`.
- **Blocker:** browser tooling must be available for completion.
- **Evidence:** current architecture and source requirement.
- **Commit:** none.
- **Remaining work:** no master-profile overwrite.
### CAREER-002 — CV Builder interaction redesign and external research
- **Source programme:** Work Phase 8.
- **Original requirement references:** `work.md:388-452`.
- **Related findings:** JT-003, JT-015, JT-025.
- **Priority:** P2.
- **Dependencies:** CAREER-001, AI-004; inspect existing advanced builder before changing it.
- **Affected components:** builder list/editor/sections/entries/reorder/visibility/autosave/validation/preview/responsive/accessibility.
- **Acceptance criteria:** all specified section/edit/add/delete/reorder/hide/validation/save/nav/preview behaviors while preserving data/templates/render/export/version/import/profile separation.
- **Required tests:** editing/collapse/add/delete/reorder/save/failure/persistence/preview.
- **Required browser verification:** authorized FlowCV research if accessible, never bypass auth; original JobTracker design at three widths/themes/keyboard/focus.
- **Required production verification:** existing variants/edit/export/public render smoke.
- **Status:** `NOT STARTED`.
- **Blocker:** FlowCV may require manual authenticated session; implementation can proceed from local evidence if research is labeled blocked.
- **Evidence:** existing builder is more complete than the programme's premise; redesign must begin with a real gap analysis.
- **Commit:** none.
- **Remaining work:** avoid rewriting already-working features.
### MAIL-001 — Consolidated job-email hub and explicit sending
- **Source programme:** Work Phase 9.
- **Original requirement references:** `work.md:454-527`.
- **Related findings:** JT-005, JT-012, JT-015, JT-022, JT-025.
- **Priority:** P2.
- **Dependencies:** BG-001, OPS-001B/C notifications, POL-001/002, provider tenant safety.
- **Affected components:** Gmail Review/Correspondence routes, shared domain/components, Gmail/Graph/IMAP, detection/linking, drafts/send audit/application embedding.
- **Acceptance criteria:** one hub plus shared application view; linked/suggested messages; provider identity/search/filter/states; editable draft and explicit confirmed idempotent send; no autonomous AI/send; weak signals never auto-link.
- **Required tests:** link/unlink/dismiss/draft/send duplicate/uncertain/provider failure/reauth/two tenants/free/pro/application embed.
- **Required browser verification:** all states at three widths/themes/keyboard; mocked providers only unless safe configured account.
- **Required production verification:** provider read/draft/send requires explicit authorized synthetic account; never real unsolicited email.
- **Status:** `NOT STARTED`.
- **Blocker:** real provider verification external; mocked/local implementation not blocked after dependencies.
- **Evidence:** final product decisions in source programme.
- **Commit:** none.
- **Remaining work:** route compatibility and one data model, no copies.
### JOBS-001 — Job-search source and assessment redesign
- **Source programme:** Work Phase 4.
- **Original requirement references:** `work.md:135-172`.
- **Related findings:** JT-015, JT-021, JT-024.
- **Priority:** P2.
- **Dependencies:** source provenance inventory; CORE fixes.
- **Affected components:** discovery DTO/storage/source labels/filter/sort/cards/import flow.
- **Acceptance criteria:** every listing shows honest source/type/original link/retrieval/deadline; derived sources labeled; source preserved on import; scan/search/filter/location/work-mode/errors/duplicates/mobile improved.
- **Required tests:** provenance mapping/filter/import preservation/empty/loading/error/duplicates.
- **Required browser verification:** three widths/themes/keyboard/long text/Norwegian/import.
- **Required production verification:** official NAV/safe provider smoke; unavailable providers labeled.
- **Status:** `NOT STARTED`.
- **Blocker:** live provider checks may be external; synthetic fixtures suffice locally.
- **Evidence:** source requirement.
- **Commit:** none.
- **Remaining work:** no scraping or inferred-as-verified source.
### JOBS-002 — Applications table and embedded workspace
- **Source programme:** Work Phase 11.
- **Original requirement references:** `work.md:562-634`.
- **Related findings:** JT-003, JT-004, JT-015, JT-021.
- **Priority:** P2.
- **Dependencies:** CORE-001/002, MAIL-001 embedding contract, AI-003 status.
- **Affected components:** applications table, filters/search/sort, route-backed drawer/modal/full-page fallback, workspace sections/focus/unsaved state.
- **Acceptance criteria:** scan-friendly priority columns; list context preserved; deep-link/back-forward/direct URL; accessible focus/close; mobile full-screen; no nested modal; full-page fallback.
- **Required tests:** route/history/filter persistence/focus/unsaved/direct link/mobile, tenant authorization.
- **Required browser verification:** three widths/themes/keyboard/back-forward/refresh/error/long data.
- **Required production verification:** existing application/workspace smoke.
- **Status:** `NOT STARTED`.
- **Blocker:** none after dependencies.
- **Evidence:** source requirement and existing workspace architecture.
- **Commit:** none.
- **Remaining work:** do not place every field in table or duplicate workspace data.
### UX-003 — Kanban theme-state correction
- **Source programme:** Work Phase 10.
- **Original requirement references:** `work.md:529-560`.
- **Related findings:** JT-015.
- **Priority:** P2.
- **Dependencies:** UX-002 shared theme tokens preferably first.
- **Affected components:** Kanban column/card/drag/focus/loading/error styles and tests.
- **Acceptance criteria:** no white dark-mode targets; all listed drag/empty/card/hover/keyboard/error states have shared-token contrast and light/mobile quality.
- **Required tests:** component/visual state coverage.
- **Required browser verification:** three widths, light/dark, pointer and keyboard drag, focus/contrast.
- **Required production verification:** board smoke.
- **Status:** `NOT STARTED`.
- **Blocker:** browser verification required for completion.
- **Evidence:** reported visual defect not yet reproduced.
- **Commit:** none.
- **Remaining work:** smallest token-level root fix.
### PRODUCT-001 — Homepage plans and respectful Pro promotion
- **Source programme:** Work Phases 12-13.
- **Original requirement references:** `work.md:636-721`.
- **Related findings:** JT-012, JT-015, JT-022.
- **Priority:** P2.
- **Dependencies:** POL-001 canonical policy.
- **Affected components:** homepage/pricing/registration/settings/nav/metadata/upgrade prompts/locked states/translations/tests.
- **Acceptance criteria:** exactly Free (no AI/core tracking) and Pro (defined AI capabilities); no invented price/trial/limit; central capability data; concise dismissible non-dark-pattern promotion.
- **Required tests:** copy/capability consistency, Free/Pro/expired/downgraded locked states, dismissal/no false generation.
- **Required browser verification:** homepage and contextual prompts at three widths/themes/keyboard/accessibility.
- **Required production verification:** configured price text only if actual billing product exists; otherwise no invented values.
- **Status:** `NOT STARTED`.
- **Blocker:** public plan behavior depends on POL-001 compatibility decision; real billing activation is external.
- **Evidence:** source requirement.
- **Commit:** none.
- **Remaining work:** inventory all current contradictory plan claims.
### VER-001 — Complete application action matrix and regression pass
- **Source programme:** Work Phase 15; Ollama validation/tests.
- **Original requirement references:** `work.md:779-903`; `ollama.md:730-798`.
- **Related findings:** all relevant audit findings, especially JT-014/JT-015/JT-016.
- **Priority:** P1 verification gate.
- **Dependencies:** all implemented work packages; matrix may be populated incrementally earlier.
- **Affected components:** `docs/verification/application-action-matrix.md`, browser evidence, regression tests.
- **Acceptance criteria:** every meaningful safe control/action has route/role/plan/result/path/loading/success/failure/auth/tenant/tests/manual/automated/finding classification; failures fixed or accurately blocked.
- **Required tests:** full backend/frontend/Python/E2E plus regressions for confirmed defects.
- **Required browser verification:** running app, synthetic users/data, 375/768/1440, themes/keyboard/focus/refresh/back/tabs/slow/error; no real email/paid provider/destructive production action.
- **Required production verification:** applicable smoke actions only after deployment; local and production classifications remain distinct.
- **Status:** `NOT STARTED`.
- **Blocker:** browser tooling/access and external providers may block individual rows, not the matrix.
- **Evidence:** audit user-journey/action gaps.
- **Commit:** none.
- **Remaining work:** create early and update per package; final sweep last.
### REL-001 — Production validation and remaining audit closure
- **Source programme:** both final reports and production validation.
- **Original requirement references:** `work.md:905-922`; `ollama.md:640-825`; audit backlog remaining phases.
- **Related findings:** all open findings.
- **Priority:** P1 release gate.
- **Dependencies:** VER-001, PROD-004, completed repository packages, backup/rollback/access.
- **Affected components:** `docs/production/production-ai-validation.md`, operations runbook, deployment evidence, audit verification logs, final reports.
- **Acceptance criteria:** truthful production/local/mocked/blocked matrix; queue/model/routing/restart/tenant/Free-Pro/privacy verified; remaining findings explicitly open/deferred; rollback proven.
- **Required tests:** full release command matrix and production synthetic smoke.
- **Required browser verification:** production journeys requiring real deployment, no private data in evidence.
- **Required production verification:** mandatory for `DONE` where source programme requires rollout.
- **Status:** `BLOCKED`.
- **Blocker:** production access plus unfinished dependencies.
- **Evidence:** current production documents explicitly say production data/access not verified.
- **Commit:** none.
- **Remaining work:** continue safe local packages; do not claim production completion.
## Conflict register summary
Full decisions are in `docs/work-programmes/decisions.md`.
1. **AI provider architecture:** ADR-004/current roadmap say one deployment provider; the newer Ollama programme explicitly requires local-first plus controlled fallback. The new programme is the target, implemented centrally and compatibly; old config/models remain for rollback.
2. **Free AI:** current code gives Free users limited AI; the new programme says Free has no AI. POL-001 must change behavior server-side without deleting existing user data or renaming persisted roles prematurely.
3. **Production authority:** Work says no production deploy unless instructed; Ollama programme and the current request authorize only scoped local-AI production work after inventory/backup/rollback. No other production mutation is authorized.
4. **Schema ownership:** OPS-001A chose one EF-owned, provider-conditional migration for `UserOperations` and deliberately omitted reconciler DDL. MariaDB script generation passes; executable server verification remains.
5. **Compose documentation:** docs claim a separate dev override, but the filename is auto-loaded by production deploy. SEC-002 corrects actual behavior.
6. **CV Builder premise:** programme asks for capabilities already present. CAREER-002 begins with a browser/code gap analysis and changes only evidenced gaps.
+18
View File
@@ -0,0 +1,18 @@
# JobTracker session handoff
Updated: 2026-08-03
- **Exact current task:** AI-002 — revalidate and implement the central local-first Ollama/provider routing policy using PROD-002 task classes, POL-002 consent gates and AI-001 execution context.
- **Last completed step:** AI-001 added reusable Pro/privacy admission, bounded priority/capacity, typed default-off worker, owner/policy/cancellation recheck, heartbeat/timeout/retry handling and configuration. POL-002 immediately before it added persistent AI opt-out/external consent plus backend/sidecar gates. AI-002 is the sole `IN PROGRESS` item.
- **Files currently modified:** all prior uncommitted programme work plus AI privacy settings/policy/controller/migration/UI/sidecar changes, `AiOperationQueue.cs`, queue tests/configuration and new architecture/verification/evidence/tracking documents. Pre-existing unrelated changes remain preserved.
- **Commands already run this session:** targeted source tracing; backend builds; EF migration scaffold/pending-model/script/update attempts; focused/full backend tests; focused/full frontend tests; frontend production build; sidecar pytest; Compose config; diff checks. Exact POL-002 commands/results are V-089V-095; AI-001 are V-096/V-097.
- **Test results:** backend 581/581; AI-001 focused queue/state/API 17/17; frontend 47/47 suites and 158/158 tests plus production build; Python sidecar 18/18; Compose config and diff check pass. Browser was not run.
- **Services currently running:** no process started in this session remains. The attempted temporary API launch command was rejected before execution. Pre-existing Docker development containers previously observed were not changed.
- **Temporary files or processes:** no process remains. `tmp/pol002-migration.db` is a disposable partial SQLite migration rehearsal; it contains no user data and stopped at the pre-existing historical migration-chain defect. No startup-test files were created because the launch command was rejected.
- **Production changes currently active:** none. No provider/model call, deployment, production configuration, model pull, paid service or production migration occurred.
- **Rollback status:** all changes are repository-only and uncommitted. Set `EXTERNAL_AI_ENABLED=false` and `WORKER_AI_OPERATIONS_ENABLED=false` for immediate local-only/inactive behavior. The AI preference migration is additive; application rollback should retain its columns. AI-001 adds no schema.
- **Uncommitted changes:** the worktree remains broadly dirty from user/prior programme work, including original `D .agent.md`, `?? AGENTS.md`, audit/todo trees and all completed package changes. Do not revert, reset, bulk-format or commit unrelated files.
- **Known failures:** browser localhost denied; MariaDB/SMTP/production unavailable; SEC-006 package upgrades need explicit internet permission; direct clean EF-only SQLite migration fails before the new preference migration because historical `AddJobEntityAndProspectStages` expects startup reconciliation. No real AI task handler is registered and all AI workers remain off.
- **Exact next action:** trace every `/summarize` and `/cv/*` call into one AI-002 task-routing matrix, then add actual-provider/result metadata and local health/circuit/fallback decisions to the AI-001 execution path without changing Strategy/CV producers yet.
- **Work that can continue independently:** AI-002 repository adapter/routing tests with fake transports; then AI-003/004 typed producers/handlers. UX-001/QA-001 can proceed after foundations. SEC-006/007 require package-index permission; PROD-001/003/004 require production access.
- **Decisions still required from the user:** none for repository-only AI-002 fake/local work. External/paid provider calls, package upgrades and production rollout/access still require explicit authority/configuration; SEC-009 deletion/retention needs the recorded retention/legal decision.