docs: add curated completed plans snapshot

This commit is contained in:
Ashley Venn 2026-06-29 11:55:22 -07:00
parent 0adbed48b6
commit c6a6eb4297
35 changed files with 4288 additions and 0 deletions

View file

@ -0,0 +1,16 @@
# Completed Plans
This folder is a curated copy of archived plan documents that still match the
current SQLite-first application.
Included documents cover:
- Implemented core/domain/scheduling/backlog/locked-time work from Blocks 01-08,
using the updated Block 06-08 files where duplicate versions exist.
- Implemented backend hardening and application-layer work from Blocks 11-14.
- The completed SQLite-first plan set from Blocks 19-29, including the current
ADRs, public API baseline, and requirements traceability matrix.
Excluded documents include superseded originals, MongoDB-targeted persistence or
runtime plans, planned/blocked UI handoff plans, old archive indexes, and review
or gap artifacts that no longer describe the implemented app shape.

View file

@ -0,0 +1,131 @@
# V1 ADR 001: Lifecycle, Metadata, and Reminder Semantics
Status: Accepted during Block 11.2
Date: 2026-06-24
## Context
The human product specification lists `planned`, `completed`, `missed`,
`cancelled`, `no longer relevant`, `backlog`, `skipped`, and `pushed` under task
status. The current backend model exposes durable `TaskStatus` values for
lifecycle state and uses statistics/scheduling results for movement history.
V1 needs one durable meaning per field before later chunks add stronger
validation, activity records, application use cases, and persistence codecs.
## Decision
V1 durable task lifecycle states are:
- `planned`: queued or placed work that has not started.
- `active`: work currently in progress.
- `completed`: work finished by the user.
- `missed`: work that did not happen in its intended time and remains as
missed history.
- `cancelled`: work that was expected but intentionally will not happen.
- `noLongerRelevant`: work dismissed because circumstances changed.
- `backlog`: unscheduled work kept for later planning.
`pushed` is not a durable task lifecycle state. It is an activity/movement event
recorded through scheduling changes, Block 13/14 activity records, and counters such
as `manuallyPushedCount`, `autoPushedCount`, `movedToBacklogCount`, and
`restoredFromBacklogCount`.
`skipped during burnout` is not a V1 lifecycle state. V1 may keep compatible
statistics and schema fields such as `skippedDuringBurnoutCount`, but the
overwhelm shield and burnout catch-up workflow remain V2 work.
## Task Type Semantics
| Task type | V1 lifecycle behavior |
|---|---|
| Flexible | `planned` and `active` tasks may be moved by scheduling operations. `completed` records completion. `missed` means the intended slot was not used; recovery actions may reschedule it as `planned` or move it to `backlog`. `cancelled` and `noLongerRelevant` remove it from active planning. |
| Critical | Required visible commitment. Automatic flexible scheduling must not move it. If missed, V1 records a missed event and places the task in `backlog` so it remains actionable. The backlog status is the durable current state; missed history is recorded in activity/stat metadata. |
| Inflexible | Required visible time-bound commitment. Automatic flexible scheduling must not move it. If missed, it remains `missed` in its original planned interval as historical context. |
| Locked | Scheduling constraint, not a normal task card. Locked time should normally be represented by locked-block models and overlay read models. If imported as a task-shaped item, it should not receive normal flexible or required task actions. |
| Surprise | Unplanned completed work logged after the fact. It is created as `completed`. If it has an interval, that interval is actual occupied time and later same-day scheduling must not ignore it. |
| Free Slot | Protected intentional rest. It blocks automatic flexible placement and normal flexible reminder directives. Explicit critical or inflexible commitments may conflict with it, but automatic scheduling must not silently move the free slot. |
## Time and Metadata Fields
The following meanings are reserved for V1:
- Planned placement: `scheduledStart` and `scheduledEnd` represent where work or
a visible commitment is planned on the schedule.
- Actual work time: actual start/end must be represented by a distinct actual
interval, added in Block 12/13. It must not be inferred from `updatedAt`.
- Completion time: completion timestamp must be represented by a distinct
completion field, added in Block 13. It must not be inferred from `updatedAt`.
- Backlog-entry time: backlog age must use a distinct backlog-entered timestamp
once added in Blocks 13/15. The current starter model uses `createdAt` only as
a documented temporary baseline for staleness markers.
- Last modification time: `updatedAt` means only "last domain-level change". It
is not a proxy for backlog entry, completion, actual work, or missed time.
Current surprise-task logging stores the known surprise interval in the existing
schedule interval fields so the baseline scheduler can repair overlaps. Block 12
must split actual occupancy from planned placement and preserve surprise
occupancy for later same-day operations.
## Project Defaults, Learned Suggestions, and Task Overrides
These are separate concepts:
- System defaults are hard-coded fallback values such as inbox project,
medium priority, `RewardLevel.notSet`, and gentle reminders.
- Configured project defaults are user/project settings stored on
`ProjectProfile`, such as default priority, reward, difficulty, duration, and
reminder profile.
- Learned suggestions are non-blocking recommendations with provenance and
confidence. They never silently overwrite configured project defaults.
- Task overrides are explicit task-level choices that win over project defaults
for that task.
Effective value resolution for future configurable fields is:
1. Explicit task override.
2. Configured project default.
3. System default.
Learned suggestions may be shown as suggested values at creation or cleanup
time, but they do not become effective values unless the user accepts them as a
task override or configured project default.
## Reminder Policy Boundary
Reminder delivery through operating-system, background, or notification services
is outside the pure Dart core.
The backend/core may compute reminder policy inputs and directives:
- task-level reminder override, added in Block 13;
- configured project reminder profile;
- effective reminder profile resolver;
- free-slot suppression directive for normal flexible reminders;
- clear conflict/interrupt directives for critical and inflexible commitments.
Effective reminder profile resolution is:
1. Task reminder override, if present.
2. Project configured reminder profile.
3. System default `ReminderProfile.gentle`.
Free-slot suppression is not a reminder profile. It is a scheduling/rest policy
directive that can suppress normal flexible reminders during protected rest.
Block 13 implements these pure-core decisions through `ReminderPolicyService`
and typed `ReminderDirective` values without adding platform notification
delivery.
## Consequences
- Later chunks must not add `pushed` or `skipped` to `TaskStatus` to make the
human status list symmetrical.
- Movement, restore, skip, and push operations need idempotent activity/stat
records in Block 13/14.
- Block 12 must treat actual surprise occupancy as occupied time independent of
planned placement.
- Blocks 13 and 15 must add explicit metadata and document mappings instead of
overloading `updatedAt`.
- V1 keeps the V2 burnout vocabulary compatible in stats/schema only and does
not implement shield or catch-up workflows.

View file

@ -0,0 +1,35 @@
# V1 ADR 002: SQLite Document Schema V1
Status: **Accepted**
Date: 2026-06-26
## Context
The project pivoted from MongoDB to **SQLitefirst** 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 / oneoff 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` | Datescoped 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` | Appendonly 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.

View file

@ -0,0 +1,26 @@
# V1 ADR 003: Embedded Local Runtime Topology
Status: **Accepted**
Date: 2026-06-26
## Context
With SQLite as the local persistence engine, V1 no longer requires a separate
service process. The entire stack can run inside a single Flutter/Dart desktop
binary.
## Decision
* **Embedded DB** The application opens an ondisk SQLite file via Drift.
* **No background daemon** starting the desktop app is enough; automated tests
use an inmemory or temporaryfile database.
* **Dev hotreload** `scripts/dev.sh` launches Flutter desktop and watches
Drift files.
* **Pluggable adapters** A future remote/sync adapter will satisfy the same
repository interfaces; switching happens at composition root.
## Rejected
* Running a local Node.js or Go service to host SQLite unnecessary complexity.
* Direct file writes bypassing Drift loses migration guarantees.
## Consequences
* Deployment simplifies to one executable per platform.
* CI can run integration tests without Docker or external DB.

View file

@ -0,0 +1,9 @@
# V1 ADR 004: Repository & Domain Boundary
Status: **Accepted**
Date: 2026-06-26
Repository interfaces (`packages/scheduler_persistence`) expose **domain objects only**.
Adapters must implement optimistic revision, immutable returns, and pass the Repository Conformance Suite (Block 26).
No open questions remain.

View file

@ -0,0 +1,9 @@
# V1 ADR 005: Export & Backup Boundary
Status: **Accepted**
Date: 2026-06-26
* **Backup** passphraseencrypted SQLite copy (`.sqlite.aes` via AES256GCM, PBKDF2 200k rounds).
* **Readable export** JSON and CSV via `ExportController`.
No open questions remain.

View file

@ -0,0 +1,8 @@
# 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.

View file

@ -0,0 +1,8 @@
# V1 ADR 007: Test Strategy
Status: **Accepted**
Date: 2026-06-26
Four layers: Unit, Contract, Migration, Integration. CI fails below 80% line coverage.
No open questions remain.

View file

@ -0,0 +1,8 @@
# 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.

View file

@ -0,0 +1,102 @@
# V1 Block 01 — Project Foundation
Status: Completed
Purpose: Establish a clean Dart package foundation, repository conventions, and starter test loop. This block should leave the repository easy for Codex to modify safely.
## Chunk 1.1 — Verify project scaffold
Recommended Codex level: low
Status: Completed with environment blocker noted
Tasks:
- Inspect `pubspec.yaml`, `analysis_options.yaml`, `README.md`, and `.gitignore`.
- Confirm the repo is a pure Dart package, not a Flutter app yet.
- Confirm `lib/scheduler_core.dart` exports only stable public entry points.
- Confirm `lib/src/` contains implementation files.
- Confirm `test/` contains at least one starter test.
Acceptance criteria:
- `dart pub get` succeeds, or any dependency issue is documented.
- `dart analyze` succeeds, or initial scaffold issues are fixed.
- `dart test` succeeds, or the failure is fixed.
Execution notes:
- Verified `pubspec.yaml`, `analysis_options.yaml`, `README.md`, and `.gitignore`.
- Confirmed the repository is currently structured as a pure Dart package, not a Flutter app.
- Confirmed `lib/scheduler_core.dart` exports the starter public entry points from `lib/src/`.
- Confirmed `lib/src/` contains implementation files and `test/` contains a starter scheduling engine test.
- Could not run `dart pub get`, `dart analyze`, or `dart test` because neither `dart` nor `flutter` is installed on `PATH` in this environment.
- Commit was deferred until the repository was initialized and repaired.
Commit suggestion:
```text
chore(project): verify starter dart scaffold
```
## Chunk 1.2 — Stabilize public API boundaries
Recommended Codex level: medium
Status: Completed with environment blocker noted
Tasks:
- Keep public exports in `lib/scheduler_core.dart` minimal.
- Ensure internal helpers remain under `lib/src/`.
- Add comments that identify which APIs are starter placeholders.
- Do not add Flutter UI code in this block.
Acceptance criteria:
- Public API is small and understandable.
- Internal implementation is not accidentally exported beyond current needs.
- Analyzer and tests pass.
Execution notes:
- Kept `lib/scheduler_core.dart` exports limited to the existing starter model, scheduling engine, and statistics surfaces.
- Confirmed implementation remains under `lib/src/`.
- Added public documentation comments that identify the starter placeholder APIs without changing scheduling behavior.
- Did not add Flutter UI code.
- Could not run `dart analyze` or `dart test` because neither `dart` nor `flutter` is installed on `PATH` in this environment.
- Commit was deferred until the repository was initialized and repaired.
BREAKPOINT: Stop here if the next requested chunk changes Codex level.
## Chunk 1.3 — Document local development commands
Recommended Codex level: low
Status: Completed with environment blocker noted
Tasks:
- Update `README.md` with setup, analyze, test, and project layout notes if missing.
- Do not duplicate the full product spec in README.
- Keep human/product detail in `Human Documentation/`.
- Keep execution detail in `Codex Documentation/`.
Acceptance criteria:
- README tells a new contributor how to run checks.
- README points Codex/humans to the correct documentation folders.
Execution notes:
- Updated `README.md` with the Dart SDK prerequisite, local setup/check commands, and when to run them.
- Added documentation boundary notes for `Human Documentation/`, `Codex Documentation/Current Software Plan/`, and `Codex Documentation/Archived plans/`.
- Did not duplicate the full product spec in `README.md`.
- Could not run `dart analyze` or `dart test` because neither `dart` nor `flutter` is installed on `PATH` in this environment.
- Commit was deferred until the repository was initialized and repaired.
Commit suggestion:
```text
docs(project): document starter development workflow
```

View file

@ -0,0 +1,172 @@
# V1 Block 02 — Domain Model
Status: Completed
Purpose: Define the core data vocabulary for the scheduling app. This model should be UI-independent and testable.
## Chunk 2.1 — Define core enums
Recommended Codex level: medium
Status: Completed with environment blocker noted
Tasks:
Add or verify enums for:
- `TaskType`: flexible, inflexible, critical, locked, surprise, freeSlot.
- `TaskStatus`: planned, active, completed, missed, cancelled, noLongerRelevant, backlog.
- `PriorityLevel`: veryLow, low, medium, high, veryHigh.
- `RewardLevel`: veryLow, low, medium, high, veryHigh, notSet.
- `DifficultyLevel`: veryEasy, easy, medium, hard, veryHard, notSet.
- `ReminderProfile`: silent, gentle, persistent, strict.
Rules:
- Reward `notSet` is its own category and must not be treated as low.
- Difficulty may have `notSet` for raw capture/default states.
- Critical and inflexible are required visible items.
- Locked blocks are hidden scheduling constraints, not ordinary tasks.
Acceptance criteria:
- Enums exist in the domain model.
- Comments document the business meaning of each value.
- Tests can import and use the enum values.
Execution notes:
- Verified all required enum values exist in `lib/src/models.dart`.
- Added business-meaning documentation comments for status, priority, reward, difficulty, and reminder values.
- Preserved `RewardLevel.notSet` and `DifficultyLevel.notSet` as neutral capture/default states.
- Added a test that imports and references core enum values through the public package export.
## Chunk 2.2 — Define task identity and fields
Recommended Codex level: high
Status: Completed with environment blocker noted
Tasks:
Create or refine a `Task` model with fields for:
- `id`
- `title`
- `projectId`
- `type`
- `status`
- `priority`
- `reward`
- `difficulty`
- `durationMinutes`
- `scheduledStart`
- `scheduledEnd`
- `parentTaskId`
- `createdAt`
- `updatedAt`
- `stats`
Rules:
- Use a copy/update pattern rather than mutating shared state unexpectedly.
- Allow optional fields for quick capture.
- Do not require every task to have reward/difficulty/time.
- Include validation helper(s) only if needed.
Acceptance criteria:
- A task can represent backlog, planned, critical, locked, and surprise items.
- A quick-capture task can be created with minimal fields.
- Tests cover default/neutral quick-capture values.
Execution notes:
- Kept the immutable `Task` model and `copyWith` update pattern.
- Added `Task.quickCapture` for minimal capture with neutral defaults and no required schedule details.
- Added tests for quick-capture defaults, including `RewardLevel.notSet`, `DifficultyLevel.notSet`, and absent schedule/duration.
BREAKPOINT: Stop here. The next chunk remains high but may expand model scope.
## Chunk 2.3 — Define project and project defaults
Recommended Codex level: high
Status: Completed with environment blocker noted
Tasks:
Create a minimal `ProjectProfile` or equivalent model with:
- `id`
- `name`
- `colorKey` or theme token
- default priority
- default reward
- default difficulty
- default reminder profile
- default duration minutes
Rules:
- Project defaults are suggestions/defaults, not hard requirements.
- Individual tasks can override project defaults.
- Learned usage statistics are future-facing; do not overbuild now.
Acceptance criteria:
- Tasks can reference a project.
- Project defaults can be applied when creating a task.
- Overrides remain possible.
Execution notes:
- Kept `ProjectProfile` minimal with id, name, color key, default priority, default reward, default difficulty, default reminder profile, and default duration.
- Added `ProjectProfile.createTask` to apply project defaults while allowing explicit task overrides.
- Added tests for default application and per-task overrides.
## Chunk 2.4 — Define task statistics model
Recommended Codex level: medium
Status: Completed with environment blocker noted
Tasks:
Add or verify a `TaskStatistics` model with counters for:
- skippedDuringBurnoutCount
- manuallyPushedCount
- autoPushedCount
- movedToBacklogCount
- restoredFromBacklogCount
- missedCount
- cancelledCount
- completedLateCount
- completedDuringLockedHoursCount
- completedDuringLockedHoursMinutes
Rules:
- Stats are internal metadata.
- Stats should support future filtering/reporting.
- Do not build report UI in V1.
Acceptance criteria:
- Statistics can be incremented through copy/update helpers.
- Tests cover at least one increment path.
Execution notes:
- Verified all required statistics counters exist.
- Added immutable increment helpers for remaining counters.
- Added a test covering a statistics increment path and preservation of existing values.
- Could not run `dart analyze` or `dart test` because neither `dart` nor `flutter` is installed on `PATH` in this environment.
- Commit was deferred until the repository was initialized and repaired.
Commit suggestion:
```text
feat(domain): define scheduling task model
```

View file

@ -0,0 +1,188 @@
# V1 Block 03 — Scheduling Engine
Status: Completed
Purpose: Implement the core behavior that makes this product valuable: flexible tasks move safely without destroying the user's intended order.
## Chunk 3.1 — Define scheduling inputs and outputs
Recommended Codex level: high
Status: Completed with environment blocker noted
Tasks:
Create clear models/functions for scheduling operations:
- Current task list.
- Locked intervals.
- Required visible intervals.
- Flexible intervals/tasks.
- Scheduling window.
- Operation result with changed tasks and notices.
Rules:
- Scheduling functions should be deterministic.
- Avoid direct database access inside the engine.
- Return results; do not hide side effects.
Acceptance criteria:
- Scheduling engine can be called with in-memory data.
- Result object can describe moved tasks and overlaps.
- Tests can assert exact task placement results.
Execution notes:
- Added `SchedulingWindow`, `SchedulingInput`, `SchedulingChange`, and `SchedulingOverlap` models.
- Expanded `SchedulingResult` and `SchedulingNotice` so operation results can report changed task placements, overlap details, and typed notices.
- Added `SchedulingEngine.analyzeSchedule` for deterministic in-memory schedule analysis without moving tasks or touching persistence.
- Added tests for in-memory task grouping, overlap reporting, and exact movement-change representation.
- Initial Dart verification was blocked while the SDK was unavailable; after repair, `dart analyze` and `dart test` passed.
- Committed after the repository was initialized and repaired.
## Chunk 3.2 — Insert backlog task into next available flexible slot
Recommended Codex level: extra high
Status: Completed with environment blocker noted
Tasks:
Implement insertion behavior:
- A backlog item can be inserted into the soonest flexible slot where it fits.
- Later flexible tasks shift forward using normal bump rules.
- Locked, inflexible, and critical blocks do not move.
- If no slot exists today, return a clear overflow result.
Acceptance criteria:
- Test: insert 15-minute task into an open 20-minute slot.
- Test: insert task before flexible task and push later flexible task.
- Test: insertion skips locked time.
- Test: insertion does not move inflexible/critical blocks.
- Test: no available slot returns an overflow/no-fit result.
Execution notes:
- Added `SchedulingEngine.insertBacklogTaskIntoNextAvailableSlot`.
- Backlog insertion now requires a flexible backlog task with positive duration.
- The insertion planner schedules the task into the earliest available in-window slot, skips locked/required visible time, and preserves planned flexible task order while pushing affected flexible tasks later.
- Locked, inflexible, critical, and non-planned scheduled flexible intervals are treated as fixed for this operation.
- Successful insertion returns updated tasks, movement notices, and exact `SchedulingChange` records.
- No-fit and overflow cases return the original task list with a typed notice.
- Added tests for open-slot insertion, bumping a later flexible task, skipping locked time, preserving inflexible/critical blocks, and overflow/no-fit.
- Initial Dart verification was blocked while the SDK was unavailable; after repair, `dart analyze` and `dart test` passed.
- Committed after the repository was initialized and repaired.
BREAKPOINT: Stop here. Confirm `extra high` mode before starting this chunk if not already set.
## Chunk 3.3 — Push flexible task to next available slot
Recommended Codex level: extra high
Status: Completed
Tasks:
Implement push behavior:
- `Push -> Next available slot` moves the selected flexible task to the next slot where it fits.
- Later flexible tasks shift forward.
- Preserve order among affected flexible tasks.
- Do not move locked, inflexible, or critical blocks.
Acceptance criteria:
- Test: pushed flexible task moves after current slot.
- Test: downstream flexible tasks are bumped in order.
- Test: locked intervals are respected.
- Test: required items remain fixed and visible.
Execution notes:
- Added `SchedulingEngine.pushFlexibleTaskToNextAvailableSlot`.
- Push requires a planned flexible task with an existing scheduled interval and positive duration.
- The selected task moves after its current slot; downstream planned flexible tasks shift later in their existing order.
- Locked, inflexible, critical, non-planned, and earlier flexible intervals remain fixed or untouched.
- Successful push returns updated tasks, movement notices, and exact `SchedulingChange` records.
- Added tests for moving after the current slot, bumping downstream flexible tasks, respecting locked intervals, and preserving required visible items.
- `dart analyze` and `dart test` passed.
## Chunk 3.4 — Push flexible task to tomorrow top of queue
Recommended Codex level: high
Status: Completed
Tasks:
Implement tomorrow behavior:
- `Push -> Tomorrow` places the task at the top of tomorrow's flexible queue.
- Preserve order among multiple rolled/pushed tasks where applicable.
- Do not require manual scheduling.
Acceptance criteria:
- Test: task receives tomorrow date/queue marker.
- Test: task is before other flexible tomorrow tasks unless required/locked time blocks it.
Execution notes:
- Added `SchedulingEngine.pushFlexibleTaskToTomorrowTopOfQueue`.
- The input scheduling window represents tomorrow's flexible scheduling window.
- The selected planned flexible task is placed in the earliest available tomorrow slot and existing planned flexible tasks in that window shift later while preserving order.
- Locked and required visible time in the tomorrow window remains fixed.
- Successful tomorrow push returns updated tasks, movement notices, and exact `SchedulingChange` records.
- Added tests for tomorrow top-of-queue placement and locked/required blocking behavior.
- `dart analyze` and `dart test` passed.
BREAKPOINT: Stop here. The next chunk drops from high/extra high to medium.
## Chunk 3.5 — End-of-day rollover
Recommended Codex level: medium
Status: Completed
Tasks:
Implement rollover behavior:
- At end of day, unfinished flexible tasks move to tomorrow.
- Rolled tasks go to top of tomorrow's flexible queue.
- Preserve order among rolled-over tasks.
- Produce a small notice such as `3 unfinished flexible tasks were moved to tomorrow`.
Do not roll over:
- Locked blocks.
- Inflexible tasks.
- Critical tasks without explicit missed/backlog handling.
- Cancelled tasks.
- Completed tasks.
Acceptance criteria:
- Tests cover all included and excluded task types.
- Notice text/count is generated.
Execution notes:
- Added `SchedulingEngine.rollOverUnfinishedFlexibleTasks`.
- Rollover moves planned and active flexible tasks that are not already in the tomorrow window.
- Rolled tasks are placed at the top of tomorrow's flexible queue, preserving current order.
- Existing planned flexible tasks in the tomorrow window shift later while preserving order.
- Locked, inflexible, critical, completed, and cancelled tasks remain unchanged.
- Rollover returns exact `SchedulingChange` records and a count notice.
- Added tests for included flexible tasks, excluded task types/statuses, order preservation, downstream tomorrow bumps, and notice count generation.
- `dart analyze` and `dart test` passed.
Commit suggestion:
```text
feat(scheduling): implement flexible task movement rules
```

