screen-locker/docs/todo/DOCS-workstream-d-shared-crdt-transport.md
2026-09-11 18:46:28 +02:00

160 lines
8.7 KiB
Markdown

# 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)