# Raw Upsert Idempotency Prep — PREP-EXCITITOR-CORE-AOC-19-003-BLOCKED-ON-19 Status: Draft (2025-11-20) Owners: Excititor Core Guild Scope: Document the idempotent raw upsert and versioning requirements once linkset extraction (19-002) is defined. ## Pending inputs - Linkset schema and conflict markers from 19-002. - Storage model choice (Mongo vs Postgres) and required unique keys per tenant/advisory/component/version_range. ## Proposed rules (draft) - Unique key: `(tenant_id, advisory_id, component_purl, version_range, source)`; store a monotonic `revision` and `ingested_at` (UTC) for traceability. - Idempotency: compute content hash over canonicalized payload; if identical, no-op; otherwise append new revision with `supersedes` pointer. - Append-only log: keep prior revisions for audit; consumers read latest by hash or highest revision per key. - Determinism: canonical JSON ordering; stable sorting by `(tenant_id, advisory_id, component_purl, version_range, revision)`. ## Handoff Use this as the prep artefact for PREP-EXCITITOR-CORE-AOC-19-003-BLOCKED-ON-19. Finalize once 19-002 freezes schema and storage choice; then wire migrations/indexes accordingly.