ENGINEERING SPECS
State Machines Specification
1. Goal
This document defines state machines for core OrbitMesh resources.
State transitions must be enforced in the Control Plane biz layer. Database updates that change state must go through these rules, not ad hoc SQL updates.
Covered resources:
- Node.
- EdgeRuntime.
- DeploymentToken.
- CapabilityBinding.
- RuntimeBinding.
- Endpoint.
- Subscription.
- DesiredState.
- RuntimeConfiguration.
- HealthCheck.
- TenantSubscription.
2. General Rules
- Every state transition has a reason and actor.
- Every state transition writes an audit event or domain event.
- Invalid transitions return
409withINVALID_STATE_TRANSITION. - Repeated idempotent transitions may return current state.
- Terminal states cannot transition except where explicitly allowed.
- Soft delete uses state first; physical deletion is out of MVP scope.
State change event shape:
{
"resource_type": "Node",
"resource_id": "node_xxx",
"from_status": "registered",
"to_status": "online",
"reason": "heartbeat_received",
"actor_type": "edge_runtime",
"actor_id": "er_xxx"
}
3. Node
Node status:
pending
registered
online
degraded
offline
disabled
deleted
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| pending | registered | Edge Runtime register | edge_runtime |
| registered | online | first heartbeat | edge_runtime |
| registered | offline | heartbeat timeout | system |
| online | degraded | health degradation | system |
| online | offline | heartbeat timeout | system |
| online | disabled | disable node | user |
| degraded | online | healthy heartbeat and probes | edge_runtime/system |
| degraded | offline | heartbeat timeout | system |
| degraded | disabled | disable node | user |
| offline | online | heartbeat received | edge_runtime |
| offline | disabled | disable node | user |
| disabled | deleted | delete node | user |
Invariants:
deletedNode is never returned in normal list APIs.disabledNode must not be selected for new desired state.- heartbeat cannot reactivate
disabledordeletedNode.
4. DeploymentToken
DeploymentToken status is derived from timestamps:
active
expired
used
revoked
Recommended DB fields:
expires_at
used_at
revoked_at
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| active | used | successful Edge Runtime register | edge_runtime |
| active | revoked | revoke token | user/system |
| active | expired | time passes | system |
Invariants:
- plaintext token is never stored.
- plaintext token is returned only once in install command.
- token use must lock the row or rely on a unique transaction condition.
5. CapabilityBinding
CapabilityBinding status:
pending
ready
degraded
disabled
deleted
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| pending | ready | desired state applied and health ready | system |
| pending | degraded | apply or health failure | system |
| ready | degraded | health degradation | system |
| degraded | ready | health recovered | system |
| ready | disabled | disable capability | user |
| degraded | disabled | disable capability | user |
| disabled | deleted | delete capability binding | user |
Invariants:
traffic.entryendpoints are not included in subscriptions unless the binding is ready.traffic.exitbindings are not selected by Traffic Policy unless ready.
6. RuntimeBinding
RuntimeBinding has three separate state dimensions. They must not be collapsed into one status field.
6.1 Binding Status
runtime_bindings.status is the control-plane binding lifecycle. It describes whether the runtime binding is part of the desired topology.
enabled
disabled
deleted
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| enabled | disabled | disable runtime binding | user |
| disabled | enabled | re-enable runtime binding | user |
| enabled | deleted | delete runtime binding | user |
| disabled | deleted | delete runtime binding | user |
Invariants:
enabledbindings are compiled into Desired State.disabledbindings remain visible for configuration but are excluded from Desired State.deletedbindings are soft-deleted and hidden from normal APIs.- The Node API exposes this field as
binding_status.
6.2 Apply Status
runtime_bindings.last_apply_status is the observed runtime state reported by Edge Runtime heartbeat.
pending
running
stopped
degraded
failed
unknown
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| pending | running | runtime installed and service healthy | edge_runtime |
| pending | failed | install or apply failed | edge_runtime |
| running | degraded | runtime or dependency degraded | edge_runtime/system |
| running | stopped | local service stopped | edge_runtime |
| running | failed | runtime apply or health failed | edge_runtime |
| degraded | running | runtime recovered | edge_runtime/system |
| stopped | running | service restarted | edge_runtime |
| failed | pending | desired state retry queued | system |
| failed | running | retry succeeded | edge_runtime |
Invariants:
- Apply status is never user-editable.
- Apply status must be derived from heartbeat or apply-result reports.
- The Node API exposes this field as
apply_status.
6.3 Install State
runtime_bindings.install_state is the observed installation state of the concrete runtime package.
pending
installed
failed
Invariants:
installedmeans the runtime binary or package is present and usable by the adapter.failedstores the reason inruntime_bindings.last_apply_error.- The Node API exposes this field as
install_state.
6.4 Runtime Local Metadata
Runtime heartbeat also persists local runtime metadata:
| Field | Source | Purpose |
|---|---|---|
runtime_version |
Runtime adapter heartbeat | Concrete runtime version, for example 1.13.13. |
runtime_path |
Runtime adapter heartbeat | Local binary path, for example /usr/local/bin/sing-box. |
service_status |
Runtime adapter heartbeat | Local service state, for example active, inactive, or unknown. |
last_apply_error |
Runtime adapter heartbeat | Last apply/install/health error. |
These fields are read-only from the console and are refreshed by Edge Runtime heartbeat.
7. Endpoint
Endpoint status:
pending
ready
degraded
disabled
deleted
Readiness depends on:
- owning Node online.
- CapabilityBinding ready.
- RuntimeBinding running.
- DNS synced when domain is required.
- certificate issued when TLS termination is required.
Endpoint subscription eligibility and serving health are separate conditions:
- eligibility is based on administrative state, Node/Runtime availability, DNS, and TLS prerequisites.
endpoint.statusrepresents resource readiness;readiness.servingrepresents listener health.- an eligible Endpoint without active protocol credentials is
readywithserving=idle. - serving health is evaluated only after Desired State contains an active listener for the Endpoint.
- first subscription binding must not require a successful listener probe because that listener is created from the subscription credential.
- a failed serving probe must not remove the Endpoint from Runtime compilation; reconcile must retain the authorized listener and allow recovery.
8. Subscription
Subscription status:
active
disabled
expired
revoked
deleted
Allowed transitions:
| From | To | Trigger | Actor |
|---|---|---|---|
| active | disabled | disable subscription | user/system |
| disabled | active | re-enable subscription | user |
| active | expired | entitlement expired | system |
| active | revoked | revoke | user/system |
| disabled | revoked | revoke | user/system |
| revoked | deleted | delete | user/system |
Invalid transitions:
revoked -> active.deleted -> *.
Invariants:
- active subscription must resolve to at least one ready
traffic.entryendpoint before public fetch succeeds. - quota exceedance blocks output but does not change lifecycle status.
- deleting a user must revoke or disable associated subscription records.
9. DesiredState
DesiredState status:
draft
compiled
published
applied
failed
rolled_back
superseded
Invariants:
(node_id, version)is unique.- version is monotonically increasing per Node.
- checksum is computed from canonical DesiredState spec.
- published state must have compiled RuntimeConfiguration rows.
- Edge Runtime advances its current version only after successful application.
- failed and rolled-back versions remain pullable while their version is newer than the Edge Runtime current version.
10. RuntimeConfiguration
RuntimeConfiguration status:
generated
published
applied
failed
rolled_back
superseded
Invariants:
- each RuntimeConfiguration belongs to exactly one DesiredState.
- each RuntimeConfiguration targets one RuntimeBinding.
- checksum is computed from canonical runtime manifest.
- manifest is runtime-specific and not used as product source of truth.