<!-- canonical: https://klappy.dev/page/odd/gate/transitions -->
<!-- content: klappy/klappy.dev@b750d7d3aa85a3e5ed6d1e2b24d63471f3df4bac -->

# Gate Transitions — Mode Transition Keys and Detection Terms

> `oddkit_gate` checks prerequisites before the operator crosses a mode boundary. Each transition is identified by a stable key, has a `from` and `to` endpoint, names the prerequisite ids that must be satisfied before the transition is considered ready, and supplies a vocabulary of detection terms used to recognize the transition in user input. The server tokenizes and Porter-stems both the detection terms and the user input, then uses BM25 scoring to pick the single best-matching transition. Top hit with score greater than zero wins; row order in the table below breaks ties. When no row scores above zero, the transition is reported as `unknown → unknown` and the gate returns `PASS` with no prerequisites checked, matching the current reversion-path convention.

---

## Summary — One Row Per Transition Key, Detection and Prerequisites Co-Located

Six declared transitions cover the mode-discipline cycle and its two guarded escalations: opening planning after exploration, opening execution after planning, reverting from execution to exploration when the plan needs rethinking, declaring completion when execution produces a validated artifact, and — the guarded ones — handing anything off to the captain. The `dispatch-to-captain-handoff` transition exists because of the offload trip-wire in `https://klappy.dev/page/canon/constraints/dispatcher-dispatches-never-executes`: a seat about to ask the captain to run/launch/commit/push/deploy anything runs its draft ask through the gate, and the gate demands proof that delegation to a subagent was attempted and that a human-only class (secret / voice / irreversible / approval) is named. Its detection vocabulary is deliberately rich in second-person tokens (you, your, captain) so BM25 routes offload phrasings here rather than to `execution-to-completion`, whose vocabulary shares operational verbs like deploy and push but carries no second-person signal. The `settled-direction-ratification` transition exists because of the let-the-gates-govern clause of the same canon constraint: a seat about to ask the captain to approve/ratify/bless/sign-off/green-light anything runs the draft ask through the gate, and the gate demands `open_fork_cited` — the ask must affirmatively name the genuinely-open fork the gates cannot resolve, because an ask that ratifies an already-recorded decision has no open fork to name and comes back NOT_READY. Its detection vocabulary is rich in approval stems (ratify, approve, bless, sign-off) and settled-record markers (already decided, per the ruling, settled call) that appear in neither the offload row (operational verbs) nor `execution-to-completion` (shipping verbs), so BM25 routes approval-shaped asks here. The word `proceed` appears exactly once in this row (in `shall I proceed`), deliberately: `proceed` is also a detection term of `exploration-to-planning`, and listing it more than once would let term frequency hijack a bare "proceed" input away from the planning transition — with a single occurrence, BM25 length normalization and row-order tiebreak keep bare "proceed" routing to `exploration-to-planning` as before. Each row carries its own detection vocabulary and prerequisite-id list, so consumers reading this file can answer "what fires this transition, and what must be true for it to pass?" in one lookup. Prerequisite ids resolve against `odd/gate/prerequisites.md` — that file defines each id's description, check vocabulary, and gap message. Detection terms are matched via BM25 over stemmed tokens; the specific-phrase-beats-single-word property of BM25 scoring means that `ready to build` outscores the bare word `ready` when both appear in the input, so the specific transition wins on score rather than relying on regex cascade order.

---

## Transitions

