sync: add PRAGMA user_version gating and scheme-tagged sync tokens #387

Open
opened 2026-08-10 19:27:49 +00:00 by KofTwentyTwo · 1 comment
KofTwentyTwo commented 2026-08-10 19:27:49 +00:00 (Migrated from github.com)

Prevents a silent-data-loss class before any sync change lands.

Two unrelated hazards, both cheap, both must precede the sync work.

1. No schema version

migrate() is CREATE TABLE IF NOT EXISTS plus additive column checks. There is no user_version, no down path, and an old binary opening a new database silently works while writing the old model — leaving two mutually invisible truths in one file. Refuse to open a database newer than the binary.

2. Sync-token shape collision

Today's checkpoint is {uidvalidity}{DELIM}{uid}. The QRESYNC token is uidvalidity:highestmodseq — same shape, different meaning. Untagged reuse hands a UIDNEXT to a server as a MODSEQ; UIDNEXT is typically the larger number, so the server answers "nothing changed" and everything below is never enumerated again. Silent loss, not a loud resync.

Prefix tokens with a scheme (v2:qresync:…, v2:condstore:…) and treat any unrecognized scheme as full_resync_required.

Design: ADR 0002 · review evidence (PR #385)

**Prevents a silent-data-loss class before any sync change lands.** Two unrelated hazards, both cheap, both must precede the sync work. ### 1. No schema version `migrate()` is `CREATE TABLE IF NOT EXISTS` plus additive column checks. There is no `user_version`, no down path, and **an old binary opening a new database silently works** while writing the old model — leaving two mutually invisible truths in one file. Refuse to open a database newer than the binary. ### 2. Sync-token shape collision Today's checkpoint is `{uidvalidity}{DELIM}{uid}`. The QRESYNC token is `uidvalidity:highestmodseq` — **same shape, different meaning**. Untagged reuse hands a UIDNEXT to a server as a MODSEQ; UIDNEXT is typically the larger number, so the server answers "nothing changed" and everything below is never enumerated again. Silent loss, not a loud resync. Prefix tokens with a scheme (`v2:qresync:…`, `v2:condstore:…`) and treat any unrecognized scheme as `full_resync_required`. Design: [ADR 0002](https://github.com/KofTwentyTwo/nuncio/blob/dev/docs/adr/0002-multi-engine-sync-model.md) · [review evidence](https://github.com/KofTwentyTwo/nuncio/blob/dev/docs/reviews/2026-08-10-multi-engine-design-review.md) (PR #385)
KofTwentyTwo commented 2026-08-10 20:30:07 +00:00 (Migrated from github.com)

Scope grew: this is now the reset mechanism, not just insurance.

ADR 0002's pre-release posture (PR #385) makes an identity-bearing schema change reset the message store and re-sync rather than migrate into a degraded model. PRAGMA user_version is what triggers and gates that, so this issue now owns:

  • refuse to open a database newer than the binary (unchanged);
  • detect an identity-schema version bump and rebuild the message store, preserving account configuration and credentials while discarding cached mail;
  • reinitialise filter_execution_logs alongside it.

The mixed-version-fleet framing is softened — running daemons at different versions against one account is explicitly unsupported pre-release. The scheme-tagged sync tokens stay exactly as specified: that hazard is silent data loss, not a compatibility concern.

**Scope grew: this is now the reset mechanism, not just insurance.** ADR 0002's pre-release posture (PR #385) makes an identity-bearing schema change reset the message store and re-sync rather than migrate into a degraded model. `PRAGMA user_version` is what triggers and gates that, so this issue now owns: - refuse to open a database newer than the binary (unchanged); - detect an identity-schema version bump and rebuild the message store, **preserving account configuration and credentials** while discarding cached mail; - reinitialise `filter_execution_logs` alongside it. The mixed-version-fleet framing is softened — running daemons at different versions against one account is explicitly unsupported pre-release. The scheme-tagged sync tokens stay exactly as specified: that hazard is silent data loss, not a compatibility concern.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KofTwentyTwo/nuncio#387