# Multi-State Transition Contract

This document freezes the Omagy workflow state transition model.

## Canonical sources of truth

Omagy workflow state is represented by:

- mode state files under `.omagy/state/{scope}/<mode>-state.json`
- active workflow inventory in `.omagy/state/{scope}/skill-active-state.json`

`skill-active-state.json` is the canonical active-set inventory. Mode state
files remain the detailed state source for each workflow.

## Approved peer combinations

Allowed workflow overlaps are intentionally narrow:

- standalone single-workflow state
- `team + ralph`
- `team + ultrawork`
- `team + ultragoal`

These are peer states. Neither mode becomes primary just because it was
activated first.

## Auto-complete handoffs

The following handoffs complete the source workflow before activating the target:

- `deep-interview -> team`
- `deep-interview -> plan`
- `deep-interview -> ralph`
- `deep-interview -> ultrawork`
- `deep-interview -> ultragoal`
- `deep-interview -> review`
- `plan -> team`
- `plan -> ralph`
- `plan -> ultragoal`
- `review -> ultraqa`
- `ultragoal -> ultraqa`
- `ralph -> ultraqa`

Plan-approved execution may enter Team, Ralph, or Ultragoal. Plan must not
launch Ultrawork directly. Ralph and Ultragoal may use Ultrawork discipline
internally without activating Ultrawork as a peer persistence owner.

## Deny-by-default policy

All unlisted overlaps are rejected without mutating existing state. In
particular:

- `ralph + ultrawork` is denied
- `ralph + ultragoal` is denied
- `ultrawork + ultragoal` is denied
- `ultrawork + ultraqa` is denied
- `team + ultraqa` is denied unless a future contract gives Team explicit QA
  ownership
- `plan + ultrawork` is denied
- `review + ultrawork` is denied

Denied transitions must name the active set, name the unsupported combination,
and tell the operator how to clear incompatible state:

```bash
omagy state clear --input '{"mode":"<mode>"}' --json
```

When MCP state tools are enabled, the equivalent recovery surface is
`omagy_state_clear` with the same mode.

## Consumer expectations

Every runtime consumer must use the same transition semantics:

- state write/start paths must call the transition evaluator before activation
- Stop hooks must respect every active approved peer state
- HUD must render approved combined state
- cancellation must clear only the requested member unless `--all` is explicit
- plugin docs must include this contract after `npm run sync-plugin`

## Regression expectations

The contract is complete only when tests prove:

- `team + ralph` is allowed in both activation orders
- `team + ultrawork` is allowed in both activation orders
- `team + ultragoal` is allowed in both activation orders
- unsupported overlaps deny without mutation
- denied transition messages mention both CLI and MCP recovery surfaces
- deep-interview handoff to Ultrawork still auto-completes
- plan handoff to Ultragoal auto-completes planning state
- HUD, Stop, and cancel behavior remain correct for approved overlaps