View file

@ -0,0 +1,148 @@
# V1 Block 04 — Backlog and Quick Capture
Status: Completed
Purpose: Support low-friction task capture and a unified backlog/wishlist model.
## Chunk 4.1 — Backlog model and filters
Recommended Codex level: medium
Status: Completed
Tasks:
Implement backlog-friendly task metadata:
- unified backlog storage/state
- filter tags or derived filters for inbox, pushed, critical missed, wishlist, stale, no reward set
- sorting keys for priority, reward vs effort, age, project, times pushed
Rules:
- Do not create separate hard backlog sections.
- Use unified backlog with filters/sorts.
- Do not preserve original schedule/order metadata when moved to backlog.
Acceptance criteria:
- Backlog tasks can be filtered by derived category.
- Moving to backlog clears active schedule placement.
- Tests verify original schedule order is not used to restore backlog items.
Execution notes:
- Added `BacklogView` as a read-only projection over the unified task list.
- Added derived backlog filters for inbox, pushed, critical missed, wishlist, stale, and no reward set.
- Added backlog sort keys for priority, reward vs effort, age, project, and times pushed.
- Added `BacklogTag.wishlist` metadata without creating separate hard backlog sections.
- Verified moving to backlog clears active schedule placement and backlog age sorting does not use original schedule order.
- `dart analyze` and `dart test` passed.
## Chunk 4.2 — Quick capture defaults
Recommended Codex level: medium
Status: Completed
Tasks:
Implement quick capture creation rules:
- Title is required.
- Default destination is backlog.
- Priority defaults to medium.
- Reward defaults to notSet.
- Difficulty may default to notSet or medium depending on model decision.
- Project defaults to Inbox/Unsorted.
- Time can remain unset.
Acceptance criteria:
- Test: minimal quick capture creates backlog task.
- Test: neutral defaults are applied.
- Test: reward notSet is preserved distinctly.
Execution notes:
- Updated `Task.quickCapture` to require a non-empty title.
- Default quick capture destination remains backlog.
- Priority now defaults to `PriorityLevel.medium`.
- Reward defaults to `RewardLevel.notSet` and remains distinct from low reward.
- Difficulty defaults to `DifficultyLevel.notSet`.
- Project defaults to `inbox`, and time remains unset.
- Added tests for title validation and neutral defaults.
- `dart analyze` and `dart test` passed.
## Chunk 4.3 — Quick capture schedule checkbox behavior
Recommended Codex level: high
Status: Completed
Tasks:
Implement behavior for `Add to next available schedule slot`:
- When unchecked, task enters backlog.
- When checked, optional scheduling fields become relevant:
- duration
- priority
- reward
- project
- flexibility
- If duration is missing, return a validation result or use a documented default.
- Insert into soonest flexible slot using the scheduling engine.
Acceptance criteria:
- Test: unchecked quick capture goes to backlog.
- Test: checked quick capture with duration schedules into next available slot.
- Test: checked quick capture without required scheduling fields is handled predictably.
Execution notes:
- Added `QuickCaptureRequest`, `QuickCaptureResult`, `QuickCaptureStatus`, and `QuickCaptureService`.
- Unchecked quick capture creates a backlog task and does not invoke scheduling.
- Checked quick capture validates duration and flexibility before scheduling.
- Missing duration returns a validation result while preserving the captured backlog task.
- Checked quick capture with duration inserts into the next available flexible slot through `SchedulingEngine.insertBacklogTaskIntoNextAvailableSlot`.
- Added tests for unchecked backlog capture, checked scheduling, and checked validation behavior.
- `dart analyze` and `dart test` passed.
BREAKPOINT: Stop here. Confirm `high` mode before implementing scheduling integration.
## Chunk 4.4 — Backlog staleness marker calculation
Recommended Codex level: low
Status: Completed
Tasks:
Implement age/staleness calculation for backlog display:
- Green: 07 days by default.
- Blue: 830 days by default.
- Purple: 31+ days by default.
- Thresholds must be configurable constants/settings model, not hardcoded everywhere.
- No automatic prompts per stale task.
Acceptance criteria:
- Tests cover fresh, aging, stale, and configurable thresholds.
Execution notes:
- Added `BacklogStalenessMarker` values for green, blue, and purple display buckets.
- Added `BacklogStalenessSettings` with configurable green and blue thresholds.
- Added `BacklogView.stalenessMarkerFor` to calculate display marker state without side effects or prompts.
- Default thresholds are green through 7 days, blue through 30 days, and purple from 31 days onward.
- Added tests for fresh, aging, stale, and custom threshold behavior.
- `dart analyze` and `dart test` passed.
Commit suggestion:
```text
feat(backlog): add unified backlog and quick capture rules
```

View file

@ -0,0 +1,141 @@
# V1 Block 05 — Recurring Locked Blocks
Status: Completed
Purpose: Locked blocks are critical MVP. They reserve time, stay hidden by default, and are not tasks.
## Chunk 5.1 — Locked block model
Recommended Codex level: high
Status: Completed
Tasks:
Create a model for locked blocks with:
- id
- name
- start/end time
- recurrence rule or simple recurrence model
- hiddenByDefault flag
- project/category optional field
- created/updated timestamps
Rules:
- Locked blocks are scheduling constraints.
- They must not render as ordinary tasks.
- They may have names in overlay mode.
Acceptance criteria:
- Model supports one-off and recurring locked blocks.
- Work-hours style recurrence can be represented.
Execution notes:
- Added `ClockTime`, `LockedWeekday`, `LockedBlockRecurrence`, and `LockedBlock`.
- Locked blocks include id, name, start/end time, optional recurrence, hidden-by-default flag, optional project id, and created/updated timestamps.
- Locked blocks remain scheduling constraints and are not modeled as ordinary tasks.
- One-off locked blocks and weekday work-hours recurrence are represented.
- Added tests for one-off locked blocks and weekday work-hours recurrence.
- `dart analyze` and `dart test` passed.
## Chunk 5.2 — One-day override model
Recommended Codex level: high
Status: Completed
Tasks:
Support one-day overrides for recurring locked blocks:
- remove a locked occurrence for a date
- shorten/extend an occurrence for a date
- add surprise locked time for a date
- avoid changing the base recurrence rule
Acceptance criteria:
- Test: Friday off removes only Friday occurrence.
- Test: half-day modifies only one date.
- Test: recurring rule remains unchanged.
Execution notes:
- Added `LockedBlockOverrideType` and `LockedBlockOverride`.
- Overrides support removing one occurrence, replacing one occurrence's times, and adding surprise locked time for one date.
- Override objects do not mutate the base recurrence rule.
- Added tests for Friday-off removal, half-day replacement, surprise locked time, and unchanged recurrence.
- `dart analyze` and `dart test` passed.
BREAKPOINT: Stop here. Confirm `high` mode before handling recurrence/override expansion.
## Chunk 5.3 — Expand locked blocks into schedule constraints
Recommended Codex level: extra high
Status: Completed
Tasks:
Implement expansion from recurring locked blocks + overrides into concrete intervals for a day.
Rules:
- Hidden-by-default affects UI only, not scheduling.
- The scheduling engine must always respect locked intervals.
- Overlay mode can reveal names and times.
Acceptance criteria:
- Test: recurring work block appears on weekdays.
- Test: one-day override removes/modifies the occurrence.
- Test: scheduling engine sees the final locked intervals.
Execution notes:
- Added an explicit `date` field for one-off locked blocks so non-recurring constraints have a testable calendar anchor.
- Added `LockedBlockOccurrence`, `LockedScheduleExpansion`, `expandLockedBlocksForDay`, and `lockedSchedulingIntervalsForDay`.
- Expansion resolves weekly recurrence, one-day remove/replace overrides, and added surprise locked time for a target day.
- Hidden-by-default remains occurrence metadata only; scheduler-facing intervals are always returned for scheduling.
- Added tests for weekday recurrence expansion, one-day remove/replace behavior, surprise locked time expansion, and scheduling engine use of final expanded locked intervals.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
## Chunk 5.4 — Track completed during locked hours
Recommended Codex level: medium
Status: Completed
Tasks:
Add helper logic to detect when a completed/surprise task overlaps locked time.
Track:
- completedDuringLockedHoursCount
- completedDuringLockedHoursMinutes
- projects completed during locked hours, if project stats exist
Acceptance criteria:
- Tests cover task completed entirely inside locked time.
- Tests cover partial overlap.
- Tests cover no overlap.
Execution notes:
- Added `completedDuringLockedHoursMinutes` to calculate completed/surprise task overlap with locked intervals.
- Added `trackCompletedDuringLockedHours` to return an updated task with locked-hour completion statistics when overlap exists.
- Overlap calculation merges intersecting locked intervals before counting minutes to avoid double counting.
- Added tests for tasks entirely inside locked time, partial overlap, no overlap, surprise task overlap, and overlapping locked intervals.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
Commit suggestion:
```text
feat(locked-time): support recurring hidden scheduling blocks
```

View file

@ -0,0 +1,350 @@
# V1 Block 06 — Task Actions and State Transitions
Status: Completed
Purpose: Define and implement the safe, low-friction actions available from task cards.
This block must keep task actions predictable, testable, and aligned with the MVP product rules. Do not add UI, sync, persistence, reports, child-task implementation, or timeline rendering here unless a chunk explicitly asks for it.
## Chunk 6.1 — Flexible task quick actions
Recommended Codex level: medium
Status: Completed
Tasks:
Support these quick actions for flexible task cards:
- Done
- Push
- Backlog
- Break up
Rules:
- Done marks completed.
- Push opens simple push destinations.
- Backlog moves to unified backlog and does not preserve original schedule order.
- Break up starts child task flow; full implementation in Block 07.
Acceptance criteria:
- Tests cover done and backlog state transitions.
- Push destination selection is represented in domain layer.
Execution notes:
- Added `FlexibleTaskActionService` for flexible card quick actions.
- Added `FlexibleTaskQuickAction` and `PushDestination` domain enums.
- Done marks a flexible task completed without changing its schedule placement.
- Backlog uses the scheduling engine backlog transition and clears schedule placement.
- Push returns explicit domain destinations: next available slot, tomorrow/top of queue, and backlog.
- Break up returns an explicit child-task-flow intent without creating children yet.
- Added tests for done, backlog, push destination representation, and break-up flow intent.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
## Chunk 6.2 — Push destination behavior
Recommended Codex level: high
Status: Completed
Tasks:
Implement push destinations:
- Next available slot.
- Tomorrow/top of queue.
- Backlog.
Explicitly exclude:
- Later today.
Acceptance criteria:
- Test: next available uses scheduling engine.
- Test: tomorrow sets tomorrow/top-of-queue metadata.
- Test: backlog clears schedule placement.
Execution notes:
- Added `PushDestinationResult` to carry selected destination metadata with the scheduling result.
- Added `FlexibleTaskActionService.applyPushDestination`.
- Next available delegates to `SchedulingEngine.pushFlexibleTaskToNextAvailableSlot`.
- Tomorrow/top-of-queue delegates to `SchedulingEngine.pushFlexibleTaskToTomorrowTopOfQueue` and reports `placesAtTomorrowTopOfQueue`.
- Backlog destination updates the task list with `SchedulingEngine.moveToBacklog`, clears placement, and records a scheduling change.
- `PushDestination` remains limited to next available slot, tomorrow/top of queue, and backlog; later today is not represented.
- Added tests for next available, tomorrow/top-of-queue metadata, backlog clearing schedule placement, and the excluded later-today destination.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
BREAKPOINT: Stop here. Confirm `extra high` mode before implementing Chunk 6.3, because the next chunk expands the regression and edge-case test suite and may require small correctness fixes.
## Chunk 6.3 — Edge-case regression test suite
Recommended Codex level: extra high
Status: Completed
Purpose:
Before adding more state-transition behavior, harden the existing implementation with a dedicated regression test suite. The goal is to prove that Blocks 02 through 06.2 are reliable before layering required-task states, surprise-task logging, child tasks, timeline state, or persistence on top of them.
Scope:
- Add tests first where possible.
- Make the smallest code changes needed to satisfy tests when tests expose real behavior gaps.
- Do not implement Required Task States from Chunk 6.4.
- Do not implement Surprise Task Logging from Chunk 6.5.
- Do not add Flutter UI.
- Do not add persistence/database code.
- Do not add sync/network behavior.
Required test organization:
- Keep existing tests passing.
- Split tests into clearer files if useful, for example:
- `test/models_test.dart`
- `test/scheduling_engine_test.dart`
- `test/backlog_test.dart`
- `test/quick_capture_test.dart`
- `test/locked_time_test.dart`
- `test/task_actions_test.dart`
- If tests remain in one file temporarily, group them with clear `group(...)` blocks.
Required edge-case coverage:
1. Domain model and copy behavior
Add or confirm tests for:
- `Task.quickCapture` trims titles.
- `Task.quickCapture` rejects empty/whitespace-only titles.
- `Task.copyWith(clearSchedule: true)` clears both `scheduledStart` and `scheduledEnd`.
- `Task.copyWith` preserves existing values when fields are not supplied.
- Any new nullable-field clear behavior, if added, is explicitly tested.
- `ProjectProfile.createTask` rejects empty/whitespace-only task titles, matching quick-capture behavior.
2. Flexible scheduling and push behavior
Add or confirm tests for:
- Next-available insertion uses the earliest flexible slot where the task fits.
- Inserting a backlog task pushes later flexible tasks forward in order.
- Flexible task order is preserved after pushing.
- Locked intervals are never moved.
- Inflexible intervals are never moved.
- Critical intervals are never moved.
- If no available slot exists, the result leaves the task unscheduled/backlogged rather than corrupting the plan.
- `PushDestination.nextAvailableSlot` delegates to the scheduling engine.
- `PushDestination.tomorrowTopOfQueue` places the task at the top of tomorrows flexible queue.
- `PushDestination.backlog` clears schedule placement and does not preserve original active-plan order.
3. End-of-day rollover safety
Add tests that specifically prevent accidental rollover corruption:
- Only unfinished flexible tasks from the intended source day roll over.
- Completed flexible tasks do not roll over.
- Cancelled tasks do not roll over.
- Backlogged tasks do not roll over.
- Critical tasks do not roll over through the flexible rollover path.
- Inflexible tasks do not roll over through the flexible rollover path.
- Future flexible tasks outside the source-day window are not pulled into tomorrow accidentally.
- Rolled-over tasks appear at the top of tomorrows flexible queue and preserve relative order among themselves.
If the current rollover API lacks enough source-day context, adjust the API minimally so the source-day boundary is explicit and covered by tests.
4. Backlog behavior and staleness
Add or confirm tests for:
- Unified backlog filtering by status/category works as expected.
- Pushed, critical-missed, wishlist, inbox, stale, and no-reward-set filters do not overlap incorrectly.
- Sorting by priority is stable and deterministic.
- Sorting by reward-vs-effort treats `RewardLevel.notSet` as its own neutral/unknown category, not as equivalent to very low reward.
- Sorting by age is deterministic when multiple tasks have the same age marker.
- Staleness marker thresholds match the configured/default rules:
- younger than/equal to 7 days = fresh/green
- older than 7 days through 30 days = aging/blue
- older than 30 days = stale/purple
- Stale filtering and staleness marker behavior use consistent timestamp semantics.
If the current model cannot distinguish task creation age from backlog age, do not add database persistence yet. Either document the limitation in code comments/tests or add a minimal in-memory/domain field only if necessary and safe for MVP.
5. Quick capture behavior
Add or confirm tests for:
- Quick capture defaults to backlog/inbox/unsorted behavior.
- Priority defaults to medium.
- Reward defaults to not set.
- Duration can remain unset when the task is not immediately scheduled.
- Checking “add to next available slot” requires or collects enough scheduling data to place the task.
- Quick capture with immediate scheduling uses normal flexible insertion/push rules.
- Quick capture cannot create blank tasks.
6. Locked block and overlay-domain behavior
Add or confirm tests for:
- Recurring locked blocks expand into concrete blocked intervals for the requested day.
- One-day remove override removes only that days instance.
- One-day replace override changes only that days interval.
- One-day add override adds surprise locked time without changing the recurring rule.
- Locked blocks are hidden by default in normal task-style output/domain views.
- Overlay/reveal data can expose the locked block name as blocked time, not as a normal task.
- Completed-during-locked-hours counters increment correctly.
- Tasks completed outside locked hours do not increment locked-hour counters.
7. Flexible action service behavior
Add or confirm tests for:
- `Done` marks flexible task completed.
- `Backlog` moves the task to backlog and clears schedule.
- `Push` returns only supported destinations.
- `Break up` returns an intent only and does not create child tasks in Block 06.
- Unsupported action/type combinations fail safely and predictably.
8. Regression and safety checks
Add tests or assertions for:
- No duplicate task IDs are created by task-action helpers unless explicitly intended.
- Scheduling results include enough change metadata for later UI/reporting.
- Required/inflexible/locked blocks are never silently converted into flexible tasks.
- All public domain services avoid mutating input lists in place unless explicitly documented.
Acceptance criteria:
- Existing test count increases meaningfully beyond the current baseline.
- The new tests cover edge cases from Blocks 02 through 06.2.
- Any code changes are minimal and directly tied to failing edge-case tests.
- No Required Task States implementation is added in this chunk.
- No Surprise Task Logging implementation is added in this chunk.
- `dart format lib test` passes.
- `dart analyze` passes.
- `dart test` passes.
- `git diff --check` passes.
- Commit with a conventional commit message.
Commit suggestion:
```text
test(tasks): add edge-case regression coverage before state transitions
```
Execution notes:
- Added `test/edge_case_regression_test.dart` as a dedicated Block 06.3 regression suite.
- Covered task title trimming/validation, `copyWith(clearSchedule: true)`, ProjectProfile task creation validation, flexible insertion no-fit safety, push order/fixed-item preservation, explicit source-window rollover safety, stable backlog sorting, consistent backlog staleness timestamps, quick capture scheduling validation, locked overlay-domain data, locked-hour counters, action-service unsupported-type handling, duplicate-id safety, change metadata, and input-list immutability.
- Added optional `sourceWindow` to `SchedulingEngine.rollOverUnfinishedFlexibleTasks` so day-end rollover can explicitly limit rolled tasks to the intended source day while preserving existing callers.
- Updated backlog stale filtering to use the same creation-age basis as staleness markers; V1 still documents that a separate backlog-entered timestamp belongs to later persistence work.
- Made `ProjectProfile.createTask` trim and reject blank titles, matching quick-capture validation.
- Made backlog sorting stable for equal sort keys by preserving source-list order.
- No Required Task States implementation was added in this chunk.
- No Surprise Task Logging implementation was added in this chunk.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
BREAKPOINT: Stop here. Confirm `medium` mode before implementing Chunk 6.4 required task state transitions.
## Chunk 6.4 — Required task states
Recommended Codex level: medium
Status: Completed
Tasks:
Implement required task state meanings:
- Done: completed.
- Missed: did not happen; visible as missed but not aggressively styled.
- Cancel: did not/will not happen; remove from active plan.
- No longer relevant: separate from cancelled.
Rules:
- Critical missed tasks move to backlog.
- Required/inflexible missed tasks remain in place/history and are marked missed.
- Cancelled and noLongerRelevant are distinct statuses.
- Locked blocks are not normal tasks and should not be handled by this state-transition service as task cards.
Acceptance criteria:
- Tests cover critical missed to backlog.
- Tests cover inflexible missed stays in schedule/history.
- Tests cover cancelled vs noLongerRelevant distinction.
- Tests cover done state for required/inflexible task cards.
- Tests cover safe handling of unsupported task types.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` pass.
Commit suggestion:
```text
feat(tasks): implement required task state transitions
```
Execution notes:
- Added `RequiredTaskAction`, `RequiredTaskActionResult`, and `RequiredTaskActionService`.
- Required visible cards now support explicit done, missed, cancel, and no-longer-relevant transitions.
- Done marks critical/inflexible tasks completed without clearing their schedule history.
- Missed critical tasks use the scheduler miss rule and move to backlog with schedule cleared.
- Missed inflexible tasks remain scheduled and marked missed for history.
- Cancelled and no-longer-relevant are distinct statuses; cancellation increments the cancellation counter.
- The service rejects flexible and locked task types so locked blocks remain outside normal task-card transitions.
- Added `test/required_task_actions_test.dart` for the required-task action rules.
- No Surprise Task Logging implementation was added in this chunk.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
BREAKPOINT: Stop here. Confirm `high` mode before implementing Chunk 6.5 surprise task logging.
## Chunk 6.5 — Surprise task logging
Recommended Codex level: high
Status: Completed
Tasks:
Implement `I did something unplanned` behavior:
- Create surprise completed task.
- Optional fields: time used, project, reward, priority.
- Surprise task occupies the time it happened.
- Flexible tasks in that time are pushed using normal rules.
- Inflexible/critical/locked blocks are not moved.
- Inflexible/critical overlaps are reported.
- Locked overlaps remain hidden by default unless reveal mode exists.
Acceptance criteria:
- Test: surprise task creates completed task.
- Test: overlapping flexible task is pushed.
- Test: overlapping inflexible/critical task is reported, not moved.
- Test: locked overlap can be tracked without rendering as task.
- Test: optional fields can be omitted without blocking save.
- Test: normal push rules are reused rather than duplicated.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` pass.
Commit suggestion:
```text
feat(tasks): implement surprise task logging
```
Execution notes:
- Added `SurpriseTaskLogRequest`, `SurpriseTaskLogResult`, and `SurpriseTaskLogService`.
- Surprise logging creates a completed `TaskType.surprise` task and trims/validates the title.
- Optional fields can be omitted; omitted time data saves an unplaced completed surprise task without blocking the log.
- When start time and time-used are supplied, the surprise task occupies that interval.
- Overlapping planned flexible tasks are moved using the existing `pushFlexibleTaskToNextAvailableSlot` behavior with the surprise interval treated as blocked time.
- Surprise-caused flexible movement increments auto-push statistics rather than manual-push statistics.
- Inflexible and critical overlaps are reported through visible overlap data and are not moved.
- Locked overlaps are tracked separately from normal task/notice output so locked time remains hidden by default.
- Added `test/surprise_task_logging_test.dart` for surprise creation, flexible movement, fixed overlap reporting, locked overlap tracking, optional fields, and cascade movement safety.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.

