CREATE TABLE assessor_import_artifacts ( id text PRIMARY KEY CHECK (btrim(id) <> ''), project_id text NOT NULL REFERENCES assessor_projects(id) ON DELETE CASCADE, assessment_id text REFERENCES assessor_assessments(id) ON DELETE CASCADE, scan_run_id text REFERENCES assessor_scan_runs(id) ON DELETE CASCADE, import_file_id text REFERENCES assessor_import_files(id) ON DELETE CASCADE, parent_artifact_id text REFERENCES assessor_import_artifacts(id) ON DELETE CASCADE, artifact_kind text NOT NULL CHECK (artifact_kind IN ('source-file', 'container-entry', 'baseline-package', 'derived-document')), relative_path text NOT NULL CHECK (btrim(relative_path) <> '' AND relative_path !~ '(^[\\/]|(^|[\\/])\.\.([\\/]|$))'), sha256 text NOT NULL CHECK (sha256 ~ '^[a-f0-9]{64}$'), size_bytes bigint NOT NULL CHECK (size_bytes >= 0), sensitivity text NOT NULL CHECK (sensitivity IN ('internal', 'confidential', 'secret')), parse_status text NOT NULL CHECK (parse_status IN ('pending', 'parsed', 'partial', 'failed', 'unsupported')), storage_kind text NOT NULL CHECK (storage_kind IN ('not-retained', 'backend-controlled')), storage_key text, created_at timestamptz NOT NULL, data jsonb NOT NULL CHECK (jsonb_typeof(data) = 'object'), CHECK ((storage_kind = 'backend-controlled' AND btrim(storage_key) <> '') OR (storage_kind = 'not-retained' AND storage_key IS NULL)) ); CREATE INDEX assessor_import_artifacts_project_idx ON assessor_import_artifacts(project_id, created_at, id); CREATE INDEX assessor_import_artifacts_parent_idx ON assessor_import_artifacts(parent_artifact_id) WHERE parent_artifact_id IS NOT NULL; CREATE INDEX assessor_import_artifacts_file_idx ON assessor_import_artifacts(import_file_id) WHERE import_file_id IS NOT NULL; CREATE TABLE assessor_import_processing_runs ( id text PRIMARY KEY CHECK (btrim(id) <> ''), project_id text NOT NULL REFERENCES assessor_projects(id) ON DELETE CASCADE, artifact_id text NOT NULL REFERENCES assessor_import_artifacts(id) ON DELETE CASCADE, supersedes_run_id text REFERENCES assessor_import_processing_runs(id) ON DELETE RESTRICT, run_status text NOT NULL CHECK (run_status IN ('complete', 'partial', 'failed')), started_at timestamptz NOT NULL, completed_at timestamptz NOT NULL CHECK (completed_at >= started_at), data jsonb NOT NULL CHECK (jsonb_typeof(data) = 'object'), CHECK (supersedes_run_id IS NULL OR supersedes_run_id <> id) ); CREATE INDEX assessor_processing_runs_artifact_idx ON assessor_import_processing_runs(artifact_id, started_at, id); CREATE TABLE assessor_ingestion_jobs ( id text PRIMARY KEY CHECK (btrim(id) <> ''), project_id text NOT NULL REFERENCES assessor_projects(id) ON DELETE CASCADE, artifact_id text REFERENCES assessor_import_artifacts(id) ON DELETE CASCADE, job_kind text NOT NULL CHECK (job_kind IN ('parse-artifact', 'extract-source', 'map-findings', 'reprocess-artifact')), idempotency_key text NOT NULL CHECK (btrim(idempotency_key) <> ''), job_status text NOT NULL CHECK (job_status IN ('queued', 'running', 'succeeded', 'dead-letter')), attempts integer NOT NULL CHECK (attempts >= 0), max_attempts integer NOT NULL CHECK (max_attempts >= 1 AND attempts <= max_attempts), available_at timestamptz NOT NULL, lease_owner text, lease_expires_at timestamptz, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, data jsonb NOT NULL CHECK (jsonb_typeof(data) = 'object'), UNIQUE (project_id, idempotency_key), CHECK ((job_status = 'running' AND btrim(lease_owner) <> '' AND lease_expires_at IS NOT NULL) OR (job_status <> 'running' AND lease_owner IS NULL AND lease_expires_at IS NULL)) ); CREATE INDEX assessor_ingestion_jobs_claim_idx ON assessor_ingestion_jobs(job_status, available_at, lease_expires_at, created_at) WHERE job_status IN ('queued', 'running'); CREATE INDEX assessor_ingestion_jobs_project_idx ON assessor_ingestion_jobs(project_id, created_at, id);