conductor(track): workspace_path_finalize_20260609 - plan with 3 phases, 4-step execution
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
# Workspace Path Finalize — Implementation Plan
|
||||
|
||||
> **For Tier 3 workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
>
|
||||
> **This is the LAST track on this issue. Do not add scope. Do not refactor anything else. Do not add new tests beyond the 2 in this plan. Do not update docs. Do not file follow-up tracks. Execute exactly what is here, then stop.**
|
||||
|
||||
**Goal:** Replace `tmp_path_factory.mktemp("live_gui_workspace")` in `tests/conftest.py` with a per-run timestamped folder under `tests/artifacts/`. Each `uv run pytest` invocation gets its own folder. All live_gui tests in that invocation share it (per-test pollution is intentional and exposes fragility).
|
||||
|
||||
**Architecture:** Module-level constants in conftest.py compute the workspace path once at import time. The `live_gui` fixture uses those constants. The `live_gui_workspace` fixture (which already exists) returns the same path via the handle. No env vars, no CLI args, no runner changes.
|
||||
|
||||
**Tech Stack:** Python 3.11+, pytest, pathlib.
|
||||
|
||||
---
|
||||
|
||||
## Pre-Phase 0: Checkpoint
|
||||
|
||||
- [ ] **Step 0.1: Pre-edit checkpoint**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; git add . && git commit -m "wip: pre-workspace-path-finalize" --allow-empty
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Apply the 1-line conftest change
|
||||
|
||||
Focus: Add module-level constants + change 2 lines in conftest.py.
|
||||
|
||||
### Task 1.1: Add the `datetime` import
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/conftest.py` (imports section, near the top)
|
||||
|
||||
- [ ] **Step 1.1.1: Read the current imports section**
|
||||
Use `manual-slop_get_file_slice` to read `tests/conftest.py:1-30` and see the existing import block.
|
||||
|
||||
- [ ] **Step 1.1.2: Add `from datetime import datetime` to the imports**
|
||||
Use `manual-slop_set_file_slice` to insert the import. The exact placement (alphabetical order, or grouped with stdlib imports) depends on what's currently there. Match the existing style.
|
||||
|
||||
**CRITICAL — verify via `ast.parse` after the edit:**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run python -c "import ast; ast.parse(open('tests/conftest.py').read()); print('OK')"
|
||||
```
|
||||
|
||||
### Task 1.2: Add module-level constants
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/conftest.py` (module-level, after imports, before the first fixture or constant)
|
||||
|
||||
- [ ] **Step 1.2.1: Find a good location**
|
||||
Read `tests/conftest.py:1-50` with `manual-slop_get_file_slice`. Find a place after imports and before the first fixture/class definition.
|
||||
|
||||
- [ ] **Step 1.2.2: Add the constants**
|
||||
Insert:
|
||||
```python
|
||||
_RUN_ID = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
_RUN_WORKSPACE = Path(f"tests/artifacts/live_gui_workspace_{_RUN_ID}")
|
||||
```
|
||||
|
||||
Use `manual-slop_set_file_slice` with the exact start_line and end_line of the insertion point.
|
||||
|
||||
**CRITICAL — 1-space indent.** These are top-level statements, no indent. Use exactly the snippet above.
|
||||
|
||||
- [ ] **Step 1.2.3: Verify syntax**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run python -c "import ast; ast.parse(open('tests/conftest.py').read()); print('OK')"
|
||||
```
|
||||
|
||||
### Task 1.3: Change the `live_gui` fixture signature
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/conftest.py:453` (the `def live_gui(...)` line)
|
||||
|
||||
- [ ] **Step 1.3.1: Read the exact line**
|
||||
Use `manual-slop_get_file_slice` to read `tests/conftest.py:453` and get the exact text.
|
||||
|
||||
- [ ] **Step 1.3.2: Remove `tmp_path_factory` from the parameter list**
|
||||
Change:
|
||||
```python
|
||||
def live_gui(request, tmp_path_factory) -> Generator["_LiveGuiHandle", None, None]:
|
||||
```
|
||||
to:
|
||||
```python
|
||||
def live_gui(request) -> Generator["_LiveGuiHandle", None, None]:
|
||||
```
|
||||
|
||||
Use `manual-slop_set_file_slice` with the exact line.
|
||||
|
||||
- [ ] **Step 1.3.3: Verify syntax**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run python -c "import ast; ast.parse(open('tests/conftest.py').read()); print('OK')"
|
||||
```
|
||||
|
||||
### Task 1.4: Replace the workspace creation
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/conftest.py:465` (the `temp_workspace = ...` line)
|
||||
|
||||
- [ ] **Step 1.4.1: Read the exact line**
|
||||
Use `manual-slop_get_file_slice` to read `tests/conftest.py:464-466` and get the exact text.
|
||||
|
||||
- [ ] **Step 1.4.2: Replace the workspace creation**
|
||||
Change:
|
||||
```python
|
||||
temp_workspace = tmp_path_factory.mktemp("live_gui_workspace")
|
||||
```
|
||||
to:
|
||||
```python
|
||||
temp_workspace = _RUN_WORKSPACE
|
||||
```
|
||||
|
||||
Use `manual-slop_set_file_slice` with the exact line.
|
||||
|
||||
- [ ] **Step 1.4.3: Verify syntax**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run python -c "import ast; ast.parse(open('tests/conftest.py').read()); print('OK')"
|
||||
```
|
||||
|
||||
### Task 1.5: Run a smoke test
|
||||
|
||||
- [ ] **Step 1.5.1: Run a single live_gui test to verify the fixture works**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run pytest tests/test_gui_startup_smoke.py -v --timeout=30
|
||||
```
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 1.5.2: Verify the workspace folder was created**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; ls tests/artifacts/ | Where-Object { $_.Name -like "live_gui_workspace_*" }
|
||||
```
|
||||
Expected: a folder like `live_gui_workspace_20260609_HHMMSS` exists.
|
||||
|
||||
- [ ] **Step 1.5.3: Verify the subprocess CWD is the new workspace**
|
||||
Run `tests/test_gui_startup_smoke.py` with `-s` to see prints, OR add a temporary `print(handle.workspace)` in the test to verify.
|
||||
|
||||
Expected: handle.workspace is `C:\projects\manual_slop\tests\artifacts\live_gui_workspace_<timestamp>`.
|
||||
|
||||
### Phase 1 commit
|
||||
|
||||
- [ ] **Step 1.C.1: Commit the conftest change**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; git add tests/conftest.py
|
||||
git commit -m "fix(test): per-run workspace under tests/artifacts/ (replaces tmp_path_factory)"
|
||||
$h = git log -1 --format='%H'
|
||||
git notes add -m "Replaces tmp_path_factory.mktemp with _RUN_WORKSPACE, a module-level constant computed once at conftest import time. Each pytest invocation gets tests/artifacts/live_gui_workspace_<YYYYMMDD_HHMMSS>/. All live_gui tests in that invocation share the workspace (per-test pollution is intentional). The workspace is gitignored via tests/artifacts/. 1 import + 2 line changes in conftest.py." $h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Add 2 verification tests
|
||||
|
||||
Focus: 2 small tests that prove the workspace is at the right path and is gitignored.
|
||||
|
||||
### Task 2.1: Write the 2 verification tests
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/test_workspace_path_finalize.py`
|
||||
|
||||
- [ ] **Step 2.1.1: Write the test file**
|
||||
Create `tests/test_workspace_path_finalize.py` with the following content:
|
||||
```python
|
||||
"""Tests for the per-run workspace path (workspace_path_finalize_20260609)."""
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_live_gui_workspace_is_under_tests_artifacts(live_gui_workspace: Path) -> None:
|
||||
"""The live_gui_workspace fixture returns a path under tests/artifacts/."""
|
||||
s = str(live_gui_workspace).replace("\\", "/")
|
||||
assert s.startswith("tests/artifacts/live_gui_workspace_"), f"Expected tests/artifacts/live_gui_workspace_*, got {s}"
|
||||
|
||||
|
||||
def test_live_gui_workspace_is_gitignored(live_gui_workspace: Path) -> None:
|
||||
"""The live_gui_workspace path is gitignored (via tests/artifacts/ in .gitignore)."""
|
||||
result = subprocess.run(
|
||||
["git", "check-ignore", str(live_gui_workspace)],
|
||||
capture_output=True, text=True, cwd="."
|
||||
)
|
||||
assert result.returncode == 0, f"Workspace {live_gui_workspace} is not gitignored. git check-ignore output: {result.stdout!r} {result.stderr!r}"
|
||||
```
|
||||
|
||||
**CRITICAL — 1-space indent for all function bodies.** The file-level content has no indent. The `def` lines have no indent. The function body lines have exactly 1 space.
|
||||
|
||||
- [ ] **Step 2.1.2: Verify syntax**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run python -c "import ast; ast.parse(open('tests/test_workspace_path_finalize.py').read()); print('OK')"
|
||||
```
|
||||
|
||||
- [ ] **Step 2.1.3: Run the 2 tests**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run pytest tests/test_workspace_path_finalize.py -v --timeout=30
|
||||
```
|
||||
Expected: 2/2 pass.
|
||||
|
||||
### Phase 2 commit
|
||||
|
||||
- [ ] **Step 2.C.1: Commit the verification tests**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; git add tests/test_workspace_path_finalize.py
|
||||
git commit -m "test(workspace): verify per-run workspace path and gitignore status"
|
||||
$h = git log -1 --format='%H'
|
||||
git notes add -m "2 tests: test_live_gui_workspace_is_under_tests_artifacts (asserts the path starts with tests/artifacts/live_gui_workspace_) and test_live_gui_workspace_is_gitignored (asserts git check-ignore returns 0 for the workspace path). Both pass with the new _RUN_WORKSPACE constant." $h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Run the full batch and verify
|
||||
|
||||
Focus: The moment of truth. tier-1 5/5, tier-2 5/5, tier-3 0 new failures. The 4 sim tests in `test_extended_sims.py` now pass.
|
||||
|
||||
### Task 3.1: Run the full batch
|
||||
|
||||
- [ ] **Step 3.1.1: Run the full batched test suite**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; uv run .\scripts\run_tests_batched.py 2>&1 | Tee-Object -FilePath "tests/artifacts/post_finalize_batch_20260609.log" | Select-Object -Last 50
|
||||
```
|
||||
|
||||
Expected:
|
||||
- tier-1: 5/5 batches pass
|
||||
- tier-2: 5/5 batches pass
|
||||
- tier-3: 0 NEW failures vs the `fe240db4` baseline
|
||||
- The 4 sim tests in `tests/test_extended_sims.py` PASS (they were failing at the `fe240db4` baseline due to the workspace path mismatch)
|
||||
|
||||
- [ ] **Step 3.1.2: If tier-3 has new failures, STOP and report**
|
||||
**DO NOT** try to fix new failures in this track. This track's scope is ONLY the workspace path. New failures are out of scope — document them in the git note and move on.
|
||||
|
||||
- [ ] **Step 3.1.3: Verify the new workspace folder exists in tests/artifacts/**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; ls tests/artifacts/ | Where-Object { $_.Name -like "live_gui_workspace_*" }
|
||||
```
|
||||
Expected: a fresh folder for this run.
|
||||
|
||||
- [ ] **Step 3.1.4: Verify the old %TEMP% workspace is NOT being used**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; ls $env:TEMP | Where-Object { $_.Name -like "pytest-of-*" }
|
||||
```
|
||||
Expected: nothing (or only stale folders from prior runs before this change). The conftest no longer creates new ones in %TEMP%.
|
||||
|
||||
### Task 3.2: Commit the batch log
|
||||
|
||||
- [ ] **Step 3.2.1: Commit the batch log**
|
||||
```powershell
|
||||
cd C:\projects\manual_slop; git add tests/artifacts/post_finalize_batch_20260609.log
|
||||
git commit -m "docs(batch): post-workspace-path-finalize batch log"
|
||||
$h = git log -1 --format='%H'
|
||||
git notes add -m "Final batch run log. tier-1 5/5, tier-2 5/5, tier-3 [count] failures. The 4 sim tests in test_extended_sims.py now pass because their os.path.abspath('tests/artifacts/...') paths resolve correctly to the project tree where the new workspace lives." $h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Final Verification
|
||||
|
||||
- [ ] All 3 commits in place
|
||||
- [ ] `tests/conftest.py` no longer uses `tmp_path_factory` in the `live_gui` fixture
|
||||
- [ ] `tests/artifacts/live_gui_workspace_<timestamp>/` exists after a pytest run
|
||||
- [ ] `.gitignore` already has `tests/artifacts/` (no change needed)
|
||||
- [ ] 2 verification tests pass
|
||||
- [ ] Full batch: tier-1 5/5, tier-2 5/5, tier-3 [count] failures (should match or improve on `fe240db4` baseline)
|
||||
- [ ] The 4 sim tests in `tests/test_extended_sims.py` pass in batch
|
||||
|
||||
## Track Done
|
||||
|
||||
After the 3 commits and the full batch verification, the track is DONE. **Do not:**
|
||||
- File follow-up tracks
|
||||
- Add scope
|
||||
- Refactor anything else
|
||||
- Update docs
|
||||
- Add more tests
|
||||
|
||||
**Do:**
|
||||
- Report the final state to the user
|
||||
- Mark the track as complete in `conductor/tracks.md`
|
||||
- Move on to the 4 upcoming tracks (qwen_llama_grok, data_oriented_error_handling, data_structure_strengthening, mcp_architecture_refactor)
|
||||
|
||||
---
|
||||
|
||||
## Execution Constraints
|
||||
|
||||
- **1-space indent, CRLF, type hints.** Per project conventions.
|
||||
- **1-line edits via `manual-slop_set_file_slice`.** Per `conductor/edit_workflow.md`. The previous attempt at a conftest refactor was reverted due to corruption — use the recommended surgical tool.
|
||||
- **Verify syntax with `ast.parse` after each edit.**
|
||||
- **No diagnostic noise in production.** No `print()` statements added to conftest.py for debugging.
|
||||
- **Per-task atomic commits.** Not batched.
|
||||
- **No "while we're at it" refactors.** This is the LAST track on this issue. Stay in scope.
|
||||
Reference in New Issue
Block a user