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.