View file

@ -0,0 +1,182 @@
# V1 Block 07 — Child Tasks
Status: Completed
Purpose: Support breaking a large task into smaller owned child tasks without adding dependency complexity.
## Chunk 7.1 — Parent/child model rules
Recommended Codex level: medium
Status: Completed
Tasks:
Implement parent/child ownership fields and helpers:
- parent task id on child tasks
- list/query children by parent
- parent can be incomplete while children are planned/completed
- parent/child helpers must remain domain-only and UI-independent
Rules:
- This is not full task dependency support.
- Do not add arbitrary DAG/dependency logic.
- Children are owned by parent only.
- Child ownership does not block scheduling unless a later planned feature explicitly adds dependency behavior.
Acceptance criteria:
- Test: child references parent.
- Test: parent can query/aggregate children through helper.
- Test: child ownership does not create dependency/blocking behavior.
Execution notes:
- Added `ChildTaskView` as a domain-only read projection over task lists.
- Added `ChildTaskSummary` for direct child status counts.
- Exported child-task helpers through `lib/scheduler_core.dart`.
- Parent/child ownership uses existing `Task.parentTaskId`.
- Helpers query direct children and parent relationships without adding dependency/DAG behavior.
- Parent auto-completion is explicitly not implemented in this chunk.
- Added `test/child_tasks_test.dart` for ownership, aggregation, incomplete parent behavior, and scheduling non-blocking behavior.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
## Chunk 7.2 — Child entry defaults
Recommended Codex level: medium
Status: Completed
Tasks:
Support row-style child entry data:
- child title
- priority up/down/dropdown value
- reward up/down/dropdown value
- time required
- optional project override
Rules:
- If no priority is set, children are inserted in the order added.
- Children can have their own reward, priority, difficulty, and time.
- Children inherit project from parent unless overridden.
- Reward can remain `not set`; do not treat missing reward as very low reward.
- Preserve original entry order for children that have no explicit priority.
Acceptance criteria:
- Tests cover child creation with explicit fields.
- Tests cover no priority preserving insertion order.
- Tests cover inherited project and overridden project.
- Tests cover reward `not set` remaining distinct from very low reward.
Execution notes:
- Added `ChildTaskEntry` for row-style child creation data.
- Child entries support title, nullable priority, reward, difficulty, duration, and optional project override.
- Child entries inherit the parent project when no override is supplied.
- Missing priority remains null so children without explicit priority can preserve row insertion order.
- Missing reward remains `RewardLevel.notSet`, distinct from `RewardLevel.veryLow`.
- Added tests for explicit child fields, project inheritance/override, reward not-set behavior, and no-priority row order.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
BREAKPOINT: Stop here. Confirm `extra high` mode before implementing the child-task edge-case regression suite.
## Chunk 7.3 — Child-task edge-case regression test suite
Recommended Codex level: extra high
Status: Completed
Tasks:
Before implementing parent auto-completion, add or expand tests for edge cases that could make child tasks behave like unwanted dependency logic.
Cover these cases:
- parent with zero children does not auto-complete by accident
- parent with planned children remains incomplete
- child completion updates child state without forcing parent completion until all children are complete
- parent completion can force-complete remaining children only through the explicit parent-complete action
- child tasks keep their parent id when scheduled, pushed, moved to backlog, or marked complete
- children without priority preserve row insertion order
- children with priority can be sorted by priority without losing stable insertion order within same-priority groups
- parent project inheritance works
- child project override works
- child task reward `not set` remains distinct from very low reward
- no arbitrary dependency/DAG fields or scheduling-blocking behavior are introduced
Rules:
- Tests should name the business rule being protected.
- Prefer small fixtures over large scenario setup.
- Do not mark this chunk complete unless `dart analyze` and `dart test` pass.
- Do not implement new user-facing behavior in this chunk unless needed to make the edge-case tests compile against planned domain APIs.
Acceptance criteria:
- A dedicated child-task test group exists.
- Tests cover ownership, ordering, inheritance, and non-dependency behavior.
- Existing scheduling and backlog tests still pass.
Execution notes:
- Added a dedicated `Child task edge-case regressions` test group.
- Covered zero-child parent non-auto-completion, planned-child parent remaining incomplete, child completion not forcing parent/sibling completion, parent completion not forcing children before an explicit parent-complete action, parent-id preservation across schedule/push/backlog/complete operations, stable priority sorting, and direct-only ownership.
- Confirmed child project inheritance/override and `RewardLevel.notSet` behavior remain covered by child-entry tests.
- Added `ChildTaskView.childrenOfSortedByPriority` for stable priority ordering of direct children.
- Did not implement parent auto-completion, parent-complete force propagation, dependency/DAG behavior, or scheduling blockers.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.
BREAKPOINT: Stop here. Confirm `high` mode before implementing auto-completion propagation.
## Chunk 7.4 — Parent auto-completion
Recommended Codex level: high
Status: Completed
Tasks:
Implement completion rules:
- Parent auto-completes when all children complete.
- Marking parent complete force-completes remaining children.
- Completing from any child can provide a domain-level option/result to mark entire parent complete.
- Parent/child completion should update relevant task statistics without duplicating events.
Rules:
- Do not silently complete sibling child tasks when one child completes.
- Do not complete parent until every child is complete unless the explicit parent-complete action is selected.
- Do not add generalized dependency resolution.
Acceptance criteria:
- Test: all children completed completes parent.
- Test: parent complete force-completes children.
- Test: partial child completion does not complete parent.
- Test: completing one child does not complete siblings.
- Test: explicit parent-complete action records the correct completion state for parent and remaining children.
Commit suggestion:
```text
feat(tasks): support parent-owned child tasks
```
Execution notes:
- Added `ChildTaskCompletionService` and `ChildTaskCompletionResult`.
- Completing a child now completes its parent only when all direct children are complete.
- Completing one child does not complete siblings.
- Partial child completion leaves the parent incomplete and exposes `canCompleteParentExplicitly`.
- Explicit parent completion force-completes remaining direct children and records `forceCompletedChildIds`.
- Parent completion is direct-child only; no generalized dependency graph behavior was added.
- Completion propagation updates task status and `updatedAt` without adding duplicate statistics events.
- Added tests for all-child auto-completion, parent force-completion, partial completion, sibling safety, and explicit parent-complete result metadata.
- `dart format lib test`, `dart analyze`, `dart test`, and `git diff --check` passed.

View file

@ -0,0 +1,165 @@
# V1 Block 08 — Today Timeline State
Status: Complete
Purpose: Prepare domain/view-state data for the Today timeline without building full Flutter UI yet unless explicitly requested.
## Chunk 8.1 — Timeline item view model
Recommended Codex level: medium
Tasks:
Create a UI-independent timeline item model with fields for:
- display title
- start/end or duration
- task type
- project color token
- background type token
- reward icon token
- difficulty icon token
- explicit time display flag
- quick actions available
- item category that distinguishes task cards from overlays
Rules:
- Thick border color is project class.
- Translucent background is task type.
- Name is text.
- Icon 1 is reward.
- Icon 2 is difficulty.
- Flexible task cards show duration; timeline position shows start/stop.
- Inflexible, critical, and locked show explicit start/end times.
- Timeline state must remain UI-framework-independent.
Acceptance criteria:
- Tests or snapshots can verify field mapping from task to timeline item.
- Tests cover flexible duration display.
- Tests cover explicit time display for inflexible, critical, and locked items.
Completed:
- Added UI-independent timeline item and mapper models in `lib/src/timeline_state.dart`.
- Exported timeline state through `lib/scheduler_core.dart`.
- Added tests for task field/token mapping, flexible duration display, explicit time display, and locked overlay category/no-actions behavior.
- Verified with `dart format lib test`, `dart analyze`, and `dart test`.
## Chunk 8.2 — Hidden locked block overlay state
Recommended Codex level: medium
Tasks:
Create overlay state for locked blocks:
- hidden by default
- temporary reveal mode
- named blocked-time overlay
- not a normal task block
- overlay item category distinct from task-card category
Acceptance criteria:
- Locked block can produce an overlay item only when reveal mode is active.
- Overlay item is distinguishable from task card item.
- Overlay item shows a name and explicit start/end times.
- Locked overlay does not expose normal task quick actions.
Completed:
- Added locked occurrence overlay mapping behind an explicit `revealHiddenLockedBlocks` flag.
- Hidden locked occurrences return no overlay unless reveal mode is active.
- Visible locked occurrences produce named overlay items with explicit times.
- Locked overlays remain distinct from task cards and expose no normal task quick actions.
- Verified with `dart format lib test`, `dart analyze`, and `dart test`.
BREAKPOINT: Stop here. Confirm `low` mode before implementing compact mode state.
## Chunk 8.3 — Compact mode state
Recommended Codex level: low
Tasks:
Add domain/app state for manual compact mode:
- Manual toggle only.
- Show current task.
- Show next required task.
- Optionally show next flexible task.
- Hide full timeline unless expanded.
Rules:
- The app must not automatically switch into compact mode after missed/pushed tasks.
- Locked blocks stay hidden in compact mode unless explicitly revealed by a separate overlay action.
- Compact mode should use existing timeline item mapping instead of duplicate display logic where practical.
Acceptance criteria:
- Compact mode flag controls compact output selection.
- Tests cover manual toggle behavior.
- Tests cover compact mode not activating automatically after pushed/missed tasks.
- Tests cover compact mode showing the next required item when one exists.
Completed:
- Added `CompactTimelineState` with a manual compact-mode flag and full-timeline expansion state.
- Added compact selection for current item, next required item, and optional next flexible item using existing timeline item mapping.
- Kept locked items out of compact selection unless separately revealed through overlay state.
- Added tests for manual toggle behavior, pushed/missed tasks not auto-enabling compact mode, next required selection, optional next flexible selection, and locked exclusion.
- Verified with `dart format lib test`, `dart analyze`, and `dart test`.
BREAKPOINT: Stop here. Confirm `medium` mode before implementing the timeline regression test suite.
## Chunk 8.4 — Timeline state regression test suite
Recommended Codex level: medium
Tasks:
Add or expand tests that protect the timeline mapping rules before Flutter UI work begins.
Cover these cases:
- flexible task card exposes duration, not forced explicit start/end text
- inflexible task card exposes explicit start/end text
- critical task card exposes explicit start/end text
- locked block overlay exposes explicit start/end text only when reveal mode is active
- locked block overlay is not treated as a task card
- project color token maps from project class/border token
- background token maps from task type
- reward icon token handles all five reward levels plus `not set`
- difficulty icon token handles all five difficulty levels
- quick actions map correctly for flexible tasks
- compact mode returns only the intended reduced item set
Rules:
- Do not implement Flutter widgets in this block unless explicitly requested later.
- Timeline models should be easy for Flutter to consume but must not import Flutter.
- Do not mark this chunk complete unless `dart analyze` and `dart test` pass.
Acceptance criteria:
- Timeline test group exists.
- Mapping rules are tested without depending on a UI framework.
- Existing scheduling, backlog, locked-block, and task-action tests still pass.
Completed:
- Expanded timeline regression coverage for all task-type background tokens.
- Added exhaustive reward icon token coverage for every reward level plus `notSet`.
- Added exhaustive difficulty icon token coverage for every difficulty level plus `notSet`.
- Added focused compact-mode reduced-output regression coverage.
- Confirmed existing timeline tests cover flexible duration display, required explicit time display, reveal-gated locked overlays, locked overlay category, project color tokens, and flexible quick actions.
- Verified with `dart format lib test`, `dart analyze`, and `dart test`.
Commit suggestion:
```text
feat(timeline): add today timeline view state models
```

View file

@ -0,0 +1,299 @@
# V1 Block 11 — Backend Baseline and Domain Contracts
Status: Complete on 2026-06-24.
Purpose: Re-establish a trustworthy executable baseline after the archived
Blocks 0110, resolve remaining V1 specification ambiguities, and harden the
core domain/time contracts before adding more scheduling, persistence, or UI
surface area.
## Chunk 11.1 — Fresh verification and V1 traceability baseline
Recommended Codex level: medium
Status: Complete on 2026-06-24.
Baseline:
- Starting commit: `775c2ed406f03a73a9b0ca621dea5b4482468616`
- Dart SDK: `3.12.2`
- Current test count: 143 passing tests
Verification commands:
- `dart pub get`: passed
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 143 tests
- `git diff --check`: passed
Documentation outputs:
- Updated `Codex Documentation/Archived plans/V1_TEST_COVERAGE_MATRIX.md` to
remove a stale reference to missing `test/quick_capture_test.dart` and record
the fresh verification result.
- Added `V1_REQUIREMENTS_TRACEABILITY_MATRIX.md`.
- Added `V1_PUBLIC_API_BASELINE.md`.
- Updated `V1_BACKEND_COMPLETION_GAP_MATRIX.md` so it no longer describes the
143-test result as only historical.
Tasks:
- Install or select a Dart SDK compatible with `pubspec.yaml`.
- Run and record:
```bash
dart pub get
dart format lib test
dart analyze
dart test
git diff --check
```
- Record the starting commit and actual current test count.
- Repair stale or incorrect entries in `V1_TEST_COVERAGE_MATRIX.md`, including
references to test files that do not exist.
- Add a V1 requirements traceability matrix that maps each human-document MVP
acceptance criterion to production APIs, tests, and one of: complete,
incomplete, intentionally deferred, or contradictory.
- Capture a public API baseline so later chunks can distinguish intentional
breaking changes from accidental ones.
- Turn every verified gap into either an active-plan reference or a narrowly
scoped issue/TODO; do not leave vague “future” claims in the completion matrix.
Rules:
- This chunk is verification and documentation only unless a minimal formatting
or test-reference correction is required.
- Do not claim the archived 143-test result is current until the suite is rerun.
- If a command cannot run, document the exact environment blocker and keep this
chunk incomplete.
- Do not edit archived plan completion notes to hide a newly discovered gap.
- Do not begin feature implementation in this chunk.
Acceptance criteria:
- All standard verification commands pass in the active environment.
- The current test count and starting commit are recorded.
- Every V1 acceptance criterion has a traceable implementation/test status.
- Stale coverage references are corrected.
- The gap matrix agrees with the active Block 1118 plan index.
BREAKPOINT: Stop here. Confirm `high` mode before resolving domain semantics.
## Chunk 11.2 — Resolve V1 lifecycle and metadata semantics
Recommended Codex level: high
Status: Complete on 2026-06-24.
Documentation outputs:
- Added `V1_ADR_001_Lifecycle_Metadata_Reminder_Semantics.md` to define durable
V1 lifecycle statuses, movement/activity semantics, task-type behavior,
planned versus actual time fields, project default precedence, and reminder
policy boundaries.
- Updated `Human Documentation/Starter Architecture Notes.md` to resolve the
human-spec `pushed`/`skipped` status ambiguity without changing product
intent.
Test outputs:
- Added `test/domain_contracts_test.dart` to lock the durable status list,
assert push remains movement metadata, keep burnout skip as stats-only
compatibility, and cover critical versus inflexible missed semantics.
Tasks:
- Add an architecture decision record that defines the durable task lifecycle
states used by V1.
- Keep movement such as manual push, automatic push, move to backlog, and restore
from backlog as activity/stat events rather than durable lifecycle statuses.
- Keep `skipped during burnout` compatible as a future activity/stat concept,
but do not add V2 shield or catch-up transitions.
- Define exact behavior for each task type in each relevant lifecycle state,
including flexible, critical, inflexible, locked, surprise, and free slot.
- Define which fields represent planned placement, actual work time, completion
time, backlog-entry time, and last modification time.
- Define critical-missed behavior as missed plus backlog placement, and
inflexible-missed behavior as missed history that retains its original
scheduled interval.
- Define how configured project defaults, learned suggestions, and task-level
overrides differ.
- Define the reminder-profile inheritance order and the boundary between backend
policy decisions and platform notification delivery.
- Update human-facing architecture notes only where needed to resolve a real
contradiction; preserve the original product intent.
Rules:
- Do not introduce V2 behavior to make the status table symmetrical.
- Do not turn every activity into a task status.
- Preserve calm, non-punitive terminology.
- The decision record must be specific enough to drive model, mapping, and test
changes in later chunks.
- Prefer one durable meaning per field; do not overload `updatedAt` as a proxy for
backlog age, completion, or actual work time.
Acceptance criteria:
- The status/event distinction is documented and covered by focused tests or
compile-time model expectations.
- Critical and inflexible missed semantics are unambiguous.
- Planned versus actual time semantics are unambiguous.
- Project defaults, learned suggestions, and task overrides have a defined
precedence model.
- No V2-only workflow has been added.
## Chunk 11.3 — Domain invariants and explicit patch semantics
Recommended Codex level: high
Status: Complete on 2026-06-24.
Implementation outputs:
- Added typed domain validation codes and `DomainValidationException`.
- Enforced non-blank task/project/locked-time identifiers and labels at domain
model boundaries.
- Enforced positive optional durations and valid scheduled, actual,
`TimeInterval`, `SchedulingWindow`, locked block, recurrence, and override
intervals.
- Added explicit nullable clear semantics for task priority, duration, schedule
interval, actual interval, parent ownership, reminder override, and project
default duration.
- Added task `actualStart`, `actualEnd`, and `reminderOverride` fields with
document mapping support.
- Rejected self-parenting and preserved direct-child-only ownership.
- Defensively copied public domain/read-model collections into unmodifiable
snapshots.
Test outputs:
- Added `test/domain_invariants_test.dart` for validation codes, clear paths,
immutable collection boundaries, and locked-time invariants.
- Updated persistence and scheduler tests for the new document fields and
immutable result snapshots.
Tasks:
- Enforce non-blank stable IDs, titles, and project IDs at model boundaries.
- Enforce positive durations when a duration is present.
- Enforce that scheduled start/end values are either both absent or both present
and that end is after start.
- Enforce valid `TimeInterval`, scheduling-window, recurrence, and override
intervals.
- Reject self-parenting and define the direct-child-only ownership boundary.
- Add explicit patch/clear semantics for nullable fields that must be removable,
including duration, priority, parent ownership, schedule placement, actual
interval, and reminder override.
- Prevent mutable input collections from leaking into immutable domain objects.
- Introduce typed validation failures/codes that application and persistence
layers can map without parsing English strings.
- Add regression tests for every invariant and every intentional clear path.
Rules:
- Keep constructors/factories consistent; do not leave a public constructor that
bypasses all invariants without a documented internal-only reason.
- Do not use magic sentinel enum values to mean “clear this field.”
- Validation must remain UI- and database-independent.
- Existing valid fixtures must continue to construct or be migrated explicitly
in Block 15.
- Error codes are stable contracts; explanatory text may change later.
Acceptance criteria:
- Invalid partial/negative/empty model states are rejected deterministically.
- Every nullable field that the product can remove has an explicit tested clear
path.
- All domain collections exposed publicly are immutable views or immutable
values.
- Application callers can distinguish validation categories without matching
message text.
- Existing scheduling behavior still passes its regression suite.
BREAKPOINT: Stop here. Confirm `extra high` mode before changing civil-time and
clock contracts.
## Chunk 11.4 — Deterministic clock, IDs, and civil-time semantics
Recommended Codex level: extra high
Status: Complete on 2026-06-24.
Implementation outputs:
- Added clock, ID, civil-date, wall-time, timezone resolver, DST policy, and
fixed-offset resolver contracts in `lib/src/time_contracts.dart`.
- Exported the time contracts from the public `scheduler_core.dart` entry point.
- Replaced hidden `DateTime.now()` fallbacks in scheduling, action, surprise
logging, and child-completion services with injected `Clock` boundaries.
- Added optional ID-generator convenience wrappers for quick capture and
surprise logging while preserving explicit request APIs.
- Migrated locked block dates and override dates to `CivilDate`; kept
`ClockTime` as a backwards-compatible alias of `WallTime`.
- Required locked-time expansion and override interval conversion to receive an
explicit `timeZoneId` and `TimeZoneResolver`.
- Documented and tested safe overnight locked-rule behavior: reject non-positive
and overnight wall-time intervals instead of splitting silently.
- Added civil-date and wall-time persistence conventions that store date-only
and wall-time strings without timezone conversion.
- Updated architecture notes and the public API baseline for the intentional
time-contract changes.
Test outputs:
- Added `test/time_contracts_test.dart` for civil-date/wall-time parsing,
midnight/month/year/leap-day boundaries, fixed offset conversion, injected
clocks/IDs, DST gap/repeat policy, reject policy codes, and overnight rejection.
- Updated locked-time, scheduling, persistence, repository, and invariant tests
to use explicit civil dates and timezone resolver boundaries.
- Current verification result: `dart test` passed with 174 tests.
Tasks:
- Introduce injectable clock and ID-generation contracts for application/domain
operations that currently fall back to `DateTime.now()` or caller-created IDs.
- Remove hidden wall-clock reads from deterministic core methods; convenience
wrappers may delegate to injected services at an outer boundary.
- Introduce explicit civil-date and wall-clock value types for recurring locked
rules and date-only overrides.
- Introduce a time-zone identifier/resolver boundary that converts a local day
and wall time into instants used by the scheduling engine.
- Define and test daylight-saving behavior for nonexistent and repeated local
times.
- Persist date-only values as date-only values and wall times as wall times; do
not convert them to UTC timestamps that can change the calendar day.
- Define whether overnight locked rules are rejected or normalized into explicit
split occurrences; implement the selected safe behavior.
- Update locked-block expansion, scheduling windows, and tests to use the new
deterministic time contracts.
- Add boundary tests for midnight, month/year transitions, leap day, DST gaps,
DST repeats, and non-UTC time zones.
Rules:
- Keep IANA/platform time-zone implementation behind an interface so the core
does not import Flutter or platform APIs.
- Do not use the machines implicit local zone as persistent business data.
- Do not silently reinterpret legacy UTC timestamps; migration belongs in Block
15 and must be fixture-tested.
- Every scheduling operation must receive an explicit operation time and owner
time-zone context through the application boundary.
- Locked and inflexible time must remain immovable through this refactor.
Acceptance criteria:
- Core tests no longer depend on the machine clock or default local time zone.
- Recurring locked blocks expand to the intended local calendar dates across DST
transitions.
- Date-only overrides round-trip without a day shift.
- Invalid/ambiguous time input follows a documented deterministic policy.
- The full verification suite passes after the time-model migration.
Commit suggestion:
```text
feat(domain): harden v1 contracts and time semantics
```

