Contracts
fsm-and-genesis-contracts.md
Phase 1 Contracts — FSM delegation, genesis invariant, SaaS lane delta
Contract 1 — validate_transition delegates to the FSM (DM-01KTH03G)
validate_transition(from_lane, to_lane, ctx) -> (ok: bool, error: str | None)
resolves aliases; then delegates to wp_state_for(resolved_from)
so the State object decides edge + guard + force.
existing (from,to,ctx) combinations (I4, I5) — including: actor-required, workspace_context, subtasks_complete_or_force, reviewer_approval, ReviewResult-required outbound from in_review, done-evidence, and force-override (force ⇒ requires actor + reason).
production caller consults ALLOWED_TRANSITIONS (or any derived edge set) as a gate — every edge/transition question routes through a WPState. ALLOWED_TRANSITIONS is removed or relegated to a non-authoritative test/graph projection.
terminal force-exit parity test (done/canceled → any lane with force+actor+reason); an architectural test asserting no production module imports ALLOWED_TRANSITIONS for an edge gate.
- Pre:
from_lane/to_laneresolve to a knownLane(else(False, "Unknown lane …")). - Behavior: identical
(ok, error)results as the historical implementation for ALL - Post: no transition-edge or guard logic remains outside the State objects; no
- Test: parametrized parity over the full historical transition+guard matrix; a dedicated
Contract 2 — Genesis non-display invariant (I2)
genesis; a genesis-state WP is never silently dropped.
assertion that no display/summary/discovery surface includes genesis.
genesis ∉ CANONICAL_LANES;genesis ∈ Lane.- Reducer summary dict EXCLUDES genesis:
{l.value: 0 for l in Lane if l is not Lane.GENESIS}. tasks.pyby_lane, runtime discovery candidate lists, and the kanban column map excludevalidate_canonical_event:genesisvalid asfrom_laneonly;to_lane=genesis→ non-canonical.- frontmatter lane validation does not offer
genesisas authorable. - Test: assert reducer real output (not a fixture) has no genesis key; grep-style architectural
Contract 3 — Read/write parity (I3)
runtime/next/discovery.py, runtime/next/decision.py, agent_utils/status.py: default an unseeded WP to Lane.GENESIS (not PLANNED).
("WP … not finalized; run spec-kitty agent mission finalize-tasks") before any workspace/worktree allocation.
exits with the actionable message and leaves no .worktrees/ entry.
wp_lane_actor_from_events,read_current_wp_state_transactionalfallback,start_implementation_statuson a genesis WP raisesWorkPackageStartRejected- Test: each reader returns genesis for an unseeded WP;
implementon an unseeded WP
Contract 4 — spec_kitty_events.Lane delta (DM-01KTH03H)
canonical lane source (incl. genesis), not a hardcoded 9-lane list.
spec_kitty_events release; no committed path/editable overrides (Shared Package Boundary).
fixture covers both old and new spec_kitty_events.
- The external
spec_kitty_events.Laneenum gains agenesismember (owning-package release). StatusTransitionPayload/WPStatusChangedacceptfrom_lane=genesis.- CLI
sync/emitter.py_PAYLOAD_RULES["WPStatusChanged"]lane set is DERIVED from the - The
genesis → plannedseed fans out without a swallowedValidationError. - Compatibility: a capability/version check guards the window before the genesis-aware
- Test: a genesis seed produces a contract-valid SaaS payload; consumer/compatibility
Contract 5 — Finalize preserves the coordination event log (baseline)
status.json over the coord worktree's seeded copies; non-coord missions still commit theirs.
finalize-tasks(coord topology) does not copy primary-checkoutstatus.events.jsonl/- Test: end-to-end coord
finalize-tasksretains bootstrap lane events (FR-019).