- **Restore 82 completed tasks** from tasks/complete/ back to tasks/ top level (all <7 days old per the cleanup policy; premature bulk archive was fixed). - **Dashboard: fix scroll-reset on auto-refresh** — renderBoard rebuilds the board via innerHTML every 2s, destroying each column-body's scrollTop. Now snapshots column-body scrollTop + board.scrollLeft + view.scrollTop before rebuild and restores after (matched by PHASE_GROUPS index). - **Dashboard UI additions** (pre-existing unstaged work): approval section cards, transition buttons, inline artifact editor (textarea for writing missing SPEC/VERDICT/etc from the detail modal). - **Bind ornith as Implement model** — config.md: Model explicit to omlx/Ornith-1.0-35B-4bit-mlx, context window 32768. Interactive autopilot already used ornith via opencode default; now explicit. - **Fix cleanup stub** — automaton-cleanup.sh had a stale --project arg pointing at a pytest temp dir (test isolation leak). Rewired to point at ~/.automaton. - **Fix plist-isolation test** — test asserted host plist doesn't exist, but a real install creates it. Now snapshots mtime before run, asserts unchanged after (only a write during the test counts as bleed). - **New Playwright smoke test** (tests/test_dashboard_ui.py) — 2 tests: board renders tasks, column scroll survives auto-refresh tick. Verified the test fails without the scroll fix (scrollTop resets to 0). Skipped via importorskip when playwright is absent (main CI stays green). - **Clarify SI loop scope in README** — new-project onboarding section documents the framework-scoped self-improvement loop and options (leave/pause/create project loop). - **CHANGELOG** documents all changes including the known model-divergence gap (mde tasks marked complete but per-role model binding was never implemented).
9.3 KiB
SPEC: State File Enforcement
Goal
Replace the fragile "check which artifacts exist" heuristic for determining task phase with an explicit .state file that is the single source of truth for a task's current phase.
Background
Currently, orchestrate.md and workflow.md determine a task's phase by checking which artifact files exist in the task folder (e.g., "if SPEC.md exists but not DESIGN.md, the task is in research phase"). This is unreliable because:
- Any agent can create any artifact file at any time, bypassing phase ordering
- File-existence checks are ambiguous (e.g., overlapping conditions when multiple artifacts exist)
- There's no authoritative record of what phase a task is in — every agent has to re-derive it
Requirements
1. .state file format
- Location:
tasks/{task-name}/.state - Content: a phase name (and optional approval status), one of:
newresearch/research:awaiting_approval/research:approveddecomposition/decomposition:awaiting_approval/decomposition:approveddesign/design:awaiting_approval/design:approvedtest_design/test_design:awaiting_approval/test_design:approvedimplementbug_findadversarial_bug_finddoc_reviewrefereecompletehuman_intervention
- The base phase name (e.g.,
research) is used for backward compatibility and when approval is not applicable - The
:awaiting_approvalsub-state means the phase artifact has been produced but not yet approved by the user - The
:approvedsub-state means the user has given explicit approval to proceed - Only phases with interactive sign-off requirements use sub-states: research, decomposition, design, test_design
- Phases without sign-off (implement, bug_find, adversarial_bug_find, doc_review, referee) use only the base name
- The file must be written atomically (write to
.state.tmp, then rename to.state) to prevent partial reads - The file must NOT be listed in task artifact checks — it is metadata, not a deliverable
2. State transitions
- Only the Orchestrator (or
status.py) may write to.state - Phase prompts must READ
.stateto confirm they are in the correct phase before acting - Transition rules match the existing state machine in
workflow.md:new→research(when task folder is created)research→research:awaiting_approval(when SPEC.md draft is presented for sign-off)research:awaiting_approval→research:approved(when user says APPROVED)research:approved→decompositionordesignorimplement(when SPEC.md is finalized)decomposition→decomposition:awaiting_approval(when DECOMPOSITION.md draft is presented)decomposition:awaiting_approval→decomposition:approved(when user says APPROVED)decomposition:approved→ sub-task research (when DECOMPOSITION.md is finalized)design→design:awaiting_approval(when DESIGN.md draft is presented)design:awaiting_approval→design:approved(when user says APPROVED)design:approved→test_designorimplement(when DESIGN.md is finalized)test_design→test_design:awaiting_approval(when TEST_PLAN.md draft is presented)test_design:awaiting_approval→test_design:approved(when user says APPROVED)test_design:approved→implement(when TEST_PLAN.md is finalized)implement→bug_find(when IMPLEMENTATION.md is produced — no approval needed)bug_find→adversarial_bug_find(when BUG_REPORT.md is produced — no approval needed)adversarial_bug_find→doc_review(when ADVERSARIAL_BUG_REPORT.md is produced — no approval needed)doc_review→referee(when DOC_REVIEW.md is produced — no approval needed)referee→complete(when VERDICT.md has PASS)referee→human_intervention(when VERDICT.md has FAIL or NEEDS_REVIEW)
Approval gate enforcement:
status.py --transitionMUST REFUSE to transition past an:awaiting_approvalsub-state- Only
status.py --approvecan move from:awaiting_approvalto:approved - Only
status.py --transitionfrom:approvedcan move to the next phase - This makes sign-off enforceable — an agent cannot skip approval and proceed
3. Backward compatibility
- If
.stateexists, it is authoritative - If
.statedoes not exist, fall back to the artifact-based heuristic (current behavior) and write.statewith the inferred phase - This ensures existing tasks without
.statecontinue to work and get migrated on first access
4. Artifact validation rules (enforced by status.py)
Each phase has a defined set of artifacts that are ALLOWED and FORBIDDEN in the task folder. These rules are enforced by status.py --validate-folder and status.py --transition:
Forbidden artifacts per phase (artifacts from future phases — must NOT exist):
| Phase | Forbidden artifacts |
|---|---|
new |
SPEC.md, DESIGN.md, DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
research |
DESIGN.md, DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
decomposition |
DESIGN.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
design |
DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
test_design |
DECOMPOSITION.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
implement |
BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
bug_find |
ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md |
adversarial_bug_find |
DOC_REVIEW.md, VERDICT.md |
doc_review |
VERDICT.md |
referee |
(none) |
complete |
(none) |
human_intervention |
(none) |
Non-artifact files are never forbidden: .state, VRAM_CONFIG.md, PARENT_SPEC.md, REVIEW.md, .state.tmp. These are metadata and can exist at any phase.
Enforcement: When status.py --transition is called, it must check for forbidden artifacts BEFORE allowing the transition. If forbidden artifacts exist, the transition is refused with a clear error identifying the offending artifacts.
5. Orchestrator updates
- Update
prompts/orchestrate.md:- State determination section must read
.statefirst, falling back to artifact heuristic - After each phase transition, the Orchestrator must write
.statewith the new phase name - The
.statefile must be written BEFORE the orchestrator begins executing the next phase
- State determination section must read
- Update
prompts/workflow.md:- Add
.stateas the canonical phase indicator - Note that artifact-based heuristic is a fallback only
- Add
5. Phase prompt updates
- Every phase prompt must include a precondition check:
Read tasks/{task}/.state. If the phase does not match this prompt's phase, STOP and report. - This is a 2-line addition to each prompt's "Read These Files" section
6. Task creation gate
- Task folders MUST be created via
status.py --create-task(defined in status-script spec) - A valid task folder has a
.statefile withnewas the initial phase --validate-folderchecks that task folders have a.statefile; folders without.statewere created manually and should be flagged--auditflags task folders without.stateas violations: "Task '{task-name}' was created manually (no .state file). Use 'python ~/.automaton/scripts/status.py --create-task' to create tasks properly."
7. Artifact integrity
.stateis NOT an artifact — it should NOT appear in state determination logic that checks artifact files.stateshould be added to.gitignorepatterns (or documented that it's transient metadata)
Acceptance Criteria
.statefile format is specified and documented (including approval sub-states)- Approval sub-states defined for research, decomposition, design, test_design
- Approval transition rules defined (
:awaiting_approval→:approvedonly via--approve) - Transition past
:awaiting_approvalwithout approval is REFUSED by--transition - Phases without sign-off (implement, bug_find, etc.) use base names only
- Atomic write mechanism is defined (write-to-tmp-then-rename)
- Fallback to artifact heuristic when
.statedoesn't exist is specified - Forbidden artifacts per phase are defined and documented
status.py --validate-folderenforces forbidden artifactsstatus.py --transitionrefuses transitions when forbidden artifacts existstatus.py --validate-folderflags task folders without.stateas manually createdstatus.py --auditflags manually created task foldersstatus.py --create-taskis the only valid way to create task foldersorchestrate.mdupdated to read/write.stateworkflow.mdupdated to reference.stateas canonical- All phase prompts include
.stateprecondition check - State transition rules match existing state machine
.stateis excluded from artifact-based state determination- Sub-task
.statefiles are scoped to sub-task folders
Non-Goals
- This spec does not cover the
status.pyscript (separate task) - This spec does not cover prompt restructuring with FORBIDDEN sections (separate task)
- This spec does not cover autopilot integration (separate task)