View file

@ -0,0 +1,203 @@
# V1 Block 12 — Occupancy Policy and Scheduling Correctness
Status: Complete on 2026-06-25.
Purpose: Make every scheduling operation use one explicit occupancy policy so
protected free slots, surprise work, required commitments, and hidden locked
time behave consistently without breaking flexible-task order.
## Chunk 12.1 — Central occupancy policy
Recommended Codex level: extra high
Status: Complete on 2026-06-25.
Tasks:
- Introduce one UI-independent occupancy classifier/policy used by insertion,
next-slot push, tomorrow push, rollover, surprise repair, and overlap analysis.
- Classify at minimum:
- hidden locked constraints
- required visible critical/inflexible intervals
- protected free slots
- movable planned flexible tasks
- active work
- completed actual occupancy, including surprise work
- non-occupying backlog/cancelled/no-longer-relevant records
- retained historical missed intervals
- Define separately whether an interval is immovable, blocks automatic flexible
placement, may be explicitly overlapped by a required commitment, and should
be reported as a conflict.
- Replace duplicated hard-coded blocker lists in scheduling operations with the
central policy.
- Ensure locked and inflexible items are never emitted as movement changes.
- Add a matrix test that runs each task type/status combination through the
policy.
Rules:
- Occupancy is not the same as visibility; hidden locked time still blocks.
- A task being completed does not erase a known actual interval from historical
occupancy.
- Backlog and cancelled/no-longer-relevant tasks do not block placement.
- Preserve flexible order unless the user explicitly selected a different
destination.
- Do not use UI card categories as scheduling policy inputs.
Acceptance criteria:
- Every scheduling operation obtains blockers/movable work from the same policy.
- Policy tests cover every V1 task type and lifecycle state.
- Locked and inflexible records remain byte-for-byte placement-stable after
automatic operations.
- The policy exposes conflict-reporting behavior independently from movement
behavior.
- Existing scheduling tests pass or are intentionally updated to the resolved
V1 contract.
BREAKPOINT: Stop here. Confirm `high` mode before implementing protected free-slot
and surprise-occupancy behavior.
## Chunk 12.2 — Protected Free Slot scheduling behavior
Recommended Codex level: high
Status: Complete on 2026-06-25.
Tasks:
- Add validated creation/update helpers for scheduled Free Slot records.
- Treat Free Slots as protected blockers for automatic flexible insertion,
pushing, tomorrow placement, and rollover.
- Allow an explicitly scheduled critical or inflexible commitment to overlap a
Free Slot without moving the Free Slot, while returning a typed interrupt or
conflict result for the application layer.
- Ensure an exact boundary touch is not treated as overlap.
- Ensure a flexible task that cannot fit around a Free Slot remains unchanged and
returns a no-slot outcome.
- Cover multiple adjacent Free Slots, whole-day protected rest, and Free Slots at
the start/end of a planning window.
- Preserve Free Slot timeline metadata for the later Today read model.
Rules:
- Free Slot means intentional protected rest, not unused capacity.
- The scheduler must not consume a Free Slot simply because it appears empty.
- Do not add automatic best-fit task suggestions in this chunk.
- Do not move a Free Slot during repair.
- Reminder suppression is implemented in Block 13, but this chunk must expose the
occupancy facts needed by that policy.
Acceptance criteria:
- Flexible tasks never land inside a protected Free Slot through any automatic
V1 scheduling operation.
- Explicit required overlap produces a typed result and does not move either the
required item or Free Slot.
- Boundary and no-fit behavior is regression-tested.
- Free Slot records remain visible to read-model mapping but never act as normal
flexible quick-action cards.
## Chunk 12.3 — Surprise, active, and completed actual occupancy
Recommended Codex level: high
Status: Complete on 2026-06-25.
Tasks:
- Persist and classify a surprise tasks actual interval as occupied time after
the initial logging operation.
- Ensure subsequent same-day insertion, push, and repair operations cannot place
flexible work over known surprise occupancy.
- Define and implement active-task occupancy using planned and/or actual interval
data from Block 11.
- Preserve known actual intervals for completed planned tasks when later
operations rebuild the day.
- Repair all overlapping planned flexible tasks in stable order when surprise
work is logged.
- Report required and locked overlap categories without exposing hidden locked
details unless reveal mode is explicitly requested.
- Make surprise logging idempotent by operation ID so retries do not duplicate
the task or push the same flexible work twice.
- Add tests for multiple surprise entries, nested overlaps, exact boundaries,
and a retry of the same operation.
Rules:
- Surprise work is already completed and is never moved by the repair operation.
- Required and locked intervals are reported, never moved.
- Hidden locked names/details must not leak through default result DTOs.
- Actual historical occupancy must not be inferred from `updatedAt`.
- Statistics are updated in Block 13; this chunk establishes scheduling facts.
Acceptance criteria:
- A logged surprise interval remains a blocker in all later same-day operations.
- Flexible repair preserves order and applies each movement once.
- Required/locked overlap outputs are typed and privacy-safe by default.
- Retrying the same surprise operation is a no-op with the original result or an
equivalent idempotent result.
- All surprise and scheduling regression tests pass.
BREAKPOINT: Stop here. Confirm `extra high` mode before replacing scheduling
message contracts and adding invariant/property tests.
## Chunk 12.4 — Structured scheduling outcomes and invariant test suite
Recommended Codex level: extra high
Status: Complete on 2026-06-25.
Tasks:
- Replace English notice text as the machine contract with stable scheduling
operation, issue, movement, and conflict codes plus structured parameters.
- Keep optional debug/default text only as non-authoritative presentation data.
- Standardize not-found, invalid-state, no-slot, overflow, conflict, and no-op
outcomes across all scheduling operations.
- Ensure overflow/no-slot paths do not partially mutate returned task state.
- Add shared invariant assertions for:
- no movable task overlaps a blocker after success
- immovable placements do not change
- flexible relative order is preserved
- task IDs remain unique
- intervals remain valid
- an idempotent replay does not add changes
- Add deterministic randomized/property-style tests over varied windows,
blockers, durations, and task order.
- Add a practical performance baseline for a large single-day task set and record
the threshold as a regression guard rather than a microbenchmark promise.
- Update callers/tests to branch on codes, not message strings.
Rules:
- Localization belongs outside the scheduling core.
- Do not silently drop warnings when converting old notice objects.
- Randomized tests must use fixed seeds and print a reproducible failing case.
- Performance work must not replace clear/correct code with opaque premature
optimization.
- Do not add non-V1 scheduling heuristics.
Acceptance criteria:
- No application/domain test relies on exact English scheduling text for logic.
- Every scheduler operation returns the same typed outcome categories.
- Property tests protect the main scheduling invariants.
- No-slot and conflict results are non-destructive.
- The standard verification suite and new scheduling matrix pass.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 203 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `high` mode before beginning Block 13.
Commit suggestion:
```text
feat(scheduling): unify v1 occupancy and structured outcomes
```

View file

@ -0,0 +1,274 @@
# V1 Block 13 — Lifecycle, Statistics, Project Defaults, and Reminder Policy
Status: Complete on 2026-06-25.
Purpose: Centralize task transitions, update internal statistics exactly once,
add project-level learned suggestions, and expose reminder-policy decisions
without implementing V2 history UI or platform notification delivery.
## Chunk 13.1 — Canonical transitions and internal activity records
Recommended Codex level: high
Status: Complete on 2026-06-25.
Tasks:
- Introduce one canonical transition service for completion, miss, cancel,
no-longer-relevant, push, move to backlog, restore from backlog, and activation.
- Route existing flexible and required action services through that transition
contract or deprecate their duplicated transition logic.
- Add immutable internal activity records with stable IDs, operation IDs,
activity codes, task/project references, occurred-at time, and the minimum
structured metadata needed for statistics and idempotency.
- Add explicit completion time and optional actual interval to the task/completion
model defined in Block 11.
- Enforce allowed transitions and idempotent terminal-state behavior.
- Preserve critical-missed-to-backlog and inflexible-missed-in-place semantics.
- Record push and backlog movement as activities without turning them into task
statuses.
- Keep activity records internal/application-facing; do not add a visible task
history feature.
Rules:
- A repeated command with the same operation ID must not create another activity
or apply the transition twice.
- Terminal transitions must not silently reopen tasks.
- Every transition returns a typed result, not an exception for expected user
states.
- Unexpected programmer misuse may still assert/throw at an internal boundary,
but application input must receive typed failures.
- Do not add overwhelm-shield or burnout-catch-up transitions.
Acceptance criteria:
- All V1 lifecycle actions pass through one transition rule set.
- Activity records distinguish manual push, automatic push, backlog movement,
completion, miss, cancellation, and no-longer-relevant.
- Duplicate operation IDs are exactly-once.
- Required-task missed behavior matches the product specification.
- Existing action tests are migrated without losing coverage.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 211 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `extra high` mode before implementing completion
accounting and locked-hour statistics.
## Chunk 13.2 — Completion accounting and exactly-once task statistics
Recommended Codex level: extra high
Status: Complete on 2026-06-25.
Tasks:
- Update manual-push, auto-push, moved-to-backlog, restored-from-backlog, missed,
and cancelled counters from canonical activities exactly once.
- Calculate `completedLateCount` from completion time versus the applicable
planned end under the documented policy.
- Expand locked occurrences for the completion/actual interval and calculate:
- completed during locked hours count
- completed during locked hours known overlap minutes
- Define the conservative fallback when a completion has a timestamp but no
actual interval; do not fabricate minutes.
- Apply the same completion accounting to surprise tasks.
- Capture the push count present at completion so average pushes before
completion can be derived at project/report level later.
- Preserve skipped-during-burnout and completed-after-shield fields as dormant
schema-compatible counters without implementing their V2 workflows.
- Add boundary tests for exact locked start/end, multiple locked occurrences,
partially overlapping work, late-by-zero, and idempotent retries.
Rules:
- Statistics updates and task transition/activity persistence must be one atomic
application operation in Block 14.
- Count/minute semantics must be documented separately when exact actual duration
is unavailable.
- Never increment a counter by replaying a read model or rebuilding Today state.
- Do not infer completion time from `updatedAt` for migrated records unless a
migration rule explicitly labels it as an approximation.
- Statistics remain quiet backend metadata.
Acceptance criteria:
- Every implemented V1 counter has a single authoritative update path.
- Duplicate commands cannot double-increment statistics.
- Late and locked-hour calculations are deterministic and boundary-tested.
- Surprise completions participate in the same accounting policy.
- The task-statistics document contract can represent all resulting values.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 218 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `high` mode before implementing child-task
orchestration.
## Chunk 13.3 — Child-task break-up and completion orchestration
Recommended Codex level: high
Status: Complete on 2026-06-25.
Tasks:
- Add a pure domain command/result for breaking one parent into an ordered set of
direct child tasks.
- Validate non-empty child titles, positive optional durations, unique IDs, and
direct ownership.
- Reject self-parenting and parent/child cycles; keep V1 ownership direct rather
than implementing a dependency graph.
- Preserve entry order when child priorities are equal or not explicitly set.
- Return all task/activity/stat mutations needed for one atomic application
transaction.
- Support completing the parent from the parent or any child and force-complete
remaining direct children exactly once.
- Auto-complete the parent when the last incomplete direct child completes.
- Record lightweight parent/child completion-pattern aggregates or activity
metadata required by the human specification.
- Add tests for empty sets, duplicate IDs, partial completion, last-child
completion, force completion, retries, and already-terminal children.
Rules:
- Do not add arbitrary dependency graphs or nested project management.
- Child tasks remain independently schedulable.
- Parent completion propagation must not erase child completion times already
recorded.
- Forced completion must use one operation context and deterministic timestamp.
- Persistence/transaction wiring is implemented in Block 14/15.
Acceptance criteria:
- Break-up produces deterministic ordered children owned by the parent.
- Last-child completion completes the parent once.
- Parent/child force completion is idempotent and preserves prior child facts.
- Direct-child/cycle constraints are tested.
- Result objects contain enough mutation data for atomic persistence.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 225 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `extra high` mode before adding learned project
statistics and suggestions.
## Chunk 13.4 — Project usage statistics and learned-default suggestions
Recommended Codex level: extra high
Status: Complete on 2026-06-25.
Tasks:
- Add a persistence-friendly `ProjectStatistics` model for V1 observations,
including completion count, known duration samples, completion-time buckets,
push totals, completions-after-push totals, and reward/difficulty distributions.
- Update project aggregates from canonical task activities/completions exactly
once.
- Expose derived values such as average push count before completion and a usual
completion-time bucket without storing lossy floating-point state where avoidable.
- Add a deterministic suggestion service for duration, completion-time window,
reward, difficulty, and reminder behavior where the available observations are
meaningful.
- Require a documented minimum sample threshold and expose sample size/confidence
with every learned suggestion.
- Keep configured project defaults authoritative; suggestions are optional and
never silently written back as configuration.
- Add tests for insufficient samples, ties, outliers, stable recomputation, and
configured-default precedence.
Rules:
- Do not add machine learning, remote analytics, or opaque scoring.
- Do not infer sensitive capacity/health conclusions.
- Use explicit deterministic aggregation that can be migrated and reproduced.
- A project with no history must still resolve neutral configured/fallback
defaults.
- Project statistics are not a V1 reports screen.
Acceptance criteria:
- Project aggregates update exactly once from activities.
- Learned suggestions include provenance, sample size, and confidence/strength.
- Configured defaults are never overwritten automatically.
- Average pushes before completion and usual completion time are derivable.
- Mapping requirements for Block 15 are documented and tested in memory.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 233 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `high` mode before implementing reminder-policy
resolution.
## Chunk 13.5 — Effective reminder and protected-rest policy
Recommended Codex level: high
Status: Complete on 2026-06-25.
Tasks:
- Add an optional task-level reminder-profile override.
- Implement an effective-profile resolver using task override, project configured
default, and documented application fallback in that order.
- Add a UI/platform-independent reminder directive model that can say deliver,
suppress, defer, or require explicit acknowledgement, with stable reason codes.
- Suppress normal flexible-task reminder directives while a protected Free Slot
is active.
- Allow critical and inflexible reminder directives to interrupt a Free Slot
according to the effective profile and required-task policy.
- Ensure `silent` produces no normal reminder directive.
- Expose enough structured data for a later platform notification scheduler
without scheduling notifications inside the core.
- Add tests across task types, all four reminder profiles, task override,
project fallback, Free Slot protection, and exact boundary times.
Rules:
- Do not implement OS notifications, background execution, escalation timers,
accounts, or sync in this chunk.
- Reminder policy must not move tasks.
- Do not let a project suggestion silently replace the configured reminder
profile.
- Use calm presentation codes; UI copy is outside the domain contract.
- Locked blocks remain hidden and are not normal reminder targets.
Acceptance criteria:
- Effective reminder resolution is deterministic and fully tested.
- Flexible reminders are suppressed during protected Free Slots.
- Required reminders may pass the protection boundary only through explicit
typed policy.
- Silent reminders produce no delivery directive.
- The core remains Flutter/platform independent.
Verification on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 243 tests
- `git diff --check`: passed
Commit suggestion:
```text
feat(domain): centralize lifecycle statistics and reminder policy
```

View file

