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.
**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)
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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()isCREATE TABLE IF NOT EXISTSplus additive column checks. There is nouser_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 isuidvalidity: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 asfull_resync_required.Design: ADR 0002 · review evidence (PR #385)
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_versionis what triggers and gates that, so this issue now owns:filter_execution_logsalongside 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.