# 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 tomorrow’s 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 tomorrow’s 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 day’s instance.
   - One-day replace override changes only that day’s 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.
