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:
+59
-17
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user