@ -0,0 +1,397 @@
# V1 Block 14 — Application Use Cases and UI-Ready Read Models
Status: Complete
Purpose: Add the orchestration layer that a future Flutter UI can call without
assembling scheduler inputs, coordinating multiple repositories, or manually
keeping tasks, activities, statistics, and notices consistent.
## Chunk 14.1 — Application operation context and unit-of-work contracts
Recommended Codex level: high
Status: Complete
Tasks:
- Introduce an application facade/use-case layer above the pure domain services.
- Define an operation context containing operation ID, current instant, owner
time-zone context, and injected ID/clock services.
- Define typed application result/failure contracts for validation, not found,
conflict, stale revision, no slot, duplicate operation, persistence failure,
and unexpected failure.
- Add a unit-of-work/repository transaction boundary capable of atomically
persisting task changes, activities, project aggregates, settings, and
operation records.
- Provide an in-memory implementation that stages changes and rolls back on
failure for deterministic tests.
- Centralize repository loading and conversion to domain inputs.
- Prevent UI callers from directly persisting a partial `SchedulingResult`.
- Add contract tests for commit, rollback, duplicate operation IDs, and typed
failure mapping.
Rules:
- The application layer may depend on domain and repository interfaces, not
Flutter widgets or MongoDB client APIs.
- One user command must have one operation ID and one atomic commit boundary.
- Expected failures return typed results and do not leak driver exceptions.
- Read-only queries must not create activities or increment statistics.
- Keep transport/JSON DTOs separate from domain models where they diverge.
Acceptance criteria:
- UI code can call one use case per user intent.
- A failed multi-record command leaves the in-memory repositories unchanged.
- Duplicate operation IDs are exactly-once.
- Result codes are stable and do not depend on English text.
- The application layer has no Flutter or MongoDB imports.
Completed implementation:
- Added `src/application_layer.dart` as a pure Dart application boundary above
the existing domain services and repository interfaces.
- Added operation context, owner time-zone context, typed result/failure
contracts, expected failure/persistence exception wrappers, owner settings,
operation records, and unit-of-work repository contracts.
- Added an in-memory staged unit-of-work implementation that commits task,
activity, project-statistics, settings, and operation-record changes
atomically, rejects duplicate operation IDs, and rolls back on typed,
validation, persistence, or unexpected failures.
- Added `ApplicationSchedulingLoader` so application commands can centralize
repository loading into `SchedulingInput` instead of letting UI callers
persist partial scheduler results.
- Added contract tests for successful commit, rollback on typed failure,
rollback on persistence failure, duplicate operation IDs, typed validation
mapping, and centralized scheduler input loading.
Verification:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 249 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `extra high` mode before building Today state and
command orchestration.
## Chunk 14.2 — Complete Today query/read model
Recommended Codex level: extra high
Status: Complete
Tasks:
- Add a `GetTodayState`-style query that loads the requested local day, app
settings, relevant tasks, projects, locked rules, one-day overrides, and
unacknowledged scheduling notices.
- Expand locked occurrences using the explicit time-zone context from Block 11.
- Produce one sorted UI-independent read model containing task cards, optional
revealed locked overlays, Free Slots, status metadata, and structured actions.
- Include full-timeline and compact-mode projections from the same source data.
- Correct compact selection so the current flexible task cannot also occupy the
“next flexible” slot after deduplication.
- Produce stable occurrence IDs that include the local date/occurrence identity,
preventing cross-day UI-key collisions.
- Include current item, next required item, optional next flexible item, day
boundaries, and pending rollover notice data.
- Keep hidden locked details absent unless reveal mode is requested.
- Add query tests for empty day, mixed task types, current boundaries, compact
mode, reveal mode, DST day, and stable ordering.
Rules:
- Read-model construction must not mutate tasks or run rollover implicitly.
- The query accepts an explicit date and operation/read instant.
- Hidden locked time may influence availability while remaining absent from the
default item list.
- Presentation text/localization is outside the read model; expose tokens/codes
and raw domain values.
- Do not import Flutter.
Acceptance criteria:
- One query returns all data needed for the V1 Today and compact views.
- Current/next selections are correct and non-duplicated.
- Locked overlay identity is stable per occurrence/day.
- Read queries have no side effects.
- Today query tests cover all V1 task types and relevant lifecycle states.
Completed implementation:
- Added `src/today_state.dart` with `GetTodayStateQuery`, request/result
objects, source-tagged timeline items, compact projection, and pending
scheduling notice read models.
- Added a read-only application boundary through `ApplicationUnitOfWork.read`
so queries do not create operation records, activities, statistics, or
rollover changes.
- Loaded owner settings, project color tokens, scheduled tasks, locked blocks,
one-day overrides, and stored scheduling snapshot notices for the requested
local day.
- Expanded locked occurrences with the explicit `TimeZoneResolver` and
owner time-zone context, including DST fixture coverage.
- Produced date-stable locked overlay IDs by passing the local date into
`TimelineItemMapper.fromLockedOccurrence`.
- Built current, next required, optional next flexible, full timeline, and
compact projections from the same sorted Today item list.
- Corrected compact next-flexible selection so the current flexible item is not
duplicated as the next flexible item.
- Added tests for empty days, mixed V1 item types, current boundaries, compact
mode, reveal mode, stable cross-day locked IDs, DST day expansion, and
deterministic equal-start ordering.
Verification:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 257 tests
- `git diff --check`: passed
## Chunk 14.3 — Atomic V1 command use cases
Recommended Codex level: extra high
Status: Complete
Tasks:
Implement application commands for:
- quick capture to backlog
- quick capture to next available slot
- backlog item to next available slot
- flexible push to next available slot
- flexible push to tomorrow/top of queue
- flexible move to backlog
- flexible/required completion
- required miss, cancel, and no-longer-relevant
- surprise completed-task logging and flexible repair
- create/update/remove a protected Free Slot
- break up a task into child tasks
- complete parent/children through the V1 propagation rules
For each command:
- load the authoritative current state through repositories
- enforce expected revision/idempotency
- invoke domain rules
- persist all task/activity/stat/project/operation changes in one unit of work
- return structured changed entities, conflicts, notices, and refreshed read
hints without requiring the UI to infer what changed
Rules:
- Do not expose a “save these scheduler results” method to UI callers.
- No command may partially commit a task movement without its statistics and
operation record.
- Preserve flexible order and immovable time invariants.
- Use application-level typed failures for expected stale/not-found/no-slot
conditions.
- Do not add batch V2 burnout recovery commands.
Acceptance criteria:
- Every V1 Today/Backlog user action has one application command.
- Each command is atomic and idempotent in the in-memory implementation.
- Statistics and activity records match resulting task state.
- Failure tests prove rollback.
- Command outputs are sufficient for a UI to refresh predictably.
Completed implementation:
- Added `src/application_commands.dart` with `V1ApplicationCommandUseCases`,
stable `ApplicationCommandCode` values, child draft input, structured command
results, and read refresh hints.
- Added atomic commands for quick capture to backlog, quick capture to next
available slot, backlog item scheduling, flexible next-slot push, flexible
tomorrow/top push, flexible move to backlog, flexible completion, required
done/missed/cancel/no-longer-relevant actions, surprise logging with flexible
repair, protected Free Slot create/update/remove, child task break-up, child
completion, parent completion, and parent-from-child completion.
- Commands load authoritative repository state, expand locked intervals through
the explicit owner time-zone context where scheduling or completion accounting
needs it, and invoke the existing pure domain services.
- Commands enforce idempotency through the operation record boundary and use
optional `expectedUpdatedAt` guards for V1 stale-write protection until Block
15 adds explicit persisted revisions.
- Commands persist changed tasks, new activities, project aggregate updates, and
operation records in one `ApplicationUnitOfWork.run` boundary.
- Command results include changed tasks, activities, project statistics, notices,
scheduling changes/overlaps, child ids, protected-rest conflicts, and read
hints so UI callers do not need to infer what changed.
- Added command tests for quick capture, backlog scheduling, stale revisions,
commit rollback, flexible pushes, backlog movement, completion/project stats,
surprise repair, Free Slot create/update/remove, child break-up, and
parent/child completion propagation.
Verification:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 268 tests
- `git diff --check`: passed
BREAKPOINT: Stop here. Confirm `high` mode before adding management queries and
startup/rollover orchestration.
## Chunk 14.4 — Backlog, project, locked-time, and settings use cases
Recommended Codex level: high
Status: Complete
Tasks:
- Add a Backlog query using repository-side candidate loading plus the existing
filter/sort/staleness policies.
- Add settings-backed configurable green/blue/purple backlog thresholds.
- Add project create/update/archive queries and commands for configured defaults,
color token, and reminder profile.
- Return learned project suggestions separately from configured values.
- Add locked-block create/update/archive commands and date-scoped one-day
add/remove/replace override commands.
- Add owner settings for time zone, day boundary/default planning window,
compact-mode preference, and backlog thresholds where appropriate.
- Add explicit acknowledge/consume behavior for one-time notices.
- Add authorization-neutral owner-scope parameters without implementing user
accounts.
- Add use-case contract examples that future Flutter state management can call.
Rules:
- Archiving a project must not orphan or silently delete its tasks.
- Removing a recurring locked block must not delete unrelated overrides without
a documented explicit policy.
- Settings changes that reinterpret dates/time zones require a typed warning or
migration path; do not silently shift existing instants.
- Backlog queries must not load an unbounded full history when repository filters
can narrow candidates.
- Do not add report dashboards.
Acceptance criteria:
- Backlog filters/sorts and configurable staleness thresholds are available
through one query contract.
- Project, locked-time, and settings changes use typed atomic commands.
- Learned suggestions remain distinguishable from configured defaults.
- Date-scoped override behavior is tested.
- No management command deletes task history implicitly.
Completed implementation:
- Added `src/application_management.dart` with
`V1ApplicationManagementUseCases`, stable management command codes, backlog
and project query contracts, typed project/locked/settings command inputs, and
notice acknowledgement results.
- Added a backlog query that loads candidates with
`TaskRepository.findByStatus(TaskStatus.backlog)` before applying the existing
backlog filter, sort, and green/blue/purple staleness marker policies.
- Used owner settings as the source for configurable backlog staleness
thresholds and added typed validation for invalid threshold updates.
- Added project create/update/archive commands plus a project defaults query
that returns configured defaults and learned `ProjectSuggestionSet` values
separately.
- Added `ProjectProfile.archivedAt` so archived projects disappear from normal
project queries without deleting or orphaning task history.
- Added locked-block create/update/archive commands and date-scoped add, remove,
and replace override commands.
- Added `LockedBlock.archivedAt` and updated locked-time expansion so archived
base blocks no longer create occurrences while unrelated add overrides remain
intact.
- Added settings updates for time zone, day boundary/default planning window,
compact-mode preference, and backlog thresholds, with typed warnings for
time-zone and planning-window reinterpretation.
- Added owner-scoped `NoticeAcknowledgementRecord` persistence, a unit-of-work
repository for acknowledgements, stable notice IDs, and Today-state filtering
for acknowledged one-time notices.
- Added management contract tests covering backlog thresholds, project
suggestion separation, project archiving without task deletion, date-scoped
locked overrides, locked-block archiving without override deletion, settings
warnings, and notice acknowledgement.
Verification:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 274 tests
- `git diff --check`: passed
## Chunk 14.5 — Rollover and app-open recovery orchestration
Recommended Codex level: high
Status: Complete
Tasks:
- Add an explicit app-open/start-day use case that determines whether a source
day needs V1 flexible-task rollover.
- Key rollover by owner scope and source local date so it runs at most once.
- Use an explicit source-day window and never pull future-day tasks into the
rollover set.
- Preserve order among rolled-over tasks at the top of tomorrows flexible queue.
- Persist the rollover operation, task/stat/activity changes, and small notice
atomically.
- Return the pending notice through Today state until it is acknowledged.
- Make retries and multiple app opens idempotent.
- Add end-to-end in-memory tests spanning capture, day close, next open, notice
acknowledgement, and a second open.
Rules:
- Do not infer a burnout gap or enter a V2 recovery flow.
- Required, locked, Free Slot, completed, and future-day tasks must not be rolled
as unfinished flexible work.
- The notice is informational and calm; application logic branches on a code and
count, not text.
- Rollover must be an explicit command, not a side effect of reading Today.
- If no work needs rollover, record or return a deterministic no-op without
creating duplicate notices.
Acceptance criteria:
- Rollover executes once per source local date.
- Future-day tasks are unaffected.
- Order and statistics are correct.
- Notice lifecycle is persisted and acknowledgeable.
- The full application facade contract suite passes in memory.
Completed implementation:
- Added `src/application_recovery.dart` with `V1AppOpenRecoveryUseCases`,
explicit source-day/target-day request objects, deterministic recovery
outcomes, and structured recovery results.
- Implemented app-open recovery as an explicit command that checks one
owner/source-local-date key and never runs as a Today-read side effect.
- Keyed rollover idempotency by deterministic owner/source-date scheduling
snapshot IDs, so retries and multiple app opens do not roll the same source
day twice even with different operation IDs.
- Loaded source-day and target-day scheduled tasks through bounded repository
window queries, preventing future-day tasks from being pulled into rollover.
- Used the existing pure scheduler rollover behavior to preserve source-day
flexible order at the top of the target day while shifting target-day flexible
tasks as needed.
- Persisted changed tasks, rollover movement activities, the deterministic
scheduling snapshot, the calm aggregate notice, and the operation record in
one unit-of-work transaction.
- Saved no-op source days with deterministic snapshots and no notice so repeated
app opens remain idempotent without creating duplicate pending notices.
- Reused the Chunk 14.4 notice acknowledgement path so Today state surfaces the
pending rollover notice until it is acknowledged.
- Added end-to-end in-memory recovery tests covering capture, next-day app open,
target queue insertion, notice visibility, acknowledgement, second-open
idempotency, no-op recording, and future-day exclusion.
Verification:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 277 tests
- `git diff --check`: passed
Commit suggestion:
```text
feat(app): add atomic v1 use cases and today read model
```

View file

@ -0,0 +1,74 @@
# V1 Block 19 — Repository & Persistence Abstraction
**Purpose**: Define repository interfaces and memory adapter.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 19.1 — Define repository interfaces
Recommended level: **XHIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Create Dart library **`packages/scheduler_persistence/lib/persistence.dart`** and declare abstract classes `TaskRepository`, `ProjectRepository`, `LockedBlockRepository`, `SettingsRepository`, `ScheduleSnapshotRepository`.
2. Each repository must expose **only** domain objects from `packages/scheduler_core` (import that package).
3. Add shared value objects in `scheduler_core` if missing (e.g., `Revision`, `OwnerId`, `PageRequest`, `Page<T>`).
4. Document every method with tripleslash Dart doc.
5. Publish typedef `RepoResult<T>` = `Either<RepositoryFailure,T>` (use sealed class).
### Acceptance criteria
1. `dart analyze` shows 0 hints in `scheduler_persistence`.
2. Running `dart test` passes new autogenerated stub tests in `packages/scheduler_persistence/test/repo_contract_smoke_test.dart`.
### Completed implementation
1. Rehomed the core package to `packages/scheduler_core` with package name `scheduler_core`.
2. Added shared repository value objects in `scheduler_core`: `OwnerId`, `Revision`, `PageRequest`, and `Page<T>`.
3. Added package `packages/scheduler_persistence` with domain-only repository contracts for tasks, projects, locked blocks, settings, and schedule snapshots.
4. Added sealed repository failure types, sealed `Either<L,R>`, and `RepoResult<T>`.
5. Added `packages/scheduler_persistence/test/repo_contract_smoke_test.dart`.
### Verification
1. `dart format test/scheduler_core_test.dart packages/scheduler_core packages/scheduler_persistence`: passed.
2. `dart analyze`: passed, no issues found.
3. `cd packages/scheduler_persistence && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_persistence && dart test`: passed, 3 tests.
5. `cd packages/scheduler_core && dart test`: passed, 298 tests.
6. `dart test`: passed, 301 tests.
---
## Chunk 19.2 — Memory adapter & conformance tests
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Implement **`packages/scheduler_persistence_memory`** with class `InMemoryTaskRepository` etc. They must implement optimistic revision (increment int).
2. Add conformance test suite in `scheduler_persistence/test/repo_conformance.dart` with shared `runRepositoryComplianceTests()`.
3. Ensure cloning (deep copy) on return values using `jsonEncode/jsonDecode` for simplicity.
### Acceptance criteria
1. Inmemory adapter passes conformance suite covering CRUD, paging, optimistic revision conflict.
2. 100% statement coverage > 80% lines in this package.
### Completed implementation
1. Added package `packages/scheduler_persistence_memory` and workspace wiring.
2. Added in-memory implementations for task, project, locked block, settings, and schedule snapshot repository contracts.
3. Implemented owner scoping, duplicate-id checks, compare-and-set saves/deletes/archives, stale-revision failures, and deterministic offset paging.
4. Added JSON round-trip defensive cloning through the existing core document mappers.
5. Added shared conformance suite `packages/scheduler_persistence/test/repo_conformance.dart`.
6. Added `packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart` and root test wrapper wiring.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_persistence/test/repo_conformance.dart packages/scheduler_persistence_memory`: passed.
3. `dart analyze`: passed, no issues found.
4. `cd packages/scheduler_persistence && dart analyze`: passed, no issues found.
5. `cd packages/scheduler_persistence_memory && dart analyze`: passed, no issues found.
6. `cd packages/scheduler_persistence && dart test`: passed, 3 tests.
7. `cd packages/scheduler_persistence_memory && dart test`: passed, 7 tests.
8. `cd packages/scheduler_core && dart test`: passed, 298 tests.
9. `dart test`: passed, 308 tests.
10. `cd packages/scheduler_persistence_memory && dart test --coverage=coverage`: passed; generated LCOV line coverage is 93.79% (302/322).
---

View file

@ -0,0 +1,77 @@
# V1 Block 20 — SQLite Persistence Adapter Package
**Purpose**: Implement Drift-based SQLite storage backend.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 20.1 — SQLite schema & Drift setup
Recommended level: **XHIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Create new Dart package **`packages/scheduler_persistence_sqlite`** with Drift as dependency.
2. Define Drift database `SchedulerDb` with tables: `tasks`, `projects`, `locked_blocks`, `settings`, `snapshots`.
3. Fields: follow domain model; include `revision INT`, `owner_id TEXT`.
4. Add drift migrations using drift_dev build runner; start at schemaVersion=1.
5. Generate DAO classes via build_runner.
### Acceptance criteria
1. `dart run build_runner build --delete-conflicting-outputs` completes with zero errors.
2. Generated drift files checked in.
### Completed implementation
1. Added package `packages/scheduler_persistence_sqlite` with Drift, `drift_dev`, and `build_runner` wiring.
2. Added `SchedulerDb` in `lib/src/scheduler_db.dart` with `schemaVersion = 1` and `MigrationStrategy(onCreate: createAll)`.
3. Added tables for `tasks`, `projects`, `locked_blocks`, `locked_overrides`, `settings`, and `snapshots`.
4. Included owner scope and optimistic revision columns on mutable rows.
5. Added generated Drift data classes/accessor mixins in `lib/src/scheduler_db.g.dart`.
6. Added a schema smoke test that opens an in-memory Drift database and checks the expected table names.
### Verification
1. `dart pub get`: passed.
2. `cd packages/scheduler_persistence_sqlite && dart run build_runner build --delete-conflicting-outputs`: passed, exit 0; current build_runner warned that the option is ignored.
3. `dart format packages/scheduler_persistence_sqlite`: passed.
4. `cd packages/scheduler_persistence_sqlite && dart analyze`: passed, no issues found.
5. `dart analyze`: passed, no issues found.
6. `cd packages/scheduler_persistence_sqlite && dart test`: passed, 1 test.
7. `dart test`: passed, 308 tests.
---
## Chunk 20.2 — SQLite adapter implementation & tests
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Implement `SqliteTaskRepository` etc mapping domain objects to Drift rows with explicit converters.
2. Use transaction for multirecord save; ensure optimistic revision by `WHERE revision = ?` clause.
3. Add repository conformance tests reused from block19 suite pointed at SQLite adapter (use `sqflite_ffi` in tests).
### Acceptance criteria
1. SQLite adapter passes full conformance suite with `sqflite_ffi` on Linux/Windows/mac.
2. Average write latency in test ≤50ms.
### Completed implementation
1. Added `SqliteTaskRepository`, `SqliteProjectRepository`, `SqliteLockedBlockRepository`, `SqliteSettingsRepository`, and `SqliteScheduleSnapshotRepository`.
2. Mapped Drift rows to domain objects through the existing core document mappers and explicit row/JSON converters.
3. Implemented duplicate-id checks, owner isolation, deterministic paging, archive behavior, snapshot retention deletion, and typed repository failures.
4. Implemented optimistic compare-and-set writes/deletes/archives with `WHERE revision = expected` clauses.
5. Added SQLite conformance tests using the Block 19 shared suite and an in-memory Drift SQLite executor.
6. Added a write-latency test for task inserts and wired SQLite tests into the root test wrapper.
### Notes
1. Tests use Drift `NativeDatabase.memory()` instead of `sqflite_ffi`. A sqflite-backed Drift executor would require `drift_sqflite`, which pulls Flutter SDK dependencies into this pure Dart adapter package.
2. The current repository contracts expose single-record writes. No multi-record repository save method exists yet; future multi-record SQLite writes should use `SchedulerDb.transaction`.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_persistence_sqlite`: passed.
3. `cd packages/scheduler_persistence_sqlite && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_persistence_sqlite && dart test`: passed, 9 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 316 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,40 @@
# V1 Block 21 — Notification Abstraction Layer
**Purpose**: Define NotificationAdapter contract.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 21.1 — NotificationAdapter contract
Recommended level: **XHIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Add package **`packages/scheduler_notifications`**.
2. Declare sealed class `NotificationRequest` with fields: `id`, `title`, `body`, `scheduledDateTimeUtc`, `payloadJson`.
3. Declare enum `NotificationFeedbackType` (clicked,dismissed,action).
4. Define abstract `NotificationAdapter` with methods `Future<void> schedule(NotificationRequest)`, `Future<void> cancel(String id)`, `Stream<NotificationFeedback>`.
5. Add stub `FakeNotificationAdapter` for tests emitting events via StreamController.
### Acceptance criteria
1. Package compiles and `dart test` passes stub test `fake_adapter_test.dart`.
### Completed implementation
1. Added package `packages/scheduler_notifications` with public entry points `notifications.dart` and `scheduler_notifications.dart`.
2. Added sealed `NotificationRequest` with factory construction and fields `id`, `title`, `body`, `scheduledDateTimeUtc`, and `payloadJson`.
3. Added `NotificationFeedbackType` with `clicked`, `dismissed`, and `action`.
4. Added `NotificationFeedback` event model.
5. Added abstract `NotificationAdapter` with `schedule`, `cancel`, and `feedback`.
6. Added `FakeNotificationAdapter` backed by a broadcast `StreamController`.
7. Wired fake adapter tests into the root test wrapper.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_notifications`: passed.
3. `cd packages/scheduler_notifications && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_notifications && dart test`: passed, 2 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 318 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,46 @@
# V1 Block 22 — OS-Notification Package
**Purpose**: Desktop notification implementation.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 22.1 — Desktop notification adapter
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Create package **`packages/scheduler_notifications_desktop`**.
2. Implement adapters per platform with conditional import using `dart:io` Platform.
3. For Linux use `notify-send` via `Process.run`; for macOS use `osascript`; for Windows use `win32` Toast via `windows_notification` package.
4. Implement fallback to write to stdout if unsupported.
5. Add adapter factory `DesktopNotificationAdapter.defaultInstance()`.
6. Write integration test using `FakeNotificationAdapter` mocks to assert scheduling logic; skip on CI if platform not supported.
### Acceptance criteria
1. Desktop adapter compiles on all OS; tests skip rather than fail on unsupported.
2. Adapter passes NotificationAdapter contract tests.
### Completed implementation
1. Added package `packages/scheduler_notifications_desktop` with public entry points `desktop_notifications.dart` and `scheduler_notifications_desktop.dart`.
2. Added `DesktopNotificationAdapter.defaultInstance()` and injectable backend support.
3. Added conditional export for IO vs non-IO environments.
4. Added Linux `notify-send` backend via `Process.run`.
5. Added macOS `osascript` backend via `Process.run`.
6. Added stdout/log fallback backend for unsupported platforms and Windows.
7. Added desktop adapter tests covering delegation, Linux/macOS command selection, fallback behavior, fake-adapter scheduling workflow, and default adapter construction.
8. Wired desktop adapter tests into the root test wrapper.
### Notes
1. Windows currently uses the stdout fallback. Adding `windows_notification` would pull Flutter SDK dependencies into this pure Dart package; a true Windows toast adapter should be revisited if the desktop packaging layer already depends on Flutter.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_notifications_desktop`: passed.
3. `cd packages/scheduler_notifications_desktop && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_notifications_desktop && dart test`: passed, 6 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 324 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,40 @@
# V1 Block 23 — Export Abstraction Layer
**Purpose**: Define Export controller and writer interface.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 23.1 — Export controller contract
Recommended level: **XHIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Add package **`packages/scheduler_export`**.
2. Define abstract class `ExportWriter` with `Future<void> begin(ExportContext)`, `Future<void> writeTask(Task)`, `Future<void> end()`, plus factory registry.
3. Define `ExportController` orchestrating repository queries and writer.
4. Provide context object with `ownerId`, `timezone`, `version`.
### Acceptance criteria
1. JSONWriter and CSVWriter stubs compile and implement interface.
2. Unit test writes small set and verifies output.
### Completed implementation
1. Added package `packages/scheduler_export` with public entry points `export.dart` and `scheduler_export.dart`.
2. Added `ExportContext` carrying `ownerId`, `timezone`, and `version`.
3. Added `ExportWriter`, `ExportWriterFactory`, and `ExportWriterRegistry` with default `json` and `csv` mappings.
4. Added `ExportController` that reads owner-scoped paged tasks through `TaskRepository` and streams them to a writer.
5. Added compiling `JsonExportWriter` and `CsvExportWriter` implementations backed by `StringSink`.
6. Added unit tests for owner-scoped JSON export, CSV output, and custom writer factory registration.
7. Wired export tests into the root test wrapper.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_export`: passed.
3. `cd packages/scheduler_export && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_export && dart test`: passed, 3 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 327 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,73 @@
# V1 Block 24 — Backup & Export Library Package
**Purpose**: Encrypted backup and readable exports.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 24.1 — Encrypted backup implementation
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Within `packages/scheduler_backup`, implement function `Future<File> createEncryptedBackup({required String passphrase})` which copies SQLite file then AES-256 encrypts with `encrypt` package.
2. Implement `Future<void> restoreEncryptedBackup(File backup, String passphrase)`.
3. Store backup in `~/ADHD_Scheduler/backups/yyyymmdd_hhmm.db.enc`.
4. Add CLI script `bin/backup.dart` for manual backups.
### Acceptance criteria
1. Roundtrip backup/restore integration test passes using temp directory.
2. Wrong passphrase throws `BackupDecryptionException`.
### Completed implementation
1. Added package `packages/scheduler_backup` with public entry points `backup.dart` and `scheduler_backup.dart`.
2. Added `createEncryptedBackup({required String passphrase})` with optional test-path overrides.
3. Added `restoreEncryptedBackup(File backup, String passphrase)` with optional target-file override.
4. Added default source path `~/ADHD_Scheduler/scheduler.sqlite` and default backup directory `~/ADHD_Scheduler/backups/`.
5. Added backup naming as `yyyymmdd_hhmm.db.enc`, with collision suffixes when needed.
6. Added authenticated encrypted backup envelope using PBKDF2-HMAC-SHA256 with 200,000 iterations and AES-256-GCM.
7. Added `BackupDecryptionException` and `BackupException`.
8. Added CLI script `bin/backup.dart` for manual encrypted backups.
9. Added temp-directory round-trip and wrong-passphrase tests.
### Verification
1. `dart pub get`: passed.
2. `dart format .` in `packages/scheduler_backup`: passed.
3. `cd packages/scheduler_backup && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_backup && dart test`: passed, 2 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed after Chunk 24.2, 332 tests.
7. `scripts/test.sh`: not present or not executable.
---
## Chunk 24.2 — Readable export writers
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Implement `JsonExportWriter` and `CsvExportWriter` in `scheduler_export_json` package.
2. Hook into `ExportController` factory mapping.
### Acceptance criteria
1. Export command `bin/export.dart --json` outputs valid JSON verified by jsonDecode.
### Completed implementation
1. Added package `packages/scheduler_export_json` with public entry points `export_json.dart` and `scheduler_export_json.dart`.
2. Added concrete `JsonExportWriter` and `CsvExportWriter` implementations.
3. Added `readableExportWriterRegistry()` that maps `json` and `csv` writer factories for `ExportController`.
4. Added CLI script `bin/export.dart` supporting `--json`, `--csv`, `--owner`, and `--timezone`.
5. Added tests for JSON export, CSV quoting, and `bin/export.dart --json` output validated with `jsonDecode`.
6. Wired export-json tests into the root test wrapper.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_export_json`: passed.
3. `cd packages/scheduler_export_json && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_export_json && dart test`: passed, 3 tests.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 332 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,37 @@
# V1 Block 25 — Scheduler Integration Tests
**Purpose**: Endtoend tests.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 25.1 — Integration test harness
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Add test file `integration/scheduler_flow_test.dart` in `packages/scheduler_integration_tests`.
2. Spin up InMemory repos, schedule engine, fake notification adapter.
3. Create tasks, invoke scheduler, assert placements, save via SQLite adapter, reload and assert persistence.
### Acceptance criteria
1. Test passes on CI in < 2s runtime.
### Completed implementation
1. Added package `packages/scheduler_integration_tests`.
2. Added required integration test file `integration/scheduler_flow_test.dart`.
3. Added test wrapper `test/scheduler_flow_test.dart` so package-level `dart test` runs the integration flow.
4. Integration flow seeds `InMemoryTaskRepository`, invokes `SchedulingEngine.insertBacklogTaskIntoNextAvailableSlot`, asserts task placement, schedules through `FakeNotificationAdapter`, saves through `SqliteTaskRepository`, reloads, and asserts persisted schedule/status.
5. Added an in-test runtime guard asserting the flow completes in under 2 seconds.
6. Wired integration test into the root test wrapper.
### Verification
1. `dart pub get`: passed.
2. `dart format test/scheduler_core_test.dart packages/scheduler_integration_tests`: passed.
3. `cd packages/scheduler_integration_tests && dart analyze`: passed, no issues found.
4. `cd packages/scheduler_integration_tests && dart test`: passed, 1 test.
5. `dart analyze`: passed, no issues found.
6. `dart test`: passed, 333 tests.
7. `scripts/test.sh`: not present or not executable.
---