| Transition Key | From | To | Prerequisites | Detection Terms |
|---|---|---|---|---|
| `planning-to-execution` | planning | execution | decisions_locked, dod_defined, irreversibility_assessed, constraints_satisfied | ready to build, ready to implement, start building, let's code, start coding, moving to execution, moving to build |
| `exploration-to-planning` | exploration | planning | problem_defined, constraints_reviewed, world_prior_cited, house_install_cited, house_canon_cited | ready to plan, start planning, let's plan, time to plan, move to planning, moving to planning, ready, let's go, proceed, move forward, next step |
| `execution-to-exploration` | execution | exploration |  | back to exploration, need to rethink, step back, stepped back, stepping back, reconsider |
| `execution-to-completion` | execution | completion | dod_met, artifacts_present | ship, shipping, shipped, deploy, release, go live, push to prod |
| `dispatch-to-captain-handoff` | execution | captain-escalation | delegation_attempted, human_only_class_named | you run it, you push, you commit, you deploy, you launch, you merge, can you run, please run this, over to you, your turn, on your machine, run this yourself, hand off to the captain, captain to run, for you to merge, leave the push to you |
| `settled-direction-ratification` | execution | captain-escalation | open_fork_cited | ratify, ratification, rubber stamp, bless the decision, your blessing, do you approve, please approve, approve the direction, approve the plan, approve the decision, awaiting your approval, ready for your approval, your sign-off, sign off on, green-light this, re-approve, re-confirm, shall I proceed, already decided, already settled, per the ruling, settled call, direction is set |

---

## Notes

Row order is the tiebreaker priority when two transitions score identically under BM25. BM25 naturally prefers specific-phrase matches over single-word matches — an input like "ready to build my feature" scores the multi-term match against `planning-to-execution` above the single-term match against `exploration-to-planning` — so row order rarely decides the winner. The ordering is kept stable regardless to produce deterministic output on genuine ties.

Detection terms are stemmed at parse time using the Porter-style stemmer in the server. Stemming covers the common inflection suffixes `ies`, `ied`, `ed`, `ing`, `tion`, `ment`, `ness`, `able`, `ible`, and `s`, which means variations like `deploying`, `released`, `started building`, `building`, and `reconsidering` match their canonical transitions even though the exact phrases are not listed. Terms that already appear in their stemmed base form — `build`, `reconsider` — match themselves directly.

The stemmer does not currently handle doubled-consonant gemination — `shipping` stems to `shipp` rather than `ship`, and `stepped` stems to `stepp` rather than `step`. For the small number of geminating words gate cares about (`ship`, `step`), the inflected forms are listed in the detection column directly so the match is by direct vocabulary rather than relying on the stemmer. This is a deliberate choice: adding a handful of explicit inflections is cheaper and more auditable than extending the stemmer, and keeps the vocabulary editable at canon rather than at the code level.

The `execution-to-exploration` transition has no prerequisites because reversion is explicitly permitted under the mode-discipline contract at `https://klappy.dev/page/canon/constraints/mode-discipline-and-bottleneck-respect`. Reversion requires only that the operator name the specific unknown that drove the reversion, which is a behavioral expectation enforced by the operator's own discipline rather than by a gated prereq check.

When no row's detection terms score above zero against the user input, the server reports the transition as `unknown → unknown`. In this case no prerequisites are looked up and the gate returns `PASS` — the convention being that an unrecognized input is not a gate crossing at all, so there is nothing to block. This matches the pre-refactor behavior encoded in the previous hardcoded detection cascade.

Prereq-ids listed in the Prerequisites column are resolved against `odd/gate/prerequisites.md`. An id that appears in this table but not in that file is a governance error; the server's minimal fallback tier carries a hardcoded vocabulary snapshot that keeps gate functional in this case, but the canon-level fix is to update one file or the other.

When the server cannot reach this file at runtime, `oddkit_gate` falls back to a hardcoded minimal vocabulary that mirrors the row order and detection terms above. The minimal tier is identified in the response envelope via `governance_source: "minimal"`; the canon tier via `governance_source: "knowledge_base"`. Both tiers run the same BM25 matcher; they differ only in whether the vocabulary is editable by updating this file or locked to the deployed worker version.

The `exploration-to-planning` row (2026-09-21) lists five prerequisite ids: the original pair plus `world_prior_cited`, `house_install_cited`, `house_canon_cited`. Those ids are defined in `odd/gate/prerequisites.md`. Planning-to-execution is unchanged.
