core.state_machine module
Atomic Redis-backed lifecycle accounting for one inbound Stargazer turn.
The lifecycle is observability/accounting state, while TurnCheckpointSession
remains the execution-recovery authority. Every mutation in this module is a
single Lua compare-and-set using Redis server time. Trace, history, checkpoint,
active-index, and inbound stream keys are colocated with the anchor stream so
the same operations remain legal under Redis Cluster.
- class core.state_machine.OperationStateMachine(redis, *, anchor_stream='sg:stream:inbound', active_ttl_seconds=691200, terminal_ttl_seconds=691200, watchdog_timeout_ms=1800000)
Bases:
objectStrict lifecycle mutations for one Redis/anchor-stream domain.
- Parameters:
- classmethod is_valid_transition(current, target)
Return true for a legal edge or an idempotent same-state replay.
- async create(trace_id, initial_state=TraceState.RECEIVED, metadata=None, *, input_fingerprint='', operation_kind='inbound_turn', stream_name='', stream_msg_id='', proof_deadline_ms=0, transition_id=None, actor='trace:create')
- async ensure_queued(trace_id, metadata=None, *, input_fingerprint='', operation_kind='inbound_turn', stream_name=None, stream_msg_id='', proof_deadline_ms=0, transition_id=None, actor='trace:queue')
- async transition_detailed(trace_id, target_state, metadata=None, *, transition_id=None, transition_fingerprint_value=None, actor='trace:transition', expected_revision=None, terminal_reason='')
- async transition(trace_id, target_state, metadata=None, **kwargs)
Compatibility wrapper preserving the former awaited boolean API.
- async heartbeat(trace_id, metadata=None, *, expected_revision=None, actor='trace:heartbeat')
- async abandon_if_due(trace_id, *, expected_revision, source_group, observed_state=None, reason='', actor='trace:watchdog')
- Return type:
- Parameters:
- async checkpoint_and_transition(trace_id, gather_output, target_state, *, transition_id=None, actor='trace:checkpoint', expected_revision=None, checkpoint_purpose='', checkpoint_binding='')
- async terminal_ack(trace_id, source_stream, group, msg_id, target_state=TraceState.COMPLETED, metadata=None, *, transition_id=None, actor='trace:terminal-ack', expected_revision=None, completion_proof='', terminal_reason='')
- async dead_letter_ack(trace_id, source_stream, group, msg_id, raw_payload, error, target_state=TraceState.DEAD_LETTERED, metadata=None, *, transition_id=None, actor='trace:dead-letter-ack', expected_revision=None, terminal_reason='')
Durably enqueue one DLQ event, ACK its source, and retire the trace.
The source stream, lifecycle keys, and lane-local outbox share one Redis Cluster slot. The Lua operation stores the generated outbox ID on the trace, making connection-loss retries return the original event instead of appending a duplicate.
- async terminal_reack(trace_id, source_stream, group, msg_id, target_state, *, actor='trace:terminal-reack')
Repair a staged terminal outbox row and repeat only its source ACK.
- Return type:
- Parameters:
- class core.state_machine.TraceKeys(trace, history, checkpoint, dead_letter_stage, active, identity_hash, anchor_stream)
Bases:
object- Parameters:
- exception core.state_machine.TraceLifecycleError
Bases:
RuntimeErrorThe Redis lifecycle script returned malformed or unsupported data.
- class core.state_machine.TraceState(*values)
-
- RECEIVED = 'RECEIVED'
- PREPROCESSING = 'PREPROCESSING'
- QUEUED = 'QUEUED'
- CLAIMED = 'CLAIMED'
- RECLAIMED = 'RECLAIMED'
- PROCESSING = 'PROCESSING'
- PRE_INFERENCE_GATHER = 'PRE_INFERENCE_GATHER'
- INFERRING = 'INFERRING'
- TOOL_EXECUTING = 'TOOL_EXECUTING'
- POSTPROCESSING = 'POSTPROCESSING'
- DELIVERING = 'DELIVERING'
- DELIVERED = 'DELIVERED'
- DEFERRED = 'DEFERRED'
- CANCEL_REQUESTED = 'CANCEL_REQUESTED'
- ERRORED = 'ERRORED'
- RETRYING = 'RETRYING'
- COMPLETED = 'COMPLETED'
- DEAD_LETTERED = 'DEAD_LETTERED'
- ABANDONED = 'ABANDONED'
- AMBIGUOUS = 'AMBIGUOUS'
- class core.state_machine.TransitionAction(*values)
-
- CREATED = 'CREATED'
- APPLIED = 'APPLIED'
- CACHED = 'CACHED'
- ALREADY_STATE = 'ALREADY_STATE'
- HEARTBEAT = 'HEARTBEAT'
- NOT_DUE = 'NOT_DUE'
- PROOF_LIVE = 'PROOF_LIVE'
- MISSING = 'MISSING'
- CONFLICT = 'CONFLICT'
- INVALID_STATE = 'INVALID_STATE'
- INVALID_PREDECESSOR = 'INVALID_PREDECESSOR'
- INVALID_ARGUMENT = 'INVALID_ARGUMENT'
- INVALID_TTL = 'INVALID_TTL'
- METADATA_TOO_LARGE = 'METADATA_TOO_LARGE'
- WRONGTYPE = 'WRONGTYPE'
- SCHEMA_CONFLICT = 'SCHEMA_CONFLICT'
- TERMINAL = 'TERMINAL'
- STALE_REVISION = 'STALE_REVISION'
- EXPIRED = 'EXPIRED'
- ACK_REQUIRED = 'ACK_REQUIRED'
- BINDING_MISSING = 'BINDING_MISSING'
- BINDING_CONFLICT = 'BINDING_CONFLICT'
- class core.state_machine.TransitionResult(action, previous_state, state, revision, history_id='', acknowledged=0, detail='')
Bases:
object- Parameters:
action (TransitionAction)
previous_state (TraceState | None)
state (TraceState | None)
revision (int)
history_id (str)
acknowledged (int)
detail (str)
- action: TransitionAction
- previous_state: TraceState | None
- state: TraceState | None
- core.state_machine.attempt_counter_key(anchor_stream='sg:stream:inbound')
Return the per-message reclaim counter hash colocated with the anchor.
- core.state_machine.canonical_metadata_json(metadata)
Encode bounded audit metadata without exposing reserved hash fields.
- core.state_machine.dead_letter_outbox_key(anchor_stream='sg:stream:inbound')
Return the durable DLQ outbox stream colocated with
anchor_stream.
- core.state_machine.ingress_transition_id(identity_hash, target_state)
Return the deterministic first-writer ingress transition identity.
- Return type:
- Parameters:
identity_hash (str)
target_state (str | TraceState)
- async core.state_machine.recover_checkpoint(redis, trace_id, *, anchor_stream='sg:stream:inbound')
Recover a current, valid compressed gather checkpoint.
The v2 colocated key is authoritative. During migration the former
sg:checkpoint:{trace_id}key is read only when no v2 record exists. Corrupt, stale, or future-schema records fail closed and require regather.
- core.state_machine.trace_keys(trace_id, anchor_stream='sg:stream:inbound')
Return the v2 lifecycle keys colocated with
anchor_stream.
- core.state_machine.trace_keys_from_identity(identity_hash, *, anchor_stream='sg:stream:inbound')
- core.state_machine.transition_fingerprint(trace_id, from_state, target_state, actor, metadata_json, input_fingerprint='')
Hash one immutable lifecycle transition request.
- Return type:
- Parameters:
trace_id (str)
from_state (str | TraceState | None)
target_state (str | TraceState)
actor (str)
metadata_json (str)
input_fingerprint (str)
- async core.state_machine.write_checkpoint_and_transition(redis, trace_id, gather_output, target_state, script_sha=None)
Compatibility wrapper around the embedded atomic checkpoint operation.
script_shais accepted for source compatibility but intentionally unused; the canonical v2 script is loaded fromscripts/state_transition.lua.- Return type:
- Parameters: