Files
Lap Tran bc7daf8590 Restore archived tasks, fix dashboard scroll-reset, bind ornith, add Playwright smoke test
- **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).
2026-06-26 10:05:18 -04:00

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:
    • new
    • research / research:awaiting_approval / research:approved
    • decomposition / decomposition:awaiting_approval / decomposition:approved
    • design / design:awaiting_approval / design:approved
    • test_design / test_design:awaiting_approval / test_design:approved
    • implement
    • bug_find
    • adversarial_bug_find
    • doc_review
    • referee
    • complete
    • human_intervention
  • The base phase name (e.g., research) is used for backward compatibility and when approval is not applicable
  • The :awaiting_approval sub-state means the phase artifact has been produced but not yet approved by the user
  • The :approved sub-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 .state to 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 → decomposition or design or implement (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_design or implement (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 --transition MUST REFUSE to transition past an :awaiting_approval sub-state
  • Only status.py --approve can move from :awaiting_approval to :approved
  • Only status.py --transition from :approved can move to the next phase
  • This makes sign-off enforceable — an agent cannot skip approval and proceed

3. Backward compatibility

  • If .state exists, it is authoritative
  • If .state does not exist, fall back to the artifact-based heuristic (current behavior) and write .state with the inferred phase
  • This ensures existing tasks without .state continue 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 .state first, falling back to artifact heuristic
    • After each phase transition, the Orchestrator must write .state with the new phase name
    • The .state file must be written BEFORE the orchestrator begins executing the next phase
  • Update prompts/workflow.md:
    • Add .state as the canonical phase indicator
    • Note that artifact-based heuristic is a fallback only

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 .state file with new as the initial phase
  • --validate-folder checks that task folders have a .state file; folders without .state were created manually and should be flagged
  • --audit flags task folders without .state as 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

  • .state is NOT an artifact — it should NOT appear in state determination logic that checks artifact files
  • .state should be added to .gitignore patterns (or documented that it's transient metadata)

Acceptance Criteria

  • .state file 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 → :approved only via --approve)
  • Transition past :awaiting_approval without 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 .state doesn't exist is specified
  • Forbidden artifacts per phase are defined and documented
  • status.py --validate-folder enforces forbidden artifacts
  • status.py --transition refuses transitions when forbidden artifacts exist
  • status.py --validate-folder flags task folders without .state as manually created
  • status.py --audit flags manually created task folders
  • status.py --create-task is the only valid way to create task folders
  • orchestrate.md updated to read/write .state
  • workflow.md updated to reference .state as canonical
  • All phase prompts include .state precondition check
  • State transition rules match existing state machine
  • .state is excluded from artifact-based state determination
  • Sub-task .state files are scoped to sub-task folders

Non-Goals

  • This spec does not cover the status.py script (separate task)
  • This spec does not cover prompt restructuring with FORBIDDEN sections (separate task)
  • This spec does not cover autopilot integration (separate task)