Skip to content

Lesson 04 — Small state machines and invariants ​

Outcome ​

Implement and test the canonical Task lifecycle without agent code.

Why this comes now ​

If state transitions are left as arbitrary string updates, every future screen and service can create impossible combinations.

Understand ​

The Task lifecycle is deliberately small: BACKLOG → READY → WORKING ⇄ NEEDS_YOU, WORKING → REVIEW ⇄ WORKING, REVIEW → DONE. Planning, verification, review progress, agent startup, and worktree preparation are separate lifecycles.

Methods should express intent: MakeReady, StartWork, NeedHuman, ResumeWork, SubmitForReview, RequestChanges, Approve rather than SetStatus.

Build the real project ​

  1. Encode allowed transitions in domain methods.
  2. Return typed/actionable errors for illegal transitions.
  3. Write exhaustive transition tests.
  4. Add placeholder policy input where approval will later need current Review/Verification evidence, but do not fake those subsystems yet.
  5. Keep a clear test showing that “agent finished” is not a Task transition because there is no agent yet.

Completion gate ​

Every valid transition is tested; every invalid edge is rejected. There is no public unrestricted status setter used by application code.

Pitfalls to avoid ​

Avoid one giant transition table if named methods remain clearer. Avoid adding statuses to represent loading spinners.

References ​

STATE_MACHINES.md, Making illegal states unrepresentable (concept).

Checkpoint ​

Update the current status. You should be able to explain why Review is a Task state but “human_review_in_progress” is not.

Forge is local-first. The docs are part of the product engineering system.