# ADR-0004: chronogrid_core – Automerge CRDT Integration for Task & Note Registers * **Status**: Accepted * **Date**: 2026-08-20 * **Deciders**: Michael Kell ## Context & Problem Statement Task 1.4 requires integrating the Automerge CRDT engine into `chronogrid_core` so that task and note entities can be modified concurrently by different peers and merged deterministically without centralized coordination. The architecture spec (`03-crdt-sync-protocol.md`) mandates LWW-Element-Set registers for primitive fields and Hybrid Logical Clocks (HLC) for causal ordering. ## Options Considered 1. **Manual LWW register implementation** — track per-field HLC timestamps in a custom data structure and resolve conflicts manually. 2. **Automerge integration with HLC companion stamps** — use Automerge's built-in CRDT merge semantics for structural conflict resolution, augmented with HLC timestamps stored inside each document for causal ordering context. 3. **Yrs (Yjs Rust port)** — alternative CRDT library focused on text collaboration. ## Decision Outcome Chosen Option: **Option 2 — Automerge + HLC** because: - Automerge provides battle-tested CRDT merge, fork, save/load, and delta-sync primitives out of the box. - Storing HLC timestamps as companion fields inside the Automerge document aligns with the spec's requirement for HLC-based LWW conflict resolution while leveraging Automerge's deterministic merge for structural integrity. - The `automerge` crate (v0.5.12) has a stable API with `AutoCommit`, `ReadDoc`, and `Transactable` traits that map cleanly to our per-entity document model. - Yrs is optimized for text sequences, not key-value LWW registers. ## Implementation Details - **`automerge = "0.5"`** added to `chronogrid_core/Cargo.toml` (resolved to v0.5.12). - **`uuid = "1"` with `v4` feature** added for entity ID generation. - **Schema extension**: `crdt_docs` table added to `schema.sql` with columns `entity_id TEXT PK`, `entity_type TEXT`, `doc_bytes BLOB`, `updated_at INTEGER`, plus `idx_crdt_docs_type` index. - **Module structure**: `crdt/` sub-module with `hlc.rs`, `doc.rs`, `task.rs`, `note.rs`. - **HLC**: `Hlc` struct with `tick()`, `update()`, `Display`/`FromStr` (format: `{wall_ms:016}-{counter:08x}-{node_id}`), and full `Ord` implementation ensuring lexicographic string order matches logical order. - **CrdtDoc**: Generic wrapper over `AutoCommit` providing typed `put_*/get_*` accessors for String, f64, i64, u64, bool scalars at the document root. - **TaskCrdt / NoteCrdt**: Entity-specific wrappers with field-level setters that automatically advance the HLC and record it in the document. - **Database persistence**: `save_crdt_doc()`, `load_crdt_doc()`, `delete_crdt_doc()` methods on `Database` for upsert/load/delete of serialized Automerge bytes. - **45 unit tests** covering: HLC ordering, tick/update/parse, all scalar types, save/load round-trips, fork/merge conflict resolution, CRDT doc DB persistence, and schema validation. ## Consequences & Trade-offs * **Positive**: Full offline-first CRDT capability; entities can be forked, edited independently, and merged without data loss. HLC provides deterministic causal ordering for the SQL layer. Zero external network dependencies (local-first mandate satisfied). * **Positive**: Automerge's compact binary format minimizes storage overhead for CRDT doc blobs. * **Negative**: Automerge 0.5.x adds ~40 transitive dependencies; binary size increases moderately. * **Negative**: Each entity requires both a SQL row and a CRDT doc blob, introducing a dual-write pattern that must be kept in sync (future work: transactional wrappers).