From 73ab153b028c63baa8ec877999cb6871291534f3 Mon Sep 17 00:00:00 2001 From: Olive Vaughn Date: Mon, 28 Sep 2026 21:03:18 -0400 Subject: [PATCH] Add project schema version --- clips/migrations/0006_project_schema_version.py | 15 +++++++++++++++ clips/models.py | 8 ++++---- clips/tests/test_api.py | 1 + clips/views.py | 5 ++++- 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 clips/migrations/0006_project_schema_version.py diff --git a/clips/migrations/0006_project_schema_version.py b/clips/migrations/0006_project_schema_version.py new file mode 100644 index 0000000..6697451 --- /dev/null +++ b/clips/migrations/0006_project_schema_version.py @@ -0,0 +1,15 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("clips", "0005_footage_stream_alter_footage_video"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="schema_version", + field=models.PositiveIntegerField(default=1), + ), + ] diff --git a/clips/models.py b/clips/models.py index 2f268df..b120873 100644 --- a/clips/models.py +++ b/clips/models.py @@ -199,14 +199,14 @@ class Block(models.Model): class Project(models.Model): """Tier 1: the document's root. - `seq` is the monotonic project version docs/architecture.md asks for. Every - write bumps it, and a client that sees `seq > local + 1` refetches — which is - what makes staleness self-healing rather than permanent once there is a - broadcast to miss. + `schema_version` identifies the stored document format. `seq` counts writes + to this particular project; it is not a format version. Every write bumps + `seq`, and a client that sees `seq > local + 1` refetches once broadcasts exist. """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=200, default="untitled") + schema_version = models.PositiveIntegerField(default=1) seq = models.PositiveBigIntegerField(default=0) palette = models.CharField(max_length=64, default="arthur/default") created = models.DateTimeField(auto_now_add=True) diff --git a/clips/tests/test_api.py b/clips/tests/test_api.py index da3b534..811fabf 100644 --- a/clips/tests/test_api.py +++ b/clips/tests/test_api.py @@ -379,6 +379,7 @@ class DocumentTests(TestCase): self.assertEqual(5, len(response.json()["written"])) loaded = self.client.get(f"/api/projects/{self.project.id}").json() + self.assertEqual(1, loaded["schema_version"]) self.assertEqual(1, len(loaded["clips"])) clip = loaded["clips"][0] self.assertEqual("c1", clip["cid"]) diff --git a/clips/views.py b/clips/views.py index 6203fe7..f485239 100644 --- a/clips/views.py +++ b/clips/views.py @@ -571,6 +571,7 @@ def _project_json(project: Project): return { "id": str(project.id), "name": project.name, + "schema_version": project.schema_version, "seq": project.seq, "palette": project.palette, "clips": clips, @@ -583,7 +584,8 @@ def projects(request): return JsonResponse( { "projects": [ - {"id": str(p.id), "name": p.name, "seq": p.seq, + {"id": str(p.id), "name": p.name, + "schema_version": p.schema_version, "seq": p.seq, "updated": p.updated.isoformat()} for p in Project.objects.all()[:100] ] @@ -690,6 +692,7 @@ def _save(project: Project, data): return JsonResponse( { "id": str(project.id), + "schema_version": project.schema_version, "seq": seq, "written": sorted(written), "removed": sorted(removed),