# 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-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. ## [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-20] - ADL-005: chronogrid_ffi Crate – Flutter Rust Bridge v2 FFI Layer - **Status**: Accepted - **Context**: Task 1.5 required generating `flutter_rust_bridge` FFI bindings to bridge all Rust storage, CRDT, and cryptographic methods to the Flutter/Dart presentation layer. - **Decision**: - Created `crates/chronogrid_ffi/` crate with `cdylib` + `staticlib` + `lib` targets, depending on `chronogrid_core`, `chronogrid_crypto`, `flutter_rust_bridge = "=2.7.0"`, and `anyhow = "1"`. - API uses a **serialized-bytes pattern**: CRDT documents cross FFI as `Vec` (Automerge binary); read functions return DTO structs (`FfiTaskData`, `FfiNoteData`, `FfiDerivedKey`). - Global `Engine` singleton (`Mutex>`) holds the `Database` connection + `Hlc` clock. Thread-safe `with_engine()` / `with_engine_mut()` helpers provide access from FRB's isolate thread pool. - 38 public FFI functions across 5 API modules: `engine` (init/close/status), `database` (CRDT doc persistence), `crypto` (key derivation + platform-gated keychain), `task_crdt` (18 create/read/set/clear/merge ops), `note_crdt` (8 create/read/set/clear/merge ops). - All fallible functions return `anyhow::Result`, which FRB v2 maps to Dart exceptions. - Keychain functions compile on all platforms but return an error on Android (delegated to Flutter KeyStore bridge). - `flutter_rust_bridge.yaml` configures codegen: Rust input from `api/`, Dart output to `apps/chronogrid_flutter/lib/src/rust/`. - Flutter `pubspec.yaml` updated with `flutter_rust_bridge: ^2.7.0`, `ffi: ^2.1.0`, `meta: ^1.11.0`. - 25 unit tests (all passing): engine lifecycle, DB CRDT doc persistence, task/note CRDT create/read/mutate/merge round-trips, crypto derivation, stateless read validation, no-engine error paths. - Full ADR at `docs/ARCHITECTURE/ADR/0005-ffi-bridge-flutter-rust-bridge.md`. ## [2026-08-22] - ADL-007: chronogrid_core Schema Extension — Phase 2 Missing Entities (Task 2.1) - **Status**: Accepted - **Context**: Task 2.1 required extending `docs/API_CONTRACTS/schema.sql` with 6 missing entity tables identified in the ADL-006 architecture review as a critical gap blocking Phase 3 and Phase 4 development. - **Decision**: - Added 6 new tables: `time_blocks`, `attachments`, `calendar_feeds`, `node_peers`, `automation_rules`, `ingestion_configs`. - All new tables include `hlc_timestamp TEXT NOT NULL` for CRDT compatibility, except `node_peers` which is managed by `chronogrid_net` and does not participate in CRDT sync. - `node_peers` has no FK to `namespaces` — it is a global peer registry scoped to the node, not to a namespace. - `attachments.storage_path` stores relative paths inside the encrypted vault directory; file bytes are stored outside SQLite to avoid BLOB size limits. - `calendar_feeds` and `ingestion_configs` store credentials as encrypted blobs (`encrypted_password_blob`, `encrypted_imap_password_blob`) — never plaintext. - `ingestion_configs` uses a `config_type` discriminator (`imap` | `file_watcher` | `hotkey`) with nullable type-specific fields, avoiding a separate table per ingestion type. - `crdt_docs.entity_type` now supports `'time_block'` in addition to `'task'` and `'note'`. - `EXPECTED_TABLES` in `crates/chronogrid_core/src/db.rs` updated from 7 to 13 entries; schema validation enforces all 13 tables on every database open. - 12 new indexes added for all new FK columns and common query patterns. - 8 new unit tests added covering CRUD round-trips, FK cascade/SET NULL behavior, and `time_block` CRDT doc persistence. - Verification script confirmed: all 13 tables present in schema.sql (PASS), Flutter analysis clean (PASS). - Full ADR at `docs/ARCHITECTURE/ADR/0007-schema-extension-phase2-entities.md`. ## [2026-08-22] - ADL-008: chronogrid_net Crate — Node Identity & Swarm Key (Task 2.2) - **Status**: Accepted - **Context**: Task 2.2 required implementing the foundational identity and cluster-authentication primitives for `chronogrid_net`: Ed25519 node keypair (`NodeIdentity`), SHA-256-derived `NodeId`, and 256-bit pre-shared `SwarmKey`. - **Decision**: - `ed25519-dalek v2` chosen for Ed25519 keypair generation (audited, `rand_core`-compatible, libp2p-compatible for Task 2.3 integration). - `NodeId` = SHA-256(public key bytes) → 32-byte / 64-hex-char stable identifier; maps directly to `node_peers.id` primary key in schema. - `SwarmKey` = 32 bytes from `OsRng`; `fingerprint()` = first 16 hex chars of SHA-256(key) → maps to `node_peers.swarm_key_fingerprint`. - Both `NodeIdentity` and `SwarmKey` implement `ZeroizeOnDrop`; `PersistedIdentity` also zeroized to prevent secret hex strings lingering in heap. - `SwarmKey::eq` uses constant-time XOR accumulation with `black_box` to mitigate timing side-channels. - Persistence: `NodeIdentity` → JSON (hex-encoded keys); `SwarmKey` → 64-char hex file. Both stored inside encrypted vault directory. - `load_or_create_identity()` and `SwarmKey::load_or_create()` provide idempotent file-backed initialization. - 27 unit tests: generation uniqueness, determinism, hex/bytes round-trips, file I/O, error paths, debug redaction, constant-time equality. - Full ADR at `docs/ARCHITECTURE/ADR/0008-net-node-identity-swarm-key.md`. ## [2026-08-22] - ADL-009: chronogrid_net Crate — Transport & Discovery Layer (Task 2.3) - **Status**: Accepted - **Context**: Task 2.3 required implementing the libp2p transport stack and peer discovery layer in `chronogrid_net`, building on the Ed25519 `NodeIdentity` and `SwarmKey` from Task 2.2. - **Decision**: - Added 3 new modules: `peer_event` (`PeerEvent` enum), `transport` (TCP+Noise+Yamux builder, `TransportConfig`, keypair conversion), `discovery` (`MdnsDiscovery` and `KademliaDht` wrappers). - **Transport:** `build_transport()` constructs a TCP + Noise XX + Yamux fallback transport. Primary QUIC transport is deferred to `SwarmBuilder::with_quic()` in Task 2.5. Noise XX (not XK) is used for TCP because XK requires pre-knowledge of the responder's static key, which is not guaranteed in a dynamic mesh. - **SwarmKey authentication:** Enforced at the application layer via the `identify` protocol. The SwarmKey fingerprint (`SHA-256(key)[0..8]` as 16 hex chars) is embedded in the `UserAgent` string (`chronogrid//swarm:`). Peers with mismatched fingerprints are disconnected by `SwarmManager` (Task 2.5) after identification. - **Keypair conversion:** `dalek_to_libp2p_keypair()` extracts the 32-byte seed from `ed25519-dalek` and re-imports into `libp2p::identity::ed25519::Keypair`. Both use the same curve parameters; the derived `PeerId` is stable. - **mDNS:** 5-minute TTL, 5-second re-query, IPv4-only, deduplication via `active_peers: HashSet`. - **Kademlia:** In-memory routing store, 60s replication / 5min publication intervals, `add_bootstrap_peer()` / `bootstrap()` API. - Added `tcp` and `yamux` libp2p feature flags (omitted from Task 2.2 declaration). - 65 unit tests pass (10 peer_event, 12 transport, 13 discovery, plus 27 from Tasks 2.2 identity/swarm_key, plus 5 doc-tests). - `KadEvent::RoutingUpdated` uses private libp2p-internal types; routing-table tracking tested via `#[cfg(test)] insert_peer_for_test()` helper; full coverage deferred to Task 2.5 integration test. - Full ADR at `docs/ARCHITECTURE/ADR/0009-net-transport-discovery-layer.md`. ## [2026-08-22] - ADL-006: Architecture Review Board Assessment & Master Development Plan v2 - **Status**: Accepted - **Context**: A comprehensive senior architecture review was conducted covering all crates, documentation, task structure, and the development plan. Phase 1 is complete and production-quality. Phases 2–5 require a structured execution plan to enable automated agent development. - **Decision**: - Created `docs/ARCHITECTURE/05-architecture-review-assessment.md` — full ARB assessment with gap analysis, risk register, and recommendations. - Created `docs/ARCHITECTURE/06-master-development-plan.md` — authoritative execution plan superseding OSAD Section 8, with 37 tasks across Phases 2–5, quality gates, and acceptance criteria traceability. - Created `docs/TASKS/phase_2_networking_and_schema.md` — 9 tasks for libp2p networking, schema extension, daemon scaffold, and verification pipeline hardening. - Created `docs/TASKS/phase_3_flutter_ui_shell.md` — 10 tasks for Flutter BLoC architecture, all 4 primary views, FRB codegen, and build scripts. - Created `docs/TASKS/phase_4_ai_and_automation.md` — 9 tasks for NLP engine, IMAP ingestion, file watchers, CalDAV server, and automation rules engine. - Created `docs/TASKS/phase_5_headless_and_release.md` — 9 tasks for daemon completion, integration testing, performance testing, and release packaging. - Fixed documentation typos in `docs/UI_UX/02-calendar-timeblocking.md` and `docs/UI_UX/03-kanban-gantt-views.md`. - Expanded `docs/WORKFLOWS/01-master-user-story.md` from a stub to a substantive workflow reference document. - Identified critical gaps: 6 missing schema tables, FFI type mismatch (`due_date: i64` vs `u64`), incomplete verification script, missing build scripts, unscaffolded daemon crate. - Confirmed all Phase 1 architectural decisions as correct — no reversals required. - Next task for automated execution: **Task 2.1 — Extend Schema with Missing Entities**.