v2.0: state enforcement, project scoping, harness integration
CI / build (push) Has been cancelled

State Enforcement (v2.0):
- .state file as single source of truth for task phase
- Approval gates for research, decomposition, design, test_design
- status.py --transition refuses illegal phase transitions
- status.py --validate-folder detects out-of-order artifacts
- status.py --audit checks all tasks for violations
- status.py --create-task is the only valid way to create tasks
- Pre-v2.0 tasks without .state are UNTRACKED -- all commands refuse them
- New --upgrade command bootstraps .state files for existing tasks

Project Scoping:
- --project flag added to all status.py commands across 16+ files
- _find_project_dir errors instead of silently falling back to ~/.automaton/
- --scope-check marks framework files OUT_OF_SCOPE when working on a project
- Dashboard handlers use stored project_root instead of re-detecting from CWD
- Prompts reference ~/.automaton/scripts/vram_detect.py (not {project}/.automaton/)

Harness Integration:
- status.py --can-edit now supports project-level checks (no --task required)
- --can-edit --file checks file scope without --task
- --json output for machine-readable harness integration
- opencode plugin (plugins/automaton-guard/plugin.ts) intercepts edit/write
- Git pre-commit hook (scripts/git-hooks/pre-commit) blocks commits without task
- Formal integration contract (contracts/harness-integration.md)

Other:
- upgrade.sh delegates to status.py --upgrade instead of manual heuristics
- Phase prompts reference --project {project} for multi-project scoping
- 200 tests passing (14 new)
This commit is contained in:
2026-06-15 14:16:46 -04:00
parent 79b783864e
commit 05c76852a2
151 changed files with 7295 additions and 632 deletions
+30
View File
@@ -0,0 +1,30 @@
# Bug Report: task-status-reason
## Summary
Audit of status_reason implementation against SPEC.md found minor issues: a dead-code branch in the status_reason message, and a pre-existing REFEREE state that's never produced.
## Bugs Found
### Bug 1: Dead message branch in status_reason for BLOCKED state
- **Severity**: Low
- **Location**: `automaton/dashboard/core/task.py:149`
- **Description**: The message `"Verdict is empty or could not be parsed"` has two scenarios:
1. Empty verdict → reachable (content is `""`, correctly returns this message)
2. Unparseable verdict → unreachable. When `parse_verdict_status()` returns `None`, the state machine in `determine_task_state()` doesn't classify the task as BLOCKED — it falls through to earlier state checks. So a task is never both BLOCKED and "could not be parsed".
- **Suggested Fix**: Change message to `"Verdict is empty"` to accurately reflect the only reachable case.
### Bug 2: REFEREE state never produced by state machine
- **Severity**: Low
- **Location**: `automaton/dashboard/core/task.py:174` (fallback `status_reason` line), and `task.py:226-272` (determine_task_state)
- **Description**: `TaskState.REFEREE` exists in the enum and in the sort order, but `determine_task_state` never returns it. When a VERDICT.md is present but unparseable, the state machine falls through to earlier artifact checks instead of assigning REFEREE. This means the fallback status reason `"In referee phase"` is unreachable, and tasks with ambiguous verdicts silently show as earlier states (e.g., RESEARCH if only SPEC.md exists alongside an unparseable VERDICT.md).
- **Pre-existing**: This predates the task and is not introduced by the implementation, but the status_reason property exposes it because the REFEREE branch is dead code.
- **Suggested Fix**: Add `if "VERDICT.md" in artifacts: return TaskState.REFEREE, artifacts` after the terminal-state checks in `determine_task_state()`, before the state machine fallthrough.
### Bug 3: REFEREE status reason is generic
- **Severity**: Low
- **Location**: `automaton/dashboard/core/task.py:175`
- **Description**: The fallthrough line `return f"In {self.state.value} phase"` would produce generic messages like `"In blocked phase"` or `"In done phase"` for states that are handled above it. This is actually dead code for all defined states since every `TaskState` value is covered by an explicit `if` branch. If a new state is added without adding a status_reason handler, it gets a generic message rather than failing loudly.
- **Suggested Fix**: Replace the fallthrough with a clear signal: either raise an error, or explicitly list the catch to alert developers when adding states.
## Score
+5