View file

@ -0,0 +1,37 @@
# V1 Block 26 — Verification & Contract Test Suite
**Purpose**: Repository contract tests.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 26.1 — Coverage & adapter verification
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Extend repo conformance tests to compute coverage report using `dart run coverage`.
2. Fail CI if coverage < 80%.
3. Ensure desktop notification adapter passes mock contract tests.
### Acceptance criteria
1. Coverage report generated in CI artifacts; threshold met.
### Completed implementation
1. Added root dev dependency `coverage`.
2. Added executable `scripts/test.sh` running `dart analyze`, `dart test`, `dart run coverage:test_with_coverage`, and an 80% coverage threshold check.
3. Added `tool/check_coverage.dart` to parse `coverage/lcov.info`, scope coverage to package `lib/` code, exclude generated `.g.dart`, and fail below threshold.
4. Added shared notification adapter contract test helper `packages/scheduler_notifications/test/notification_adapter_contract.dart`.
5. Ran the contract against `FakeNotificationAdapter`.
6. Ran the same contract against `DesktopNotificationAdapter` using a recording backend.
7. Normalized desktop adapter cancellation ids before passing them to the backend.
### Verification
1. `dart pub get`: passed.
2. `dart format ...`: passed for touched Dart files.
3. `cd packages/scheduler_notifications && dart analyze && dart test`: passed, 4 tests.
4. `cd packages/scheduler_notifications_desktop && dart analyze && dart test`: passed, 8 tests.
5. `scripts/test.sh`: passed.
6. Coverage result: 83.31% package `lib/` line coverage, above the 80% threshold.
---

View file

@ -0,0 +1,69 @@
# V1 Block 27 — Deployment & Dev Experience
**Purpose**: Dev scripts and packaging.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 27.1 — Dev/test scripts & CI
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Create `scripts/dev.dart` which executes `dart run build_runner watch` and launches Flutter desktop with hot reload pointing to local SQLite file.
2. Create `scripts/test.dart` running `dart pub global activate coverage`, `dart test --coverage=coverage`, then combine reports.
3. GitHub Actions YAML to run tests matrix {ubuntu-latest, windows-latest, macos-latest}.
### Acceptance criteria
1. Running `dart run scripts/dev.dart` starts app and prints sqlite path.
2. CI green on all platforms.
### Completed implementation
1. Added `scripts/dev.dart` that prints the SQLite path, starts `dart run build_runner watch --delete-conflicting-outputs`, and launches `flutter run` for the current/selected desktop device with `SCHEDULER_SQLITE_PATH`.
2. Added `scripts/test.dart` that runs `dart pub global activate coverage`, `dart test --coverage=coverage`, combines LCOV with `coverage:format_coverage`, and enforces the 80% threshold.
3. Updated `scripts/test.sh` to run analyzer plus `scripts/test.dart`.
4. Added GitHub Actions workflow `.github/workflows/ci.yml` with test matrix `ubuntu-latest`, `windows-latest`, and `macos-latest`.
5. Added `scripts/bootstrap_dev.sh` and `scripts/dev.sh` wrappers so the
agent rule file has concrete shell entry points for setup and development.
### Verification
1. `dart pub get`: passed.
2. `dart format scripts/dev.dart scripts/test.dart`: passed.
3. `dart analyze`: passed, no issues found.
4. `dart run scripts/test.dart`: passed, coverage 83.27%.
5. `bash -n scripts/bootstrap_dev.sh scripts/dev.sh`: passed.
6. `scripts/test.sh`: passed.
7. `dart run scripts/dev.dart` and `scripts/dev.sh`: not executed locally because they launch a long-running Flutter desktop session and require the Flutter app/toolchain.
---
## Chunk 27.2 — Packaging scripts
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Add `scripts/build.dart` building Flutter macOS .app, Windows .exe + msix, Linux AppImage.
2. Document prerequisites in README.
### Acceptance criteria
1. Artifacts upload step in CI produces release binaries.
### Completed implementation
1. Added `scripts/build.dart` with platform targets `current`, `macos`, `windows`, and `linux`.
2. macOS target runs `flutter build macos --release` and copies `.app` artifacts.
3. Windows target runs `flutter build windows --release`, copies the release bundle, and runs `dart run msix:create`.
4. Linux target runs `flutter build linux --release` and `appimage-builder --recipe AppImageBuilder.yml --skip-test`.
5. Added tagged CI packaging job with matrix `linux`, `windows`, and `macos`, plus artifact upload from `build/releases/`.
6. Replaced README with workspace test, development, packaging, and prerequisite instructions.
7. Added `scripts/package_release.sh` wrapper for the release packaging runner
named in the agent rule file.
### Verification
1. `dart format scripts/build.dart`: passed.
2. `dart analyze`: passed, no issues found.
3. `bash -n scripts/package_release.sh`: passed.
4. `scripts/test.sh`: passed.
5. Packaging commands were not executed locally because they require Flutter desktop toolchains, platform-specific packaging tools, and app packaging config.
---

View file

@ -0,0 +1,36 @@
# V1 Block 28 — Projectwide Documentation Sweep
**Purpose**: JavaDoc-style commenting.
> **Note for Codex**: Follow tasks exactly; avoid exploratory calls when tasks specify names/files/tests.
## Chunk 28.1 — Documentation sweep
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Enable `dart doc` in CI; fail build if undocumented public members.
2. Add docs to all public symbols across packages using tripleslash style.
3. Document build scripts and CI YAML with comments at top describing purpose.
### Acceptance criteria
1. `dart doc` generates site without warnings.
2. CI passes doc coverage gate.
### Completed implementation
1. Added `tool/check_docs.dart` to generate docs for every package with a `lib/` directory under `doc/api/packages/`.
2. The doc gate fails on any `dart doc` warning or nonzero doc generation exit.
3. Added doc generation to `scripts/test.dart`, so `scripts/test.sh` and CI run the docs gate.
4. Updated CI artifact upload to include generated docs under `doc/api/`.
5. Added `.gitignore` entry for generated `doc/api/` output.
6. Fixed unresolved documentation references in `scheduler_core`, `scheduler_export`, and `scheduler_export_json`.
7. Added top-of-file purpose comments to `scripts/dev.dart`, `scripts/test.dart`, `scripts/build.dart`, `tool/check_coverage.dart`, `tool/check_docs.dart`, and `.github/workflows/ci.yml`.
### Verification
1. `dart run tool/check_docs.dart`: passed; docs generated for all public-library packages with 0 warnings and 0 errors.
2. `dart analyze`: passed, no issues found.
3. `scripts/test.sh`: passed.
4. Coverage result in final gate: 83.27% package `lib/` line coverage, above the 80% threshold.
---

View file

@ -0,0 +1,153 @@
# V1 Block 29 — Flutter UI Foundation
**Purpose**: Restart the V1 Flutter UI foundation after the SQLite-first backend
refresh, without moving scheduling or persistence rules into widgets.
> **Note for Codex**: Keep the scheduler core Flutter-free. UI code may depend
> on public package APIs and read models only.
## Chunk 29.1 — Flutter app shell and in-memory composition
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Add `apps/focus_flow_flutter` as a Flutter application outside the root Dart
workspace for now.
2. Wire a minimal in-memory composition root using public scheduler packages.
3. Render provisional Today and Backlog shells from application/read-model data.
4. Add app startup, theme/token placeholders, and a widget test harness.
5. Document UI-specific analyze/test commands without changing `scripts/test.sh`
until Flutter CI gating is intentionally added.
### Acceptance criteria
1. `cd apps/focus_flow_flutter && flutter analyze` passes.
2. `cd apps/focus_flow_flutter && flutter test` passes.
3. Core packages remain Flutter-free and `scripts/test.sh` still passes.
4. UI code does not import Drift, SQLite, platform notification APIs, or core
`lib/src/` paths directly.
5. Today and Backlog screens render from read-model objects, not duplicated
scheduling rules.
BREAKPOINT: Stop here. Confirm `high` before adding navigation/controllers and
component contracts.
### Completed implementation
1. Added `apps/focus_flow_flutter` as a Flutter desktop app outside the root
Dart workspace.
2. Added a local path dependency on `packages/scheduler_core`.
3. Replaced the starter counter template with `FocusFlowApp`, a seeded
`DemoSchedulerComposition`, and Today/Backlog tabs rendered from
`TodayState` and `BacklogQueryResult`.
4. Added a widget test that verifies Today and Backlog read-model data renders
through the Flutter shell.
5. Documented app-local Flutter analyze/test commands in the README.
### Verification
1. `flutter pub get` in `apps/focus_flow_flutter`: passed.
2. `dart format apps/focus_flow_flutter/lib/main.dart apps/focus_flow_flutter/test/widget_test.dart`: passed.
3. `cd apps/focus_flow_flutter && flutter analyze`: passed, no issues found.
4. `cd apps/focus_flow_flutter && flutter test`: passed, 1 widget test.
---
## Chunk 29.2 — UI controllers and component contracts
Recommended level: **HIGH**
Status: Complete on 2026-06-26.
### Tasks
1. Split seeded composition, read controllers, and widgets into focused files
under `apps/focus_flow_flutter/lib/`.
2. Add controller states for loading, empty, typed failure, and retry paths for
Today and Backlog.
3. Add provisional component contracts for timeline rows, compact panels,
backlog rows, notice banners, and staleness markers.
4. Centralize token-to-visual mapping for project color, task type background,
reward icon, and difficulty icon.
5. Add widget tests for compact rendering, backlog empty state, and typed failure
state.
### Acceptance criteria
1. `cd apps/focus_flow_flutter && flutter analyze` passes.
2. `cd apps/focus_flow_flutter && flutter test` passes.
3. `scripts/test.sh` still passes.
4. Widgets import app controllers/read models, not persistence adapters or
scheduler internals.
5. Component contracts satisfy the remaining MVP-AC-05 token-mapping gap without
locking final visual design.
BREAKPOINT: Stop here. Confirm `high` before adding command flows and a vertical
quick-capture smoke slice.
### Completed implementation
1. Split `lib/main.dart` into app shell, seeded composition, read controllers,
visual-token mapping, and focused widgets under `apps/focus_flow_flutter/lib/`.
2. Added `UiReadController<T>` and `ApplicationReadController<T>` with loading,
data, empty, typed-failure, and retry states.
3. Added provisional component contracts for compact panels, timeline rows,
backlog rows, notice banners, staleness markers, empty state, and failure
state.
4. Centralized project color, task-type background, reward icon, difficulty
icon, and staleness-marker visual mapping in `SchedulerVisualTokens`.
5. Added widget tests for seeded Today/Backlog rendering, compact rendering,
Backlog empty state, and typed failure retry.
### Verification
1. `dart format lib test` in `apps/focus_flow_flutter`: passed.
2. `cd apps/focus_flow_flutter && flutter analyze`: passed, no issues found.
3. `cd apps/focus_flow_flutter && flutter test`: passed, 4 widget tests.
4. Forbidden-import scan for app `lib/` and `test/`: no persistence adapters,
scheduler `src/` imports, Drift, or SQLite imports found.
---
## Chunk 29.3 — Command flows and vertical quick-capture slice
Recommended level: **HIGH**
Status: Complete on 2026-06-28.
### Tasks
1. Add UI controllers for quick capture, schedule-from-backlog, and mark-done
commands using public application command use cases.
2. Add forms/actions for title-only quick capture, duration entry, and done.
3. Refresh Today and Backlog controllers after successful commands.
4. Add typed conflict/failure states for command attempts.
5. Add a widget/integration smoke test for quick capture → Backlog → schedule →
Today → done using in-memory composition.
### Acceptance criteria
1. `cd apps/focus_flow_flutter && flutter analyze` passes.
2. `cd apps/focus_flow_flutter && flutter test` passes.
3. `scripts/test.sh` still passes.
4. Widgets continue to call public app controllers/use cases only.
5. No scheduling rules are implemented in Flutter widgets.
BREAKPOINT: Stop here. Confirm `high` before adding persistent SQLite-backed UI
composition or broader screen expansion.
### Completed implementation
1. Added `SchedulerCommandController` command states and public-use-case-backed
command methods for quick capture, schedule-from-backlog, and mark-done.
2. Wired the command controller into the app shell, Backlog pane, and Today pane,
with successful commands refreshing both read controllers.
3. Added title-only quick capture, duration entry/schedule actions, done actions,
and command status/failure feedback in the Flutter widgets.
4. Added a vertical widget smoke test for quick capture → Backlog → schedule →
Today → done using the in-memory demo composition.
5. Bounded widget-test settling through a shared helper so `pumpAndSettle` cannot
wait indefinitely.
### Verification
1. `scripts/bootstrap_dev.sh`: passed.
2. `cd apps/focus_flow_flutter && flutter analyze`: passed, no issues found.
3. `cd apps/focus_flow_flutter && flutter test`: passed, 5 widget tests.
4. `scripts/test.sh`: passed, including root analyze, 338 Dart tests, 83.27%
package coverage, documentation checks, and API doc generation.
5. Forbidden-import scan for app `lib/` and `test/`: no persistence adapters,
scheduler `src/` imports, Drift, SQLite, platform APIs, or `dart:io` imports
found.
---
---

View file

