This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(KR-P2-I-skeleton): operational state machine — enums + transition table (no emit, no wire-in)#27
Merged
Conversation
…n table (no emit, no wire-in) Skeleton-only: ships R4.1 §9.1's runtime operational state machine as a pure dataclass + enum + transition-table layer. No chain-event emission, no agent-loop wire-in, no startup hooks. Both follow on after substrate-round Bucket C (event-type literals) + KR-P2-H (boot gates) + KR-P2-I-integration (which folds this skeleton into the agent loop). # Why ship the skeleton now CC#2 is building the Operational State admin panel in parallel; they import `PrimaryState`, `DegradationReason`, and `ClaimPermission` for type safety. Shipping the dataclass layer now decouples that frontend work from the substrate-round critical path. # New module: agent/operational_state.py - `PrimaryState` — 5-member enum (booting / ready / active / paused / stopped) per R4.1 §9.1. Per R4.1 footnote, DEGRADED is NOT a primary_state — it's modeled as the derived flag `OperationalState.is_degraded()`. - `DegradationReason` — 8-member enum (cost / auth / dispatch / substrate / migration / operator / token_expiring / retry_ceiling). - `ClaimPermission` — 3-member enum (none / critical_only / normal). - `OperationalState` — frozen dataclass snapshot with `with_*` factory methods (immutable; produce derived instances). - `StateTransition` — frozen dataclass row of the transition table. - `TRANSITION_TABLE` — 15-row tuple covering all R4.1 §9.1 transitions, with `any → PAUSED` and `any → STOPPED` shorthand expanded into per-from-state rows so single-pass lookup works. - `is_valid_transition` / `transitions_from` / `transitions_to` — read-only query helpers. Enum string values are treated as load-bearing wire format (CC#2 admin panel + future substrate event payloads consume them verbatim). # Tests: tests/test_operational_state.py — 54 (incl. parametrize) - Enum value strings match R4.1 §9.1 verbatim + correct cardinality - OperationalState immutability (frozen=True) + defaults - `is_degraded()` truth table - All four `with_*` factory methods: new-instance + original-untouched - `is_valid_transition` parametrized: 12 known transitions True, 10 unknown False (terminal STOPPED, self-loops, illegal jumps) - `transitions_from(BOOTING)` returns 6 rows (1 R4.1 row per to-state, plus the duplicate-arrow rows from the `any → PAUSED` and `any → STOPPED` expansions) - `transitions_to(STOPPED)` returns 5 rows (one per concrete from-state, plus the duplicate BOOTING→STOPPED arrow from "invariant fail" vs "STOP-KORA L4/L5" triggers) - `transitions_from(STOPPED)` empty (terminal) - Enum round-trip via `.value` / `EnumCls(value_str)` for all members # Bucket-spec inconsistencies adjusted (non-blocking) - Bucket §5 test #1 says "8 PrimaryState members"; R4.1 §9.1 + the bucket's own §3 enum block list 5. Test asserts 5 (matches reality). - Bucket §5 tests #8 / #9 say "4 BOOTING-origin / 4 STOPPED-arrival"; the bucket's TRANSITION_TABLE expansion of "any → PAUSED/STOPPED" yields 6 / 5 respectively (one row per concrete from-state, with same-arrow rows for different triggers). Tests assert 6 / 5 and document the expansion rationale in the docstring. # §8 pre-push grep sanity check passes - `grep -n "kora__append_event\|IsoKronMemoryProvider\|tool_executor" agent/operational_state.py` — zero matches. - `grep -rn "operational_state\|OperationalState" gateway/ kora_cli/ agent/tool_executor.py` — zero matches. # Honest scope Pure dataclass + enum + transition table. No imports of `IsoKronMemoryProvider`, no append-event MCP calls, no startup hooks, no agent-loop coupling, no persistence. Emit + wire-in lives in the KR-P2-I-integration follow-on (post-Bucket-C). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rafe-walker
added a commit
that referenced
this pull request
May 21, 2026
…nt (#26) GET /api/operational-state stub (READY/normal/no-degradation, stub:true). OperationalStatePage.tsx with STUB DATA banner (conditional), primary-state badge with per-state tone, claim-permission pill, degradation chips with hover blurbs, transition-history table, valid-next-states list. Read-only, manual Reload only. api.ts typed enums anchored to R4.1 §9.1 verbatim (matches PR #27 Python enum strings). 8 new + 47/47 full suite tests; tsc + vite clean. Flip-over plan: swap stub function body to project from real OperationalState singleton when KR-P2-I-integration lands; frontend continues unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
KR-P2-I-skeleton — ships R4.1 §9.1's runtime operational state machine as a pure dataclass + enum + transition-table layer. No chain-event emission, no agent-loop wire-in, no startup hooks. Both follow on after substrate-round Bucket C (event-type literals) + KR-P2-H (boot gates) + KR-P2-I-integration (which folds this into the agent loop).
CC#2 imports
PrimaryState,DegradationReason, andClaimPermissionfor the Operational State admin panel; shipping the dataclass layer decouples that frontend work from the substrate-round critical path.R4.1 §9.1 spec:
kora_docs/21_program_council/Kora_v1_Program_Spec_R4.1_FINAL.md#9-1New module —
agent/operational_state.pyPrimaryState— 5 members (booting/ready/active/paused/stopped). DEGRADED is not a primary state per R4.1; it's the derived flagis_degraded().DegradationReason— 8 members (cost/auth/dispatch/substrate/migration/operator/token_expiring/retry_ceiling).ClaimPermission— 3 members (none/critical_only/normal).OperationalState— frozen dataclass withwith_added_reason/with_removed_reason/with_primary_state/with_claim_permissionfactory methods.StateTransition+TRANSITION_TABLE— 15-row tuple covering all R4.1 §9.1 transitions, withany → PAUSED/any → STOPPEDshorthand expanded per concrete from-state so single-pass lookup works.is_valid_transition/transitions_from/transitions_to— read-only query helpers.Enum string values are treated as load-bearing wire format (CC#2 admin panel + future substrate event payloads consume them verbatim).
Bucket-spec inconsistencies (resolved, non-blocking)
Two minor typos in the bucket §5 test descriptions vs the §3 enum / table definitions; resolved by following the definitions:
Honest non-scope
Per bucket §4, this PR deliberately omits:
agent/tool_executor.pymodificationsgateway/,kora_cli/)IsoKronMemoryProviderintegration / actor-loop couplingOperationalStateManagersingleton / service-locatorTest plan
uv run pytest tests/test_operational_state.py -v— 54 passed (Python 3.11.15, pytest 9.0.2)kora__append_event|IsoKronMemoryProvider|tool_executorinagent/operational_state.py) — zero matchesoperational_state|OperationalStateleakage ingateway/,kora_cli/,agent/tool_executor.py) — zero matchesuv run ruff check agent/operational_state.py tests/test_operational_state.py— clean🤖 Generated with Claude Code