PostgreSQL) tracks artifacts with provenance_chain and content_hash but has no concept of versions. An artifact is a single immutable record. To support iterative refinement (e.g., protein designs, model checkpoints, evolving datasets), we need explicit version tracking where each version is its own row linked to its predecessor.Add columns to the artifacts table:
ALTER TABLE artifacts ADD COLUMN version_number INTEGER DEFAULT 1;
ALTER TABLE artifacts ADD COLUMN parent_version_id TEXT DEFAULT NULL;
ALTER TABLE artifacts ADD COLUMN version_tag TEXT DEFAULT NULL;
ALTER TABLE artifacts ADD COLUMN changelog TEXT DEFAULT NULL;
ALTER TABLE artifacts ADD COLUMN is_latest BOOLEAN DEFAULT 1;Add indexes:
CREATE INDEX idx_artifacts_version_lineage ON artifacts(parent_version_id);
CREATE INDEX idx_artifacts_latest ON artifacts(artifact_type, is_latest) WHERE is_latest = 1;
CREATE INDEX idx_artifacts_version_tag ON artifacts(version_tag) WHERE version_tag IS NOT NULL;
CREATE INDEX idx_artifacts_type_entity_latest ON artifacts(artifact_type, entity_ids, is_latest) WHERE is_latest = 1;Add constraints (enforced in application code):
parent_version_id must reference an existing artifact id (same artifact_type)version_number must be parent.version_number + 1is_latest = TRUEmigrations/003_add_artifact_versioning.py002_add_quests.py)version_number=1, is_latest=TRUE, parent_version_id=NULLmigrations/081_add_artifact_versioning.py(artifact_type, entity_ids, is_latest)artifact_registry.py updated to include new columns in INSERT statementsregister_artifact() accepts optional version_number, parent_version_id, version_tag, changelog paramsscidex DB (dbname=scidex user=scidex_app host=localhost)version_number (integer, default=1), parent_version_id (text), version_tag (text), changelog (text), is_latest (integer, default=1) — all 5 columns presentidx_artifacts_version_lineage, idx_artifacts_latest, idx_artifacts_version_tagregister_artifact() accepts all 5 version params: version_number, parent_version_id, version_tag, changelog, is_latest
(artifact_type, entity_ids, is_latest) is not present in PostgreSQL, so the task is only partially satisfied on current main.698ed86b2d0b08da8ecfbbd596b07d4846e10306register_artifact() already exposes version params.(artifact_type, entity_ids, is_latest).migrations/111_add_artifacts_type_entity_latest_index.py using CREATE INDEX CONCURRENTLY IF NOT EXISTS to avoid blocking the hot artifacts table.tests/test_artifact_versioning.py to be PostgreSQL-native, verify the new composite index, and smoke-test default version fields via register_artifact().python migrations/111_add_artifacts_type_entity_latest_index.py and PYTHONPATH=. python tests/test_artifact_versioning.py → both passed; live counts after migration: 47,494 artifacts / 47,478 at version 1 / 47,463 latest.python migrations/111_add_artifacts_type_entity_latest_index.py → Migration 111 applied: created idx_artifacts_type_entity_latestPYTHONPATH=. python tests/test_artifact_versioning.py → passed, including schema, indexes, and a default register_artifact() insert smoke testpg_indexes now includes idx_artifacts_type_entity_latest on (artifact_type, entity_ids, is_latest) with WHERE (is_latest = 1)
tests/test_artifact_versioning.py to verify acceptance criteria081_add_artifact_versioning.py (deployed as migration 40 on main){
"completion_shas": [
"b9a46968c35d93f349e684e36b3eec490580c0b8",
"856422caf086c0ee29416c1922ff68e62f547f6c"
],
"completion_shas_checked_at": "2026-04-14T00:43:53.605384+00:00"
}