@ -0,0 +1,582 @@
# V1 Public API Baseline
Status: Captured during Block 11.1.
Starting commit: `775c2ed406f03a73a9b0ca621dea5b4482468616`
Public import:
```dart
import 'package:scheduler_core/scheduler_core.dart';
```
The public library entry point is `lib/scheduler_core.dart`. It exports the
following source files:
- `src/models.dart`
- `src/application_commands.dart`
- `src/application_layer.dart`
- `src/application_management.dart`
- `src/application_recovery.dart`
- `src/backlog.dart`
- `src/child_tasks.dart`
- `src/document_mapping.dart`
- `src/free_slots.dart`
- `src/locked_time.dart`
- `src/occupancy_policy.dart`
- `src/persistence_contract.dart`
- `src/project_statistics.dart`
- `src/quick_capture.dart`
- `src/reminder_policy.dart`
- `src/repositories.dart`
- `src/scheduling_engine.dart`
- `src/task_actions.dart`
- `src/task_lifecycle.dart`
- `src/task_statistics.dart`
- `src/time_contracts.dart`
- `src/today_state.dart`
- `src/timeline_state.dart`
This baseline is used by later chunks to distinguish intentional breaking
changes from accidental API drift.
## Public enums
| File | Enums |
|---|---|
| `src/application_commands.dart` | `ApplicationCommandCode` |
| `src/application_management.dart` | `ApplicationManagementCommandCode`, `OwnerSettingsWarningCode` |
| `src/application_recovery.dart` | `AppOpenRecoveryOutcome` |
| `src/application_layer.dart` | `ApplicationFailureCode` |
| `src/document_mapping.dart` | `DocumentMappingFailureCode` |
| `src/models.dart` | `DomainValidationCode`, `TaskType`, `TaskStatus`, `PriorityLevel`, `RewardLevel`, `DifficultyLevel`, `ReminderProfile`, `BacklogTag` |
| `src/backlog.dart` | `BacklogFilter`, `BacklogSortKey`, `BacklogStalenessMarker` |
| `src/free_slots.dart` | `RequiredCommitmentScheduleStatus` |
| `src/locked_time.dart` | `LockedWeekday`, `LockedBlockOverrideType` |
| `src/occupancy_policy.dart` | `OccupancyCategory`, `OccupancySource` |
| `src/project_statistics.dart` | `ProjectCompletionTimeBucket`, `ProjectSuggestionType`, `ProjectSuggestionConfidence` |
| `src/quick_capture.dart` | `QuickCaptureStatus` |
| `src/reminder_policy.dart` | `ReminderDirectiveAction`, `ReminderDirectiveReason`, `EffectiveReminderProfileSource` |
| `src/scheduling_engine.dart` | `SchedulingNoticeType`, `SchedulingOperationCode`, `SchedulingOutcomeCode`, `SchedulingIssueCode`, `SchedulingMovementCode`, `SchedulingConflictCode` |
| `src/task_actions.dart` | `FlexibleTaskQuickAction`, `RequiredTaskAction`, `PushDestination` |
| `src/task_lifecycle.dart` | `TaskTransitionCode`, `TaskActivityCode`, `TaskTransitionOutcomeCode` |
| `src/time_contracts.dart` | `LocalTimeResolution`, `NonexistentLocalTimePolicy`, `RepeatedLocalTimePolicy` |
| `src/today_state.dart` | `TodayTimelineItemSource` |
| `src/timeline_state.dart` | `TimelineItemCategory`, `TimelineBackgroundToken`, `TimelineRewardIconToken`, `TimelineDifficultyIconToken`, `TimelineQuickAction` |
## Public classes and top-level functions
| File | Public API |
|---|---|
| `src/application_commands.dart` | `ApplicationChildTaskDraft`, `ApplicationCommandReadHint`, `ApplicationCommandResult`, `V1ApplicationCommandUseCases` |
| `src/application_layer.dart` | `OwnerTimeZoneContext`, `ApplicationOperationContext`, `ApplicationFailure`, `ApplicationResult`, `ApplicationFailureException`, `ApplicationPersistenceException`, `ApplicationOperationRecord`, `NoticeAcknowledgementRecord`, `OwnerSettings`, `TaskActivityRepository`, `ProjectStatisticsRepository`, `OwnerSettingsRepository`, `NoticeAcknowledgementRepository`, `ApplicationOperationRepository`, `ApplicationUnitOfWorkRepositories`, `ApplicationUnitOfWork`, `ApplicationSchedulingLoader`, `InMemoryApplicationUnitOfWork` |
| `src/application_management.dart` | `GetBacklogRequest`, `BacklogItemReadModel`, `BacklogQueryResult`, `GetProjectDefaultsRequest`, `ProjectDefaultsQueryResult`, `ProjectProfileDraft`, `ProjectProfileUpdate`, `LockedBlockDraft`, `LockedBlockUpdate`, `OwnerSettingsUpdateResult`, `OwnerSettingsUpdate`, `NoticeAcknowledgementResult`, `V1ApplicationManagementUseCases` |
| `src/application_recovery.dart` | `RunAppOpenRecoveryRequest`, `AppOpenRecoveryResult`, `V1AppOpenRecoveryUseCases` |
| `src/models.dart` | `DomainValidationException`, `Task`, `ProjectProfile`, `TimeInterval` |
| `src/backlog.dart` | `BacklogStalenessSettings`, `BacklogView` |
| `src/child_tasks.dart` | `ChildTaskEntry`, `ChildTaskBreakUpRequest`, `ChildTaskBreakUpResult`, `ChildTaskBreakUpService`, `ChildTaskView`, `ChildTaskCompletionResult`, `ChildTaskCompletionService`, `ChildTaskSummary` |
| `src/document_mapping.dart` | `DocumentMappingException`, `DocumentMetadata`, `PersistenceEnumMapping`, `TaskDocumentMapping`, `TaskStatisticsDocumentMapping`, `ProjectDocumentMapping`, `ProjectStatisticsDocumentMapping`, `LockedBlockRecurrenceDocumentMapping`, `LockedBlockDocumentMapping`, `LockedBlockOverrideDocumentMapping`, `TaskActivityDocumentMapping`, `OwnerSettingsDocumentMapping`, `BacklogStalenessDocumentMapping`, `NoticeAcknowledgementDocumentMapping`, `ApplicationOperationDocumentMapping`, `SchedulingSnapshotDocumentMapping`, `SchedulingWindowDocumentMapping`, `TimeIntervalDocumentMapping`, `SchedulingNoticeDocumentMapping`, `SchedulingChangeDocumentMapping`, `SchedulingOverlapDocumentMapping`, `TaskDocumentExtension`, `TaskStatisticsDocumentExtension`, `ProjectStatisticsDocumentExtension` |
| `src/free_slots.dart` | `ProtectedFreeSlotConflict`, `RequiredCommitmentScheduleResult`, `FreeSlotService` |
| `src/locked_time.dart` | `ClockTime`, `LockedBlockRecurrence`, `LockedBlock`, `LockedBlockOccurrence`, `LockedBlockOverride`, `LockedScheduleExpansion`, `expandLockedBlocksForDay`, `lockedSchedulingIntervalsForDay`, `trackCompletedDuringLockedHours`, `completedDuringLockedHoursMinutes` |
| `src/occupancy_policy.dart` | `OccupancyEntry`, `OccupancyPolicy` |
| `src/persistence_contract.dart` | `v1SchemaVersion`, `PersistenceDateTimeConvention`, `PersistenceCivilDateConvention`, `PersistenceWallTimeConvention`, `PersistenceEnumName`, V1 document field-name classes |
| `src/project_statistics.dart` | `ProjectStatistics`, `ProjectStatisticsApplicationResult`, `ProjectStatisticsAggregationService`, `ProjectSuggestionPolicy`, `ProjectSuggestion`, `ProjectSuggestionSet`, `ProjectDefaultResolution`, `ProjectSuggestionService` |
| `src/quick_capture.dart` | `QuickCaptureRequest`, `QuickCaptureResult`, `QuickCaptureService` |
| `src/reminder_policy.dart` | `EffectiveReminderProfile`, `ReminderDirective`, `ReminderPolicyService` |
| `src/repositories.dart` | `SchedulingStateSnapshot`, `InMemoryTaskRepository`, `InMemoryProjectRepository`, `InMemoryLockedBlockRepository`, `InMemorySchedulingSnapshotRepository` |
| `src/scheduling_engine.dart` | `SchedulingWindow`, `SchedulingInput`, `SchedulingChange`, `SchedulingOverlap`, `SchedulingNotice`, `SchedulingResult`, `SchedulingEngine` |
| `src/task_actions.dart` | `FlexibleTaskActionResult`, `PushDestinationResult`, `RequiredTaskActionResult`, `SurpriseTaskLogRequest`, `SurpriseTaskLogResult`, `FlexibleTaskActionService`, `RequiredTaskActionService`, `SurpriseTaskLogService` |
| `src/task_lifecycle.dart` | `TaskActivity`, `TaskActivityApplicationResult`, `TaskActivityAccountingService`, `TaskTransitionResult`, `TaskTransitionService` |
| `src/task_statistics.dart` | `TaskStatistics` |
| `src/time_contracts.dart` | `Clock`, `SystemClock`, `FixedClock`, `IdGenerator`, `SequentialIdGenerator`, `CivilDate`, `WallTime`, `TimeZoneResolutionOptions`, `ResolvedLocalDateTime`, `TimeZoneResolver`, `FixedOffsetTimeZoneResolver` |
| `src/today_state.dart` | `GetTodayStateRequest`, `TodayTimelineItem`, `TodayCompactState`, `TodayPendingNotice`, `TodayState`, `GetTodayStateQuery` |
| `src/timeline_state.dart` | `TimelineItem`, `CompactTimelineState`, `TimelineItemMapper` |
## Current model baseline
`TaskType` values:
- `flexible`
- `inflexible`
- `critical`
- `locked`
- `surprise`
- `freeSlot`
`TaskStatus` values:
- `planned`
- `active`
- `completed`
- `missed`
- `cancelled`
- `noLongerRelevant`
- `backlog`
Current notable model fields:
- `Task`: `id`, `title`, `projectId`, `type`, `status`, `priority`,
`reward`, `difficulty`, `durationMinutes`, `scheduledStart`, `scheduledEnd`,
`actualStart`, `actualEnd`, `completedAt`, `parentTaskId`, `backlogTags`,
`reminderOverride`, `createdAt`, `updatedAt`, `stats`
- `ProjectProfile`: `id`, `name`, `colorKey`, default priority/reward/
difficulty/reminder profile/duration fields, `archivedAt`
- `ProjectStatistics`: completion count, duration sample counts,
completion-time buckets, pushes-before-completion totals, reward/difficulty
distributions, and reminder-profile observations
- `TimeInterval`: `start`, `end`, optional `label`
- `TaskStatistics`: skip/push/backlog/missed/cancelled/late/locked-hour,
completed-after-shield, and push-before-completion counters. Parent/child
completion patterns are carried as activity metadata.
Known baseline gaps to preserve as explicit later work:
- `TaskStatus` does not include `pushed` or `skipped`; Chunk 11.2 resolves the
status/event distinction.
- `Task` does not yet have an explicit backlog-entered timestamp field.
- Instant ranges still use `DateTime`; locked recurrence dates, wall-clock
rules, clocks, IDs, and timezone resolution are explicit Chunk 11.4
contracts.
## Intentional API Changes After Baseline
Chunk 11.3 intentionally changed the public API:
- Added `DomainValidationCode` and `DomainValidationException`.
- Added `Task.actualStart`, `Task.actualEnd`, and `Task.reminderOverride`.
- Added explicit `copyWith` clear flags for nullable task fields.
- Added `ProjectProfile.copyWith(clearDefaultDuration: true)`.
- Changed several public value constructors from `const` to runtime-validating
constructors.
- Public collection fields now expose unmodifiable snapshots instead of caller
mutable collections.
Chunk 11.4 intentionally changed the public API:
- Added clock, ID, civil-date, wall-time, timezone resolver, DST policy, and
fixed-offset resolver contracts in `src/time_contracts.dart`.
- Exported `src/time_contracts.dart` from `scheduler_core.dart`.
- Added `nonexistentLocalTime` and `ambiguousLocalTime` validation codes.
- Changed `ClockTime` to a backwards-compatible alias of `WallTime`.
- Changed locked block dates and override dates from `DateTime` to `CivilDate`.
- Changed locked-time expansion helpers and override interval conversion to
require explicit `timeZoneId` and `TimeZoneResolver`.
- Added injected `Clock` boundaries to scheduling/action/child completion
services and optional `IdGenerator` convenience wrappers for quick capture and
surprise logging.
- Added civil-date and wall-time persistence conventions that store strings
without timezone conversion.
Chunk 12.1 intentionally changed the public API:
- Added `src/occupancy_policy.dart` and exported it from `scheduler_core.dart`.
- Added `OccupancyCategory`, `OccupancySource`, `OccupancyEntry`, and
`OccupancyPolicy`.
- Added policy-derived `SchedulingInput.occupancyEntries`,
`SchedulingInput.movablePlannedFlexibleTasks`, and
`SchedulingInput.conflictReportingOccupancies`.
- Changed `SchedulingInput.blockedIntervals` to derive from the central
occupancy policy rather than from duplicated task-type filters.
Chunk 12.2 intentionally changed the public API:
- Added `src/free_slots.dart` and exported it from `scheduler_core.dart`.
- Added `RequiredCommitmentScheduleStatus`, `ProtectedFreeSlotConflict`,
`RequiredCommitmentScheduleResult`, and `FreeSlotService`.
- Added validated Free Slot create/update helpers and a typed explicit required
commitment scheduling result for protected-rest conflicts.
Chunk 12.3 intentionally changed the public API:
- Added optional `revealHiddenLockedDetails` parameters to
`SurpriseTaskLogService.log` and `SurpriseTaskLogService.logNew`.
- Defined `SurpriseTaskLogRequest.id` as the idempotency key for retrying the
same surprise log operation.
- Surprise tasks with known time now populate `actualStart` and `actualEnd` in
addition to the existing scheduled interval compatibility fields.
Chunk 12.4 intentionally changed the public API:
- Added stable scheduler code enums: `SchedulingOperationCode`,
`SchedulingOutcomeCode`, `SchedulingIssueCode`, `SchedulingMovementCode`, and
`SchedulingConflictCode`.
- Added `SchedulingResult.operationCode` and `SchedulingResult.outcomeCode`.
- Added `SchedulingNotice.issueCode`, `SchedulingNotice.movementCode`,
`SchedulingNotice.conflictCode`, and immutable `SchedulingNotice.parameters`.
- Changed `SchedulingNotice` from a `const` constructor to a runtime constructor
so notice parameters can be defensively copied.
- Added a `SchedulingResult` assertion that each notice uses at most one issue,
movement, or conflict code.
Chunk 13.1 intentionally changed the public API:
- Added `src/task_lifecycle.dart` and exported it from `scheduler_core.dart`.
- Added `TaskTransitionCode`, `TaskActivityCode`, `TaskTransitionOutcomeCode`,
`TaskActivity`, `TaskTransitionResult`, and `TaskTransitionService`.
- Added `Task.completedAt` and `Task.copyWith(clearCompletion: true)`.
- Added `TaskActivityDocumentFields` and `TaskDocumentFields.completedAt`.
- Added activity and transition outcome fields to flexible, push-destination, and
required task action results.
- Routed flexible/required direct action services through the canonical
transition service while preserving existing scheduling helper compatibility.
Chunk 13.2 intentionally changed the public API:
- Added `TaskActivityApplicationResult` and `TaskActivityAccountingService`.
- Added `TaskStatistics.completedAfterShieldCount`,
`TaskStatistics.completedAfterPushCount`, and
`TaskStatistics.totalPushesBeforeCompletion`.
- Added `TaskStatistics.recordPushesBeforeCompletion`.
- Added matching `TaskStatisticsDocumentFields` constants and document mapping.
- Added `appliedActivityIds` and `lockedIntervals` parameters to
`TaskTransitionService.apply`.
- Added actual/locked interval parameters to flexible and required action
completion paths.
- Added `SurpriseTaskLogResult.activities` and routed surprise completion
through the same accounting boundary.
Chunk 13.3 intentionally changed the public API:
- Added `ChildTaskBreakUpRequest`, `ChildTaskBreakUpResult`, and
`ChildTaskBreakUpService`.
- Added `activities` and `transitionOutcomeCodes` to
`ChildTaskCompletionResult`.
- Added `transitionService` injection to `ChildTaskCompletionService`.
- Added `operationId`, existing-activity, and applied-activity parameters to
child and parent completion methods.
- Added `ChildTaskCompletionService.completeParentFromChild`.
- Routed parent/child completion through canonical lifecycle transitions and
parent/child completion metadata.
Chunk 13.4 intentionally changed the public API:
- Added `src/project_statistics.dart` and exported it from `scheduler_core.dart`.
- Added project-statistics enums, aggregate model, exactly-once aggregation
result/service, suggestion policy/result types, and configured-default
resolution.
- Added `ProjectStatisticsDocumentFields`,
`ProjectStatisticsDocumentMapping`, and `ProjectStatisticsDocumentExtension`.
- Added project-statistics field sets to the persistence field registry.
- Expanded completion activity metadata with duration, reward, difficulty, and
reminder-profile observations for project aggregation.
Chunk 13.5 intentionally changed the public API:
- Added `src/reminder_policy.dart` and exported it from `scheduler_core.dart`.
- Added reminder directive action/reason enums and effective-profile source
enum.
- Added `EffectiveReminderProfile`, `ReminderDirective`, and
`ReminderPolicyService`.
- Added deterministic effective-profile resolution using task override, project
configured default, then fallback.
- Added typed reminder directives for normal delivery, suppression, deferral,
and required-task acknowledgement, including protected Free Slot suppression.
Chunk 14.1 intentionally changed the public API:
- Added `src/application_layer.dart` and exported it from
`scheduler_core.dart`.
- Added application operation context, owner time-zone context, typed
result/failure contracts, and expected application/persistence exceptions.
- Added activity, project-statistics, owner-settings, operation-record, and
unit-of-work repository contracts for application orchestration.
- Added `OwnerSettings`, `ApplicationOperationRecord`,
`ApplicationSchedulingLoader`, and `InMemoryApplicationUnitOfWork`.
- Added in-memory staged transaction behavior with exactly-once operation
records and rollback on typed failures or persistence failures.
Chunk 14.2 intentionally changed the public API:
- Added `src/today_state.dart` and exported it from `scheduler_core.dart`.
- Added `GetTodayStateQuery`, `GetTodayStateRequest`, `TodayState`,
`TodayTimelineItem`, `TodayCompactState`, and `TodayPendingNotice`.
- Added `TodayTimelineItemSource` for stable task-vs-overlay source metadata.
- Added `ApplicationUnitOfWork.read` so application queries can access
repositories without creating operation records.
- Added an optional `occurrenceDate` parameter to
`TimelineItemMapper.fromLockedOccurrence` so Today read models can produce
date-stable locked overlay IDs.
- Updated compact next-flexible selection so the current flexible item is not
also returned as `nextFlexibleItem`.
Chunk 14.3 intentionally changed the public API:
- Added `src/application_commands.dart` and exported it from
`scheduler_core.dart`.
- Added `ApplicationCommandCode`, `ApplicationChildTaskDraft`,
`ApplicationCommandReadHint`, `ApplicationCommandResult`, and
`V1ApplicationCommandUseCases`.
- Added atomic V1 commands for quick capture, backlog scheduling, flexible
push/backlog/completion, required task actions, surprise logging, protected
Free Slot create/update/remove, child break-up, and parent/child completion.
- Command results return changed tasks, persisted activities, project aggregate
updates, scheduler notices/changes/overlaps, child ids, and read refresh
hints.
- Application command failures use stable `ApplicationFailureCode` values for
not found, stale revision, no slot, validation, persistence, and duplicate
operation outcomes.
Chunk 14.4 intentionally changed the public API:
- Added `src/application_management.dart` and exported it from
`scheduler_core.dart`.
- Added management query/command contracts for backlog, project defaults,
project create/update/archive, locked-block create/update/archive, one-day
locked overrides, owner settings updates, and notice acknowledgement.
- Added `ProjectProfile.archivedAt` and `LockedBlock.archivedAt` soft-archive
fields.
- Added `NoticeAcknowledgementRecord` and
`NoticeAcknowledgementRepository`.
- Added stable notice IDs to `TodayPendingNotice` and Today-state filtering for
acknowledged notices.
Chunk 14.5 intentionally changed the public API:
- Added `src/application_recovery.dart` and exported it from
`scheduler_core.dart`.
- Added `AppOpenRecoveryOutcome`, `RunAppOpenRecoveryRequest`,
`AppOpenRecoveryResult`, and `V1AppOpenRecoveryUseCases`.
- Added `InMemoryApplicationUnitOfWork.currentSchedulingSnapshots` for
application/recovery contract tests.
Chunk 15.2 intentionally changed the public API:
- Replaced legacy enum `.name` document encoding in `document_mapping.dart` with
explicit stable V1 code tables through `PersistenceEnumMapping`.
- Added `DocumentMappingFailureCode`, `DocumentMappingException`, and
`DocumentMetadata`.
- Expanded document codecs to every V1 persisted entity: project profiles,
project statistics, locked blocks/overrides, activities, owner settings,
notice acknowledgements, operation records, scheduling snapshots, notices,
changes, overlaps, windows, intervals, civil dates, and wall times.
- Changed top-level document `toDocument` helpers/extensions to require owner
scope and V1 metadata where the domain model does not carry it directly.
- Expanded `persistence_contract.dart` with `v1SchemaVersion`, common document
fields, and V1 field sets for every persisted repository entity.
Chunk 15.3 intentionally changed the public API:
- Added `src/document_migration.dart` and exported it from `scheduler_core.dart`.
- Added `V1DocumentMigrationService` for pure Dart V0-to-V1 migration of task,
project, locked block, and locked override documents.
- Added typed migration surface area:
`DocumentMigrationEntity`, `DocumentMigrationStatus`,
`DocumentMigrationFailureCode`, `DocumentMigrationNoteCode`,
`DocumentMigrationProvenance`, `DocumentMigrationNote`,
`DocumentMigrationReport`, and `DocumentMigrationResult`.
- Migration results expose `document`, `isSuccess`, and `shouldWrite` so
persistence adapters can dry-run migrations and refuse to overwrite unreadable
source documents.
- Legacy backlog tasks now carry explicit provenance when `backlogEnteredAt` is
approximated from `createdAt`.
Chunk 15.4 intentionally changed the public API:
- Added adapter-neutral repository conflict/paging/record contracts:
`RepositoryFailureCode`, `RepositoryFailure`, `RepositoryMutationResult`,
`RepositoryRecord`, `RepositoryPageRequest`, `RepositoryPage`, and
`BacklogCandidateQuery`.
- Expanded `TaskRepository` with owner, project, parent, backlog-candidate,
local-day/window, record/revision, insert, and compare-and-set save methods.
- Expanded `ProjectRepository` and `LockedBlockRepository` with owner-scoped
paged queries, revision records, compare-and-set saves, duplicate insert
failures, archive methods, and date-scoped locked override lookup.
- Expanded application-layer repository interfaces for task activity owner
queries/appends, project statistics/settings revision saves, notice
acknowledgement insert/paging, and idempotent operation lookup/insert.
- In-memory unit-of-work repositories now track owner/revision metadata in the
staged transaction state.
Chunk 15.5 intentionally changed the public API:
- Added V1 collection/index contract types and constants:
`PersistenceCollections`, `PersistenceIndexDirection`,
`PersistenceIndexField`, `PersistenceIndexSpec`, `RepositoryQueryNames`, and
`PersistenceIndexCatalog`.
- Added bounded payload/retention guard surface:
`PersistencePayloadLimits`, `PersistenceGuardResult`, and
`PersistencePayloadGuard`.
- Added repository integrity failure codes for invalid revisions and owner
mismatches.
- Added `V1_BLOCK_16_REPOSITORY_ADAPTER_CHECKLIST.md` for the former document
adapter implementation prerequisites, archived after the SQLite-first pivot.
Chunk 19.1 intentionally changed the public/package API:
- Rehomed the core library under `packages/scheduler_core` with public import
`package:scheduler_core/scheduler_core.dart`.
- Added shared repository value objects exported from `scheduler_core`:
`OwnerId`, `Revision`, `PageRequest`, and `Page<T>`.
- Added `packages/scheduler_persistence` with domain-only repository
interfaces for tasks, projects, locked blocks, settings, and schedule
snapshots.
- Added `RepositoryFailure` variants, sealed `Either<L, R>`, and
`RepoResult<T>` for expected repository success/failure paths.
Chunk 19.2 intentionally changed the public/package API:
- Added `packages/scheduler_persistence_memory` with
`InMemoryTaskRepository`, `InMemoryProjectRepository`,
`InMemoryLockedBlockRepository`, `InMemorySettingsRepository`, and
`InMemoryScheduleSnapshotRepository`.
- Added package entry points
`package:scheduler_persistence_memory/persistence_memory.dart` and
`package:scheduler_persistence_memory/memory.dart`.
- Added shared adapter conformance test surface
`runRepositoryComplianceTests()` and `RepositoryComplianceFactories` under
`packages/scheduler_persistence/test/repo_conformance.dart`.
Chunk 20.1 intentionally changed the public/package API:
- Added `packages/scheduler_persistence_sqlite` with Drift-backed schema
package entry point `package:scheduler_persistence_sqlite/sqlite.dart`.
- Added `SchedulerDb` with schema version 1 and generated Drift table/data
classes for `tasks`, `projects`, `locked_blocks`, `locked_overrides`,
`settings`, and `snapshots`.
- Added generated accessor classes: `TaskDao`, `ProjectDao`, `LockedBlockDao`,
`SettingsDao`, and `SnapshotDao`.
Chunk 20.2 intentionally changed the public/package API:
- Added SQLite repository implementations exported from
`package:scheduler_persistence_sqlite/sqlite.dart`:
`SqliteTaskRepository`, `SqliteProjectRepository`,
`SqliteLockedBlockRepository`, `SqliteSettingsRepository`, and
`SqliteScheduleSnapshotRepository`.
- Added SQLite adapter conformance and write-latency tests under
`packages/scheduler_persistence_sqlite/test/`.
Chunk 21.1 intentionally changed the public/package API:
- Added `packages/scheduler_notifications` with package entry points
`package:scheduler_notifications/notifications.dart` and
`package:scheduler_notifications/scheduler_notifications.dart`.
- Added notification abstraction types: `NotificationRequest`,
`NotificationFeedbackType`, `NotificationFeedback`, `NotificationAdapter`,
and `FakeNotificationAdapter`.
Chunk 22.1 intentionally changed the public/package API:
- Added `packages/scheduler_notifications_desktop` with package entry points
`package:scheduler_notifications_desktop/desktop_notifications.dart` and
`package:scheduler_notifications_desktop/scheduler_notifications_desktop.dart`.
- Added desktop notification types: `DesktopNotificationPlatform`,
`DesktopNotificationBackend`, `DesktopNotificationAdapter`,
`StdoutNotificationBackend`, and the IO backends for Linux/macOS.
Chunk 23.1 intentionally changed the public/package API:
- Added `packages/scheduler_export` with package entry points
`package:scheduler_export/export.dart` and
`package:scheduler_export/scheduler_export.dart`.
- Added readable export contracts and orchestration types: `ExportContext`,
`ExportWriter`, `ExportWriterFactory`, `ExportWriterRegistry`,
`ExportController`, `ExportException`, and `ExportRepositoryException`.
- Added sink-backed writer implementations `JsonExportWriter` and
`CsvExportWriter`.
Chunk 24.1 intentionally changed the public/package API:
- Added `packages/scheduler_backup` with package entry points
`package:scheduler_backup/backup.dart` and
`package:scheduler_backup/scheduler_backup.dart`.
- Added encrypted backup functions `createEncryptedBackup`,
`restoreEncryptedBackup`, `defaultSchedulerSqliteFile`, and
`defaultSchedulerBackupDirectory`.
- Added backup constants `defaultSchedulerDirectoryName`,
`defaultSchedulerDatabaseFileName`, and
`defaultSchedulerBackupDirectoryName`.
- Added backup exceptions `BackupException` and
`BackupDecryptionException`.
Chunk 24.2 intentionally changed the public/package API:
- Added `packages/scheduler_export_json` with package entry points
`package:scheduler_export_json/export_json.dart` and
`package:scheduler_export_json/scheduler_export_json.dart`.
- Added readable writer factory `readableExportWriterRegistry`.
- Added concrete readable export writers `JsonExportWriter` and
`CsvExportWriter`.
- Added CLI export command `bin/export.dart`.
Chunk 25.1 intentionally changed the workspace test surface:
- Added test-only package `packages/scheduler_integration_tests`.
- Added integration harness `integration/scheduler_flow_test.dart` covering
scheduler placement, fake notification scheduling, SQLite save, and reload.
Chunk 26.1 intentionally changed the verification surface:
- Added executable `scripts/test.sh` as the required analyze/test/coverage gate.
- Added `tool/check_coverage.dart` for LCOV threshold enforcement.
- Added shared notification adapter contract test helper
`packages/scheduler_notifications/test/notification_adapter_contract.dart`.
- Desktop notification adapter cancellation now normalizes ids before backend
cancellation.
Chunk 27.1 intentionally changed the dev/CI surface:
- Added `scripts/dev.dart` for local build-runner watch plus Flutter desktop
launch with a SQLite path define.
- Added `scripts/test.dart` for cross-platform coverage collection and LCOV
combination.
- Added `scripts/bootstrap_dev.sh` and `scripts/dev.sh` shell entry points for
agent-compatible setup and desktop development.
- Added GitHub Actions test matrix in `.github/workflows/ci.yml`.
Chunk 27.2 intentionally changed the packaging surface:
- Added `scripts/build.dart` for platform-specific Flutter desktop packaging.
- Added `scripts/package_release.sh` shell entry point for release packaging.
- Added tagged CI release artifact upload steps.
- Replaced README content with workspace test, dev, packaging, and prerequisite
instructions.
Chunk 28.1 intentionally changed the documentation verification surface:
- Added `tool/check_docs.dart` to generate package docs and fail on warnings.
- Added generated docs upload under the CI artifact step.
- Added generated `doc/api/` output to `.gitignore`.
- Fixed unresolved public API documentation references in core and export
packages.
Chunk 29.1 intentionally changed the UI surface:
- Added provisional Flutter app `apps/focus_flow_flutter` outside the root Dart
workspace.
- Added app-local path dependency on `packages/scheduler_core`.
- Added `FocusFlowApp`, `DemoSchedulerComposition`, `SchedulerHome`,
`TodayPane`, and `BacklogPane` in the Flutter app.
- Added widget test coverage for rendering Today and Backlog read-model data.
Chunk 29.2 intentionally changed the UI surface:
- Split the Flutter shell into `app.dart`, `composition/`, `controllers/`,
`theme/`, and `widgets/`.
- Added `UiReadController<T>`, `ApplicationReadController<T>`, and
`SchedulerReadState<T>` variants for loading, data, empty, and typed failure
states.
- Added `SchedulerVisualTokens` for centralized project/task/reward/difficulty
and staleness visual mappings.
- Added component widgets for Today, Backlog, compact panels, timeline rows,
backlog rows, notice banners, empty states, and failure retry states.
- Expanded Flutter widget coverage to 4 tests.
## Repository contracts
The current repository surface is pure Dart and adapter-backed:
- Core legacy repository fakes remain in `scheduler_core` for existing domain
services and tests.
- The Block 19 repository abstraction lives in `scheduler_persistence`.
- The Block 19 conformance-tested memory adapter lives in
`scheduler_persistence_memory`.
- The Block 20 conformance-tested SQLite adapter lives in
`scheduler_persistence_sqlite`.
- Application transaction behavior is represented by
`InMemoryApplicationUnitOfWork`.
- Application read-query behavior uses `ApplicationUnitOfWork.read`, which
stages repository access without committing operation records.
Future SQLite adapter work must remain behind repository interfaces and must not
import storage APIs into the scheduling core.

