162 lines
5.3 KiB
Markdown
162 lines
5.3 KiB
Markdown
# undo_redo_lifecycle_fix_20260605 Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Resolve the `test_undo_redo_lifecycle` failure. Phase 1: verify state-sync fix is sufficient. Phase 2: investigate snapshot mechanism if needed. Phase 3: flake-fix with polling if needed.
|
|
|
|
**Architecture:** Sequential investigation. Cheapest fix first.
|
|
|
|
**Tech Stack:** Python 3.11+, pytest 9.0.
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
| File | Change | Purpose |
|
|
|---|---|---|
|
|
| (Phase 1) None | | |
|
|
| (Phase 2) `src/history.py`, `src/gui_2.py`, `tests/test_undo_redo_ai_input_snapshot.py` | Possibly modify | Fix snapshot if it doesn't include ai_input |
|
|
| (Phase 3) `tests/test_undo_redo_sim.py` | Possibly modify | Replace time.sleep with polling |
|
|
|
|
---
|
|
|
|
## Task 1: Phase 1 — Run the test, see if it passes after the state-sync fix
|
|
|
|
**Files:** (no changes; verification)
|
|
|
|
- [ ] **Step 1.1: Run the test in isolation**
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; uv run pytest tests/test_undo_redo_sim.py::test_undo_redo_lifecycle -v --timeout=60
|
|
```
|
|
|
|
Expected outcomes:
|
|
- **A) PASSES** → Done. The state-sync fix is sufficient. Skip to Task 4 (documentation).
|
|
- **B) FAILS** → Proceed to Task 2 (Phase 2: investigate snapshot).
|
|
|
|
- [ ] **Step 1.2: Document the outcome**
|
|
|
|
If passes: commit a doc-only note confirming state-sync fixed it.
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; git -c core.autocrlf=false commit --allow-empty -m "verify: undo_redo_lifecycle passes after state-sync fix"
|
|
$h = git -C C:\projects\manual_slop log -1 --format='%H'
|
|
git -C C:\projects\manual_slop notes add -m "Confirmed: the ui_ai_input property delegation in live_gui_state_sync_20260605 fixes test_undo_redo_lifecycle. The snapshot reads app.ui_ai_input (now delegated to controller.ui_ai_input where the value lives) and captures the right value. Undo restores correctly." $h
|
|
```
|
|
|
|
If fails: proceed to Task 2.
|
|
|
|
---
|
|
|
|
## Task 2: Phase 2 — Check the snapshot mechanism for `ai_input`
|
|
|
|
**Files:** (read-only; possibly modify later)
|
|
|
|
- [ ] **Step 2.1: Read `UISnapshot` definition**
|
|
|
|
Read `src/history.py` to find the `UISnapshot` dataclass. List its fields.
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; uv run python -c "
|
|
import re
|
|
with open('src/history.py', 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
m = re.search(r'class UISnapshot', content)
|
|
if m:
|
|
print(content[m.start():m.start()+500])
|
|
"
|
|
```
|
|
|
|
- [ ] **Step 2.2: Check if `ai_input` is a field**
|
|
|
|
- **A) `ai_input` is a field** → Task 3: check `_apply_snapshot` for restore line.
|
|
- **B) `ai_input` is NOT a field** → Add it. See Step 2.3.
|
|
|
|
- [ ] **Step 2.3: If `ai_input` is missing from UISnapshot, add it**
|
|
|
|
Add `ai_input: str = ""` to the UISnapshot dataclass.
|
|
|
|
In `src/gui_2.py:_take_snapshot` (line 551), add `ai_input=self.ui_ai_input,`.
|
|
|
|
In `src/gui_2.py:_apply_snapshot` (line 569), add `self.ui_ai_input = snapshot.ai_input`.
|
|
|
|
Commit:
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; git add src/history.py src/gui_2.py
|
|
git -C C:\projects\manual_slop commit -m "fix(gui_2): add ai_input to UISnapshot for undo/redo round-trip"
|
|
$h = git -C C:\projects\manual_slop log -1 --format='%H'
|
|
git -C C:\projects\manual_slop notes add -m "Add ai_input field to UISnapshot (src/history.py), capture in _take_snapshot, restore in _apply_snapshot. The undo/redo system was silently dropping ai_input changes; this fixes test_undo_redo_lifecycle." $h
|
|
```
|
|
|
|
- [ ] **Step 2.4: Run the test**
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; uv run pytest tests/test_undo_redo_sim.py::test_undo_redo_lifecycle -v --timeout=60
|
|
```
|
|
|
|
Expected: 1 passed.
|
|
|
|
If still fails → proceed to Task 3 (Phase 3: flake-fix with polling).
|
|
|
|
---
|
|
|
|
## Task 3: Phase 3 — Test-ordering / flake investigation
|
|
|
|
**Files:**
|
|
- Modify: `tests/test_undo_redo_sim.py` (replace time.sleep with polling)
|
|
|
|
- [ ] **Step 3.1: Add the polling helpers (or import from wait_for_ready track)**
|
|
|
|
```python
|
|
import time
|
|
|
|
def wait_for_value(client, item, expected, timeout=5.0):
|
|
deadline = time.time() + timeout
|
|
while time.time() < deadline:
|
|
if client.get_value(item) == expected:
|
|
return
|
|
time.sleep(0.1)
|
|
raise TimeoutError(f"Item '{item}' did not become {expected!r} within {timeout}s")
|
|
```
|
|
|
|
- [ ] **Step 3.2: Replace the time.sleep calls**
|
|
|
|
- [ ] **Step 3.3: Run the test**
|
|
|
|
- [ ] **Step 3.4: Commit**
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; git add tests/test_undo_redo_sim.py
|
|
git -C C:\projects\manual_slop commit -m "test(undo_redo): replace time.sleep with wait_for_value polling"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 4: Update tracks.md
|
|
|
|
**Files:**
|
|
- Modify: `conductor/tracks.md`
|
|
|
|
- [ ] **Step 4.1: Add a note about the outcome**
|
|
|
|
```powershell
|
|
cd C:\projects\manual_slop; git add conductor/tracks.md
|
|
git -C C:\projects\manual_slop commit -m "conductor: undo_redo_lifecycle sub-track complete"
|
|
```
|
|
|
|
---
|
|
|
|
## Self-Review
|
|
|
|
- **Spec coverage:** 3-phase sequential investigation. State-sync fix may resolve it (Phase 1). If not, snapshot investigation (Phase 2). If not, flake-fix (Phase 3).
|
|
- **Placeholders:** None.
|
|
- **Type consistency:** `ai_input: str` matches the existing type.
|
|
- **Risk:** Low — only investigation + minimal source change.
|
|
|
|
---
|
|
|
|
## Execution Handoff
|
|
|
|
Inline execution. Up to 4 tasks; some may be skipped depending on the outcome of Phase 1.
|