# Workstream D — Shared CRDT transport library across 4 repos ## Status Scoping pass complete — see `workstream-d-scoping-findings.md` (2026-07-04) for the answers to the four questions below and the two sub-decisions that fell out of it (both resolved by explicit user call, 2026-07-04). **The two shared libraries are now implemented and locally verified (2026-07-05):** - `~/src/utils/crdt-sync` (Python) — 60 tests, 100% branch coverage, clean ruff/mypy/pylint/bandit/pre-commit. Local git repo, one commit. - `~/src/utils/crdt_sync_dart` (pure Dart, no Flutter dep) — 59 tests, clean `dart analyze`. Local git repo, one commit. Both implement the unified LWW-map-with-sticky-remove scheme (`Hlc`, `Record`/`merge_record`, `Log`/`merge_logs`) plus a GitHub Contents-API transport client and a domain-agnostic `sync_log`/`syncLog` orchestrator. Both were originally pushed as standalone public repos (2026-07-05, matching `gatelock`'s convention), then consolidated (2026-07-10) into the shared `github.com/kuhyx/utils` monorepo alongside `gatelock` and `guard-lib`, each as its own subdirectory. Consume via `crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.1.0#subdirectory=crdt-sync` (Python) or a pubspec `git:`/`path:` dependency pointing at `crdt_sync_dart-v0.1.0`/`crdt_sync_dart` (Dart). **Not yet done — none of the four apps have been migrated onto it yet**: todo (off `sqlite_crdt`), diet-guard (Python + Dart merge code), wake-alarm (`shutdown-wrapper.sh` rewrite), and screen-locker's own Workstream C adoption. Each is its own separate, production-code-touching task per the scoping doc's per-app cost estimates. Split out from the original status-view plan (`~/.claude/plans/screen-locker-status-streamed-feigenbaum.md`, Workstream A). ## The decision this workstream implements Per explicit prior user decision: build a shared **Python** CRDT transport library (used by screen-locker, diet-guard, wake-alarm PC-sides) and a shared **Dart** CRDT transport library (used by todo, diet-guard app, wake-alarm `phone_app`, screen-locker's `workout_app`), with **all four apps adopting CRDT-based merge** — not just todo's existing use of it. This was flagged during the original planning conversation as more complexity than diet-guard/wake-alarm/screen-locker's simpler log data strictly needs, and the user chose it anyway as a deliberate future-proofing call. That tradeoff decision stands; this document doesn't re-litigate it, only records what's actually true about the current state so a future scoping pass starts from facts, not assumptions. ## What's actually true today (verified by reading the code, not assumed) **todo's "CRDT approach" is the `sqlite_crdt` package**, not hand-rolled logic: `todo/lib/sync/sync_service.dart` imports `package:sqlite_crdt/sqlite_crdt.dart` and syncs by "pulling every other device's full CRDT changeset" (per that file's own doc comment) — merge conflict resolution is handled entirely inside that library, not in app code. This matters: Workstream D's Dart-side library is not "extract what todo already built," it's "wrap/standardize how todo already uses a third-party package," which is a smaller and clearer task than a from-scratch CRDT implementation. **diet-guard and wake-alarm do NOT use CRDTs today.** Their existing "merge" mechanisms are much simpler: - diet-guard: `_sync_merge.merge_logs` (`~/src/diet-guard/diet_guard/_sync_merge.py`, 81 lines) is a tombstone-aware, entry-key-based merge — closer to last-write-wins per entry than a general CRDT. Transport is `_sync_github.GitHubSyncClient` against a private repo's Contents API (see Workstream C's doc for the concrete interface). - wake-alarm: `shutdown-wrapper.sh` reads a **private GitHub Gist** directly in bash — no merge logic at all, because it's a single current value (next wake time), not a growing log. This is the piece the original plan flags as needing a rewrite ("wake-alarm's current bash-based PC-side gist reader... into something that can participate in a CRDT merge") — but note its data model (one current value, no history) may not even need CRDT semantics; forcing it into the same abstraction as diet-guard's growing log is itself a design choice to confirm, not a given. **No existing Python CRDT-backed storage layer exists in any of these repos.** Unlike the Dart side (where `sqlite_crdt` is a mature, adopted package), the Python PC-side transport library has no equivalent starting point. This is the biggest unknown in scoping this workstream: does a suitable Python CRDT library exist and fit sqlite/JSON-log use cases, or does "shared Python CRDT transport library" mean writing CRDT merge logic from scratch in Python? That question needs an answer before any time/complexity estimate for this workstream means anything. ## Why this is a separate, large task (not a natural extension of A/B/C) - Spans 4 repositories (todo, diet-guard, wake-alarm, screen-locker) and 2 languages (Dart, Python). - Touches production sync code in apps that are already shipping and working (diet-guard's Contents-API sync, wake-alarm's Gist reader) — regressions here have real user-facing consequences (diet-guard's own memory notes record a prior 3-day silent outage from a similar deployment-path mismatch — see `feedback-verify-real-deployment-path.md` in this user's memory). - Requires picking one canonical transport primitive (Gist vs. Contents-API repo, per Workstream C's open question) that all four apps then share — a decision this document deliberately does not make, since it depends on Workstream C's resolution. - The Python-side CRDT gap (previous section) may turn "build a shared library" into "evaluate/adopt a third-party Python CRDT library" or "design a minimal CRDT scheme from scratch" — materially different scopes that need to be distinguished before estimating. ## Scoping pass — what actually needs to happen before coding starts This is not an implementation plan. Before any code is written for this workstream, produce (as a separate, dedicated planning task): 1. **Python CRDT landscape check**: does a maintained Python package exist that plays well with SQLite or flat JSON logs (the data shapes diet-guard/wake-alarm/screen-locker actually use today)? If none fits, decide: adopt something not-quite-right, or hand-roll a minimal CRDT (e.g. a simple LWW-register or OR-set scheme, since the data here is genuinely simple — daily log entries, not concurrent rich-text editing). 2. **Transport primitive decision**: Gist vs. Contents-API repo (see Workstream C) — must be settled first since the shared library wraps whichever one is chosen, for all 4 apps, not per-app. 3. **Per-app migration cost, assessed individually**: - todo: likely smallest — already on `sqlite_crdt`, mainly a question of whether it also needs to move onto the shared library's transport wrapper, or keeps its current transport untouched. - diet-guard: rewrite `_sync_merge.py`'s tombstone-LWW merge onto a real CRDT scheme, both Python (`_sync.py`) and Dart (`app/lib/services/sync_merge.dart`) sides. - wake-alarm: full rewrite of `shutdown-wrapper.sh`'s bash Gist reader into something CRDT-capable — the single biggest unknown, since it's currently the simplest and most different data model of the four (single value, no log, no merge today at all). - screen-locker: net-new — no existing sync of any kind yet (Workstream C is what introduces sync here at all; if C is built with "local, throwaway sync code" per its own doc, D's arrival means replacing that code, not extending it). 4. **Sequencing relative to Workstream C**: confirm whether C should be (a) built on local throwaway sync code now and migrated onto D's library later, or (b) blocked until D's library exists. This is Workstream C's open question too — resolve it once, here or there, not independently in both places. ## Explicitly out of scope for the scoping pass itself Do not write any CRDT library code, do not touch any of the 4 repos' existing sync mechanisms, and do not commit to the Python-CRDT-library question's answer without actually researching current (as of when this task is picked up) Python package options — the answer may be stale by the time this is scoped for real. ## Critical files (reference only — read, do not modify, during scoping) - `~/src/todo/lib/sync/sync_service.dart`, `sync_settings.dart` (CRDT-via-package pattern) - `~/src/diet-guard/diet_guard/_sync.py`, `_sync_github.py`, `_sync_merge.py` - `~/src/diet-guard/app/lib/services/sync_service.dart`, `sync_merge.dart` - `~/src/wake-alarm/shutdown-wrapper.sh` - `docs/todo/workstream-c-github-sync-workout-data.md` (this repo — resolve its open questions jointly with this one, not independently)