Fix 7 bugs in autopilot.py, add 43 tests

Fixes from functional correctness review:
- PHASE_PRIORITY: add code_review (was missing, caused wrong task selection)
- cmd_drive: implement→code_review (was illegal implement→bug_find)
- cmd_drive: add handlers for code_review and code_review:approved
- _all_tasks: skip tasks/complete/ (was showing completed tasks as phase=None)
- _all_tasks: recurse into subtasks/ (subtasks were invisible to autopilot)
- _all_tasks: use .automaton/tasks for non-framework projects (was project/tasks)
- is_terminal: only True for complete (human_intervention has legal transitions)
- needs_user_input: flag human_intervention as blocked (was auto-driving it)

Tests cover all 8 bugs: PHASE_PRIORITY ordering, every phase transition,
code_review handlers, complete/ exclusion, subtask recursion, project path,
terminal state, user-input detection, human_intervention handling.
This commit is contained in:
Lap Tran
2026-06-25 07:11:44 -04:00
parent 4b3d92c9a2
commit 715f6f9495
2 changed files with 375 additions and 17 deletions
+59 -17
View File
@@ -24,15 +24,17 @@ AUTOMATON_DIR = Path.home() / ".automaton"
PHASE_PRIORITY = {
"referee": 12,
"doc_review": 10,
"adversarial_bug_find": 8,
"bug_find": 6,
"implement": 5,
"test_design": 4,
"design": 3,
"decomposition": 2,
"research": 1,
"new": 0,
"doc_review": 11,
"adversarial_bug_find": 10,
"bug_find": 9,
"code_review": 8,
"implement": 7,
"test_design": 6,
"design": 5,
"decomposition": 4,
"research": 3,
"new": 2,
"human_intervention": 1,
}
@@ -60,13 +62,28 @@ def _read_state(task_path: Path) -> Optional[str]:
def _all_tasks(project_dir: Path) -> list[tuple[str, Path]]:
tasks_dir = project_dir / "tasks"
if not tasks_dir.is_dir():
"""Scan all tasks (including subtasks) for a project.
Mirrors ``status.py:_all_task_dirs``: skips ``tasks/complete/``,
recurses into ``subtasks/``, uses ``.automaton/tasks`` for non-framework
projects.
"""
if project_dir == AUTOMATON_DIR:
base = AUTOMATON_DIR / "tasks"
else:
base = project_dir / ".automaton" / "tasks"
if not base.is_dir():
return []
result = []
for subdir in sorted(tasks_dir.iterdir()):
if subdir.is_dir():
result.append((subdir.name, subdir))
for entry in sorted(base.iterdir()):
if not entry.is_dir() or entry.name.startswith(".") or entry.name == "complete":
continue
result.append((entry.name, entry))
subtasks = entry / "subtasks"
if subtasks.exists():
for sub in sorted(subtasks.iterdir()):
if sub.is_dir() and not sub.name.startswith("."):
result.append((f"{entry.name}/{sub.name}", sub))
return result
@@ -87,11 +104,16 @@ def scan_all_tasks(project_dir: Path) -> list[dict]:
def is_terminal(task: dict) -> bool:
"""Check if a task is in a terminal state."""
"""Check if a task is in a terminal state.
Only ``complete`` is terminal. ``human_intervention`` has legal
transitions (→ referee, → complete) so the autopilot can still
suggest next steps for it.
"""
phase = task.get("phase")
if phase is None:
return False
return phase in ("complete", "human_intervention")
return phase == "complete"
def needs_user_input(task: dict) -> bool:
@@ -101,6 +123,8 @@ def needs_user_input(task: dict) -> bool:
return False
if phase.endswith(":awaiting_approval"):
return True
if phase == "human_intervention":
return True
task_path = Path(task["path"])
verdict_file = task_path / "VERDICT.md"
if verdict_file.exists():
@@ -246,6 +270,13 @@ def cmd_drive(args):
print(
f" python ~/.automaton/scripts/status.py --approve --task {t['name']} --project {project_dir}"
)
elif t["phase"] == "human_intervention":
print(
f" Review {t['name']} — transition to referee or complete:"
)
print(
f" python ~/.automaton/scripts/status.py --transition referee --task {t['name']} --project {project_dir}"
)
else:
print(f" Review {t['name']}/VERDICT.md and take action")
return 0
@@ -313,8 +344,19 @@ def cmd_drive(args):
elif base == "implement":
print("→ Write implementation, generate IMPLEMENTATION.md, then transition:")
print(
f" python ~/.automaton/scripts/status.py --transition bug_find --task {task['name']} --project {project_dir}"
f" python ~/.automaton/scripts/status.py --transition code_review --task {task['name']} --project {project_dir}"
)
elif base == "code_review":
if phase == "code_review":
print("→ Generate CODE_REVIEW.md, then transition to awaiting_approval:")
print(
f" python ~/.automaton/scripts/status.py --transition code_review:awaiting_approval --task {task['name']} --project {project_dir}"
)
elif phase == "code_review:approved":
print("→ Transition to bug_find:")
print(
f" python ~/.automaton/scripts/status.py --transition bug_find --task {task['name']} --project {project_dir}"
)
elif base == "bug_find":
print("→ Generate BUG_REPORT.md, then transition:")
print(