# Tasks: Inventory Core (040)

**Input**: `specs/040-inventory-core/spec.md`, `specs/040-inventory-core/plan.md`

## P1 — MVP (US1/US2)

- [X] T001 [US1] Add migrations: `inventory_items` (unique: tenant_id+policy_type+external_id; indexes; last_seen fields)
- [X] T002 [US1] Add migrations: `inventory_sync_runs` (tenant_id, selection_hash, status, started/finished, counts, stable error codes)
- [X] T003 [US1] Implement deterministic `selection_hash` (canonical JSON: sorted keys + sorted arrays; sha256)
- [X] T004 [US1] Implement inventory upsert semantics (idempotent, no duplicates)
- [X] T005 [US1] Enforce tenant isolation for all inventory + run read/write paths
- [X] T006 [US2] Implement derived “missing” query semantics vs latest completed run for same (tenant_id, selection_hash)
- [X] T007 [US2] Missing confidence rule: partial/failed or had_errors => low confidence
- [X] T008 [US2] Enforce `meta_jsonb` whitelist (drop unknown keys; never fail sync)
- [X] T009 [US1] Guardrail: inventory sync must not create snapshots/backups (no writes to `policy_versions`/`backup_*`)

## P2 — Observability & Safety (US3 + NFR)

- [X] T010 [US3] Run lifecycle: ensure run records include counts + stable error codes (visible and actionable)
- [X] T011 [NFR] Locking/idempotency: prevent overlapping runs per (tenant_id, selection_hash)
- [X] T012 [NFR] Concurrency: enforce global + per-tenant limits (queue/semaphore strategy)
- [X] T013 [NFR] Throttling resilience: backoff + jitter for transient Graph failures (429/503)
- [X] T014 [NFR] Safe logging & safe persistence: store only stable `error_codes` + bounded safe context in run records (no secrets/tokens; no log parsing required)

## Tests (Required for runtime behavior)

- [X] T020 [US1] Pest: upsert prevents duplicates; `last_seen_at` and `last_seen_run_id` update
- [X] T021 [US2] Pest: missing derived per latest completed run for same (tenant_id, selection_hash)
- [X] T022 [US2] Pest: selection isolation (run for selection Y does not affect selection X)
- [X] T023 [US2] Pest: partial/failed/had_errors => missing is low confidence
- [X] T024 [US2] Pest: meta whitelist drops unknown keys (no exception; no persistence)
- [X] T025 [NFR] Pest: selection_hash determinism (array ordering invariant)
- [X] T026 [NFR] Pest: lock prevents overlapping runs for same (tenant_id, selection_hash)
- [X] T027 [NFR] Pest: run error persistence contains no secrets/tokens (assert error context is bounded; no “Bearer ” / access token patterns; prefer error_codes)
- [X] T028 [US1] Pest: inventory sync creates no rows in `policy_versions` and `backup_*` tables (assert counts unchanged)

## Notes

- “deleted” is reserved and MUST NOT be produced in this feature.
