feat(6845): every instance has an id lineage, and every full backup carries it
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 1m37s
CI & Build / integration (push) Successful in 2m7s
CI & Build / Build & push image (push) Successful in 22s

instance_identity is one row made by migration 0127 with a random id, so an
instance has it before its first account. A full backup carries it in its
header as instance_id (the tar manifest header and the JSON top level);
BACKUP_VERSION is 28. The table rides in _NOT_INCLUDED: a restore decides from
the header value rather than copying a row.

Two stores with the same id number their rows the same way. That is what lets
a later step roll a live instance back by original id, refuse a backup whose
ids would land on unrelated rows, and have a fresh-instance restore adopt the
backup's id (adopt_instance_id).

Milestone 582, step 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-04 19:53:45 -05:00
co-authored by Claude Opus 5.5
parent 3c01e17559
commit 6d8db0bb65
7 changed files with 171 additions and 4 deletions
+26
View File
@@ -0,0 +1,26 @@
from datetime import datetime
from sqlalchemy import CheckConstraint, DateTime, Integer, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from grimoire.models import Base
class InstanceIdentity(Base):
"""The one row naming this database's id lineage.
Two stores with the same instance id number their rows the same way: one
is the other, or a restore of it made with the original ids kept. That is
what lets a backup roll a live instance back by id, and what refuses a
backup whose ids would land on unrelated rows. Made by the migration, so
an instance has it before anyone registers.
"""
__tablename__ = "instance_identity"
__table_args__ = (CheckConstraint("id = 1", name="ck_instance_identity_single_row"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1)
instance_id: Mapped[str] = mapped_column(Text, nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)