refinement of upcoming tracks

This commit is contained in:
2026-03-06 15:41:33 -05:00
parent 3ce6a2ec8a
commit fca40fd8da
24 changed files with 2388 additions and 391 deletions

View File

@@ -1,21 +1,129 @@
# Track Specification: Manual Block/Unblock Control (manual_block_control_20260306)
## Overview
Allow user to manually block or unblock tickets with custom reasons. Currently blocked tickets rely on dependency resolution; add manual override.
Allow user to manually block or unblock tickets with custom reasons. Currently blocked tickets rely solely on dependency resolution; add manual override capability.
## Current State Audit
### Already Implemented (DO NOT re-implement)
#### Ticket Status (src/models.py)
- **`Ticket` dataclass** has `status` field: "todo" | "in_progress" | "completed" | "blocked"
- **`blocked_reason` field**: `Optional[str]` - exists but only set by dependency cascade
- **`mark_blocked(reason: str)` method**: Sets status="blocked", stores reason
#### DAG Blocking (src/dag_engine.py)
- **`cascade_blocks()` method**: Transitively marks tickets as blocked when dependencies are blocked
- **Dependency resolution**: Tickets blocked if any `depends_on` is not "completed"
- **No manual override exists**
#### GUI Display (src/gui_2.py)
- **`_render_ticket_dag_node()`**: Renders ticket nodes with status colors
- **Blocked nodes shown in distinct color**
- **No block/unblock buttons**
### Gaps to Fill (This Track's Scope)
- No way to manually set blocked status
- No way to add custom block reason
- No way to manually unblock (clear blocked status)
- Visual indicator for manual vs dependency blocking
## Architectural Constraints
- **Clear Indication**: Manual blocks MUST be visually distinct.
- **Audit Trail**: Block reason MUST be logged.
### DAG Validity
- Manual block MUST trigger cascade to downstream tickets
- Manual unblock MUST check dependencies are satisfied
- Cannot unblock if dependencies still blocked
### Audit Trail
- Block reason MUST be stored in Ticket
- Distinguish manual vs dependency blocking
### State Synchronization
- Block/unblock MUST update GUI immediately
- MUST persist to track state
## Architecture Reference
### Key Integration Points
| File | Lines | Purpose |
|------|-------|---------|
| `src/models.py` | 40-60 | `Ticket.mark_blocked()`, `blocked_reason` |
| `src/dag_engine.py` | 30-50 | `cascade_blocks()` - call after manual block |
| `src/gui_2.py` | 2700-2800 | `_render_ticket_dag_node()` - add buttons |
| `src/project_manager.py` | 238-260 | Track state persistence |
### Proposed Ticket Enhancement
```python
# Add to Ticket dataclass:
manual_block: bool = False # True if blocked manually, False if dependency
def mark_manual_block(self, reason: str) -> None:
self.status = "blocked"
self.blocked_reason = f"[MANUAL] {reason}"
self.manual_block = True
def clear_manual_block(self) -> None:
if self.manual_block:
self.status = "todo"
self.blocked_reason = None
self.manual_block = False
```
## Functional Requirements
- **Block Button**: Manually block selected ticket.
- **Unblock Button**: Remove manual block.
- **Reason Field**: Enter custom block reason.
- **Visual Indicator**: Blocked tickets clearly marked.
### FR1: Block Button
- Button on each ticket node to block
- Opens text input for block reason
- Sets `manual_block=True`, calls `mark_manual_block()`
### FR2: Unblock Button
- Button on blocked tickets to unblock
- Only enabled if dependencies are satisfied
- Clears manual block, sets status to "todo"
### FR3: Reason Display
- Show block reason on hover or in node
- Different visual for manual vs dependency block
- Show "[MANUAL]" prefix for manual blocks
### FR4: Cascade Integration
- Manual block triggers `cascade_blocks()`
- Manual unblock recalculates blocked status
## Non-Functional Requirements
| Requirement | Constraint |
|-------------|------------|
| Response Time | Block/unblock takes effect immediately |
| Persistence | Block state saved to track state |
| Visual Clarity | Manual blocks clearly distinguished |
## Testing Requirements
### Unit Tests
- Test `mark_manual_block()` sets correct fields
- Test `clear_manual_block()` restores todo status
- Test cascade after manual block
### Integration Tests (via `live_gui` fixture)
- Block ticket via GUI, verify status changes
- Unblock ticket, verify status restored
- Verify cascade affects downstream tickets
## Out of Scope
- Blocking during execution (kill first, then block)
- Scheduled/conditional blocking
- Block templates
## Acceptance Criteria
- [ ] Block button works.
- [ ] Unblock button works.
- [ ] Reason field saves.
- [ ] Visual indicator shows blocked status.
- [ ] Reason displayed in UI.
- [ ] Block button on each ticket
- [ ] Unblock button on blocked tickets
- [ ] Reason input saves to ticket
- [ ] Visual indicator distinguishes manual vs dependency
- [ ] Reason displayed in UI
- [ ] Cascade triggered on block/unblock
- [ ] State persisted to track state
- [ ] 1-space indentation maintained