From 932a7409fc4989d16e0c0fea2cd41f4199c1983a Mon Sep 17 00:00:00 2001 From: Ashley Venn Date: Mon, 6 Jul 2026 20:06:45 -0700 Subject: [PATCH] docs: refresh stale completed ADRs --- .../V1_ADR_002_SQLite_Document_Schema_V1.md | 68 +++++++++++++------ .../V1_ADR_005_Export_Backup_Boundary.md | 30 +++++++- .../V1_ADR_006_Schedule_Snapshot_Policy.md | 30 +++++++- .../V1_ADR_008_Notification_Abstraction.md | 41 ++++++++++- .../V1_ADR_002_SQLite_Document_Schema_V1.md | 38 +++++++++++ .../V1_ADR_005_Export_Backup_Boundary.md | 12 ++++ .../V1_ADR_006_Schedule_Snapshot_Policy.md | 11 +++ .../V1_ADR_008_Notification_Abstraction.md | 11 +++ 8 files changed, 210 insertions(+), 31 deletions(-) create mode 100644 archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_002_SQLite_Document_Schema_V1.md create mode 100644 archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_005_Export_Backup_Boundary.md create mode 100644 archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_006_Schedule_Snapshot_Policy.md create mode 100644 archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_008_Notification_Abstraction.md diff --git a/Codex Documentation/Completed Plans/V1_ADR_002_SQLite_Document_Schema_V1.md b/Codex Documentation/Completed Plans/V1_ADR_002_SQLite_Document_Schema_V1.md index d5d918d..f41bed9 100644 --- a/Codex Documentation/Completed Plans/V1_ADR_002_SQLite_Document_Schema_V1.md +++ b/Codex Documentation/Completed Plans/V1_ADR_002_SQLite_Document_Schema_V1.md @@ -1,35 +1,59 @@ -# V1 ADR 002: SQLite Document Schema V1 + + + +# V1 ADR 002: SQLite Document Schema V2 + +Status: **Accepted; updated to match current app state** -Status: **Accepted** Date: 2026-06-26 +Last reviewed: 2026-07-07 + ## Context -The project pivoted from MongoDB to **SQLite‑first** persistence. -We need a stable, versioned relational schema that maps cleanly to the domain -objects while staying behind the repository abstraction. Drift will manage -migrations. + +The project is SQLite-first. The local app persists scheduler state in a Drift +database and keeps storage details behind repository and application-unit-of-work +boundaries. + +The original V1 schema was implemented and then migrated to the current Drift +schema version 2 when application-layer records became durable state. ## Decision -* **Database file**: `adhd_scheduler.sqlite` in the user data directory. -* **Schema version**: `1` (managed by Drift). + +* **Database file**: `scheduler.sqlite` under `~/ADHD_Scheduler/` by default. + Runtime composition may override this with `SCHEDULER_SQLITE_PATH`, and dev + tooling may pass `--sqlite`. +* **Schema version**: `2`, managed by Drift. Version 1 files are supported as + migration inputs; downgrades are not supported. * **Tables** | Table | Purpose | Key fields | |-------|---------|------------| -| `tasks` | Authoritative task rows | `id TEXT PRIMARY KEY`, `owner_id TEXT`, `project_id`, `parent_id`, `type`, `status`, `priority`, `reward`, `difficulty`, `scheduled_start_utc`, `scheduled_end_utc`, `actual_start_utc`, `actual_end_utc`, `completed_at_utc`, `revision INT`, `created_at_utc`, `updated_at_utc`, `backlog_entered_at_utc`, `backlog_entered_provenance TEXT` | -| `projects` | Project configuration | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `color_key`, config defaults …, `archived_at_utc`, `revision` | -| `locked_blocks` | Recurring / one‑off locked time | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `date TEXT`, `start_time TEXT`, `end_time TEXT`, `recurrence_json`, `hidden_by_default INT`, `archived_at_utc`, `revision` | -| `locked_overrides` | Date‑scoped overrides | `id TEXT PRIMARY KEY`, `owner_id`, `locked_block_id`, `date TEXT`, `type`, JSON fields | -| `settings` | One row per owner | `owner_id TEXT PRIMARY KEY`, `timezone_id`, `day_start_minutes`, `day_end_minutes`, `compact_mode INT`, `revision` | -| `activities` | Append‑only internal events | `id TEXT PRIMARY KEY`, `owner_id`, `task_id`, `code`, `occurred_at_utc`, `metadata_json` | -| `snapshots` | Bounded diagnostic schedule snapshots | `id TEXT PRIMARY KEY`, `owner_id`, `operation_name`, `source_date TEXT`, `window_json`, `notice_json`, `changes_json`, `retention_expires_utc` | +| `tasks` | Authoritative task rows | `id TEXT PRIMARY KEY`, `owner_id`, `title`, `project_id`, `parent_id`, `type`, `status`, `priority`, `reward`, `difficulty`, `duration_minutes`, scheduled/actual/completed UTC timestamps, `backlog_tags_json`, `reminder_override`, `stats_json`, `backlog_entered_at_utc`, `backlog_entered_provenance`, `revision`, `created_at_utc`, `updated_at_utc` | +| `task_activities` | Append-only task activity facts | `id TEXT PRIMARY KEY`, `owner_id`, `task_id`, `project_id`, `operation_id`, `code`, `occurred_at_utc`, `metadata_json` | +| `projects` | Project configuration | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `color_key`, configured defaults, `archived_at_utc`, `revision`, `created_at_utc`, `updated_at_utc` | +| `project_statistics` | Project-level aggregate statistics | `project_id PRIMARY KEY`, `owner_id`, completion and suggestion-count fields, `revision`, `created_at_utc`, `updated_at_utc` | +| `locked_blocks` | Recurring / one-off locked time | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `date`, `start_time`, `end_time`, `recurrence_json`, `hidden_by_default`, `project_id`, `archived_at_utc`, `revision`, timestamps | +| `locked_overrides` | Date-scoped locked-block overrides | `id TEXT PRIMARY KEY`, `owner_id`, `locked_block_id`, `date`, override type and payload fields | +| `settings` | One row per owner | `owner_id TEXT PRIMARY KEY`, `timezone_id`, `day_start_minutes`, `day_end_minutes`, `compact_mode`, `backlog_staleness_json`, `revision`, timestamps | +| `snapshots` | Bounded diagnostic schedule snapshots | `id TEXT PRIMARY KEY`, `owner_id`, `captured_at_utc`, `operation_name`, `source_date`, `target_date`, JSON payload columns, `retention_expires_utc`, `truncated`, `revision`, timestamps | +| `application_operations` | Committed operation records for idempotency | `operation_id TEXT PRIMARY KEY`, `owner_id`, `operation_name`, `committed_at_utc` | +| `notice_acknowledgements` | Owner-scoped acknowledged notice records | composite key `owner_id, notice_id`, `acknowledged_at_utc`, `revision`, timestamps | -* All timestamps are stored as **UTC**. -* Optimistic concurrency: every mutable row carries `revision`. Updates must - include `WHERE revision = :expected` and increment on success. -* Drift migrations are generated and tested; downgrades are not supported. +* UTC timestamps are stored in Drift `DateTime` columns. Civil dates and wall + times remain text fields where the domain model requires calendar-local values. +* Mutable domain/application records carry optimistic `revision` values. Updates + must compare the expected revision and increment on success. Append-only + activity and operation records are immutable facts and do not use mutable-save + revision checks. +* Schema version 2 migrations create the application-layer tables and indexes + needed for task activity, project statistics, idempotent operations, and notice + acknowledgements. ## Consequences -* Domain objects remain unchanged; adapters translate. -* Backup library (Block 24) can copy and encrypt this single file. -* Repository contract tests assert schema integrity via Drift introspection. \ No newline at end of file + +* Domain objects remain unchanged; adapters translate between domain objects and + SQLite rows. +* The backup library copies and encrypts this single SQLite file. +* Repository conformance tests cover adapter behavior, while Drift schema tests + verify version 2 tables and version 1 upgrade behavior. diff --git a/Codex Documentation/Completed Plans/V1_ADR_005_Export_Backup_Boundary.md b/Codex Documentation/Completed Plans/V1_ADR_005_Export_Backup_Boundary.md index d469568..eae9fd6 100644 --- a/Codex Documentation/Completed Plans/V1_ADR_005_Export_Backup_Boundary.md +++ b/Codex Documentation/Completed Plans/V1_ADR_005_Export_Backup_Boundary.md @@ -1,9 +1,33 @@ + + + # V1 ADR 005: Export & Backup Boundary -Status: **Accepted** +Status: **Accepted; updated to match current app state** + Date: 2026-06-26 -* **Backup** – passphrase‑encrypted SQLite copy (`.sqlite.aes` via AES‑256‑GCM, PBKDF2 200 k rounds). -* **Readable export** – JSON and CSV via `ExportController`. +Last reviewed: 2026-07-07 + +## Decision + +* **Backup**: passphrase-encrypted copy of the local SQLite database bytes. + Defaults: + * source DB: `~/ADHD_Scheduler/scheduler.sqlite` + * backup directory: `~/ADHD_Scheduler/backups` + * backup filename: `yyyymmdd_hhmm.db.enc` +* **Backup cryptography**: AES-256-GCM with PBKDF2-HMAC-SHA256 key derivation, + 200,000 iterations, random salt, and random nonce. The encoded file is a JSON + envelope containing format metadata, salt, nonce, ciphertext, and MAC. +* **Restore**: decrypts a `.db.enc` backup and atomically replaces the target + SQLite file. +* **Readable export**: JSON and CSV are produced through `ExportController` and + export writer implementations. + +## Boundary + +Encrypted backup is the restorable binary preservation path for the SQLite +runtime database. JSON and CSV exports are readable user/data-portability outputs +and are not the canonical restore format. No open questions remain. diff --git a/Codex Documentation/Completed Plans/V1_ADR_006_Schedule_Snapshot_Policy.md b/Codex Documentation/Completed Plans/V1_ADR_006_Schedule_Snapshot_Policy.md index cb33034..edbb9c8 100644 --- a/Codex Documentation/Completed Plans/V1_ADR_006_Schedule_Snapshot_Policy.md +++ b/Codex Documentation/Completed Plans/V1_ADR_006_Schedule_Snapshot_Policy.md @@ -1,8 +1,32 @@ + + + # V1 ADR 006: Schedule Snapshot Policy -Status: **Accepted** +Status: **Accepted; updated to match current app state** + Date: 2026-06-26 -Persist committed diagnostic snapshots only; bounded retention 30 days or until notices acknowledged. +Last reviewed: 2026-07-07 -No open questions remain. +## Decision + +Persist committed diagnostic schedule snapshots only. Snapshots are diagnostic +records, not authoritative task state. + +Snapshot retention is bounded by a `retention_expires_utc` timestamp derived from +the snapshot capture time plus 30 days. Repository cleanup deletes snapshots whose +retention expiry is before the cleanup instant. + +Notice acknowledgement is stored separately in `notice_acknowledgements`. The +Today read model suppresses acknowledged notices when presenting pending notice +state, but acknowledgement does not delete the source snapshot early. + +## Consequences + +* Snapshot rows can remain available for diagnostics until their retention + expiry even after all displayed notices have been acknowledged. +* Notice acknowledgement is an application-layer read-model concern, not a + snapshot lifecycle rule. +* Cleanup jobs and tests should target `retention_expires_utc`, not notice + acknowledgement status. diff --git a/Codex Documentation/Completed Plans/V1_ADR_008_Notification_Abstraction.md b/Codex Documentation/Completed Plans/V1_ADR_008_Notification_Abstraction.md index 4a7afbe..1f254b7 100644 --- a/Codex Documentation/Completed Plans/V1_ADR_008_Notification_Abstraction.md +++ b/Codex Documentation/Completed Plans/V1_ADR_008_Notification_Abstraction.md @@ -1,8 +1,43 @@ + + + # V1 ADR 008: Notification Abstraction -Status: **Accepted** +Status: **Accepted; updated to match current app state** + Date: 2026-06-26 -`NotificationAdapter` interface abstracts scheduling/cancellation and feedback stream. Desktop implementation in `scheduler_notifications_desktop`; Fake adapter for tests. +Last reviewed: 2026-07-07 -No open questions remain. +## Decision + +`NotificationAdapter` in `scheduler_notifications` is the platform-neutral +boundary for reminder delivery. It exposes: + +* `schedule(NotificationRequest request)` +* `cancel(String id)` +* `Stream feedback` + +The pure scheduler core computes reminder policy and directive values only. It +does not import desktop, OS, process, or notification APIs. + +The test fake, `FakeNotificationAdapter`, stores scheduled requests, +normalizes/captures cancellations, and can emit feedback events for workflow +tests. + +The desktop implementation lives in `scheduler_notifications_desktop`. +It delegates to platform backends: + +* Linux: `notify-send` +* macOS: `osascript` +* Windows and unsupported platforms: stdout fallback + +The current desktop adapter satisfies the feedback-stream contract with an empty +stream. OS-level click/action feedback is not implemented in V1. + +## Consequences + +* Reminder delivery remains replaceable at the composition boundary. +* Core tests can use the fake adapter without depending on platform APIs. +* Future OS feedback support must extend the desktop package without changing + the scheduler core boundary. diff --git a/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_002_SQLite_Document_Schema_V1.md b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_002_SQLite_Document_Schema_V1.md new file mode 100644 index 0000000..a090eac --- /dev/null +++ b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_002_SQLite_Document_Schema_V1.md @@ -0,0 +1,38 @@ + + + +# V1 ADR 002: SQLite Document Schema V1 + +Status: **Accepted** +Date: 2026-06-26 + +## Context +The project pivoted from MongoDB to **SQLite‑first** persistence. +We need a stable, versioned relational schema that maps cleanly to the domain +objects while staying behind the repository abstraction. Drift will manage +migrations. + +## Decision +* **Database file**: `adhd_scheduler.sqlite` in the user data directory. +* **Schema version**: `1` (managed by Drift). +* **Tables** + +| Table | Purpose | Key fields | +|-------|---------|------------| +| `tasks` | Authoritative task rows | `id TEXT PRIMARY KEY`, `owner_id TEXT`, `project_id`, `parent_id`, `type`, `status`, `priority`, `reward`, `difficulty`, `scheduled_start_utc`, `scheduled_end_utc`, `actual_start_utc`, `actual_end_utc`, `completed_at_utc`, `revision INT`, `created_at_utc`, `updated_at_utc`, `backlog_entered_at_utc`, `backlog_entered_provenance TEXT` | +| `projects` | Project configuration | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `color_key`, config defaults …, `archived_at_utc`, `revision` | +| `locked_blocks` | Recurring / one‑off locked time | `id TEXT PRIMARY KEY`, `owner_id`, `name`, `date TEXT`, `start_time TEXT`, `end_time TEXT`, `recurrence_json`, `hidden_by_default INT`, `archived_at_utc`, `revision` | +| `locked_overrides` | Date‑scoped overrides | `id TEXT PRIMARY KEY`, `owner_id`, `locked_block_id`, `date TEXT`, `type`, JSON fields | +| `settings` | One row per owner | `owner_id TEXT PRIMARY KEY`, `timezone_id`, `day_start_minutes`, `day_end_minutes`, `compact_mode INT`, `revision` | +| `activities` | Append‑only internal events | `id TEXT PRIMARY KEY`, `owner_id`, `task_id`, `code`, `occurred_at_utc`, `metadata_json` | +| `snapshots` | Bounded diagnostic schedule snapshots | `id TEXT PRIMARY KEY`, `owner_id`, `operation_name`, `source_date TEXT`, `window_json`, `notice_json`, `changes_json`, `retention_expires_utc` | + +* All timestamps are stored as **UTC**. +* Optimistic concurrency: every mutable row carries `revision`. Updates must + include `WHERE revision = :expected` and increment on success. +* Drift migrations are generated and tested; downgrades are not supported. + +## Consequences +* Domain objects remain unchanged; adapters translate. +* Backup library (Block 24) can copy and encrypt this single file. +* Repository contract tests assert schema integrity via Drift introspection. diff --git a/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_005_Export_Backup_Boundary.md b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_005_Export_Backup_Boundary.md new file mode 100644 index 0000000..17dcd92 --- /dev/null +++ b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_005_Export_Backup_Boundary.md @@ -0,0 +1,12 @@ + + + +# V1 ADR 005: Export & Backup Boundary + +Status: **Accepted** +Date: 2026-06-26 + +* **Backup** – passphrase‑encrypted SQLite copy (`.sqlite.aes` via AES‑256‑GCM, PBKDF2 200 k rounds). +* **Readable export** – JSON and CSV via `ExportController`. + +No open questions remain. diff --git a/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_006_Schedule_Snapshot_Policy.md b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_006_Schedule_Snapshot_Policy.md new file mode 100644 index 0000000..83d39f2 --- /dev/null +++ b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_006_Schedule_Snapshot_Policy.md @@ -0,0 +1,11 @@ + + + +# V1 ADR 006: Schedule Snapshot Policy + +Status: **Accepted** +Date: 2026-06-26 + +Persist committed diagnostic snapshots only; bounded retention 30 days or until notices acknowledged. + +No open questions remain. diff --git a/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_008_Notification_Abstraction.md b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_008_Notification_Abstraction.md new file mode 100644 index 0000000..688a251 --- /dev/null +++ b/archive/Archived plans/2026-07-07 stale completed ADRs/V1_ADR_008_Notification_Abstraction.md @@ -0,0 +1,11 @@ + + + +# V1 ADR 008: Notification Abstraction + +Status: **Accepted** +Date: 2026-06-26 + +`NotificationAdapter` interface abstracts scheduling/cancellation and feedback stream. Desktop implementation in `scheduler_notifications_desktop`; Fake adapter for tests. + +No open questions remain.