Skip to content

chore(control): add versioned first-party database migrations #115

Closed

Description

@abruption

Problem

The control service has an explicit compiled migration command, but it currently migrates only Better Auth's schema. session-peer's first-party tables are created from runtime constructors:

  • auth.ts: relay_public_signups
  • app.ts: relay_device_claims
  • relay-control.ts: devices, challenges, operations, contract metadata and public-state revision

This makes a fresh database work, but it does not provide a complete, versioned upgrade contract for an installed Alpha service. The existing registration marker correctly refuses to reinterpret an incompatible draft database; the next step is an operator-reviewable migration path that preserves devices, revocation tombstones, operation receipts and revision history.

Proposed behavior

  • Add a versioned first-party migration ledger for every session-peer-owned control table and index.
  • Make the compiled migration entry point run Better Auth migrations and first-party migrations under the same service identity and writer lock.
  • Keep each first-party migration transactional and idempotent. Record completion only after the schema/data change commits.
  • Change normal service startup to validate the expected schema and fail with an actionable migration_required health/error state rather than creating or altering first-party tables.
  • Preserve the zero_based_v1 registration contract, stable principals, generations, revoked tombstones, pending/committed operations and the monotonic public revision.
  • Require a consistent protected snapshot before an upgrade that changes persistent state. Never restore or delete state automatically after migration failure.
  • Document preflight, migrate, start, verify and rollback/fencing steps for generic and KR deployments.

Acceptance criteria

  • A fresh empty state migrates to the complete current schema without starting the HTTP service.
  • A sanitized v1.0.0-alpha.1 database fixture upgrades without losing users, devices, tombstones, receipts or revision state.
  • Re-running the migration is a no-op and reports the installed schema version.
  • Normal startup against an old, partial, future or corrupted schema fails closed and does not mutate it.
  • Fault injection covers interruption before commit, failed commit, restart after a completed migration and a migration error after the protected snapshot.
  • Backup/restore tests verify schema version together with SQLite integrity, signing-key/JWKS identity and replay/public revision fencing.
  • Node 22/24 and the actual Node/Python control integration suite pass from both a fresh and upgraded fixture.

Non-goals

  • Silently renumbering generations, replacing stable principals or deleting receipts.
  • Automatically running migration from ExecStartPre or every service start.
  • Treating an old database snapshot as an authorized rollback.
  • Changing OAuth provider identities or public signup policy.

This is a v1.0.0-beta gate. It should be coordinated with the deployment layout work in #111; later source modularization in #112 must consume the resulting migration contract rather than inventing another one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions