Status: Progress tracked - Last updated Dec 2024
| Category | Total | Fixed | Partial | Remaining |
|---|---|---|---|---|
| Performance | 8 | 6 | 0 | 2 |
| Code Quality | 5 | 4 | 0 | 1 |
| Testing Gaps | 6 | 6 | 0 | 0 |
| Documentation | 6 | 6 | 0 | 0 |
File: src/app/model/hierarchy.rs
Solution: Now uses TaskCache.children HashMap for O(1) lookups.
// Current: Uses pre-built cache
if let Some(children) = self.task_cache.children.get(¤t_id) { ... }File: src/domain/duplicate_detector.rs
Solution: Pre-groups tasks by project_id and caches lowercase titles.
- Lines 86-98: Pre-computes lowercase titles once
- Lines 101-114: Only compares within same project groups
- Complexity reduced from O(n²) to O(Σ(p²)) where p is tasks per project
- Added tests for Unicode/emoji, long titles, special characters
File: src/app/model/filtering/matching.rs
Solution: Uses HashSet for O(1) tag lookup.
// Current: HashSet-based lookup
let task_tags_lower: HashSet<String> = task.tags.iter().map(|t| t.to_lowercase()).collect();
filter_tags.iter().any(|ft| task_tags_lower.contains(ft))File: src/storage/backends/in_memory/task_repo.rs
Solution: Changed ExportData.tasks from Vec<Task> to HashMap<TaskId, Task>.
// Current: O(1) HashMap operations
fn create_task(&mut self, task: &Task) -> StorageResult<()> {
if self.data().tasks.contains_key(&task.id) {
return Err(StorageError::already_exists("Task", task.id.to_string()));
}
self.data_mut().tasks.insert(task.id, task.clone());
Ok(())
}
fn get_task(&self, id: &TaskId) -> StorageResult<Option<Task>> {
Ok(self.data().tasks.get(id).cloned())
}Updated files:
src/storage/repository.rs- ExportData struct definitionsrc/storage/backends/in_memory/task_repo.rs- All CRUD operationssrc/storage/backends/markdown/storage.rs- Import/exportsrc/storage/backends/sqlite/storage.rs- Import/exportsrc/bin/taskflow/commands/pipe/handlers/- CLI handlers
File: src/app/model/storage.rs
Solution: Created modify_task_with_undo() helper (line 481).
pub fn modify_task_with_undo<F>(&mut self, task_id: &TaskId, modifier: F) -> bool
where F: FnOnce(&mut Task),
{
let before = task.clone();
modifier(task);
let after = task.clone();
self.undo_stack.push(UndoAction::TaskModified { before, after });
true
}Used throughout src/app/update/task.rs for SetStatus, SetPriority, CyclePriority, MoveToProject.
File: src/storage/backends/sqlite/task_repo.rs
Status: Some allocations remain but are unavoidable with dynamic SQL. The params! macro requires owned String values for dynamic queries.
File: src/app/model/cache.rs
All indexes now present:
- ✅
tasks: HashMap<TaskId, Task>- Primary - ✅
task_cache.children: HashMap<TaskId, Vec<TaskId>>- Hierarchy - ✅
task_cache.time_entries_by_task- Time tracking - ✅
task_cache.work_logs_by_task- Work logs - ✅
task_cache.tasks_by_project: HashMap<Option<ProjectId>, Vec<TaskId>>- Project lookup - ✅
task_cache.tasks_by_due_date: HashMap<Option<NaiveDate>, Vec<TaskId>>- Due date lookup - ✅
task_cache.contexts: HashSet<String>- Pre-computed @-prefixed tags
Solution: Added rebuild_secondary_indexes() method called from rebuild_caches(). Query methods all_contexts() and tasks_for_day() now use cached indexes for O(1) lookups.
Files: Multiple in src/app/update/
Status: Calls are strategic and justified by data modifications. Uses pre-computed FilterCache for fast execution.
File: src/domain/filter_dsl/lexer.rs
Solution: Uses pattern matching and if-let guards instead of unwrap().
// Current: Safe pattern matching
match remaining.chars().next() {
Some(ch) => Err(ParseError::unexpected_char(start, ch)),
None => Err(ParseError::unexpected_eof("token")),
}File: src/app/update/navigation/ (now a module directory)
Solution: Refactored 756-line monolithic function into 10 view-specific modules:
src/app/update/navigation/
├── mod.rs # Main dispatcher (~120 lines)
├── calendar.rs # Calendar navigation + helpers
├── sidebar.rs # Sidebar navigation + helpers
├── kanban.rs # Kanban board navigation
├── eisenhower.rs # Eisenhower matrix navigation
├── weekly_planner.rs # Weekly planner navigation
├── timeline.rs # Timeline view navigation
├── reports.rs # Reports panel navigation
├── network.rs # Network view navigation
├── task_list.rs # Basic Up/Down/First/Last/PageUp/PageDown
└── view.rs # GoToView handling
Benefits:
- Each module is focused and under 100 lines
- Removed
#[allow(clippy::too_many_lines)] - Easier to navigate and maintain view-specific logic
File: src/domain/filter.rs
Solution: Extracted sort logic into impl SortField methods.
impl SortField {
pub fn compare(&self, a: &Task, b: &Task) -> Ordering {
match self {
SortField::CreatedAt => a.created_at.cmp(&b.created_at),
SortField::UpdatedAt => a.updated_at.cmp(&b.updated_at),
SortField::DueDate => Self::compare_due_date(a, b),
SortField::Priority => Self::compare_priority(a, b),
SortField::Title => a.title.to_lowercase().cmp(&b.title.to_lowercase()),
SortField::Status => Self::compare_status(a, b),
}
}
// Private helper methods for each field type...
}
pub fn compare_sort_order(a: &Task, b: &Task) -> Ordering { ... }Updated: src/app/model/filtering/visibility.rs now uses sort_field.compare(a, b) - reduced 50-line closure to ~15 lines.
File: src/app/update/task.rs
Solution: Uses modify_task_with_undo() helper. See Performance Issue #5.
Files:
src/app/model/filtering/matching.rs:81- Alternative API methodsrc/bin/taskflow/commands/pipe/types.rs- Public API for external toolssrc/ui/components/evening_review/queries.rs- Query builder utilities
Status: Annotations are intentional - code serves as API contract or test utilities.
All testing gaps have been addressed:
Added property-based tests in tests/proptest_tests.rs:
- ✅ Operator precedence edge cases (AND binds tighter than OR)
- ✅ Date range boundary validation
- ✅ Malformed input handling (fuzz testing)
Added tests in src/app/update/tests/goal.rs:
- ✅ Tests linking KeyResults to Goals
- ✅ Progress calculation with 0 target (division edge case)
- ✅ Multiple KeyResults aggregation
Added tests in tests/stress.rs:
- ✅ Deep hierarchy tests (depth 10, linear chains 1000+)
- ✅ JSON/SQLite backend stress tests (1000+ tasks)
- ✅ Filtered query performance tests
Added tests in src/storage/export/*.rs:
- ✅ CSV special character handling (commas, quotes, newlines, unicode)
- ✅ ICS escaping and structure validation
- ✅ DOT/Mermaid structure verification (all statuses, edges)
Added tests in src/domain/habit/tests.rs and src/app/update/task.rs:
- ✅ Year boundary crossing (weekly habits)
- ✅ Leap year handling (EveryNDays frequency)
- ✅ Monthly tasks on 31st in short months
- ✅ Unicode/emoji in titles
- ✅ Very long titles
- ✅ Special characters
- ✅ Stress tests with large datasets
All documentation gaps have been addressed:
- ✅ Analytics Module (
src/domain/analytics.rs) - Added type overview table, ReportConfig examples, cross-references - ✅ Work Log Module (
src/domain/work_log.rs) - Added usage pattern workflow, TimeEntry comparison - ✅ Calendar Event Module (
src/domain/calendar_event.rs) - Added ICS import mapping, enum status docs, query examples - ✅ Pomodoro Module (
src/domain/pomodoro.rs) - Added session lifecycle, phase transitions, pause/resume docs - ✅ Goal/KeyResult Modules (
src/domain/goal.rs,key_result.rs) - Added OKR workflow, linked tasks example - ✅ Tag Module (
src/domain/tag.rs) - Added naming conventions, filter DSL integration examples
All identified quick wins have been addressed:
- ✅ Changed ExportData to HashMap (Dec 2024)
- ✅ Added secondary indexes to TaskCache (Dec 2024)
- ✅ Extracted sort logic into SortField methods (Dec 2024)
- ✅ Split handle_navigation() into view-specific modules (Dec 2024)
cargo test
cargo clippy --all-targets
cargo bench # if benchmarks added