Skip to content

[claude] FW Lite: don't store the ClientId in the project database #2431

Description

@myieye

[Claude-drafted]

ProjectData.ClientId — the identity FW Lite uses to author new Harmony commits — lives inside the project's SQLite file. Copying the DB (second machine, restored backup, duplicated folder) therefore copies the authority to write as that client, which violates Harmony's single-writer-per-ClientId invariant and permanently forks sync (see sillsdev/harmony#79).

The goal is to move ClientId authority out of the copyable DB so that a copied/restored DB naturally gets a fresh identity. Minting extra ClientIds is cheap (one SyncState entry — same cost as a re-download today), so designs should fail toward new IDs, never toward reusing one.

One possible shape (illustrative, not a settled design):

  • A random dbInstanceId in ProjectData, written once at create/download.
  • An app-local record {dbInstanceId → clientId, lastOwnWriteWatermark} outside the project folder.
  • On open: no record for this dbInstanceId → this install never wrote this DB → fresh ClientId. Record exists but the DB's newest own commit is older than the watermark → DB was rolled back/replaced → fresh ClientId.

Whatever the mechanism, it needs careful per-platform thought: "app-local storage" and backup/restore semantics differ across Windows, Android, iOS, and web (e.g. Android auto-backup and iCloud restores may clone the app-local record along with the DB), which changes what each platform's variant actually protects against. Cases no local scheme can catch (full-device restore) fall back to the harmony-side tripwire.

fw-headless and seeded downloads: fw-headless maintains its own CRDT DB per project and must follow the same rule — its ClientId can't live in that DB either. Beyond correctness, that unlocks a fast path for initial project downloads: instead of pulling the full commit history and replaying it from scratch (today's GetChanges from an empty SyncState), the server could stream a ready-made DB (snapshots and projected tables included) and the client would then do a normal sync, playing back only the commits newer than the seed — almost always FAR fewer. Streaming a DB is only safe once the DB carries no writer identity.

Related hygiene, optional: LocalResource paths and ProjectData.Role/LastUserName/LastUserId are also install/user-local state living in the copyable DB; they could move to the same app-local record if ProjectData is being touched anyway.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions