diff --git a/Codex Documentation/Current Software Plan/V1_BLOCKS_07_10_UPDATED/V1_BLOCK_08_Today_Timeline_State.md b/Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State.md similarity index 89% rename from Codex Documentation/Current Software Plan/V1_BLOCKS_07_10_UPDATED/V1_BLOCK_08_Today_Timeline_State.md rename to Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State.md index 66d2ebb..0eba29e 100644 --- a/Codex Documentation/Current Software Plan/V1_BLOCKS_07_10_UPDATED/V1_BLOCK_08_Today_Timeline_State.md +++ b/Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State.md @@ -1,6 +1,6 @@ # V1 Block 08 — Today Timeline State -Status: In progress — Chunks 8.1, 8.2, and 8.3 complete +Status: Complete Purpose: Prepare domain/view-state data for the Today timeline without building full Flutter UI yet unless explicitly requested. @@ -149,6 +149,15 @@ Acceptance criteria: - 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 diff --git a/Codex Documentation/Current Software Plan/V1_BLOCK_08_Today_Timeline_State.md b/Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State_UPDATED.md similarity index 89% rename from Codex Documentation/Current Software Plan/V1_BLOCK_08_Today_Timeline_State.md rename to Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State_UPDATED.md index 66d2ebb..0eba29e 100644 --- a/Codex Documentation/Current Software Plan/V1_BLOCK_08_Today_Timeline_State.md +++ b/Codex Documentation/Archived plans/V1_BLOCK_08_Today_Timeline_State_UPDATED.md @@ -1,6 +1,6 @@ # V1 Block 08 — Today Timeline State -Status: In progress — Chunks 8.1, 8.2, and 8.3 complete +Status: Complete Purpose: Prepare domain/view-state data for the Today timeline without building full Flutter UI yet unless explicitly requested. @@ -149,6 +149,15 @@ Acceptance criteria: - 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 diff --git a/Codex Documentation/Current Software Plan/README.md b/Codex Documentation/Current Software Plan/README.md index 80a1f64..937cffa 100644 --- a/Codex Documentation/Current Software Plan/README.md +++ b/Codex Documentation/Current Software Plan/README.md @@ -1,7 +1,7 @@ # Current Software Plan -Execute active V1 block documents in numeric order. Blocks 01-07 are completed -and archived; the next active block is Block 08. +Execute active V1 block documents in numeric order. Blocks 01-08 are completed +and archived; the next active block is Block 09. ## Execution rules @@ -33,6 +33,6 @@ Do not infer a new level name. 5. `V1_BLOCK_05_Recurring_Locked_Blocks.md` 6. `V1_BLOCK_06_Task_Actions_State_Transitions_UPDATED.md` — archived 7. `V1_BLOCK_07_Child_Tasks.md` — archived -8. `V1_BLOCK_08_Today_Timeline_State.md` +8. `V1_BLOCK_08_Today_Timeline_State.md` — archived 9. `V1_BLOCK_09_Persistence_Preparation.md` 10. `V1_BLOCK_10_Testing_Documentation_Handoff.md` diff --git a/test/timeline_state_test.dart b/test/timeline_state_test.dart index acbf181..6816c5c 100644 --- a/test/timeline_state_test.dart +++ b/test/timeline_state_test.dart @@ -44,6 +44,96 @@ void main() { ]); }); + test('background token maps from every task type', () { + final expectedTokens = { + TaskType.flexible: TimelineBackgroundToken.flexible, + TaskType.inflexible: TimelineBackgroundToken.inflexible, + TaskType.critical: TimelineBackgroundToken.critical, + TaskType.locked: TimelineBackgroundToken.locked, + TaskType.surprise: TimelineBackgroundToken.surprise, + TaskType.freeSlot: TimelineBackgroundToken.freeSlot, + }; + + for (final entry in expectedTokens.entries) { + final task = scheduledTask( + id: entry.key.name, + title: entry.key.name, + projectId: project.id, + type: entry.key, + createdAt: createdAt, + start: start, + end: end, + ); + + expect( + mapper.fromTask(task).backgroundToken, + entry.value, + reason: entry.key.name, + ); + } + }); + + test('reward icon token handles every reward level plus not set', () { + final expectedTokens = { + RewardLevel.notSet: TimelineRewardIconToken.notSet, + RewardLevel.veryLow: TimelineRewardIconToken.veryLow, + RewardLevel.low: TimelineRewardIconToken.low, + RewardLevel.medium: TimelineRewardIconToken.medium, + RewardLevel.high: TimelineRewardIconToken.high, + RewardLevel.veryHigh: TimelineRewardIconToken.veryHigh, + }; + + for (final entry in expectedTokens.entries) { + final task = scheduledTask( + id: entry.key.name, + title: entry.key.name, + projectId: project.id, + type: TaskType.flexible, + reward: entry.key, + createdAt: createdAt, + start: start, + end: end, + ); + + expect( + mapper.fromTask(task).rewardIconToken, + entry.value, + reason: entry.key.name, + ); + } + }); + + test('difficulty icon token handles every difficulty level plus not set', + () { + final expectedTokens = { + DifficultyLevel.notSet: TimelineDifficultyIconToken.notSet, + DifficultyLevel.veryEasy: TimelineDifficultyIconToken.veryEasy, + DifficultyLevel.easy: TimelineDifficultyIconToken.easy, + DifficultyLevel.medium: TimelineDifficultyIconToken.medium, + DifficultyLevel.hard: TimelineDifficultyIconToken.hard, + DifficultyLevel.veryHard: TimelineDifficultyIconToken.veryHard, + }; + + for (final entry in expectedTokens.entries) { + final task = scheduledTask( + id: entry.key.name, + title: entry.key.name, + projectId: project.id, + type: TaskType.flexible, + difficulty: entry.key, + createdAt: createdAt, + start: start, + end: end, + ); + + expect( + mapper.fromTask(task).difficultyIconToken, + entry.value, + reason: entry.key.name, + ); + } + }); + test('flexible task cards display duration while retaining position', () { final task = scheduledTask( id: 'laundry', @@ -331,6 +421,64 @@ void main() { expect(state.nextRequiredItem!.id, 'required'); expect(state.compactItems.map((item) => item.id), ['required']); }); + + test('compact mode returns only the reduced current and next items', () { + final current = scheduledTask( + id: 'current', + title: 'Current', + projectId: project.id, + type: TaskType.flexible, + createdAt: createdAt, + start: DateTime(2026, 6, 20, 9), + end: DateTime(2026, 6, 20, 10), + ); + final nextRequired = scheduledTask( + id: 'next-required', + title: 'Next required', + projectId: project.id, + type: TaskType.inflexible, + createdAt: createdAt, + start: DateTime(2026, 6, 20, 10), + end: DateTime(2026, 6, 20, 10, 30), + ); + final laterRequired = scheduledTask( + id: 'later-required', + title: 'Later required', + projectId: project.id, + type: TaskType.critical, + createdAt: createdAt, + start: DateTime(2026, 6, 20, 12), + end: DateTime(2026, 6, 20, 12, 30), + ); + final laterFlexible = scheduledTask( + id: 'later-flexible', + title: 'Later flexible', + projectId: project.id, + type: TaskType.flexible, + createdAt: createdAt, + start: DateTime(2026, 6, 20, 13), + end: DateTime(2026, 6, 20, 13, 30), + ); + + final state = mapper.compactStateForTasks( + tasks: [laterFlexible, laterRequired, nextRequired, current], + now: DateTime(2026, 6, 20, 9, 15), + manualCompactModeEnabled: true, + ); + + expect(state.compactItems.map((item) => item.id), [ + 'current', + 'next-required', + ]); + expect( + state.compactItems.map((item) => item.id), + isNot(contains('later-required')), + ); + expect( + state.compactItems.map((item) => item.id), + isNot(contains('later-flexible')), + ); + }); }); }