# Implementation Plan: Task Name Column ## Overview Add the `name__c` database column to the Task model and all task queries, enabling users to see and look up tasks by their short human-readable name. Changes span model, database layer, protocol, and MCP tool output. ## Tasks - [x] 1. Add name field to Task model and update TrinoClient queries - [x] 1.1 Add `name: Optional[str]` field to the Task dataclass in `models.py` - Insert `name: Optional[str]` after `id` field - Field must be Optional since `name__c` can be NULL in the database - _Requirements: 1.1, 1.4_ - [x] 1.2 Update `get_open_tasks` SQL queries in `trino_client.py` to SELECT `t.name__c` - Add `t.name__c` to the unlimited query SELECT clause - Add `t.name__c` to the CTE inner SELECT and outer SELECT in the limited query - Update row unpacking to extract the name value - Populate `name` field in Task construction (map NULL to None) - _Requirements: 1.2, 1.4_ - [x] 1.3 Update `get_task_by_id` SQL query in `trino_client.py` to SELECT `t.name__c` - Add `t.name__c` to the SELECT clause - Update row unpacking to extract the name value - Populate `name` field in Task construction (map NULL to None) - _Requirements: 1.3, 1.4_ - [ ]* 1.4 Write property test: Task name field preserves database value - **Property 1: Task name field preserves database value** - Generate random `(name__c_value | None)` values using Hypothesis - Construct Task objects via the row-mapping pattern, assert `task.name == input_value` - **Validates: Requirements 1.1, 1.2, 1.3, 1.4** - [x] 2. Add `get_task_by_name` to protocol and TrinoClient - [x] 2.1 Add `get_task_by_name` method to `DBClient` protocol in `database/types.py` - Method signature: `def get_task_by_name(self, name: str) -> Task | None` - Include docstring: "Fetch one published task by its short name (name__c)." - _Requirements: 3.1_ - [x] 2.2 Implement `get_task_by_name` in `TrinoClient` - SQL query selects same columns as `get_task_by_id` plus `t.name__c` - WHERE clause filters on `t.name__c = ?` and `t.status__c = ?` - ORDER BY `t.createddate DESC` to handle duplicates (return first match) - Reuse same row-assembly logic as `get_task_by_id` - Return None for empty string input or no matching rows - _Requirements: 3.1, 3.2, 3.3_ - [ ]* 2.3 Write property test: Name lookup returns correct task - **Property 3: Name lookup returns correct task** - Generate random tasks with unique names, mock DB cursor - Call `get_task_by_name(name)`, assert returned task's name matches - **Validates: Requirements 3.2** - [x] 3. Checkpoint - Ensure all tests pass, ask the user if questions arise. - [x] 4. Update MCP tool output formatting - [x] 4.1 Add "Name" column to `list_open_tasks` output table - Add "Name" to the header list (between task_id and Title) - Add `str(task.name or "")` to each row - Update the empty-row fallback to include the extra column - _Requirements: 2.1_ - [x] 4.2 Add "Name" to `get_task_details` summary table - Add "Name" to the header list - Add `str(task.name or "")` to the row data - _Requirements: 2.2_ - [ ]* 4.3 Write property test: Task output contains name - **Property 2: Task output contains name** - Generate random Task objects with non-None names using `st.text(min_size=1)` - Format through output functions, assert name appears as substring - **Validates: Requirements 2.1, 2.2** - [x] 5. Update `get_task_details` resolution logic - [x] 5.1 Add name-based fallback resolution in `get_task_details` tool - After `get_task_by_id` returns None, call `db_client.get_task_by_name(task_id)` - If both return None, return "Task not found or not published: {task_id}" - _Requirements: 3.4, 3.5_ - [ ]* 5.2 Write property test: Name resolution equivalence - **Property 4: Name resolution equivalence** - Generate a task with non-None name, mock both lookup methods - Call `get_task_details` with name and with ID, assert outputs identical - **Validates: Requirements 3.4** - [ ]* 5.3 Write property test: Unknown identifier returns not-found - **Property 5: Unknown identifier returns not-found** - Generate random strings not matching any known task ID or name - Call `get_task_details`, assert output contains "not found" - **Validates: Requirements 3.3, 3.5** - [x] 6. Update FakeDBClient in tests and add `get_task_by_name` stub - Add `name` field to `FakeTask` in existing test files - Add `get_task_by_name` method to `FakeDBClient` - Update existing test assertions that check table headers (add "Name" column) - _Requirements: 3.1_ - [x] 7. Final checkpoint - Ensure all tests pass, ask the user if questions arise. ## Notes - Tasks marked with `*` are optional and can be skipped for faster MVP - Each task references specific requirements for traceability - Property tests use Hypothesis with `@settings(max_examples=100)` - The implementation language is Python (matching the existing codebase)