View file

@ -0,0 +1,141 @@
# V1 Requirements Traceability Matrix
Status: Baseline captured during Block 11.1.
Review basis:
- `Human Documentation/Overall App Design Spec.docx`, section 25, plus MVP
requirements from sections 5-19.
- `Human Documentation/Unified Product Design Summary.md`
- `Human Documentation/Starter Architecture Notes.md`
- Public exports from `lib/scheduler_core.dart`
- Tests under `test/`
Starting commit: `775c2ed406f03a73a9b0ca621dea5b4482468616`
Verification result on 2026-06-24:
- `dart pub get`: passed
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 143 tests
- `git diff --check`: passed
Latest Block 12 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 203 tests
- `git diff --check`: passed
Latest Block 13.1 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 211 tests
- `git diff --check`: passed
Latest Block 13.2 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed
- `dart analyze`: passed, no issues found
- `dart test`: passed, 218 tests
- `git diff --check`: passed
Latest Block 13.3 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 225 tests
- `git diff --check`: passed
Latest Block 13.4 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 233 tests
- `git diff --check`: passed
Latest Block 13.5 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 243 tests
- `git diff --check`: passed
Latest Block 14.1 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 249 tests
- `git diff --check`: passed
Latest Block 14.2 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 257 tests
- `git diff --check`: passed
Latest Block 14.3 verification result on 2026-06-25:
- `dart format lib test`: passed, 0 files changed after final format
- `dart analyze`: passed, no issues found
- `dart test`: passed, 268 tests
- `git diff --check`: passed
Status values:
- `complete`: Current backend APIs and tests cover the requirement.
- `incomplete`: Some required backend, application, persistence, or UI-facing
contract work remains.
- `intentionally deferred`: The human spec places this outside MVP, or the
active plan explicitly defers it.
- `contradictory`: The human spec conflicts with the V1 backend direction and
an active plan must resolve it without silently changing behavior.
## Section 25 MVP acceptance criteria
| ID | Acceptance criterion | Production API surface | Representative tests | Status | Active-plan reference or issue |
|---|---|---|---|---|---|
| MVP-AC-01 | Create a task through quick capture with only a title. | `V1ApplicationCommandUseCases.quickCaptureToBacklog`, `Task.quickCapture`, `QuickCaptureRequest`, `QuickCaptureService.capture` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds the atomic application command boundary. |
| MVP-AC-02 | Store quick-capture tasks in Backlog with neutral defaults. | `Task.quickCapture`, `QuickCaptureService.capture`, `TaskStatus.backlog`, `PriorityLevel.medium`, `RewardLevel.notSet`, inbox project default, `TaskDocumentFields.backlogEnteredAt` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/document_mapping_test.dart`, `packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart` | complete | Backlog-entered timestamp fields are covered by document mapping and SQLite persistence. |
| MVP-AC-03 | Optionally schedule a quick-capture task into the next available slot after entering duration. | `V1ApplicationCommandUseCases.quickCaptureToNextAvailableSlot`, `QuickCaptureRequest.scheduleImmediately`, `QuickCaptureService.capture`, `SchedulingEngine.insertBacklogTaskIntoNextAvailableSlot` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/scheduling_invariants_test.dart`, `test/application_commands_test.dart` | complete | Block 12 covers scheduling rules; Chunk 14.3 adds the atomic application command boundary. |
| MVP-AC-04 | Create recurring hidden locked blocks and one-day overrides. | `LockedBlock`, `LockedBlockRecurrence.weekly`, `LockedBlockOverride.remove`, `LockedBlockOverride.replace`, `LockedBlockOverride.add`, `expandLockedBlocksForDay` | `test/scheduling_engine_test.dart`, `test/timeline_state_test.dart`, `test/edge_case_regression_test.dart` | complete | Date-only/time-zone hardening remains in Chunk 11.4 and Block 15. |
| MVP-AC-05 | Render Today as a timeline with project border, task-type background, task name, reward icon, and difficulty icon. | `GetTodayStateQuery`, `TodayState`, `TodayTimelineItem`, `TimelineItemMapper`, `TimelineItem`, timeline token enums, `TodayPane`, `TimelineRow`, `SchedulerVisualTokens` | `test/timeline_state_test.dart`, `test/today_state_test.dart`, `apps/focus_flow_flutter/test/widget_test.dart` | complete | Backend Today read model and provisional Flutter token-driven rendering are complete through Block 29.2; final visual design remains intentionally open. |
| MVP-AC-06 | Use compact Today mode manually. | `GetTodayStateQuery`, `TodayCompactState`, `TimelineItemMapper.compactStateForTasks`, `CompactTimelineState`, `CompactPanel` | `test/timeline_state_test.dart`, `test/today_state_test.dart`, `test/application_management_test.dart`, `packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart`, `apps/focus_flow_flutter/test/widget_test.dart` | complete | Complete at backend/read-model and settings-persistence level, including current/next deduplication; Block 29.2 renders compact state through a component contract, while a user-facing toggle remains a later UI command/control task. |
| MVP-AC-07 | Push flexible tasks to next available slot, tomorrow, or backlog. | `V1ApplicationCommandUseCases.pushFlexibleToNextAvailableSlot`, `V1ApplicationCommandUseCases.pushFlexibleToTomorrowTopOfQueue`, `V1ApplicationCommandUseCases.moveFlexibleToBacklog`, `FlexibleTaskActionService.applyPushDestination`, `SchedulingEngine` push methods, `TaskActivityCode` | `test/scheduling_engine_test.dart`, `test/required_task_actions_test.dart`, `test/task_lifecycle_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds atomic application commands with persisted activities and operation records. |
| MVP-AC-08 | Move backlog items into the soonest flexible slot where they fit and shift later flexible tasks. | `V1ApplicationCommandUseCases.scheduleBacklogItemToNextAvailableSlot`, `SchedulingEngine.insertBacklogTaskIntoNextAvailableSlot` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/occupancy_policy_test.dart`, `test/free_slots_test.dart`, `test/scheduling_invariants_test.dart`, `test/application_commands_test.dart` | complete | Block 12 covers scheduling rules; Chunk 14.3 adds the atomic application command boundary. |
| MVP-AC-09 | Automatically roll unfinished flexible tasks to tomorrow/top of queue with a small notice. | `SchedulingEngine.rolloverUnfinishedFlexibleTasks`, `SchedulingNotice`, `TodayPendingNotice`, `GetTodayStateQuery`, `V1AppOpenRecoveryUseCases` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/scheduling_invariants_test.dart`, `test/today_state_test.dart`, `test/application_recovery_test.dart` | complete | Domain movement, durable app-open recovery orchestration, scheduling snapshots, and Today pending-notice lifecycle are complete. |
| MVP-AC-10 | Log unplanned completed tasks and push overlapping flexible tasks normally. | `V1ApplicationCommandUseCases.logSurpriseTask`, `SurpriseTaskLogRequest`, `SurpriseTaskLogService.log`, `SurpriseTaskLogResult`, `Task.completedAt` | `test/surprise_task_logging_test.dart`, `test/scheduling_invariants_test.dart`, `test/task_lifecycle_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds atomic surprise logging use case with flexible repair, activity persistence, project stats, and operation records. |
| MVP-AC-11 | Break a large task into child tasks with row-level priority, reward, and duration. | `V1ApplicationCommandUseCases.breakUpTask`, `ApplicationChildTaskDraft`, `ChildTaskEntry`, `ChildTaskBreakUpRequest`, `ChildTaskBreakUpResult`, `ChildTaskBreakUpService`, `ChildTaskView` | `test/child_tasks_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds atomic child break-up command wiring. |
| MVP-AC-12 | Auto-complete parent tasks when all children are done and allow force-completing all children from the parent or a child. | `V1ApplicationCommandUseCases.completeChildTask`, `V1ApplicationCommandUseCases.completeParentTask`, `V1ApplicationCommandUseCases.completeParentFromChild`, `ChildTaskCompletionService`, `ChildTaskCompletionResult`, parent-child helpers, `TaskActivity` | `test/child_tasks_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds atomic parent/child completion command wiring. |
| MVP-AC-13 | Display backlog staleness icons without per-task stale prompts. | `BacklogStalenessMarker`, `BacklogStalenessSettings`, `BacklogView`, `OwnerSettings`, `BacklogPane` | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/application_management_test.dart`, `packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart`, `apps/focus_flow_flutter/test/widget_test.dart` | complete | Backend marker, settings persistence, and provisional Flutter backlog icon rendering are complete without per-task stale prompts. |
| MVP-AC-14 | Track baseline internal statistics needed for later reports and filtering. | `TaskStatistics`, `ProjectStatistics`, `TaskActivity`, `TaskActivityApplicationResult`, `TaskActivityAccountingService`, `ProjectStatisticsAggregationService`, `ApplicationUnitOfWork`, `V1ApplicationCommandUseCases`, selected action services | `test/scheduling_engine_test.dart`, `test/required_task_actions_test.dart`, `test/document_mapping_test.dart`, `test/task_lifecycle_test.dart`, `test/child_tasks_test.dart`, `test/project_statistics_test.dart`, `test/application_layer_test.dart`, `test/application_commands_test.dart` | complete | Chunks 13.1-13.4 add canonical statistics/accounting; Chunk 14.3 persists command activities and project aggregate updates atomically in memory. Blocks 19-20 add repository contracts and SQLite adapter conformance. |
## Additional MVP backend requirements
| ID | Requirement | Production API surface | Representative tests | Status | Active-plan reference or issue |
|---|---|---|---|---|---|
| MVP-SUP-01 | Flexible tasks move while locked, inflexible, and critical time does not move automatically. | `OccupancyPolicy`, `SchedulingInput.blockedIntervals`, `SchedulingEngine` placement methods | `test/scheduling_engine_test.dart`, `test/edge_case_regression_test.dart`, `test/occupancy_policy_test.dart`, `test/scheduling_invariants_test.dart` | complete | Block 12 centralizes occupancy and adds structured outcomes plus invariant coverage for immovable placements. |
| MVP-SUP-02 | Critical missed tasks are marked missed and moved to backlog. | `RequiredTaskActionService`, `SchedulingEngine.markMissed`, `TaskTransitionService`, `TaskType.critical` | `test/scheduling_engine_test.dart`, `test/required_task_actions_test.dart`, `test/task_lifecycle_test.dart` | complete | Chunk 13.1 records both missed and moved-to-backlog activities. |
| MVP-SUP-03 | Inflexible missed tasks are marked missed and left in place/history. | `RequiredTaskActionService`, `SchedulingEngine.markMissed`, `TaskTransitionService`, `TaskType.inflexible` | `test/scheduling_engine_test.dart`, `test/required_task_actions_test.dart`, `test/task_lifecycle_test.dart` | complete | Actual/historical interval semantics are formalized in Chunk 11.2 and Block 12. |
| MVP-SUP-04 | Cancelled and no-longer-relevant are separate calm lifecycle outcomes. | `TaskStatus.cancelled`, `TaskStatus.noLongerRelevant`, `RequiredTaskAction`, `TaskActivityCode` | `test/required_task_actions_test.dart`, `test/task_lifecycle_test.dart` | complete | Chunk 13.1 centralizes both transitions and emits distinct activity codes. |
| MVP-SUP-05 | Free Slot is intentional rest that blocks normal flexible placement and suppresses normal flexible reminders. | `V1ApplicationCommandUseCases.createProtectedFreeSlot`, `V1ApplicationCommandUseCases.updateProtectedFreeSlot`, `V1ApplicationCommandUseCases.removeProtectedFreeSlot`, `TaskType.freeSlot`, `OccupancyPolicy`, `FreeSlotService`, `ReminderPolicyService`, timeline tokens | `test/timeline_state_test.dart`, `test/occupancy_policy_test.dart`, `test/free_slots_test.dart`, `test/scheduling_invariants_test.dart`, `test/reminder_policy_test.dart`, `test/application_commands_test.dart` | complete | Blocks 12 and 13 cover scheduling/reminder policy; Chunk 14.3 adds atomic protected Free Slot commands. |
| MVP-SUP-06 | Project defaults apply, learned suggestions stay optional, and task reminder overrides are possible. | `ProjectProfile`, `ProjectStatistics`, `ProjectSuggestionService`, `ProjectDefaultResolution`, `ReminderPolicyService`, `Task.reminderOverride`, `ReminderProfile` | `test/scheduling_engine_test.dart`, `test/domain_invariants_test.dart`, `test/project_statistics_test.dart`, `test/reminder_policy_test.dart` | complete | Chunk 13.5 adds effective reminder resolution without using learned suggestions as silent configuration. |
| MVP-SUP-07 | Repository boundaries prepare for swappable persistence without coupling the scheduler to database APIs. | Repository interfaces, in-memory repositories, SQLite repositories, `ApplicationUnitOfWork`, `V1ApplicationCommandUseCases`, document mapping helpers | `test/repositories_test.dart`, `test/document_mapping_test.dart`, `test/persistence_edge_cases_test.dart`, `test/application_layer_test.dart`, `test/application_commands_test.dart`, `packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart`, `packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart` | complete | Blocks 19-20 add domain-only repository contracts, in-memory conformance, SQLite adapter conformance, durable revisions, and compare-and-set saves. |
| MVP-SUP-08 | Hidden locked time remains hidden by default, with explicit reveal as an overlay. | `LockedBlockOccurrence.hiddenByDefault`, `TimelineItemMapper.fromLockedOccurrence`, `GetTodayStateQuery`, `TodayTimelineItem` | `test/timeline_state_test.dart`, `test/edge_case_regression_test.dart`, `test/today_state_test.dart` | complete | Chunk 14.2 adds hidden-by-default Today omission, explicit reveal mode, and date-stable locked overlay IDs. |
| MVP-SUP-09 | Push/backlog/restore movement should be activity/stat data, not shame language. | `TaskStatistics`, `ProjectStatistics`, `TaskActivity`, `TaskActivityCode`, `SchedulingChange`, `SchedulingMovementCode`, `ApplicationUnitOfWork`, `V1ApplicationCommandUseCases`, action result objects | `test/scheduling_engine_test.dart`, `test/required_task_actions_test.dart`, `test/scheduling_invariants_test.dart`, `test/task_lifecycle_test.dart`, `test/project_statistics_test.dart`, `test/application_layer_test.dart`, `test/application_commands_test.dart` | complete | Chunk 14.3 adds atomic command persistence for movement activities, task stats, project stats, and operation records. |
| MVP-SUP-10 | The human spec lists `pushed` and `skipped` as statuses. | `TaskStatus` excludes both; movement and burnout compatibility are modeled as activity/stat metadata. | `test/domain_contracts_test.dart` | contradictory | Resolved by `V1_ADR_001_Lifecycle_Metadata_Reminder_Semantics.md`; the contradiction is kept visible so later chunks do not add movement labels as statuses. |
## Intentionally deferred human-spec items
| ID | Requirement | Status | Deferred location |
|---|---|---|---|
| DEF-01 | Week view and month view. | intentionally deferred | V2/non-MVP. |
| DEF-02 | Weekly reports and dashboard. | intentionally deferred | V2/non-MVP; internal stats remain MVP baseline only. |
| DEF-03 | Overwhelm shield and burnout catch-up flow. | intentionally deferred | V2/non-MVP. |
| DEF-04 | Drag-and-drop reordering. | intentionally deferred | V2/non-MVP. |
| DEF-05 | Visible per-task history panel. | intentionally deferred | V2/non-MVP. |
| DEF-06 | Task dependencies and context tags. | intentionally deferred | Wishlist/non-MVP. |
| DEF-07 | Flexible-task overrun behavior. | intentionally deferred | Wishlist/non-MVP decision. |

View file

@ -8,6 +8,7 @@ This folder contains Codex-facing execution plans and implementation guidance.
Codex Documentation/
├── README.md
├── Current Software Plan/
├── Completed Plans/
└── Archived plans/
```
@ -31,6 +32,17 @@ Codex Documentation/Archived plans/
This is not optional. Completed plans must not remain in Current Software Plan.
## Completed Plans
Curated completed-plan copies live in:
```text
Codex Documentation/Completed Plans/
```
This folder is a current-state snapshot, not a full archive mirror. It should
exclude superseded, stale, or refactored-away archive documents.
## Plan status convention
Each plan file should clearly indicate whether it is: