chronogrid/DECISION_LOG.md

47 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Architectural Decision Log (ADL)
## [2026-08-09] - ADL-001: Distributed Local-First System Baseline
- **Status**: Accepted
- **Context**: Design a multi-platform (Windows, Linux, Android, Headless) productivity engine for time, project, and note management without centralized servers.
- **Decision**: Adopted Rust core with SQLCipher local storage, Automerge CRDT delta sync over libp2p, and Flutter presentation layer bound via C-FFI.
## [2026-08-19] - ADL-003: chronogrid_core Crate – SQLCipher 4.x Database Initializer
- **Status**: Accepted
- **Context**: Task 1.3 required implementing the `chronogrid_core` crate with SQLCipher 4.x encrypted database initialization matching `docs/API_CONTRACTS/schema.sql`.
- **Decision**:
- `rusqlite` v0.31 with `bundled-sqlcipher-vendored-openssl` feature bundles both SQLCipher and OpenSSL, ensuring a hermetic build with no external C library dependencies.
- The 32-byte Argon2id-derived master key is passed as a **raw hex key** via `PRAGMA key = "x'…'"`, bypassing SQLCipher's internal PBKDF2 derivation since Argon2id already provides equivalent or stronger protection.
- `PRAGMA cipher_compatibility = 4` enforces SQLCipher 4.x defaults (AES-256-CBC, HMAC-SHA512 page auth, 64 KiB page size).
- `PRAGMA foreign_keys = ON` is set on every connection per the schema specification.
- The canonical schema SQL from `docs/API_CONTRACTS/schema.sql` is embedded via `include_str!` at compile time, ensuring single-source-of-truth alignment without runtime file I/O.
- Post-initialization validation confirms all 6 expected tables exist (`namespaces`, `projects`, `tasks`, `notes`, `task_note_links`, `ingestion_logs`) plus 4 indexes.
- `Database` struct provides `open(path, key)` for file-backed and `open_in_memory(key)` for test databases; key length is validated at 32 bytes.
- 11 unit tests cover: table/index creation, FK enforcement, cascade deletes, wrong-key rejection, key length validation, schema idempotency, and CRUD round-trips across all tables.
## [2026-08-20] - ADL-004: chronogrid_core – Automerge CRDT Integration for Task & Note Registers
- **Status**: Accepted
- **Context**: Task 1.4 required integrating the Automerge CRDT engine into `chronogrid_core` so task and note entities support offline-first LWW register mutations with HLC-based causal ordering.
- **Decision**:
- Added `automerge = "0.5"` (resolved to v0.5.12) and `uuid = "1"` with `v4` feature to `chronogrid_core/Cargo.toml`.
- Extended `schema.sql` with `crdt_docs` table (`entity_id TEXT PK`, `entity_type TEXT`, `doc_bytes BLOB`, `updated_at INTEGER`) and `idx_crdt_docs_type` index.
- Implemented `crdt/` sub-module: `Hlc` (Hybrid Logical Clock with `tick()`/`update()`/`Display`/`FromStr`), `CrdtDoc` (generic Automerge wrapper with typed scalar accessors), `TaskCrdt` (11 mutable fields), `NoteCrdt` (4 mutable fields).
- Each entity mutation stamps the document with an advancing HLC timestamp. Fork/merge delegates to Automerge's deterministic conflict resolution.
- `Database` gained `save_crdt_doc()`, `load_crdt_doc()`, `delete_crdt_doc()` for serialized Automerge blob persistence.
- Added `CoreError::Crdt` and `CoreError::HlcParse` error variants.
- 45 unit tests (all passing): HLC ordering/parse, all scalar types, save/load/fork/merge round-trips, CRDT doc DB persistence, schema validation with `crdt_docs` table.
- Full ADR at `docs/ARCHITECTURE/ADR/0004-core-automerge-crdt-integration.md`.
## [2026-08-09] - ADL-002: chronogrid_crypto Crate – Argon2id KDF & OS Keychain
- **Status**: Accepted
- **Context**: Task 1.2 required implementing the `chronogrid_crypto` crate with Argon2id master-key derivation and OS-native keychain bindings per `docs/ARCHITECTURE/02-security-and-crypto.md`.
- **Decision**:
- Argon2id parameters pinned: 64 MiB memory, 3 iterations, 4 threads, 16-byte random salt, 32-byte output.
- `DerivedKey` struct implements `Zeroize + Drop` to scrub sensitive memory on scope exit.
- OS keychain abstracted via `keyring` crate v3 (Windows Credential Manager / DPAPI, Linux SecretService / libsecret). Android keychain is excluded (`cfg(not(target_os = "android"))`) and will be handled by Flutter KeyStore bridge in Task 1.5.
- Raw key material is Base64-encoded before credential-store insertion for UTF-8 backend compatibility.
- Inline Base64 encode/decode helpers avoid adding an external Base64 dependency.