#![allow(clippy::too_many_arguments)]
use super::OptionValueExt;
#[macro_export]
macro_rules! mob_catalog_machine_dsl {
($rust_crate:literal, $rust_module:literal) => {
meerkat_machine_dsl::machine! {
machine MobMachine {
version: 2,
rust: $rust_crate / $rust_module,
state {
lifecycle_phase: MobPhase,
destroy_admitted: bool,
live_runtime_ids: Set<AgentRuntimeId>,
externally_addressable_runtime_ids: Set<AgentRuntimeId>,
runtime_fence_tokens: Map<AgentRuntimeId, FenceToken>,
identity_runtime_generations: Map<AgentIdentity, Generation>,
identity_runtime_fence_tokens: Map<AgentIdentity, FenceToken>,
active_run_count: u64,
flow_authority_schema_version: u64,
run_status: Map<RunId, Enum<FlowRunStatus>>,
run_ordered_steps: Map<RunId, Seq<StepId>>,
run_tracked_steps: Map<RunId, Set<StepId>>,
run_step_status: Map<RunId, Map<StepId, Option<Enum<StepRunStatus>>>>,
run_output_recorded: Map<RunId, Map<StepId, bool>>,
run_step_condition_results: Map<RunId, Map<StepId, Option<bool>>>,
run_step_has_conditions: Map<RunId, Map<StepId, bool>>,
run_step_dependencies: Map<RunId, Map<StepId, Seq<StepId>>>,
run_step_dependency_modes: Map<RunId, Map<StepId, Enum<DependencyMode>>>,
run_step_branches: Map<RunId, Map<StepId, Option<BranchId>>>,
run_step_collection_policies: Map<RunId, Map<StepId, Enum<CollectionPolicyKind>>>,
run_step_quorum_thresholds: Map<RunId, Map<StepId, u32>>,
run_step_target_counts: Map<RunId, Map<StepId, u64>>,
run_step_target_success_counts: Map<RunId, Map<StepId, u64>>,
run_step_target_terminal_failure_counts: Map<RunId, Map<StepId, u64>>,
run_target_retry_counts: Map<RunId, Map<String, u64>>,
run_failure_count: Map<RunId, u64>,
run_consecutive_failure_count: Map<RunId, u64>,
run_escalation_threshold: Map<RunId, u64>,
run_max_step_retries: Map<RunId, u32>,
run_ready_frames: Map<RunId, Seq<FrameId>>,
run_ready_frame_membership: Map<RunId, Set<FrameId>>,
run_ready_frame_membership_flat: Set<FrameId>,
run_pending_body_frame_loops: Map<RunId, Seq<LoopInstanceId>>,
run_pending_body_frame_loop_membership: Map<RunId, Set<LoopInstanceId>>,
run_pending_body_frame_loop_membership_flat: Set<LoopInstanceId>,
run_active_node_count: Map<RunId, u64>,
run_active_frame_count: Map<RunId, u64>,
run_last_granted_frame: Map<RunId, Option<FrameId>>,
run_last_granted_loop: Map<RunId, Option<LoopInstanceId>>,
run_max_active_nodes: Map<RunId, u64>,
run_max_active_frames: Map<RunId, u64>,
run_max_frame_depth: Map<RunId, u64>,
frame_scope: Map<FrameId, Enum<FrameScope>>,
frame_phase: Map<FrameId, Enum<FrameStatus>>,
frame_run: Map<FrameId, RunId>,
frame_parent_loop: Map<FrameId, Option<LoopInstanceId>>,
frame_iteration: Map<FrameId, u32>,
frame_tracked_nodes: Map<FrameId, Set<FlowNodeId>>,
frame_ordered_nodes: Map<FrameId, Seq<FlowNodeId>>,
frame_node_kind: Map<FrameId, Map<FlowNodeId, Enum<FlowNodeKind>>>,
frame_node_dependencies: Map<FrameId, Map<FlowNodeId, Seq<FlowNodeId>>>,
frame_node_dependency_modes: Map<FrameId, Map<FlowNodeId, Enum<DependencyMode>>>,
frame_node_step_ids: Map<FrameId, Map<FlowNodeId, StepId>>,
frame_node_loop_ids: Map<FrameId, Map<FlowNodeId, LoopId>>,
frame_node_status: Map<FrameId, Map<FlowNodeId, Enum<NodeRunStatus>>>,
frame_ready_queue: Map<FrameId, Seq<FlowNodeId>>,
frame_output_recorded: Map<FrameId, Map<FlowNodeId, bool>>,
frame_last_admitted_node: Map<FrameId, Option<FlowNodeId>>,
frame_node_condition_results: Map<FrameId, Map<FlowNodeId, Option<bool>>>,
frame_node_branches: Map<FrameId, Map<FlowNodeId, Option<BranchId>>>,
loop_phase: Map<LoopInstanceId, Enum<LoopStatus>>,
loop_parent_frame: Map<LoopInstanceId, FrameId>,
loop_parent_node: Map<LoopInstanceId, FlowNodeId>,
loop_definition: Map<LoopInstanceId, LoopId>,
loop_depth: Map<LoopInstanceId, u32>,
loop_stage: Map<LoopInstanceId, Enum<LoopIterationStage>>,
loop_current_iteration: Map<LoopInstanceId, u64>,
loop_last_completed_iteration: Map<LoopInstanceId, u64>,
loop_max_iterations: Map<LoopInstanceId, u64>,
loop_active_body_frame: Map<LoopInstanceId, Option<FrameId>>,
pending_spawn_count: u64,
pending_spawn_sessions: Map<AgentIdentity, SessionId>,
coordinator_bound: bool,
member_startup_binding_requested: Set<AgentRuntimeId>,
member_startup_runtime_ready: Set<AgentRuntimeId>,
member_startup_ready: Set<AgentRuntimeId>,
member_kickoff_pending: Set<AgentIdentity>,
member_kickoff_starting: Set<AgentIdentity>,
member_kickoff_callback_pending: Set<AgentIdentity>,
member_kickoff_started: Set<AgentIdentity>,
member_kickoff_failed: Set<AgentIdentity>,
member_kickoff_cancelled: Set<AgentIdentity>,
member_kickoff_error: Map<AgentIdentity, String>,
member_kickoff_objective_ids: Map<AgentIdentity, String>,
// Stable placed-kickoff correlation survives terminal custody
// release so exact replay can be distinguished from a different
// kickoff for the same member. The UUID string is simultaneously
// the runtime input id, idempotency key, and interaction id.
member_kickoff_input_ids: Map<AgentIdentity, InputId>,
retained_placed_kickoff_obligations: Map<AgentIdentity, PlacedKickoffObligation>,
member_placed_kickoff_outcome_kinds: Map<AgentIdentity, Enum<PlacedKickoffOutcomeKind>>,
member_placed_kickoff_outcome_errors: Map<AgentIdentity, String>,
member_placed_kickoff_closure_kinds: Map<AgentIdentity, Enum<PlacedKickoffClosureKind>>,
// First-class controlling-side custody for placed autonomous
// kickoff. Pending means record-before-send exists and the host
// terminal is not yet durably resolved by MobMachine. Resolved
// means the kickoff lifecycle is terminal and the exact host row
// must remain retained until its ACK is confirmed.
pending_placed_kickoff_outcomes: Set<PlacedKickoffObligation>,
resolved_placed_kickoff_outcomes: Set<PlacedKickoffObligation>,
objective_owner_ids: Map<String, AgentIdentity>,
objective_outcomes: Map<String, String>,
concluded_objective_ids: Set<String>,
// Identity-level restore failures are lifecycle facts owned by
// MobMachine. Projection code may surface the reason, but the
// Broken/terminal classification comes from this map.
member_restore_failures: Map<AgentIdentity, String>,
// Stable consumer refusal code paired with a restore failure that
// specifically came from the generated runtime-binding route.
// The reason remains display detail; this map preserves the
// typed code without parsing that detail.
member_restore_failure_codes: Map<AgentIdentity, String>,
// Runtime retirement is a durable pending obligation from
// admission until archival completion. Consumer-refusal code and
// detail are diagnostic facts; the session correlation is broader
// than a refusal and survives restart so the route can be retried.
runtime_retire_refusal_codes: Map<AgentRuntimeId, String>,
runtime_retire_refusal_reasons: Map<AgentRuntimeId, String>,
runtime_retire_pending_sessions: Map<AgentRuntimeId, SessionId>,
// Durable intermediate proof for peer-only/external runtimes: the
// remote runtime has acknowledged retirement, but supervisor
// revocation and terminal member archival may still be pending.
// This exact runtime-scoped marker prevents a cold retry from
// re-authorizing or re-retiring an already-terminal remote owner.
remote_runtime_retired_ids: Set<AgentRuntimeId>,
// Durable second-stage proof for peer-only/external runtimes: the
// exact supervisor binding has acknowledged revocation. Once this
// marker exists, retry is purely local (recipient-trust cleanup +
// terminal journal publication) and must never depend on the
// intentionally retired remote runtime remaining reachable.
remote_supervisor_revoked_ids: Set<AgentRuntimeId>,
// Machine-owned revival obligation: members whose live
// materialization was observed missing while a durable session
// snapshot still exists. Inserted by the revivable arm of
// ClassifyMemberLiveMaterialization; cleared by the
// ResolveMemberRevival* resolutions and by every lifecycle
// transition that replaces or clears the member's restore
// classification. The session-registry cache never owns this fact.
member_revival_pending: Set<AgentIdentity>,
// Machine-owned member execution-health projection. The shell
// supplies raw execution snapshots; MobMachine detects progress
// token changes, owns the last-progress timestamp, and classifies
// degradation/wedging from elapsed time.
member_run_open: Map<AgentIdentity, bool>,
member_in_flight_work: Map<AgentIdentity, u64>,
member_progress_tokens: Map<AgentIdentity, String>,
// Highest wall-clock observation accepted for this identity. Raw
// clocks may move backwards; stale samples are ignored so neither
// progress time nor machine-owned health can regress.
member_last_observed_at_ms: Map<AgentIdentity, u64>,
member_last_progress_at_ms: Map<AgentIdentity, u64>,
member_last_progress_event: Map<AgentIdentity, Enum<MemberProgressEventKind>>,
member_health_class: Map<AgentIdentity, Enum<MemberHealthClass>>,
// --- Spawn-execution phase ladder (machine owns the phase ORDER) ---
// A lightweight per-identity phase ladder: `BeginSpawnExec` opens
// the window (Opened), `CommitSpawnMembership` commits the membership
// facts (Opened -> MembershipCommitted), `CommitSpawnActivation`
// closes it (-> Settled, the entry is removed). The shell still runs
// each individual finalization step; the machine only OWNS + VALIDATES
// the phase order (Begin before Commit before Activate). No
// per-obligation tracking and no per-step request effects (those
// exploded the mob x meerkat composition state space). Absence of an
// entry == Settled (no spawn in flight), making every late-arrival /
// post-teardown input total.
spawn_exec_phase: Map<AgentIdentity, Enum<SpawnExecPhase>>,
// Per-runtime lifecycle marker (Active vs Retiring). Tracks the
// draining/retiring sub-state independently of the mob-level
// lifecycle phase so generated SubmitWork authority can decide
// whether fresh work may route while retire-drain is in flight.
member_state_markers: Map<AgentRuntimeId, MobMemberState>,
// Undirected wiring edges between agent identities. Stored as
// ordered pairs (smaller identity first) wrapped in WiringEdge
// so the DSL sees a single opaque key type.
wiring_edges: Set<WiringEdge>,
// Respawn-only desired-topology hold. The durable retirement-start
// observation installs it while the exact old runtime is Retiring;
// terminal removal keeps it and successor membership consumes it.
pending_respawn_topology: Set<AgentIdentity>,
// Generation-scoped durable tombstones for respawn helper
// compositions that ended without a replacement. While the old
// runtime is still Retiring this switches terminal cleanup back to
// ordinary unwiring without deleting the graph authority needed
// to remove physical trust. After terminal removal the same
// signal atomically prunes the retained desired graph.
abandoned_respawn_topology: Map<AgentIdentity, Generation>,
// Descriptor-bearing external peer trust edges. These are not
// member-to-member wiring edges: the endpoint carries the external
// peer's routing id, address, and signing key, so it has its own
// machine-owned fact instead of being projected into WiringEdge by
// peer name.
external_peer_edges: Set<ExternalPeerEdge>,
external_peer_edges_by_key: Map<ExternalPeerKey, ExternalPeerEdge>,
// Mob-wide supervisor bridge authority. The runtime may mint
// cryptographic candidates, but the current public supervisor
// identity/epoch/protocol and pending rotation record are
// machine facts because they drive trust, stale-authority
// rejection, and bridge command admission.
supervisor_authority_peer_id: Option<PeerId>,
supervisor_authority_signing_key: Option<PeerSigningKey>,
supervisor_authority_epoch: Option<u64>,
supervisor_authority_protocol_version: Option<SupervisorProtocolVersion>,
supervisor_pending_authority_peer_id: Option<PeerId>,
supervisor_pending_authority_signing_key: Option<PeerSigningKey>,
supervisor_pending_authority_epoch: Option<u64>,
supervisor_pending_authority_protocol_version: Option<SupervisorProtocolVersion>,
// Stable mob-wide operation identity for the in-flight supervisor
// rotation. This is recorded before the first remote submission so
// caller retries observe/re-submit the same operation rather than
// inferring mutation truth from a bridge reply.
supervisor_pending_authority_operation_id: Option<String>,
supervisor_pending_authority_accepted_peer_ids: Set<PeerId>,
supervisor_pending_authority_member_target_names: Map<PeerId, String>,
supervisor_pending_authority_member_target_addresses: Map<PeerId, String>,
// Machine-owned trust-install-before-authorization-terminality
// window (dogma row R044). The comms router requires recipient
// trust before a bridge command can be routed, so the shell must
// install trust ahead of the `AuthorizeSupervisor`/`BindMember`
// terminality verdict. Every such window is recorded here as an
// explicit obligation: recorded before trust install, removed by
// `ResolvePendingRecipientTrust` on confirmed-accept terminality
// or by `RollbackPendingRecipientTrust` after the shell rolls the
// installed trust back on a failure path. Volatile like the trust
// it tracks (no wall-clock state; trivially recoverable as empty).
pending_recipient_trust: Set<PeerId>,
// Owner bridge-session lifecycle authority. The shell may observe
// the owning session, but MobMachine owns whether the mob is
// indexed to that session, whether owner archive should destroy
// it, and whether it is an implicit delegation mob.
owner_bridge_session_id: Option<SessionId>,
owner_bridge_destroy_on_archive: bool,
implicit_delegation_mob: bool,
// Identity → current runtime binding. Survives within a
// generation; respawn replaces the runtime id for the same
// identity.
identity_to_runtime: Map<AgentIdentity, AgentRuntimeId>,
member_session_bindings: Map<AgentIdentity, SessionId>,
member_profile_names: Map<AgentIdentity, String>,
member_runtime_modes: Map<AgentIdentity, Enum<SpawnPolicyRuntimeMode>>,
member_peer_ids: Map<AgentIdentity, PeerId>,
member_peer_endpoints: Map<AgentIdentity, MemberPeerEndpoint>,
// Generation-scoped endpoint history retained when durable
// session-head recovery rotates a member's comms identity without
// changing its runtime generation. The current endpoint is never
// present in this set. Historical endpoints authorize exact,
// reciprocal stale-trust cleanup on still-wired member edges and
// are cleared whenever the generation is replaced or terminal.
member_prior_peer_endpoints: Map<AgentIdentity, Set<MemberPeerEndpoint>>,
pending_session_ingress_detach_runtime_ids: Set<AgentRuntimeId>,
// Dynamic auto-spawn policy facts. The opaque callback remains a
// shell observation source, but MobMachine owns whether policy is
// enabled, the active revision, and every typed resolution that
// can admit unknown-member external work.
spawn_policy_enabled: bool,
spawn_policy_revision: u64,
spawn_policy_resolution_revision: Map<AgentIdentity, u64>,
spawn_policy_resolution_profiles: Map<AgentIdentity, String>,
spawn_policy_resolution_runtime_modes: Map<AgentIdentity, Option<Enum<SpawnPolicyRuntimeMode>>>,
spawn_policy_resolution_absent: Set<AgentIdentity>,
// Effective profile material authorized for the next member
// session build. The shell may resolve inline/realm profiles and
// inherited-tool overlays, but MobMachine owns the exact material
// digest and addressability fact that `Spawn` may admit.
spawn_profile_authority_profile_names: Map<AgentIdentity, String>,
spawn_profile_authority_models: Map<AgentIdentity, String>,
spawn_profile_authority_material_digests: Map<AgentIdentity, String>,
spawn_profile_authority_tool_config_digests: Map<AgentIdentity, String>,
spawn_profile_authority_skills_digests: Map<AgentIdentity, String>,
spawn_profile_authority_provider_params_digests: Map<AgentIdentity, Option<String>>,
spawn_profile_authority_output_schema_digests: Map<AgentIdentity, Option<String>>,
spawn_profile_authority_external_addressable: Map<AgentIdentity, bool>,
topology_epoch: u64,
// Mob coordination board authority (folded from the former
// standalone MobCoordinationLifecycleAuthorityMachine). MobMachine
// owns the per-entity work-intent and resource-claim records,
// their optimistic-concurrency revisions, affected resource sets,
// owner-presence facts, raw expiry timestamps (NOT a pre-reduced
// `is_expired` bool), and the monotonic coordination event cursor.
// Every admission/status/overlap conclusion is recomputed in-DSL
// from these maps plus raw caller facts — no trusted reducer.
work_intent_status: Map<WorkIntentId, Enum<MobCoordinationWorkIntentStatus>>,
work_intent_revision: Map<WorkIntentId, u64>,
work_intent_resources: Map<WorkIntentId, Set<CoordinationResourceRef>>,
work_intent_owner_present: Map<WorkIntentId, bool>,
work_intent_expires_at_ms: Map<WorkIntentId, Option<u64>>,
resource_claim_status: Map<ResourceClaimId, Enum<MobCoordinationResourceClaimStatus>>,
resource_claim_kind: Map<ResourceClaimId, Enum<MobCoordinationResourceClaimKind>>,
resource_claim_revision: Map<ResourceClaimId, u64>,
resource_claim_resources: Map<ResourceClaimId, Set<CoordinationResourceRef>>,
resource_claim_owner_present: Map<ResourceClaimId, bool>,
resource_claim_expires_at_ms: Map<ResourceClaimId, Option<u64>>,
coordination_event_next_sequence: u64,
// Wave-G1 catalog folds.
// Row #293: declared default topology-edge policy. Applied in-DSL
// for edges with no matching declarative rule. Defaults to Allow to
// preserve the former shell `map_or(Allow, ..)` behavior.
topology_default_policy: Enum<PolicyDecision>,
// Row #314: per-identity external-member rebind capability. Minted
// by the bridge/spawn chokepoints; read by
// project_external_member_observation instead of deriving from
// roster bootstrap_token presence.
external_member_rebind_capability: Map<AgentIdentity, Enum<ExternalMemberRebindCapability>>,
// Row #320: orphan budget for detached turns. Seeded once from
// `definition.limits.max_orphaned_turns` via `SeedOrphanBudget`.
// A non-retryable timeout detaches while budget > 0 (decrementing
// it), otherwise cancels.
orphan_budget: u64,
// Row #351: machine-owned membership intent. `ReconcileRunning`
// recomputes the spawn/retire diff against `identity_to_runtime`
// into these sets; the handle reads them and executes mechanically.
desired_members: Set<AgentIdentity>,
members_to_spawn: Set<AgentIdentity>,
members_to_retire: Set<AgentIdentity>,
adaptive_active_run: Option<AdaptiveRunId>,
adaptive_run_phase: Map<AdaptiveRunId, Enum<AdaptiveRunPhase>>,
adaptive_stop_reason: Map<AdaptiveRunId, Enum<AdaptiveStopReason>>,
adaptive_limit_max_depth: Map<AdaptiveRunId, u64>,
adaptive_limit_max_total_decisions: Map<AdaptiveRunId, u64>,
adaptive_limit_max_repair_attempts: Map<AdaptiveRunId, u64>,
adaptive_limit_max_layer_failures: Map<AdaptiveRunId, u64>,
adaptive_limit_max_attempts_per_layer: Map<AdaptiveRunId, u64>,
adaptive_limit_max_members_per_layer: Map<AdaptiveRunId, u64>,
adaptive_limit_max_total_spawned_members: Map<AdaptiveRunId, u64>,
adaptive_limit_max_active_members: Map<AdaptiveRunId, u64>,
adaptive_limit_max_retained_layer_mobs: Map<AdaptiveRunId, u64>,
adaptive_limit_max_aggregate_tokens: Map<AdaptiveRunId, u64>,
adaptive_limit_max_aggregate_tool_calls: Map<AdaptiveRunId, u64>,
adaptive_limit_allowed_model_classes: Map<AdaptiveRunId, Set<String>>,
adaptive_limit_allowed_tool_classes: Map<AdaptiveRunId, Set<String>>,
adaptive_limit_allowed_skill_identities: Map<AdaptiveRunId, Set<String>>,
adaptive_limit_allowed_auth_binding_refs: Map<AdaptiveRunId, Set<String>>,
adaptive_deadline_ms: Map<AdaptiveRunId, u64>,
adaptive_depth: Map<AdaptiveRunId, u64>,
adaptive_total_decisions: Map<AdaptiveRunId, u64>,
adaptive_repair_attempts: Map<AdaptiveRunId, u64>,
adaptive_layer_failures: Map<AdaptiveRunId, u64>,
adaptive_total_spawned_members: Map<AdaptiveRunId, u64>,
adaptive_active_members: Map<AdaptiveRunId, u64>,
adaptive_retained_layer_mobs: Map<AdaptiveRunId, u64>,
adaptive_aggregate_token_reserved: Map<AdaptiveRunId, u64>,
adaptive_aggregate_token_actual: Map<AdaptiveRunId, u64>,
adaptive_aggregate_tool_call_reserved: Map<AdaptiveRunId, u64>,
adaptive_aggregate_tool_call_actual: Map<AdaptiveRunId, u64>,
adaptive_active_layer: Map<AdaptiveRunId, AdaptiveLayerId>,
adaptive_layer_adaptive_run: Map<AdaptiveLayerId, AdaptiveRunId>,
adaptive_layer_phase: Map<AdaptiveLayerId, Enum<AdaptiveLayerPhase>>,
adaptive_layer_attempt: Map<AdaptiveLayerId, u64>,
adaptive_layer_member_count: Map<AdaptiveLayerId, u64>,
adaptive_layer_plan_digest: Map<AdaptiveLayerId, String>,
adaptive_layer_child_mob_id: Map<AdaptiveLayerId, MobId>,
adaptive_layer_token_reservation: Map<AdaptiveLayerId, u64>,
adaptive_layer_tool_call_reservation: Map<AdaptiveLayerId, u64>,
adaptive_layer_run_id: Map<AdaptiveLayerId, RunId>,
adaptive_layer_result_digest: Map<AdaptiveLayerId, String>,
adaptive_layer_fault: Map<AdaptiveLayerId, Enum<AdaptiveLayerSetupFaultKind>>,
adaptive_layer_disposition: Map<AdaptiveLayerId, Enum<AdaptiveLayerDispositionKind>>,
adaptive_missing_body_digest: Map<AdaptiveRunId, String>,
// --- Multi-host mobs (§6.1/§6.2/§6.5): hosts, placement, grants ---
// Hosts the mob has committed a bind with. Membership here means
// the bind handshake completed (host_bind_phase = Bound); a
// Requested-only host is tracked solely in host_bind_phase.
mob_hosts: Set<HostId>,
host_public_keys: Map<HostId, PeerSigningKey>,
host_endpoints: Map<HostId, PeerAddress>,
// Per-host binding authority epoch. Monotonicity is enforced by
// the HostRebound guard (strict >), not by an invariant (history
// is not invariant-expressible).
host_authority_epochs: Map<HostId, u64>,
// Durable binding generation is distinct from the supervisor
// authority epoch. It advances on every fresh bind and is exact
// across all host-addressed work, fencing delayed operations from
// a revoked binding. Highwater survives RevokeHost.
host_binding_generations: Map<HostId, u64>,
host_binding_generation_highwater: Map<HostId, u64>,
// Exact authenticated revoke terminals. Historical generations
// remain so a dormant carrier can retire after later bind cycles;
// ordinary remote behavior still requires the current active gen.
confirmed_host_binding_revocations: Set<HostBindingGenerationTombstone>,
// Exact replacement-bind request tuple for a revoked host that
// still owns retained placements. Keeping this disjoint from
// host_bind_phase prevents Requested from becoming live routing
// authority before CommitHostBind restores Bound atomically.
replacement_host_bind_endpoints: Map<HostId, PeerAddress>,
replacement_host_binding_generations: Map<HostId, u64>,
// Requested | Bound; absence = unbound/untracked.
host_bind_phase: Map<HostId, Enum<HostBindPhase>>,
// Host capability record (§6.1 single enumeration), decomposed
// into flat per-capability maps because the DSL metadata cannot
// model bool/u64/Set fields inside a struct value
// (TypePathStructFieldAtom supports only String/Named/
// OptionalNamed). All chapters extend THIS block, nowhere else.
host_protocol_min: Map<HostId, u64>,
host_protocol_max: Map<HostId, u64>,
host_engine_versions: Map<HostId, String>,
host_durable_sessions: Map<HostId, bool>,
host_autonomous_members: Map<HostId, bool>,
host_hard_cancel_member: Map<HostId, bool>,
host_tracked_input_cancel: Map<HostId, bool>,
host_memory_store: Map<HostId, bool>,
host_mcp: Map<HostId, bool>,
host_resolvable_providers: Map<HostId, Set<String>>,
host_approval_forwarding: Map<HostId, bool>,
// §16 DL5: presence IS the live capability; absence = live-incapable.
// Populated/refreshed only by CommitHostBind/HostRebound (rebind
// without the endpoint clears it — restart truthfulness); cleared
// by RevokeHost.
host_live_endpoints: Map<HostId, LiveWsEndpointUrl>,
// ABSENT = controlling host (local). Present = remote placement.
// RevokeHost keeps placement entries (the §9 revival ladder owns
// re-placement); the destroy-retirement family removes them.
member_placement: Map<AgentIdentity, HostId>,
// Durable placed-spawn carrier attempt facts. These mirrors are
// intentionally exact and non-derivable: they are the machine
// authority used to compare a materialization acknowledgement
// with the carrier row opened before the remote handoff.
pending_placed_spawn_ids: Map<AgentIdentity, PlacedSpawnId>,
pending_placed_spawn_generations: Map<AgentIdentity, Generation>,
pending_placed_spawn_fence_tokens: Map<AgentIdentity, FenceToken>,
pending_placed_spawn_hosts: Map<AgentIdentity, HostId>,
pending_autonomous_placed_spawns: Set<AgentIdentity>,
pending_placed_spawn_host_binding_generations: Map<AgentIdentity, u64>,
pending_placed_spawn_spec_digests: Map<AgentIdentity, String>,
pending_placed_spawn_provision_operation_ids: Map<AgentIdentity, String>,
pending_placed_spawn_operation_owner_session_ids: Map<AgentIdentity, SessionId>,
// A committed placed member retains its stable spawn id until the
// exact committed carrier row has been compare-deleted.
current_placed_spawn_ids: Map<AgentIdentity, PlacedSpawnId>,
current_placed_spawn_host_binding_generations: Map<AgentIdentity, u64>,
current_placed_spawn_provision_operation_ids: Map<AgentIdentity, String>,
current_placed_spawn_operation_owner_session_ids: Map<AgentIdentity, SessionId>,
// Cleanup is a first-class identity/fence/phase obligation. The
// runtime may only delete a carrier row after this exact value has
// been authorized and may only clear it after compare-delete
// succeeds or reports AlreadyAbsent.
pending_placed_carrier_cleanup: Set<PlacedCarrierCleanupObligation>,
// Mirrors member_restore_failures for the materialization step.
member_materialization_failures: Map<AgentIdentity, String>,
// §18 O2: keeps the pump obligated for dispatched remote turn
// directives until the downstream flow terminal is durable, the
// exact host row is resolved, and the host confirms its ACK.
remote_turn_dispatch_sequence: u64,
pending_remote_turn_outcomes: Set<RemoteTurnObligation>,
committed_remote_turn_outcomes: Set<RemoteTurnObligation>,
resolved_remote_turn_outcomes: Set<RemoteTurnObligation>,
// Ordinary placed `TurnCompleted` calls have a volatile RPC
// promise but durable host journal custody. Record the exact
// input/residency before send; timeout or cold recovery requests
// exact cancellation without treating the caller deadline as a
// semantic terminal. Resolved rows remain until the ONE member
// pump proves the host applied their ACK.
placed_completion_dispatch_sequence: u64,
placed_completion_lifecycle_quiescing: bool,
placed_completion_lifecycle_intent: Option<Enum<PlacedCompletionLifecycleIntentKind>>,
pending_placed_completion_outcomes: Set<PlacedCompletionObligation>,
cancel_requested_placed_completion_outcomes: Set<PlacedCompletionObligation>,
resolved_placed_completion_outcomes: Set<PlacedCompletionObligation>,
// §6.2 (D4): outstanding cross-host route INSTALL obligations.
// Remove is synchronous pre-unwire authority and never enters
// this volatile ledger. Fail-closed by construction (uninstalled
// trust is rejected by the receiver); this set makes install
// convergence observable, retryable, and reportable.
pending_route_installs: Set<RouteInstallObligation>,
// §6.5 grants: principal -> granted control scopes + raw expiry.
// Expiry is DATA checked at the enforcement seam; the machine
// never reads a clock.
operator_grant_scopes: Map<PrincipalId, Set<Enum<ControlScope>>>,
operator_grant_expiries: Map<PrincipalId, Option<u64>>,
// §15.4: controlling-side resolved PortableMemberSpec digest per
// identity. Presence = resolved (single-shot, consumed with the
// other spawn_profile_authority_* maps at membership commit).
spawn_profile_authority_resolved_spec_digests: Map<AgentIdentity, String>,
}
init(Running) {
destroy_admitted = false,
live_runtime_ids = EmptySet,
externally_addressable_runtime_ids = EmptySet,
runtime_fence_tokens = EmptyMap,
identity_runtime_generations = EmptyMap,
identity_runtime_fence_tokens = EmptyMap,
active_run_count = 0,
flow_authority_schema_version = 7,
run_status = EmptyMap,
run_ordered_steps = EmptyMap,
run_tracked_steps = EmptyMap,
run_step_status = EmptyMap,
run_output_recorded = EmptyMap,
run_step_condition_results = EmptyMap,
run_step_has_conditions = EmptyMap,
run_step_dependencies = EmptyMap,
run_step_dependency_modes = EmptyMap,
run_step_branches = EmptyMap,
run_step_collection_policies = EmptyMap,
run_step_quorum_thresholds = EmptyMap,
run_step_target_counts = EmptyMap,
run_step_target_success_counts = EmptyMap,
run_step_target_terminal_failure_counts = EmptyMap,
run_target_retry_counts = EmptyMap,
run_failure_count = EmptyMap,
run_consecutive_failure_count = EmptyMap,
run_escalation_threshold = EmptyMap,
run_max_step_retries = EmptyMap,
run_ready_frames = EmptyMap,
run_ready_frame_membership = EmptyMap,
run_ready_frame_membership_flat = EmptySet,
run_pending_body_frame_loops = EmptyMap,
run_pending_body_frame_loop_membership = EmptyMap,
run_pending_body_frame_loop_membership_flat = EmptySet,
run_active_node_count = EmptyMap,
run_active_frame_count = EmptyMap,
run_last_granted_frame = EmptyMap,
run_last_granted_loop = EmptyMap,
run_max_active_nodes = EmptyMap,
run_max_active_frames = EmptyMap,
run_max_frame_depth = EmptyMap,
frame_scope = EmptyMap,
frame_phase = EmptyMap,
frame_run = EmptyMap,
frame_parent_loop = EmptyMap,
frame_iteration = EmptyMap,
frame_tracked_nodes = EmptyMap,
frame_ordered_nodes = EmptyMap,
frame_node_kind = EmptyMap,
frame_node_dependencies = EmptyMap,
frame_node_dependency_modes = EmptyMap,
frame_node_step_ids = EmptyMap,
frame_node_loop_ids = EmptyMap,
frame_node_status = EmptyMap,
frame_ready_queue = EmptyMap,
frame_output_recorded = EmptyMap,
frame_last_admitted_node = EmptyMap,
frame_node_condition_results = EmptyMap,
frame_node_branches = EmptyMap,
loop_phase = EmptyMap,
loop_parent_frame = EmptyMap,
loop_parent_node = EmptyMap,
loop_definition = EmptyMap,
loop_depth = EmptyMap,
loop_stage = EmptyMap,
loop_current_iteration = EmptyMap,
loop_last_completed_iteration = EmptyMap,
loop_max_iterations = EmptyMap,
loop_active_body_frame = EmptyMap,
pending_spawn_count = 0,
pending_spawn_sessions = EmptyMap,
coordinator_bound = true,
member_startup_binding_requested = EmptySet,
member_startup_runtime_ready = EmptySet,
member_startup_ready = EmptySet,
member_kickoff_pending = EmptySet,
member_kickoff_starting = EmptySet,
member_kickoff_callback_pending = EmptySet,
member_kickoff_started = EmptySet,
member_kickoff_failed = EmptySet,
member_kickoff_cancelled = EmptySet,
member_kickoff_error = EmptyMap,
member_kickoff_objective_ids = EmptyMap,
member_kickoff_input_ids = EmptyMap,
retained_placed_kickoff_obligations = EmptyMap,
member_placed_kickoff_outcome_kinds = EmptyMap,
member_placed_kickoff_outcome_errors = EmptyMap,
member_placed_kickoff_closure_kinds = EmptyMap,
pending_placed_kickoff_outcomes = EmptySet,
resolved_placed_kickoff_outcomes = EmptySet,
objective_owner_ids = EmptyMap,
objective_outcomes = EmptyMap,
concluded_objective_ids = EmptySet,
member_restore_failures = EmptyMap,
member_restore_failure_codes = EmptyMap,
runtime_retire_refusal_codes = EmptyMap,
runtime_retire_refusal_reasons = EmptyMap,
runtime_retire_pending_sessions = EmptyMap,
remote_runtime_retired_ids = EmptySet,
remote_supervisor_revoked_ids = EmptySet,
member_revival_pending = EmptySet,
member_run_open = EmptyMap,
member_in_flight_work = EmptyMap,
member_progress_tokens = EmptyMap,
member_last_observed_at_ms = EmptyMap,
member_last_progress_at_ms = EmptyMap,
member_last_progress_event = EmptyMap,
member_health_class = EmptyMap,
spawn_exec_phase = EmptyMap,
member_state_markers = EmptyMap,
wiring_edges = EmptySet,
pending_respawn_topology = EmptySet,
abandoned_respawn_topology = EmptyMap,
external_peer_edges = EmptySet,
external_peer_edges_by_key = EmptyMap,
supervisor_authority_peer_id = None,
supervisor_authority_signing_key = None,
supervisor_authority_epoch = None,
supervisor_authority_protocol_version = None,
supervisor_pending_authority_peer_id = None,
supervisor_pending_authority_signing_key = None,
supervisor_pending_authority_epoch = None,
supervisor_pending_authority_protocol_version = None,
supervisor_pending_authority_operation_id = None,
supervisor_pending_authority_accepted_peer_ids = EmptySet,
supervisor_pending_authority_member_target_names = EmptyMap,
supervisor_pending_authority_member_target_addresses = EmptyMap,
pending_recipient_trust = EmptySet,
owner_bridge_session_id = None,
owner_bridge_destroy_on_archive = false,
implicit_delegation_mob = false,
identity_to_runtime = EmptyMap,
member_session_bindings = EmptyMap,
member_profile_names = EmptyMap,
member_runtime_modes = EmptyMap,
member_peer_ids = EmptyMap,
member_peer_endpoints = EmptyMap,
member_prior_peer_endpoints = EmptyMap,
pending_session_ingress_detach_runtime_ids = EmptySet,
spawn_policy_enabled = false,
spawn_policy_revision = 0,
spawn_policy_resolution_revision = EmptyMap,
spawn_policy_resolution_profiles = EmptyMap,
spawn_policy_resolution_runtime_modes = EmptyMap,
spawn_policy_resolution_absent = EmptySet,
spawn_profile_authority_profile_names = EmptyMap,
spawn_profile_authority_models = EmptyMap,
spawn_profile_authority_material_digests = EmptyMap,
spawn_profile_authority_tool_config_digests = EmptyMap,
spawn_profile_authority_skills_digests = EmptyMap,
spawn_profile_authority_provider_params_digests = EmptyMap,
spawn_profile_authority_output_schema_digests = EmptyMap,
spawn_profile_authority_external_addressable = EmptyMap,
topology_epoch = 0,
work_intent_status = EmptyMap,
work_intent_revision = EmptyMap,
work_intent_resources = EmptyMap,
work_intent_owner_present = EmptyMap,
work_intent_expires_at_ms = EmptyMap,
resource_claim_status = EmptyMap,
resource_claim_kind = EmptyMap,
resource_claim_revision = EmptyMap,
resource_claim_resources = EmptyMap,
resource_claim_owner_present = EmptyMap,
resource_claim_expires_at_ms = EmptyMap,
coordination_event_next_sequence = 1,
topology_default_policy = PolicyDecision::Allow,
external_member_rebind_capability = EmptyMap,
orphan_budget = 0,
desired_members = EmptySet,
members_to_spawn = EmptySet,
members_to_retire = EmptySet,
adaptive_active_run = None,
adaptive_run_phase = EmptyMap,
adaptive_stop_reason = EmptyMap,
adaptive_limit_max_depth = EmptyMap,
adaptive_limit_max_total_decisions = EmptyMap,
adaptive_limit_max_repair_attempts = EmptyMap,
adaptive_limit_max_layer_failures = EmptyMap,
adaptive_limit_max_attempts_per_layer = EmptyMap,
adaptive_limit_max_members_per_layer = EmptyMap,
adaptive_limit_max_total_spawned_members = EmptyMap,
adaptive_limit_max_active_members = EmptyMap,
adaptive_limit_max_retained_layer_mobs = EmptyMap,
adaptive_limit_max_aggregate_tokens = EmptyMap,
adaptive_limit_max_aggregate_tool_calls = EmptyMap,
adaptive_limit_allowed_model_classes = EmptyMap,
adaptive_limit_allowed_tool_classes = EmptyMap,
adaptive_limit_allowed_skill_identities = EmptyMap,
adaptive_limit_allowed_auth_binding_refs = EmptyMap,
adaptive_deadline_ms = EmptyMap,
adaptive_depth = EmptyMap,
adaptive_total_decisions = EmptyMap,
adaptive_repair_attempts = EmptyMap,
adaptive_layer_failures = EmptyMap,
adaptive_total_spawned_members = EmptyMap,
adaptive_active_members = EmptyMap,
adaptive_retained_layer_mobs = EmptyMap,
adaptive_aggregate_token_reserved = EmptyMap,
adaptive_aggregate_token_actual = EmptyMap,
adaptive_aggregate_tool_call_reserved = EmptyMap,
adaptive_aggregate_tool_call_actual = EmptyMap,
adaptive_active_layer = EmptyMap,
adaptive_layer_adaptive_run = EmptyMap,
adaptive_layer_phase = EmptyMap,
adaptive_layer_attempt = EmptyMap,
adaptive_layer_member_count = EmptyMap,
adaptive_layer_plan_digest = EmptyMap,
adaptive_layer_child_mob_id = EmptyMap,
adaptive_layer_token_reservation = EmptyMap,
adaptive_layer_tool_call_reservation = EmptyMap,
adaptive_layer_run_id = EmptyMap,
adaptive_layer_result_digest = EmptyMap,
adaptive_layer_fault = EmptyMap,
adaptive_layer_disposition = EmptyMap,
adaptive_missing_body_digest = EmptyMap,
mob_hosts = EmptySet,
host_public_keys = EmptyMap,
host_endpoints = EmptyMap,
host_authority_epochs = EmptyMap,
host_binding_generations = EmptyMap,
host_binding_generation_highwater = EmptyMap,
confirmed_host_binding_revocations = EmptySet,
replacement_host_bind_endpoints = EmptyMap,
replacement_host_binding_generations = EmptyMap,
host_bind_phase = EmptyMap,
host_protocol_min = EmptyMap,
host_protocol_max = EmptyMap,
host_engine_versions = EmptyMap,
host_durable_sessions = EmptyMap,
host_autonomous_members = EmptyMap,
host_hard_cancel_member = EmptyMap,
host_tracked_input_cancel = EmptyMap,
host_memory_store = EmptyMap,
host_mcp = EmptyMap,
host_resolvable_providers = EmptyMap,
host_approval_forwarding = EmptyMap,
host_live_endpoints = EmptyMap,
member_placement = EmptyMap,
pending_placed_spawn_ids = EmptyMap,
pending_placed_spawn_generations = EmptyMap,
pending_placed_spawn_fence_tokens = EmptyMap,
pending_placed_spawn_hosts = EmptyMap,
pending_autonomous_placed_spawns = EmptySet,
pending_placed_spawn_host_binding_generations = EmptyMap,
pending_placed_spawn_spec_digests = EmptyMap,
pending_placed_spawn_provision_operation_ids = EmptyMap,
pending_placed_spawn_operation_owner_session_ids = EmptyMap,
current_placed_spawn_ids = EmptyMap,
current_placed_spawn_host_binding_generations = EmptyMap,
current_placed_spawn_provision_operation_ids = EmptyMap,
current_placed_spawn_operation_owner_session_ids = EmptyMap,
pending_placed_carrier_cleanup = EmptySet,
member_materialization_failures = EmptyMap,
remote_turn_dispatch_sequence = 0,
pending_remote_turn_outcomes = EmptySet,
committed_remote_turn_outcomes = EmptySet,
resolved_remote_turn_outcomes = EmptySet,
placed_completion_dispatch_sequence = 0,
placed_completion_lifecycle_quiescing = false,
placed_completion_lifecycle_intent = None,
pending_placed_completion_outcomes = EmptySet,
cancel_requested_placed_completion_outcomes = EmptySet,
resolved_placed_completion_outcomes = EmptySet,
pending_route_installs = EmptySet,
operator_grant_scopes = EmptyMap,
operator_grant_expiries = EmptyMap,
spawn_profile_authority_resolved_spec_digests = EmptyMap,
}
terminal [Destroyed]
phase MobPhase {
Running,
Stopped,
Completed,
Destroyed,
}
input MobMachineInput {
RunFlow {
run_id: RunId,
step_ids: Set<StepId>,
ordered_steps: Seq<StepId>,
step_status: Map<StepId, Option<Enum<StepRunStatus>>>,
output_recorded: Map<StepId, bool>,
step_condition_results: Map<StepId, Option<bool>>,
step_has_conditions: Map<StepId, bool>,
step_dependencies: Map<StepId, Seq<StepId>>,
step_dependency_modes: Map<StepId, Enum<DependencyMode>>,
step_branches: Map<StepId, Option<BranchId>>,
step_collection_policies: Map<StepId, Enum<CollectionPolicyKind>>,
step_quorum_thresholds: Map<StepId, u32>,
step_target_counts: Map<StepId, u64>,
step_target_success_counts: Map<StepId, u64>,
step_target_terminal_failure_counts: Map<StepId, u64>,
escalation_threshold: u64,
max_step_retries: u32,
max_active_nodes: u64,
max_active_frames: u64,
max_frame_depth: u64,
},
CreateRunSeed {
run_id: RunId,
step_ids: Set<StepId>,
ordered_steps: Seq<StepId>,
step_status: Map<StepId, Option<Enum<StepRunStatus>>>,
output_recorded: Map<StepId, bool>,
step_condition_results: Map<StepId, Option<bool>>,
step_has_conditions: Map<StepId, bool>,
step_dependencies: Map<StepId, Seq<StepId>>,
step_dependency_modes: Map<StepId, Enum<DependencyMode>>,
step_branches: Map<StepId, Option<BranchId>>,
step_collection_policies: Map<StepId, Enum<CollectionPolicyKind>>,
step_quorum_thresholds: Map<StepId, u32>,
step_target_counts: Map<StepId, u64>,
step_target_success_counts: Map<StepId, u64>,
step_target_terminal_failure_counts: Map<StepId, u64>,
escalation_threshold: u64,
max_step_retries: u32,
max_active_nodes: u64,
max_active_frames: u64,
max_frame_depth: u64,
},
CreateFrameSeed {
run_id: RunId,
frame_id: FrameId,
frame_scope: Enum<FrameScope>,
loop_instance_id: Option<LoopInstanceId>,
iteration: u32,
tracked_nodes: Set<FlowNodeId>,
ordered_nodes: Seq<FlowNodeId>,
node_kind: Map<FlowNodeId, Enum<FlowNodeKind>>,
node_dependencies: Map<FlowNodeId, Seq<FlowNodeId>>,
node_dependency_modes: Map<FlowNodeId, Enum<DependencyMode>>,
node_branches: Map<FlowNodeId, Option<BranchId>>,
node_step_ids: Map<FlowNodeId, StepId>,
node_loop_ids: Map<FlowNodeId, LoopId>,
node_status: Map<FlowNodeId, Enum<NodeRunStatus>>,
ready_queue: Seq<FlowNodeId>,
output_recorded: Map<FlowNodeId, bool>,
node_condition_results: Map<FlowNodeId, Option<bool>>,
last_admitted_node: Option<FlowNodeId>,
},
CreateLoopSeed {
loop_instance_id: LoopInstanceId,
parent_frame_id: FrameId,
parent_node_id: FlowNodeId,
loop_id: LoopId,
depth: u32,
max_iterations: u64,
},
RecordLoopBodyFrameCompleted {
loop_instance_id: LoopInstanceId,
iteration: u64,
},
RecordLoopUntilConditionMet {
loop_instance_id: LoopInstanceId,
iteration: u64,
},
RecordLoopUntilConditionFailed {
loop_instance_id: LoopInstanceId,
iteration: u64,
},
AuthorizeFlowRunReducerCommand {
run_id: RunId,
command: Enum<FlowRunReducerCommandKind>,
step_id: Option<StepId>,
step_status: Option<Enum<StepRunStatus>>,
target_count: Option<u64>,
frame_id: Option<FrameId>,
node_id: Option<FlowNodeId>,
loop_instance_id: Option<LoopInstanceId>,
retry_key: Option<String>,
},
AuthorizeFlowFrameReducerCommand {
frame_id: FrameId,
command: Enum<FlowFrameReducerCommandKind>,
node_id: Option<FlowNodeId>,
node_status: Option<Enum<NodeRunStatus>>,
terminal_status: Option<Enum<FrameStatus>>,
},
AuthorizeLoopIterationReducerCommand {
loop_instance_id: LoopInstanceId,
command: Enum<LoopIterationReducerCommandKind>,
body_frame_id: Option<FrameId>,
body_frame_iteration: Option<u64>,
},
CancelFlow { run_id: RunId },
FlowStatus,
ClassifyFlowRunTerminality { run_id: RunId, status: Enum<FlowRunStatus> },
ClassifyFlowStepTerminality { run_id: RunId, step_id: StepId, status: Enum<StepRunStatus> },
ClassifyFlowFrameTerminalStatus { frame_id: FrameId },
ClassifyFlowRunPublicResult { run_id: RunId, status: Enum<FlowRunStatus> },
// Spawn-execution phase ladder (machine owns the phase ORDER).
// A lightweight 3-step ladder, NOT a per-obligation drain: the
// machine validates Begin-before-Commit-before-Activate, while the
// shell still executes the individual finalization steps. The
// per-obligation feedback inputs + per-step request effects were
// removed because they exploded the mob x meerkat composition state
// space. `BeginSpawnExec` opens the per-identity window (carrying the
// original Spawn authority guards); `CommitSpawnMembership` (renamed
// `Spawn`, full membership field set retained — the verbatim
// SpawnRunning* update/emit blocks consume those fields) commits the
// membership facts; `CommitSpawnActivation` closes the window;
// `AbortSpawnExec` clears it. Activation/abort are total over an
// absent (Settled) phase entry, mirroring `KickoffQuiesced`.
// Multi-host (§6.1/§15.4/§18.9/§19.L1/L5): the opener additionally
// carries the requested placement plus RAW portability/capability
// observations extracted by the shell from the spawn spec (one pure
// presence bool per non-portable or secret-bearing field; profiled
// capability requirements as bools; the requested resume session
// id). Placement None makes every denial guard vacuous, so local
// spawns are untouched. MobMachine — not the shell — owns the
// portability/placement admission verdict.
BeginSpawnExec {
agent_identity: AgentIdentity,
agent_runtime_id: AgentRuntimeId,
fence_token: FenceToken,
generation: Generation,
profile_material_digest: String,
external_addressable: bool,
runtime_mode: Enum<SpawnPolicyRuntimeMode>,
bridge_session_id: Option<SessionId>,
replacing: Option<SessionId>,
placement: Option<HostId>,
workgraph_required: bool,
rust_bundles_present: bool,
per_spawn_external_tools_present: bool,
mob_default_external_tools_present: bool,
default_llm_client_override_present: bool,
host_surface_mcp_allowlist_present: bool,
inherited_tool_filter_present: bool,
shell_env_present: bool,
mcp_stdio_env_present: bool,
mcp_http_headers_present: bool,
memory_required: bool,
mcp_required: bool,
resume_session_id: Option<SessionId>,
placed_spawn_id: Option<PlacedSpawnId>,
placed_provision_operation_id: Option<String>,
placed_operation_owner_session_id: Option<SessionId>,
effective_profile_override_present: bool,
effective_model_override_present: bool,
},
// Multi-host (§6.1/§15.4): the remote arm carries the
// materialization-ack facts (member endpoint, digest echo, engine
// version echo) as Option fields; local constructors pass None and
// the local/remote arms are discriminated by the spawn_exec_phase
// rung (Opened vs MaterializePending), so roster truth is never
// published before the owning host confirmed.
CommitSpawnMembership { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, profile_material_digest: String, external_addressable: bool, runtime_mode: Enum<SpawnPolicyRuntimeMode>, bridge_session_id: Option<SessionId>, replacing: Option<SessionId>, member_peer_endpoint: Option<MemberPeerEndpoint>, spec_digest_echo: Option<String>, ack_engine_version: Option<String>, placed_spawn_id: Option<PlacedSpawnId>, provision_operation_id: Option<String> },
CommitSpawnActivation { agent_identity: AgentIdentity },
AbortSpawnExec { agent_identity: AgentIdentity },
AuthorizePlacedCarrierCleanup { obligation: PlacedCarrierCleanupObligation },
ResolvePlacedCarrierCleanup { obligation: PlacedCarrierCleanupObligation },
AuthorizeSpawnProfile { agent_identity: AgentIdentity, profile_name: String, model: String, profile_material_digest: String, tool_config_digest: String, skills_digest: String, provider_params_digest: Option<String>, output_schema_digest: Option<String>, external_addressable: bool, resolved_spec_digest: Option<String> },
ClassifySpawnManyFailure { observation: Enum<MobSpawnManyFailureObservationKind> },
ClassifyMemberWait { agent_identity: AgentIdentity },
ObserveMemberProgress {
agent_identity: AgentIdentity,
run_open: bool,
in_flight_work: u64,
progress_token: String,
observed_at_ms: u64,
},
// Flow topology edge admission. The shell extracts the pure
// rule-match verdict from the declarative `TopologyRules`
// (`evaluate_topology`) and the configured enforcement mode, then
// feeds both here as a witness. The MobMachine — not the shell —
// decides the admission verdict (`Admitted` / `DeniedStrict` /
// `DeniedAdvisory`) and the shell mirrors that verdict. The roles
// are echoed so the shell can reconstruct the `TopologyViolation`
// error / advisory notice from the machine's emitted verdict.
ResolveFlowDelegationEdgeAdmission { from_role: String, to_role: String, rule_verdict: Enum<MobFlowDelegationEdgeRuleVerdictKind>, mode: Enum<MobFlowDelegationEdgeModeKind> },
// Remote-member runtime observation terminality. The bridge consumer
// observes a remote member's runtime state (a pure wire projection)
// during respawn/destroy cleanup; MobMachine — not the bridge shell
// — owns whether that observed state is terminal. The shell mirrors
// the emitted verdict to decide whether cleanup may stop or must
// force-destroy.
ClassifyRemoteMemberRuntimeObservation { observed_state: Enum<MobRemoteMemberRuntimeObservedState> },
// Composite spawn-member operator admission. The tool shell extracts
// RAW, atomic observations and feeds them here WITHOUT pre-composing
// them: whether the operator holds manage scope over the target mob
// (`manage_scope_present`), whether the operator's spawn-profile
// scope SET for the target mob CONTAINS the requested profile
// (`profile_scope_contains`, a raw per-profile set-membership fact —
// NOT OR'd with manage scope), and the per-argument presence of every
// privileged spawn argument (`privileged_*_present`, one pure
// `.is_some()` observation per argument; a surface fills only the
// arguments its own tool accepts and leaves the rest `false`).
// MobMachine — not the tool shell — owns the privileged-argument SET
// membership POLICY (which arguments are privileged) by OR-ing the
// presence facts, and composes the `manage_scope_present ||
// profile_scope_contains` profile-scope disjunction, deciding the
// Allow/Deny verdict the shell mirrors (Deny -> access_denied).
ResolveSpawnMemberAdmission {
manage_scope_present: bool,
profile_scope_contains: bool,
privileged_resume_bridge_session_present: bool,
privileged_resume_session_present: bool,
privileged_backend_present: bool,
privileged_runtime_mode_present: bool,
privileged_launch_mode_present: bool,
privileged_tool_access_policy_present: bool,
privileged_tooling_present: bool,
privileged_auth_binding_present: bool,
},
// Per-mob operator admission for current-mob-scoped tools. The tool
// shell extracts a single pure observation — whether the operator
// holds manage scope over the current mob (a machine-owned
// operator-scope projection) — and feeds it here. MobMachine — not
// the tool shell — decides the Allow/Deny admission verdict, which
// the shell mirrors (Deny -> access_denied).
ResolveCurrentMobAdmission { can_manage_mob: bool },
// Coarse spawn-tool admission for the spawn-member tool surfaces
// (`spawn_member` / `spawn_many_members`). The tool shell extracts
// TWO raw, atomic observations — whether the operator can manage the
// current mob (`can_manage_mob`, a machine-minted operator-scope
// membership projection) and whether the operator's spawn-profile
// scope for the mob is non-empty (`spawn_profile_scope_present`, a
// machine-owned operator-scope set-non-empty projection) — and feeds
// BOTH here without pre-composing them. MobMachine — not the tool
// shell — composes the disjunction (`can_manage_mob ||
// spawn_profile_scope_present`) and decides the Allow/Deny admission
// verdict, which the shell mirrors (Deny -> access_denied). This
// coarse gate has unique coverage over the empty-specs
// `spawn_many_members` case (zero per-member iterations fire no
// per-member admission), so it must be machine-routed rather than
// reduced in the shell.
ResolveSpawnToolAdmission {
can_manage_mob: bool,
spawn_profile_scope_present: bool,
},
// Operator create-mob admission for the mob-creation tool surface.
// The tool shell extracts a single pure observation — whether the
// operator holds the create-mobs capability bit (a machine-minted
// operator-authority projection) — and feeds it here. MobMachine —
// not the tool shell — decides the Allow/Deny admission verdict,
// which the shell mirrors (Deny -> access_denied).
ResolveCreateMobAdmission { can_create_mobs: bool },
// Operator profile-mutation admission for realm-profile mutation
// tools. The tool shell extracts a single pure observation —
// whether the operator holds the mutate-profiles capability bit (a
// machine-minted operator-authority projection) — and feeds it
// here. MobMachine — not the tool shell — decides the Allow/Deny
// admission verdict, which the shell mirrors (Deny ->
// access_denied).
ResolveProfileMutationAdmission { can_mutate_profiles: bool },
// Within-mob member-operation eligibility classification. Spawn
// finalization, peer messaging, and respawn finalization require the
// mob to be live and running. MobMachine — not a handwritten shell
// phase pre-check off `self.state()` — owns that eligibility over
// its own lifecycle phase plus the `destroy_admitted` marker. The
// owning actor extracts no fact (the verdict is read entirely from
// machine-owned state); it drives this input and mirrors
// `DeniedNotRunning` to the same `InvalidTransition` rejection it
// previously produced. Pure classification across all phases.
ClassifyMemberOperationEligibility {},
// Bridge-rejection recovery classification. When a mob sends a
// bridge command that requires an already-bound supervisor (e.g.
// `AuthorizeSupervisor`) and the member replies with a typed
// rejection cause (a pure wire projection), MobMachine — not a
// handwritten shell helper — owns whether that cause is recoverable
// by re-running `BindMember` (`RebindRecover`) or must bubble up as
// fatal (`FatalBubbleUp`). The machine-owning caller (actor /
// resume builder) mirrors the emitted recovery verdict to gate the
// real rebind control flow.
ClassifyBridgeRejectionRecovery { rejection_cause: Enum<MobBridgeRejectionCause> },
// Pending-supervisor-acceptance classification. When a supervisor
// rotation has already-accepted remote peers and the actor
// re-verifies a pending peer's acceptance by replaying the
// `AuthorizeSupervisor` command under the pending authority, the
// member may reply with a typed wire rejection cause (a pure wire
// projection). MobMachine — not a handwritten shell reducer — owns
// whether that cause means the peer is NOT confirmed and must be
// re-attempted (`NotConfirmedReattempt`: the peer rebound to current
// authority), the pending authority is stale (`StalePendingAuthority`),
// or it is a hard fatal rejection (`Fatal`). The actor mirrors the
// emitted verdict to gate re-attempt-vs-error control flow.
ClassifyPendingSupervisorAcceptance { rejection_cause: Enum<MobBridgeRejectionCause> },
// Total, level-triggered identity convergence classification.
// These are ephemeral observations only: no intent, lease, receipt,
// or realization fact is mirrored into MobMachine state.
ClassifyIdentityReconciliation {
intent: Enum<IdentityAuthorityCondition>,
lease: Enum<IdentityLeaseCondition>,
external_binding_required: bool,
initial_delivery_required: bool,
session_creation_receipt: Enum<IdentityReceiptCondition>,
retirement_receipt: Enum<IdentityReceiptCondition>,
session: Enum<IdentitySessionCondition>,
runtime: Enum<IdentityResourceCondition>,
member: Enum<IdentityResourceCondition>,
external_binding_receipt: Enum<IdentityReceiptCondition>,
external_trust: Enum<IdentityExternalTrustCondition>,
external_ceremony: Enum<IdentityExternalCeremonyCondition>,
initial_delivery_receipt: Enum<IdentityReceiptCondition>,
initial_delivery: Enum<IdentityInitialDeliveryCondition>,
wiring: Enum<IdentityResourceCondition>,
},
EnsureMember { agent_identity: AgentIdentity },
Reconcile { desired: Set<AgentIdentity>, retire_stale: bool },
// Classify member-scoped pending-spawn teardown for a public
// retire request from canonical membership + spawn-incarnation
// truth. The shell supplies only the stable identity. MobMachine
// emits one structural verdict: cancel the exact pending session
// while retiring the named committed incarnation, proceed with a
// committed incarnation that has no pending spawn, or preserve a
// pending later incarnation because no committed member exists.
ClassifyRetirePendingSpawnDisposition { agent_identity: AgentIdentity },
Retire { mob_id: MobId, agent_runtime_id: AgentRuntimeId, agent_identity: AgentIdentity, generation: Generation, releasing: Option<SessionId>, session_id: Option<SessionId> },
RetireAbsent { agent_identity: AgentIdentity },
RequestPendingSessionIngressDetachForMobDestroy { mob_id: MobId, agent_runtime_id: AgentRuntimeId },
Respawn { agent_runtime_id: AgentRuntimeId },
RetireAll,
BindOwnerBridgeSession { bridge_session_id: SessionId, destroy_on_owner_archive: bool, implicit_delegation_mob: bool },
// Track-B (R5): explicit identity-level wiring and session-binding
// mutation inputs. These drive `wiring_edges` and
// `member_session_bindings` directly at DSL authority,
// independent of the Spawn/Retire lifecycle.
//
// The `edge` field on `WireMembers`/`UnwireMembers` carries a
// pre-normalized `WiringEdge` (a <= b). Callers construct the
// edge via `WiringEdge::new(a, b)` before submitting.
WireMembers { edge: WiringEdge },
WireMembersWithTrust { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity },
UnwireMembers { edge: WiringEdge },
CleanupRetiringMemberWiring { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RestoreRetiringMemberWiring { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
WireExternalPeer { key: ExternalPeerKey, edge: ExternalPeerEdge },
RegisterMemberPeer { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation, fence_token: FenceToken, peer_endpoint: MemberPeerEndpoint },
AuthorizeMemberEndpointMigrationTrustCleanup { edge: WiringEdge, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, retained_peer_endpoint: MemberPeerEndpoint },
AuthorizeMemberPeerRebind { agent_identity: AgentIdentity, expected_peer_endpoint: MemberPeerEndpoint },
AuthorizeMemberPeerOverlay { agent_identity: AgentIdentity, expected_peer_endpoint: MemberPeerEndpoint },
AuthorizeRetiringMemberPeerOverlayCleanup { recipient_identity: AgentIdentity, expected_recipient_endpoint: MemberPeerEndpoint, retiring_identity: AgentIdentity, retiring_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
AuthorizeMemberTrustWiring { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity },
AuthorizeMemberTrustUnwiring { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity },
AuthorizeMemberTrustCleanup { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity },
AuthorizeMemberTrustCleanupObserved { edge: WiringEdge, a_identity: AgentIdentity, a_peer_id: PeerId, b_identity: AgentIdentity, b_peer_id: PeerId },
AuthorizeRetiringMemberTrustCleanupObserved { edge: WiringEdge, a_identity: AgentIdentity, a_peer_id: PeerId, b_identity: AgentIdentity, b_peer_id: PeerId, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
AuthorizeExternalPeerReciprocalTrust { key: ExternalPeerKey, agent_identity: AgentIdentity },
UnwireExternalPeer { key: ExternalPeerKey, edge: ExternalPeerEdge },
CleanupRetiringExternalPeer { key: ExternalPeerKey, edge: ExternalPeerEdge, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RestoreRetiringExternalPeer { key: ExternalPeerKey, edge: ExternalPeerEdge, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
CleanupRetiringExternalPeerObservedAbsent { key: ExternalPeerKey, edge: ExternalPeerEdge, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RestoreRetiringExternalPeerObservedAbsent { key: ExternalPeerKey, edge: ExternalPeerEdge, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
AdmitSupervisorRotation,
ProvisionSupervisorAuthority { peer_id: PeerId, signing_key: PeerSigningKey, epoch: u64, protocol_version: SupervisorProtocolVersion },
RecordSupervisorPendingRotation { current_peer_id: PeerId, current_epoch: u64, current_protocol_version: SupervisorProtocolVersion, operation_id: String, pending_peer_id: PeerId, pending_signing_key: PeerSigningKey, pending_epoch: u64, pending_protocol_version: SupervisorProtocolVersion, accepted_peer_ids: Set<PeerId>, active_peer_ids: Set<PeerId>, member_target_names: Map<PeerId, String>, member_target_addresses: Map<PeerId, String> },
CommitSupervisorRotation { current_peer_id: PeerId, current_epoch: u64, current_protocol_version: SupervisorProtocolVersion, operation_id: String, next_peer_id: PeerId, next_signing_key: PeerSigningKey, next_epoch: u64, next_protocol_version: SupervisorProtocolVersion },
ClearSupervisorAuthorityForDestroy { current_peer_id: PeerId, current_signing_key: PeerSigningKey, current_epoch: u64, protocol_version: SupervisorProtocolVersion },
RestoreSupervisorAuthorityAfterDestroyRollback { peer_id: PeerId, signing_key: PeerSigningKey, epoch: u64, protocol_version: SupervisorProtocolVersion, pending_operation_id: Option<String>, pending_peer_id: Option<PeerId>, pending_signing_key: Option<PeerSigningKey>, pending_epoch: Option<u64>, pending_protocol_version: Option<SupervisorProtocolVersion>, pending_accepted_peer_ids: Set<PeerId>, pending_member_target_names: Map<PeerId, String>, pending_member_target_addresses: Map<PeerId, String> },
// Dogma row R044: trust-install-before-terminality obligation.
// Recorded before the shell installs recipient trust for a routed
// bridge command; removed on authorization terminality success
// (Resolve) or after the shell rolls the installed trust back on
// a failure path (Rollback). Set semantics make all three inputs
// idempotent so nested authorize/bind windows for the same peer
// compose without double-record/double-resolve failures.
RecordPendingRecipientTrust { peer_id: PeerId },
ResolvePendingRecipientTrust { peer_id: PeerId },
RollbackPendingRecipientTrust { peer_id: PeerId },
// --- Multi-host mobs (§6.1): host bind lifecycle ---
// Opens (or idempotently re-requests) the bind window for a member
// host and emits the RequestHostBind handoff the shell realizes
// over comms.
BeginHostBind { host_id: HostId, expected_endpoint: PeerAddress, binding_generation: u64 },
// Commits the accepted bind: records identity, endpoint, epoch,
// and the full capability record (flat maps — the §6.1 single
// enumeration). The optional live endpoint is §16 DL5 capability.
CommitHostBind {
host_id: HostId,
pubkey: PeerSigningKey,
endpoint: PeerAddress,
epoch: u64,
binding_generation: u64,
protocol_min: u64,
protocol_max: u64,
engine_version: String,
durable_sessions: bool,
autonomous_members: bool,
hard_cancel_member: bool,
tracked_input_cancel: bool,
memory_store: bool,
mcp: bool,
resolvable_providers: Set<String>,
approval_forwarding: bool,
live_endpoint: Option<LiveWsEndpointUrl>,
},
// Host restarted and re-bound at a strictly higher epoch; the
// capability record is re-declared wholesale (absent live endpoint
// CLEARS the entry — restart truthfulness, D5).
HostRebound {
host_id: HostId,
epoch: u64,
binding_generation: u64,
protocol_min: u64,
protocol_max: u64,
engine_version: String,
durable_sessions: bool,
autonomous_members: bool,
hard_cancel_member: bool,
tracked_input_cancel: bool,
memory_store: bool,
mcp: bool,
resolvable_providers: Set<String>,
approval_forwarding: bool,
live_endpoint: Option<LiveWsEndpointUrl>,
},
// Exact authenticated host-fact refresh. Epoch/G identify the
// current binding; the full capability + optional live endpoint
// set is persisted under the emitted witness before publication.
RefreshHostCapabilities {
host_id: HostId,
epoch: u64,
binding_generation: u64,
protocol_min: u64,
protocol_max: u64,
engine_version: String,
durable_sessions: bool,
autonomous_members: bool,
hard_cancel_member: bool,
tracked_input_cancel: bool,
memory_store: bool,
mcp: bool,
resolvable_providers: Set<String>,
approval_forwarding: bool,
live_endpoint: Option<LiveWsEndpointUrl>,
},
// Clears every host fact (bind, keys, endpoint, epoch,
// capabilities, live endpoint). Placed members KEEP their
// member_placement entry — the §9 revival ladder owns
// re-placement.
RevokeHost { host_id: HostId, binding_generation: u64 },
// Advances only the durable carrier's host-binding generation.
// The shell prepares this transition, performs the exact durable
// carrier CAS, then commits this state update.
PromoteCommittedPlacedSpawnCarrierBinding { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host_id: HostId, expected_host_binding_generation: u64, host_binding_generation: u64 },
// §6.1 materialization failure recorder. Keeps the spawn-exec
// rung at MaterializePending so a retry with the same
// (identity, generation, fence) stays idempotent; AbortSpawnExec
// clears on final abort.
RecordMemberMaterializationFailure { agent_identity: AgentIdentity, kind: String },
// --- Multi-host mobs (§6.2, D4): route install obligations ---
// Obligations arrive whole (the DSL cannot construct struct
// values in updates); the machine validates the observation
// against its own wiring/host facts and owns the outstanding set.
// Resolve/Rollback are idempotent set removals, mirroring the
// pending_recipient_trust trio.
RecordRouteInstall { obligation: RouteInstallObligation },
// Synchronous pre-commit authorization for route removal. The
// edge intentionally remains wired while the shell obtains every
// remote ACK; only then may UnwireMembers + MembersUnwired commit.
// No volatile obligation is opened, so a crash before the durable
// unwire simply recovers the still-wired edge and repairs Install.
AuthorizeRouteRemovalBeforeUnwire { obligation: RouteInstallObligation },
ResolveRouteInstall { obligation: RouteInstallObligation },
RollbackRouteInstall { obligation: RouteInstallObligation },
// --- Multi-host mobs (§18 O2): remote turn-outcome obligations ---
RecordRemoteTurnObligation { obligation: RemoteTurnObligation },
AbortRemoteTurnObligation { obligation: RemoteTurnObligation },
CommitRemoteTurnOutcome { obligation: RemoteTurnObligation },
ResolveRemoteTurnObligation { obligation: RemoteTurnObligation },
AcknowledgeRemoteTurnOutcome { obligation: RemoteTurnObligation },
DisposeRemoteTurnObligation { obligation: RemoteTurnObligation },
// Ordinary placed TurnCompleted cleanup. The promise is volatile;
// these inputs own only the host journal row and exact ACK/cancel
// convergence.
RecordPlacedCompletionObligation { obligation: PlacedCompletionObligation },
RequestPlacedCompletionCancellation { obligation: PlacedCompletionObligation },
ResolvePlacedCompletionOutcome { obligation: PlacedCompletionObligation },
ClosePlacedCompletionOutcome { obligation: PlacedCompletionObligation },
AcknowledgePlacedCompletionOutcome { obligation: PlacedCompletionObligation },
DisposePlacedCompletionOutcome { obligation: PlacedCompletionObligation },
BeginPlacedCompletionLifecycleQuiesce { intent: Enum<PlacedCompletionLifecycleIntentKind> },
EndPlacedCompletionLifecycleQuiesce { intent: Enum<PlacedCompletionLifecycleIntentKind> },
// --- Multi-host mobs (§6.5/§8): principal control-scope grants ---
// Expiry is data; the machine stores it and never reads a clock —
// the sealed policy at the enforcement seam compares.
GrantOperatorScopes { principal: PrincipalId, scopes: Set<Enum<ControlScope>>, expires_at_ms: Option<u64> },
// Revocation carries the proposed (revoked, remaining) partition
// and the machine REVALIDATES it against the recorded grant
// (set difference is not expressible in DSL updates; the
// ObserveCoordinationResourceClaimOverlap revalidation precedent).
RevokeOperatorScopes { principal: PrincipalId, revoked: Set<Enum<ControlScope>>, remaining: Set<Enum<ControlScope>> },
// --- Multi-host mobs (§15 R6): member-operator upcall admission ---
// The shell extracts the sender peer id from the verified
// envelope; MobMachine — not the shell — adjudicates roster
// membership, sender-key match, placement, and host liveness.
ResolveMemberOperatorAdmission { agent_identity: AgentIdentity, requester_generation: Generation, requester_fence_token: FenceToken, requester_host_id: HostId, requester_host_binding_generation: u64, requester_member_session_id: SessionId, sender_peer_id: PeerId, request_id: String },
// --- Multi-host mobs (§18.9): flow step dispatch classification ---
// Pure classification over machine facts (member_runtime_modes,
// member_placement, host_durable_sessions); the flow engine
// mirrors the emitted dispatch verdict.
ClassifyFlowStepDispatch { run_id: RunId, step_id: StepId, target: AgentIdentity, overlay_present: bool },
SessionIngressDetachedForMobDestroy { mob_id: MobId, agent_runtime_id: AgentRuntimeId },
SessionIngressDetachFailedForMobDestroy { mob_id: MobId, agent_runtime_id: AgentRuntimeId, reason: String },
SubmitWork { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, work_id: WorkId, origin: Enum<WorkOrigin> },
ResolveSubmitWorkRejection { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, origin: Enum<WorkOrigin> },
// Generated composition refusal closure. Each input is bound by
// `meerkat_mob_seam` to one concrete routed effect kind; the shell
// supplies only the consumer's stable code + display detail.
ResolveRuntimeBindingRefusal { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, session_id: SessionId, refusal_code: String, reason: String },
ResolveRuntimeIngressRefusal { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, session_id: SessionId, work_id: WorkId, origin: Enum<WorkOrigin>, refusal_code: String, reason: String },
ResolveRuntimeRetireRefusal { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, session_id: SessionId, refusal_code: String, reason: String },
RetryRuntimeRetire { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId },
RecordRemoteMemberRuntimeRetired { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RecordRemoteMemberSupervisorRevoked { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
CancelWork { work_id: WorkId },
CancelAllWork { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
ResolveCancelAllWorkRejection { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
Stop,
Resume,
Complete,
Reset,
Destroy,
RosterSnapshot,
ListMembers,
ListMembersIncludingRetiring,
ListAllMembers,
MemberStatus,
SubscribeAgentEvents { agent_identity: AgentIdentity },
// §6.5: the shell's session-bound-runtime observation is joined by
// the remote-member observation (identities with a placement); the
// machine guards BOTH against its own maps so the mob-wide stream
// can no longer silently omit external members.
SubscribeAllAgentEvents { session_bound_runtimes: Set<AgentRuntimeId>, external_members: Set<AgentIdentity> },
SubscribeMobEvents { initial_cursor: u64, channel_capacity: u64, poll_interval_ms: u64, session_bound_runtimes: Set<AgentRuntimeId>, external_members: Set<AgentIdentity> },
SubscribeStructuralEvents { after_cursor: u64, latest_cursor: u64, explicit_after_cursor: bool, batch_limit: u64, channel_capacity: u64 },
AuthorizeMobEventRouterMemberSubscription { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
AuthorizeMobEventRouterMemberRemoval { agent_identity: AgentIdentity },
PollEvents,
PollEventsStrict { after_cursor: u64, latest_cursor: u64, limit: u64 },
ReplayAllEvents,
RecordOperatorActionProvenance { tool_name: String, principal_token: OpaquePrincipalToken, caller_provenance: Option<MobToolCallerProvenance>, audit_invocation_id: Option<String> },
GetMember,
SetSpawnPolicy { enabled: bool },
ResolveSpawnPolicy { agent_identity: AgentIdentity, revision: u64, profile_name: Option<String>, runtime_mode: Option<Enum<SpawnPolicyRuntimeMode>> },
Shutdown,
// Shutdown observes mechanical session/runtime carriers for one
// exact autonomous roster incarnation. MobMachine owns the
// semantic choice: interrupt a live member, or skip a
// disposal-complete Retiring row retained only to retry terminal
// journal publication. Disposal may be either a Mob-owned archive
// or a host-owned runtime release. Placed release completion is an
// exact durable event observation supplied by the shell; peer-only
// completion is already represented in machine-owned checkpoint
// and supervisor-revocation markers.
ResolveAutonomousShutdownMemberAction {
agent_identity: AgentIdentity,
agent_runtime_id: AgentRuntimeId,
fence_token: FenceToken,
generation: Generation,
session_id: Option<SessionId>,
session_has_live_actor: bool,
session_projection_visible: bool,
runtime_residue_present: bool,
archive_authority_known: bool,
placed_release_confirmed: bool,
},
ForceCancel { agent_identity: AgentIdentity },
KickoffMarkPending { member_id: AgentIdentity, objective_id: String },
BindObjectiveOwner { owner_id: AgentIdentity, objective_id: String },
ConcludeObjective { member_id: AgentIdentity, objective_id: String, outcome: String },
KickoffMarkStarting { member_id: AgentIdentity },
// Placed autonomous kickoff is a durable, host-retained tracked
// turn. Start atomically binds exact custody to the ordinary
// kickoff lifecycle; Resolve moves it to ACK-pending custody;
// certified pre-admission rejection closes it without an ACK.
StartPlacedKickoff { obligation: PlacedKickoffObligation },
ResolvePlacedKickoffStarted { obligation: PlacedKickoffObligation },
ResolvePlacedKickoffCallbackPending { obligation: PlacedKickoffObligation },
ResolvePlacedKickoffFailed { obligation: PlacedKickoffObligation, error: String },
ResolvePlacedKickoffCancelled { obligation: PlacedKickoffObligation },
RejectPlacedKickoffBeforeAdmission { obligation: PlacedKickoffObligation, error: String },
AcknowledgePlacedKickoffOutcome { obligation: PlacedKickoffObligation },
DisposePlacedKickoffObligation { obligation: PlacedKickoffObligation },
StartupMarkReady { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
KickoffResolveStarted { member_id: AgentIdentity },
KickoffResolveCallbackPending { member_id: AgentIdentity },
KickoffResolveFailed { member_id: AgentIdentity, error: String },
KickoffCancelRequested { member_id: AgentIdentity },
KickoffClear { member_id: AgentIdentity },
// 0.7.2 disciplined shell inputs (L5, rows 12/13): feedback input
// that closes the machine-owned kickoff-waiter drain obligation
// opened by member retire / destroy-retire transitions via the
// `RequestKickoffQuiesce` effect. TOTAL over kickoff state: an
// in-flight kickoff is recorded Cancelled (with persist + notice
// effects), an idle/terminal kickoff is an accepted no-op, and the
// Destroyed phase accepts it as a typed late arrival. The shell
// never probes kickoff state before firing it.
KickoffQuiesced { member_id: AgentIdentity },
// 0.7.2 disciplined shell inputs (L5, row 14): typed teardown
// closure for an in-flight pending spawn. Replaces the former
// shell habit of laundering teardown cancellation through the
// `CompleteSpawn` success signal. TOTAL: absent identities and the
// Destroyed phase are accepted no-ops, so idempotent re-drains
// and post-teardown stragglers never surface as guard rejections.
CancelPendingSpawn { agent_identity: AgentIdentity },
// ---------------------------------------------------------------
// Wave-G1 catalog folds (rows #14, #181, #260, #261, #293, #314,
// #320). These lower duplicate-admission, respawn-generation,
// step-fault classification, supervisor escalation, topology-edge
// verdict, external-member rebind capability, and turn-timeout
// disposition into MobMachine authority. Each carries only RAW
// typed caller facts; MobMachine owns every verdict.
// ---------------------------------------------------------------
// Row #14: duplicate-member admission probe. The actor reads the
// emitted verdict instead of probing the PendingSpawnLineage map.
ProbeMemberAdmission { agent_identity: AgentIdentity },
// Row #181: compute the next monotone respawn generation. The
// actor reads the emitted generation instead of `generation.next()`.
ComputeRespawnGeneration { agent_identity: AgentIdentity },
// Row #260: classify a typed step-output fault into retry/terminal.
ClassifyStepOutputFault {
run_id: RunId,
step_id: StepId,
target_retry_key: String,
fault: Enum<StepOutputFaultKind>,
attempt: u32,
max_retries: u32,
},
// Row #261: supervisor escalation. Presence of an eligible target is
// structural (two inputs, no `Option<AgentIdentity>`): a target was
// selected, or no eligible target exists.
EscalateToSupervisor {
run_id: RunId,
step_id: StepId,
supervisor_identity: AgentIdentity,
turn_timeout_ms: u64,
},
EscalateToSupervisorNoEligibleTarget { run_id: RunId, step_id: StepId },
// Row #293: topology-edge admission verdict. The shell projects the
// declarative rule match (if any) as `Option<PolicyDecision>`;
// MobMachine applies the declared default policy for unmatched edges.
// `from_role`/`to_role` are opaque role strings (no `ProfileName`
// type is bound in the mob catalog metadata; the existing
// FlowDelegationEdgeAdmission effect uses `String` too).
EvaluateTopologyEdge {
from_role: String,
to_role: String,
rule_match: Option<Enum<PolicyDecision>>,
},
// Row #314: external-member rebind capability. The bridge supplies
// the typed capability bit; the projection reads the machine map.
SetExternalMemberRebindCapability {
agent_identity: AgentIdentity,
capability: Enum<ExternalMemberRebindCapability>,
},
// Row #320: turn-timeout disposition. `orphan_budget` is a typed
// machine field; the shell reads the detach/cancel/retryable verdict.
ClassifyTurnTimeoutDisposition { timed_out_run_id: RunId, retryable: bool },
// Row #320 (G1 regression fix): one-time orphan-budget seed. The
// lead dispatches this once at actor build from
// `definition.limits.max_orphaned_turns` (default 8) so non-retryable
// timeouts can detach rather than always classifying Canceled.
SeedOrphanBudget { budget: u64 },
// ---------------------------------------------------------------
// Mob coordination board inputs (folded). These carry only RAW
// typed caller facts: no `already_exists`, no `current_revision`
// as a trusted input, no `owning_mob_ref_matches`, no `is_expired`,
// no `current_next_sequence`, and no pre-decided `overlap_ids`.
// MobMachine recomputes/revalidates every conclusion in-DSL.
// ---------------------------------------------------------------
RecordCoordinationWorkIntent {
intent_id: WorkIntentId,
requested_status: Enum<MobCoordinationWorkIntentStatus>,
owner_present: bool,
summary_present: bool,
metadata_public: bool,
draft_mob_id: MobId,
authority_mob_id: MobId,
resource_tokens: Set<CoordinationResourceRef>,
expires_at_ms: Option<u64>,
},
RecordCoordinationResourceClaim {
claim_id: ResourceClaimId,
requested_kind: Enum<MobCoordinationResourceClaimKind>,
requested_status: Enum<MobCoordinationResourceClaimStatus>,
owner_present: bool,
metadata_public: bool,
draft_mob_id: MobId,
authority_mob_id: MobId,
resource_tokens: Set<CoordinationResourceRef>,
expires_at_ms: Option<u64>,
},
UpdateCoordinationWorkIntentStatus {
intent_id: WorkIntentId,
expected_revision: u64,
requested_status: Enum<MobCoordinationWorkIntentStatus>,
now_ms: u64,
},
UpdateCoordinationResourceClaimStatus {
claim_id: ResourceClaimId,
expected_revision: u64,
requested_status: Enum<MobCoordinationResourceClaimStatus>,
now_ms: u64,
},
ObserveCoordinationResourceClaimOverlap {
claim_id: ResourceClaimId,
now_ms: u64,
candidate_overlap_ids: Seq<ResourceClaimId>,
},
InitializeAdaptiveRun {
adaptive_run_id: AdaptiveRunId,
max_depth: u64,
max_total_decisions: u64,
max_repair_attempts: u64,
max_layer_failures: u64,
max_attempts_per_layer: u64,
max_members_per_layer: u64,
max_total_spawned_members: u64,
max_active_members: u64,
max_retained_layer_mobs: u64,
max_aggregate_tokens: u64,
max_aggregate_tool_calls: u64,
allowed_model_classes: Set<String>,
allowed_tool_classes: Set<String>,
allowed_skill_identities: Set<String>,
allowed_auth_binding_refs: Set<String>,
deadline_ms: u64,
},
RecordPlanningDecision {
adaptive_run_id: AdaptiveRunId,
decision_kind: Enum<AdaptiveDecisionKind>,
},
RecordPlanRejected {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
},
ResolveLayerAdmission {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
plan_digest: String,
child_mob_id: MobId,
member_count: u64,
token_reservation: u64,
tool_call_reservation: u64,
used_model_classes: Set<String>,
used_tool_classes: Set<String>,
used_skill_identities: Set<String>,
used_auth_binding_refs: Set<String>,
observed_at_ms: u64,
},
RecordLayerProvisioned {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
},
RecordLayerRunStarted {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
child_run_id: RunId,
},
IngestLayerTerminal {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
result_class: Enum<FlowRunPublicResultClassKind>,
actual_tokens: u64,
actual_tool_calls: u64,
},
RecordLayerSetupFault {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
fault: Enum<AdaptiveLayerSetupFaultKind>,
spawned_members: u64,
requested_members: u64,
},
RecordLayerInterrupted {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
},
RecordLayerResultValidated {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
result_digest: String,
},
RecordLayerResultInvalid {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
},
RecordLayerMobDestroyed {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
},
RecordLayerMobRetained {
adaptive_run_id: AdaptiveRunId,
layer_id: AdaptiveLayerId,
attempt: u64,
disposition: Enum<AdaptiveLayerDispositionKind>,
},
RecordCleanupResolved { adaptive_run_id: AdaptiveRunId },
RecordBodyEvidenceMissing { adaptive_run_id: AdaptiveRunId, missing_digest: String },
ResolveAdaptiveFinish {
adaptive_run_id: AdaptiveRunId,
final_result_digest: String,
},
RequestAdaptiveCancel { adaptive_run_id: AdaptiveRunId },
RecordDeadlineObserved { adaptive_run_id: AdaptiveRunId, observed_at_ms: u64 },
}
surface_only [
FlowStatus,
RosterSnapshot,
ListMembers,
ListMembersIncludingRetiring,
ListAllMembers,
MemberStatus,
CancelWork,
PollEvents,
ReplayAllEvents,
GetMember
]
signal MobMachineSignal {
ObserveRuntimeReady { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
RetireMember { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, session_id: Option<SessionId> },
AdmitDestroyMemberRetire { mob_id: MobId, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, session_id: Option<SessionId> },
ObserveRuntimeRetired { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
// Both retirement-archived signals carry the typed session
// disposal observed from the local provisioner or host release
// acknowledgement; shell code must not infer it from reachability.
ObserveMemberRetirementArchived { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, session_id: Option<SessionId>, disposal: Enum<MemberSessionDisposal>, preserve_machine_topology: bool },
ObserveRemoteMemberRetirementArchivedAndSupervisorRevoked { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, preserve_machine_topology: bool },
ObserveDestroyMemberRetirementArchived { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, session_id: Option<SessionId>, disposal: Enum<MemberSessionDisposal> },
ResolveRespawnTopologyRestore { agent_identity: AgentIdentity, failed_peer_ids: Seq<RespawnTopologyPeerId> },
DestroyMob { session_id: SessionId },
ObserveRuntimeDestroyed { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken },
RecoverRosterMember { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, profile_name: String, runtime_mode: Enum<SpawnPolicyRuntimeMode>, external_addressable: bool },
RecoverMemberSessionBinding { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, bridge_session_id: SessionId, replacing: Option<SessionId> },
RecoverSpawnedMemberPeerEndpoint { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, peer_endpoint: MemberPeerEndpoint },
RecoverMemberPeerEndpoint { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, bridge_session_id: SessionId, peer_endpoint: MemberPeerEndpoint },
RecoverRosterMemberReset { agent_identity: AgentIdentity, previous_agent_runtime_id: AgentRuntimeId, previous_generation: Generation, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RecoverRosterMemberRetiring { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation, session_id: Option<SessionId>, host_id: Option<HostId> },
RecoverRosterMemberRetirementStarted { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation, releasing: Option<SessionId>, session_id: Option<SessionId>, retiring_peer_endpoint: Option<MemberPeerEndpoint>, preserve_machine_topology: bool },
ObserveRespawnTopologyPreservationStarted { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
ObserveRespawnTopologyAbandoned { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RecoverRemoteMemberRuntimeRetired { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RecoverRemoteMemberSupervisorRevoked { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Generation },
RecoverRosterMemberRetired { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation, preserve_machine_topology: bool, preservation_started: bool },
ConvergeRecoveredRosterTopology { edge: WiringEdge, a_identity: AgentIdentity, b_identity: AgentIdentity },
ConvergeRecoveredRespawnTopology { agent_identity: AgentIdentity },
RecoverMemberKickoff { member_id: AgentIdentity, phase: KickoffPhase, error: Option<String> },
RecoverObjectiveBinding { member_id: AgentIdentity, objective_id: String },
RecoverFinalizedPlacedKickoff { obligation: PlacedKickoffObligation, outcome_kind: Enum<PlacedKickoffOutcomeKind>, outcome_error: Option<String>, closure_kind: Enum<PlacedKickoffClosureKind> },
RecoverObjectiveConclusion { member_id: AgentIdentity, objective_id: String, outcome: String },
RecoverRosterWiring { edge: WiringEdge },
RecoverRosterUnwire { edge: WiringEdge },
RecoverExternalPeerWiring { key: ExternalPeerKey, edge: ExternalPeerEdge },
RecoverExternalPeerUnwire { key: ExternalPeerKey },
RecoverSupervisorAuthority { peer_id: PeerId, signing_key: PeerSigningKey, epoch: u64, protocol_version: SupervisorProtocolVersion, pending_operation_id: Option<String>, pending_peer_id: Option<PeerId>, pending_signing_key: Option<PeerSigningKey>, pending_epoch: Option<u64>, pending_protocol_version: Option<SupervisorProtocolVersion>, pending_accepted_peer_ids: Set<PeerId>, pending_member_target_names: Map<PeerId, String>, pending_member_target_addresses: Map<PeerId, String> },
// Durable multi-host recovery lives beside supervisor recovery so
// builder replay restores bound-host authority before dispatch.
RecoverHostBindRequest { host_id: HostId, expected_endpoint: PeerAddress, binding_generation: u64, replacement: bool },
RecoverHostBinding { host_id: HostId, pubkey: PeerSigningKey, endpoint: PeerAddress, epoch: u64, binding_generation: u64, protocol_min: u64, protocol_max: u64, engine_version: String, durable_sessions: bool, autonomous_members: bool, hard_cancel_member: bool, tracked_input_cancel: bool, memory_store: bool, mcp: bool, resolvable_providers: Set<String>, approval_forwarding: bool, live_endpoint: Option<LiveWsEndpointUrl> },
RecoverHostBindingGenerationHighwater { host_id: HostId, binding_generation: u64 },
RecoverConfirmedHostBindingRevocation { host_id: HostId, binding_generation: u64 },
RecoverRemoteTurnDispatchSequence { dispatch_sequence: u64 },
RecoverPlacedCompletionDispatchSequence { dispatch_sequence: u64 },
RecoverPendingPlacedCompletion { obligation: PlacedCompletionObligation, cancellation_requested: bool },
RecoverResolvedPlacedCompletion { obligation: PlacedCompletionObligation },
RecoverCompletedWithCleanupCustody,
RecoverOwnerBridgeSession { bridge_session_id: SessionId, destroy_on_owner_archive: bool, implicit_delegation_mob: bool },
RecoverMemberRestoreFailure { agent_identity: AgentIdentity, reason: String },
RecoverPendingPlacedSpawn { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host_id: HostId, host_binding_generation: u64, spec_digest: String, runtime_mode: Enum<SpawnPolicyRuntimeMode>, provision_operation_id: String, operation_owner_session_id: SessionId },
RecoverCommittedPlacedSpawn { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation, fence_token: FenceToken, host_id: HostId, host_binding_generation: u64, member_session_id: SessionId, member_peer_endpoint: MemberPeerEndpoint, profile_name: String, runtime_mode: Enum<SpawnPolicyRuntimeMode>, external_addressable: bool, provision_operation_id: String, operation_owner_session_id: SessionId },
RecoverPlacedCarrierCleanup { obligation: PlacedCarrierCleanupObligation },
ClassifyMemberLiveMaterialization { agent_identity: AgentIdentity, observation: Enum<MemberLiveMaterializationObservationKind>, reason: String },
ResolveMemberRevivalSucceeded { agent_identity: AgentIdentity },
ResolveMemberRevivalFailed { agent_identity: AgentIdentity, reason: String },
AdmitDestroyCleanup,
AdmitDestroyStorageFinalizing,
MarkCompleted,
StartRun,
FinishRun,
BeginCleanup,
FinishCleanup,
InitializeOrchestrator,
BindCoordinator,
UnbindCoordinator,
StageSpawn { agent_identity: AgentIdentity, session_id: SessionId },
CompleteSpawn { agent_identity: AgentIdentity },
StartFlow,
CompleteFlow,
StopOrchestrator,
ResumeOrchestrator,
DestroyOrchestrator,
ForceCancelMember,
MemberPeerExposed,
MemberTerminalized,
OperationPeerTrusted,
PeerInputAdmitted,
CreateRun,
}
effect MobMachineEffect {
RequestRuntimeBinding { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Option<Generation>, session_id: SessionId },
SpawnProfileAuthorized { agent_identity: AgentIdentity, profile_name: String, model: String, profile_material_digest: String, tool_config_digest: String, skills_digest: String, provider_params_digest: Option<String>, output_schema_digest: Option<String>, external_addressable: bool, resolved_spec_digest: Option<String> },
RequestRuntimeIngress { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Option<Generation>, session_id: SessionId, work_id: WorkId, origin: Enum<WorkOrigin> },
RequestPeerRuntimeIngress { agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, generation: Option<Generation>, work_id: WorkId, origin: Enum<WorkOrigin> },
SubmitWorkRejected { agent_runtime_id: AgentRuntimeId, origin: Enum<WorkOrigin>, reason: Enum<SubmitWorkRejectReasonKind>, expected_fence_token: Option<FenceToken>, actual_fence_token: Option<FenceToken> },
CancelAllWorkRejected { agent_runtime_id: AgentRuntimeId, reason: Enum<CancelAllWorkRejectReasonKind>, expected_fence_token: Option<FenceToken>, actual_fence_token: Option<FenceToken> },
RequestRuntimeRetire { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, session_id: SessionId },
RequestRuntimeDestroy { session_id: SessionId },
RuntimeBindingRefusalClassified { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, session_id: SessionId, refusal_code: String, reason: String },
RuntimeIngressRefusalClassified { agent_runtime_id: AgentRuntimeId, session_id: SessionId, work_id: WorkId, origin: Enum<WorkOrigin>, refusal_code: String, reason: String },
RuntimeRetireRefusalClassified { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, session_id: SessionId, refusal_code: String, reason: String },
PendingSpawnOperationOwnerAuthorized { agent_identity: AgentIdentity, session_id: SessionId },
RequestSessionIngressDetachForMobDestroy { mob_id: MobId, agent_runtime_id: AgentRuntimeId },
AppendLifecycleJournal { kind: Enum<MobLifecycleJournalKind>, agent_identity: Option<AgentIdentity>, agent_runtime_id: Option<AgentRuntimeId>, fence_token: Option<FenceToken>, generation: Option<Generation>, session_id: Option<SessionId> },
PersistPlacedCompletionLifecycleIntent { intent: Enum<PlacedCompletionLifecycleIntentKind>, active: bool },
AppendOperatorActionProvenance { tool_name: String, principal_token: OpaquePrincipalToken, caller_provenance: Option<MobToolCallerProvenance>, audit_invocation_id: Option<String> },
EmitMemberLifecycleNotice { kind: Enum<MemberLifecycleKind> },
EmitRunLifecycleNotice,
EmitFlowRunNotice,
AppendFailureLedger,
FlowTerminalized,
FlowRunTerminal { run_id: RunId },
FlowRunNonTerminal { run_id: RunId },
FlowStepTerminal { run_id: RunId, step_id: StepId },
FlowStepNonTerminal { run_id: RunId, step_id: StepId },
FlowFrameTerminalStatusClassified { frame_id: FrameId, terminal_status: Enum<FrameStatus> },
FlowFrameTerminalStatusUnavailable { frame_id: FrameId },
FlowRunPublicResultClassified { run_id: RunId, result: Enum<FlowRunPublicResultClassKind> },
EscalateSupervisor,
NotifyCoordinator,
ExposePendingSpawn,
EmitMemberTerminalNotice,
AdmitPeerInput,
EmitProgressNote,
PersistKickoffUpdate { member_id: AgentIdentity, phase: KickoffPhase },
PersistKickoffFailureUpdate { member_id: AgentIdentity, phase: KickoffPhase, error: String },
EmitKickoffLifecycleNotice { member_id: AgentIdentity, intent: Enum<KickoffIntent> },
PersistObjectiveOwnerBinding { owner_id: AgentIdentity, objective_id: String },
PersistObjectiveConclusion { member_id: AgentIdentity, objective_id: String, outcome: String },
// 0.7.2 L5 (rows 12/13): machine-owned drain obligation for the
// autonomous-kickoff completion-waiter task. Emitted by every
// member retire / destroy-retire admission. The shell discharges
// it (abort + await the waiter task, resolve its waiters with a
// typed terminal outcome) and closes it with the `KickoffQuiesced`
// feedback input. Member retirement archival and mob destroy are
// guarded on closure (kickoff not in flight), mirroring the
// mob-destroy session-ingress-detach obligation shape.
RequestKickoffQuiesce { member_id: AgentIdentity },
// 0.7.2 L5 (row 14): machine-owned drain obligation for in-flight
// spawn-provisioning waiter tasks at destroy admission. Emitted by
// `AdmitDestroyCleanup`. The shell aborts + awaits every pending
// spawn task, fails its waiters with a typed cancellation, and
// closes each machine obligation with `CancelPendingSpawn`;
// `Destroy`/`DestroyMob` are guarded on the pending-spawn table
// being drained instead of silently wiping it.
RequestPendingSpawnQuiesceForDestroy,
// (Spawn-execution phase ladder emits NO request effects — the
// machine only owns the phase order; the shell realizes each step.)
// Row #14: machine-owned duplicate-member admission verdict. The
// actor mirrors this (Admitted -> Ok; DuplicateRejected ->
// MemberAlreadyExists) instead of probing the PendingSpawnLineage map.
MemberAdmissionProbed { agent_identity: AgentIdentity, verdict: Enum<MemberAdmissionVerdictKind> },
// Row #181: machine-owned next monotone respawn generation. The
// actor consumes `next_generation` instead of `generation.next()`.
RespawnGenerationComputed { agent_identity: AgentIdentity, next_generation: Generation },
// Row #260: machine-owned step-output fault disposition. The flow
// shell mirrors Retry (attempt+=1, continue) / Terminal (fail). The
// typed `terminal_cause` flows into terminalization (row #126).
StepOutputFaultClassified {
run_id: RunId,
step_id: StepId,
target_retry_key: String,
disposition: Enum<StepFaultDispositionKind>,
terminal_cause: Enum<StepOutputFaultKind>,
},
// Row #261: machine-owned supervisor escalation request. The shell
// runs the internal turn with the machine-supplied timeout and
// realizes the escalation evidence.
SupervisorEscalationRequested {
run_id: RunId,
step_id: StepId,
supervisor_identity: AgentIdentity,
turn_timeout_ms: u64,
},
// Row #261: machine-owned typed escalation failure. Fail-closed is a
// typed terminal cause, not a free-form `SupervisorEscalation` string.
SupervisorEscalationFailed {
run_id: RunId,
step_id: StepId,
cause: Enum<SupervisorEscalationFailureCause>,
},
// Row #293: machine-owned topology-edge verdict. The FlowEngine reads
// the verdict; the default policy is applied in-DSL for unmatched edges.
TopologyEdgeVerdictResolved {
from_role: String,
to_role: String,
verdict: Enum<PolicyDecision>,
},
// Row #320: machine-owned turn-timeout disposition. The shell mirrors
// Detached (reconcile detached turn) / Canceled (abort) / Retryable.
TurnTimeoutDispositionClassified {
timed_out_run_id: RunId,
disposition: Enum<TurnTimeoutDisposition>,
},
// Row #351: machine-owned membership-intent effects emitted by the
// single-identity EnsureMember path. The handle mechanically realizes
// spawn/retain/retire instead of computing the desired-vs-current diff.
MemberSpawnRequired { agent_identity: AgentIdentity },
MemberRetainRequired { agent_identity: AgentIdentity },
MemberRetireRequired { agent_identity: AgentIdentity },
AutonomousShutdownMemberActionResolved {
action: Enum<AutonomousShutdownMemberActionKind>,
agent_identity: AgentIdentity,
agent_runtime_id: AgentRuntimeId,
fence_token: FenceToken,
generation: Generation,
session_id: Option<SessionId>,
},
SpawnPolicyResolutionRecorded { agent_identity: AgentIdentity, revision: u64, profile_name: Option<String>, runtime_mode: Option<Enum<SpawnPolicyRuntimeMode>> },
OwnerBridgeSessionBound { bridge_session_id: SessionId, destroy_on_owner_archive: bool, implicit_delegation_mob: bool },
RespawnTopologyRestoreResolved { agent_identity: AgentIdentity, result: Enum<RespawnTopologyRestoreResultKind>, failed_peer_ids: Seq<RespawnTopologyPeerId> },
MemberLiveMaterializationClassified { agent_identity: AgentIdentity, observation: Enum<MemberLiveMaterializationObservationKind>, verdict: Enum<MemberRevivalVerdictKind>, reason: String },
SpawnManyFailureClassified { observation: Enum<MobSpawnManyFailureObservationKind>, cause: Enum<MobSpawnManyFailureCauseKind> },
MemberWaitClassified { agent_identity: AgentIdentity, result: Enum<MemberWaitClassificationKind> },
// Machine-owned flow topology edge admission verdict. The shell
// mirrors this (DeniedStrict -> TopologyViolation block;
// DeniedAdvisory -> advisory notice; Admitted -> proceed) instead
// of computing+enforcing the admission itself.
FlowDelegationEdgeAdmissionResolved { from_role: String, to_role: String, admission: Enum<MobFlowDelegationEdgeAdmissionKind> },
// Machine-owned terminality verdict for an observed remote-member
// runtime state. The bridge shell mirrors this to decide whether
// confirmatory cleanup may stop (Terminal) or must force-destroy
// (NonTerminal).
RemoteMemberRuntimeTerminalityClassified { observed_state: Enum<MobRemoteMemberRuntimeObservedState>, terminality: Enum<MobRemoteMemberRuntimeTerminality> },
// Machine-owned composite spawn-member operator admission verdict.
// The tool shell mirrors this (Denied -> access_denied; Allowed ->
// proceed) instead of composing+enforcing the admission itself.
SpawnMemberAdmissionResolved { admission: Enum<MobSpawnMemberAdmissionKind> },
// Machine-owned per-mob operator admission verdict for current-mob
// tools. The tool shell mirrors this (Denied -> access_denied;
// Allowed -> proceed) instead of composing the admission itself.
CurrentMobAdmissionResolved { admission: Enum<MobCurrentMobAdmissionKind> },
// Machine-owned coarse spawn-tool admission verdict for the
// spawn-member tool surfaces. The tool shell mirrors this (Denied ->
// access_denied; Allowed -> proceed) instead of composing the
// admission itself.
SpawnToolAdmissionResolved { admission: Enum<MobSpawnToolAdmissionKind> },
// Machine-owned operator create-mob admission verdict. The tool
// shell mirrors this (Denied -> access_denied; Allowed -> proceed)
// instead of composing the admission itself.
CreateMobAdmissionResolved { admission: Enum<MobCreateMobAdmissionKind> },
// Machine-owned operator profile-mutation admission verdict. The
// tool shell mirrors this (Denied -> access_denied; Allowed ->
// proceed) instead of composing the admission itself.
ProfileMutationAdmissionResolved { admission: Enum<MobProfileMutationAdmissionKind> },
MemberOperationEligibilityResolved { admission: Enum<MobMemberOperationEligibilityKind> },
// Structural, incarnation-scoped retire verdicts. Separate effect
// variants keep cancel / no-cancel / preserve impossible to blur
// through an optional field in handwritten code.
RetirePendingSpawnCancellationAuthorized { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation, pending_spawn_session_id: SessionId },
RetireCommittedIncarnationWithoutPendingSpawnResolved { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, generation: Generation },
RetireAbsentPendingSpawnPreservationResolved { agent_identity: AgentIdentity },
// Machine-owned bridge-rejection recovery verdict. The mob shell
// mirrors this (RebindRecover -> re-run BindMember; FatalBubbleUp ->
// bubble the rejection up) instead of reducing the raw wire cause
// into a recoverable-vs-fatal conclusion itself.
BridgeRejectionRecoveryClassified { rejection_cause: Enum<MobBridgeRejectionCause>, recovery: Enum<MobBridgeRejectionRecovery> },
// Machine-owned pending-supervisor-acceptance verdict. The actor
// mirrors this (NotConfirmedReattempt -> drop the accepted peer and
// re-attempt; StalePendingAuthority -> error with the stale-pending
// message; Fatal -> bubble the rejection) instead of reducing the
// raw wire cause into an acceptance/recovery conclusion itself.
PendingSupervisorAcceptanceClassified { rejection_cause: Enum<MobBridgeRejectionCause>, verdict: Enum<MobPendingSupervisorAcceptanceKind> },
// Pure level-triggered obligation selected from the caller's fresh
// observations. It grants no write authority by itself; target-local
// actuation still requires the intent/lease/resource CAS permit.
IdentityReconciliationClassified { decision: Enum<IdentityReconcileDecision> },
// Machine-owned frame-seed disposition. `CreateFrameSeed` is
// idempotent: a fresh seed emits `Seeded`, while re-seeding an
// already-tracked frame emits `AlreadySeeded` (a no-op) instead of
// a guard rejection the shell would have to reinterpret. The flow
// shell mirrors both as success — `AlreadySeeded` short-circuits
// (idempotent re-confirm), `Seeded` proceeds to snapshot validation.
FrameSeedConfirmed { frame_id: FrameId, disposition: Enum<MobFrameSeedDisposition> },
// Track-B (R5): canonical topology-change signals consumed by
// the `RecomputeMobPeerOverlay` composition driver.
//
// - `WiringGraphChanged` fires when `wiring_edges` mutates.
// - `MemberSessionBindingChanged` fires on every binding
// mutation (set, rotated, or released), carrying the
// before/after session ids as `Option<SessionId>`. Absence
// of a value means "no binding on this side of the
// transition": `old=None, new=Some` → set, `Some, Some` →
// rotate, `Some, None` → release.
//
// Topology-change signals carry the post-transition
// `topology_epoch` so the driver can linearize recomputes
// against the newest topology snapshot. Trust handoffs carry the
// topology epoch they authorize; member unwiring is a two-step
// authorize-then-remove path, so its handoff carries the next
// epoch that the graph-removal transition must produce.
WiringGraphChanged { epoch: u64 },
MemberSessionBindingChanged { epoch: u64, agent_identity: AgentIdentity, old_session_id: Option<SessionId>, new_session_id: Option<SessionId> },
SessionProvisionOperationOwnerAuthorized { agent_identity: AgentIdentity, session_id: SessionId },
MemberTrustWiringRequested { edge: WiringEdge, a_peer_id: PeerId, b_peer_id: PeerId, a_endpoint: MemberPeerEndpoint, b_endpoint: MemberPeerEndpoint, epoch: u64 },
MemberTrustUnwiringRequested { edge: WiringEdge, a_peer_id: PeerId, b_peer_id: PeerId, epoch: u64 },
WiringTrustRepairRequested { edge: WiringEdge },
ExternalPeerTrustWiringRequested { edge: ExternalPeerEdge, local_peer_id: PeerId, peer_id: PeerId, epoch: u64 },
ExternalPeerTrustUnwiringRequested { edge: ExternalPeerEdge, local_peer_id: PeerId, peer_id: PeerId, epoch: u64 },
ExternalPeerTrustRepairRequested { edge: ExternalPeerEdge, local_peer_id: PeerId, peer_id: PeerId, epoch: u64 },
MemberPeerRegistered { agent_identity: AgentIdentity, peer_id: PeerId },
MemberPeerRebindAuthorized { agent_identity: AgentIdentity, peer_id: PeerId, peer_endpoint: MemberPeerEndpoint },
MemberPeerOverlayAuthorized { agent_identity: AgentIdentity, peer_id: PeerId, peer_overlay_endpoints: Set<MemberPeerEndpoint>, epoch: u64 },
ExternalPeerReciprocalTrustRequested { key: ExternalPeerKey, edge: ExternalPeerEdge, peer_id: PeerId, peer_endpoint: MemberPeerEndpoint, epoch: u64 },
PersistSupervisorAuthority { peer_id: PeerId, signing_key: PeerSigningKey, epoch: u64, protocol_version: SupervisorProtocolVersion, pending_operation_id: Option<String>, pending_peer_id: Option<PeerId>, pending_signing_key: Option<PeerSigningKey>, pending_epoch: Option<u64>, pending_protocol_version: Option<SupervisorProtocolVersion>, pending_accepted_peer_ids: Set<PeerId>, pending_member_target_names: Map<PeerId, String>, pending_member_target_addresses: Map<PeerId, String> },
DeleteSupervisorAuthority { peer_id: PeerId, signing_key: PeerSigningKey, epoch: u64, protocol_version: SupervisorProtocolVersion },
// D-wiring-observability (#27): pair-valued notice emitted from
// `WireMembers`/`UnwireMembers` alongside `WiringGraphChanged`.
// Unlike `WiringGraphChanged` (opaque epoch bump), this carries
// the `WiringEdge` so external observers (event store,
// telemetry) can reconstruct which identity pair was wired or
// unwired. Separate from `EmitMemberLifecycleNotice` because
// wiring is pair-valued, not per-member.
EmitWiringLifecycleNotice { kind: Enum<WiringLifecycleKind>, edge: WiringEdge },
// Descriptor-bearing external peer trust notice. Carries the
// endpoint fields (`peer_id`, `address`, `signing_key`) that
// cannot be represented by a member `WiringEdge`.
EmitExternalPeerWiringLifecycleNotice { kind: Enum<WiringLifecycleKind>, edge: ExternalPeerEdge },
AuthorizeAgentEventSubscription { agent_identity: AgentIdentity, session_id: SessionId },
RejectAgentEventSubscription { agent_identity: AgentIdentity, reason: Enum<EventSubscriptionRejectReasonKind> },
AuthorizeAllAgentEventSubscription { session_bound_runtimes: Set<AgentRuntimeId>, external_members: Set<AgentIdentity> },
RejectAllAgentEventSubscription { reason: Enum<EventSubscriptionRejectReasonKind> },
AuthorizeMobEventRouter { initial_cursor: u64, channel_capacity: u64, poll_interval_ms: u64, session_bound_runtimes: Set<AgentRuntimeId> },
AuthorizeMobEventRouterMemberSubscription { agent_identity: AgentIdentity, agent_runtime_id: AgentRuntimeId, fence_token: FenceToken, session_id: SessionId },
AuthorizeMobEventRouterMemberRemoval { agent_identity: AgentIdentity },
AuthorizeStructuralEventSubscription { after_cursor: u64, explicit_after_cursor: bool, batch_limit: u64, channel_capacity: u64 },
RejectStructuralEventSubscription { after_cursor: u64, latest_cursor: u64 },
AuthorizeStrictEventPoll { after_cursor: u64, limit: u64 },
RejectStrictEventPoll { after_cursor: u64, latest_cursor: u64 },
// Mob coordination board effects (folded). Each carries the
// machine-computed revision / event sequence.
WorkIntentRecorded {
intent_id: WorkIntentId,
status: Enum<MobCoordinationWorkIntentStatus>,
revision: u64,
resource_tokens: Set<CoordinationResourceRef>,
expires_at_ms: Option<u64>,
event_kind: Enum<MobCoordinationEventKind>,
sequence: u64,
},
ResourceClaimRecorded {
claim_id: ResourceClaimId,
kind: Enum<MobCoordinationResourceClaimKind>,
status: Enum<MobCoordinationResourceClaimStatus>,
revision: u64,
resource_tokens: Set<CoordinationResourceRef>,
expires_at_ms: Option<u64>,
event_kind: Enum<MobCoordinationEventKind>,
sequence: u64,
},
WorkIntentStatusChanged {
intent_id: WorkIntentId,
status: Enum<MobCoordinationWorkIntentStatus>,
revision: u64,
event_kind: Enum<MobCoordinationEventKind>,
sequence: u64,
},
ResourceClaimStatusChanged {
claim_id: ResourceClaimId,
status: Enum<MobCoordinationResourceClaimStatus>,
revision: u64,
event_kind: Enum<MobCoordinationEventKind>,
sequence: u64,
},
ResourceClaimOverlapObserved {
claim_id: ResourceClaimId,
overlap_ids: Seq<ResourceClaimId>,
event_kind: Enum<MobCoordinationEventKind>,
sequence: u64,
},
AdaptiveRunInitialized { adaptive_run_id: AdaptiveRunId },
AdaptivePlanningDecisionRecorded { adaptive_run_id: AdaptiveRunId, decision_kind: Enum<AdaptiveDecisionKind> },
AdaptivePlanRejected { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId },
AdaptiveLayerAdmissionResolved { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, admission: Enum<AdaptiveLayerAdmissionKind> },
AdaptiveLayerProvisioned { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, attempt: u64 },
AdaptiveLayerRunStarted { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, attempt: u64, child_run_id: RunId },
AdaptiveLayerTerminalIngested { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, result_class: Enum<FlowRunPublicResultClassKind> },
AdaptiveLayerSetupFaultRecorded { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, fault: Enum<AdaptiveLayerSetupFaultKind> },
AdaptiveLayerInterrupted { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId },
AdaptiveLayerResultValidated { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, result_digest: String },
AdaptiveLayerResultInvalid { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId },
AdaptiveLayerCleanupObserved { adaptive_run_id: AdaptiveRunId, layer_id: AdaptiveLayerId, disposition: Enum<AdaptiveLayerDispositionKind> },
AdaptiveCleanupResolved { adaptive_run_id: AdaptiveRunId },
AdaptiveBodyEvidenceMissing { adaptive_run_id: AdaptiveRunId, missing_digest: String },
AdaptiveRunTerminalized { adaptive_run_id: AdaptiveRunId, reason: Enum<AdaptiveStopReason> },
// --- Multi-host mobs (§6.1/§6.2/§6.5/§15/§18.9) ---
// Cross-process bind handshake handoff; the consumer is the remote
// host's MobHostBindingAuthority (never in-process), so this is an
// external handoff, not a routed effect.
RequestHostBind { host_id: HostId, endpoint: PeerAddress, binding_generation: u64 },
HostRegistered { host_id: HostId, epoch: u64, binding_generation: u64 },
HostReboundRecorded { host_id: HostId, epoch: u64, binding_generation: u64 },
HostCapabilitiesRefreshed { host_id: HostId, epoch: u64, binding_generation: u64 },
HostRevoked { host_id: HostId, binding_generation: u64 },
// Cross-process materialization handoff. spec_digest is the
// machine-owned resolved digest (§15.4 invariant: never a shell
// echo).
PersistPendingPlacedSpawn { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host: HostId, host_binding_generation: u64, spec_digest: String, effective_profile_override_present: bool, effective_model_override_present: bool, provision_operation_id: String, operation_owner_session_id: SessionId },
RequestMemberMaterialization { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, spec_digest: String, host: HostId, host_binding_generation: u64, provision_operation_id: String, operation_owner_session_id: SessionId },
CommitPlacedSpawnCarrier { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host: HostId, host_binding_generation: u64, spec_digest: String, member_session_id: SessionId, member_peer_endpoint: MemberPeerEndpoint, ack_engine_version: String, provision_operation_id: String, operation_owner_session_id: SessionId },
PromoteCommittedPlacedSpawnCarrierBinding { spawn_id: PlacedSpawnId, agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host: HostId, expected_host_binding_generation: u64, host_binding_generation: u64 },
PlacedCarrierCleanupRequested { obligation: PlacedCarrierCleanupObligation },
PlacedCarrierCleanupAuthorized { obligation: PlacedCarrierCleanupObligation },
PlacedCarrierCleanupResolved { obligation: PlacedCarrierCleanupObligation },
// Cross-process release handoff (§19.L2): the one disposal verb
// for HostMaterialized members; doubles as the §9 orphan
// reconciliation verb.
RequestMemberRelease { agent_identity: AgentIdentity, generation: Generation, fence_token: FenceToken, host: HostId },
// Cross-process route-install handoff (§6.2). Endpoint material
// is resolved by the realizing shell from machine-projected
// member_peer_endpoints at install time.
RouteInstallRequested { obligation: RouteInstallObligation },
MemberOperatorAdmitted { agent_identity: AgentIdentity, request_id: String },
MemberOperatorRejected { agent_identity: AgentIdentity, request_id: String, cause: Enum<MemberOperatorRejectKind> },
FlowStepDispatchClassified { run_id: RunId, step_id: StepId, target: AgentIdentity, dispatch: Enum<FlowStepDispatchKind> },
// §6.5 third subscription outcome: the member is real and bound,
// but its event stream lives on a member host.
AuthorizeExternalAgentEventSubscription { agent_identity: AgentIdentity, host: HostId },
GrantRecorded { principal: PrincipalId, scopes: Set<Enum<ControlScope>>, expires_at_ms: Option<u64> },
GrantRevoked { principal: PrincipalId, revoked: Set<Enum<ControlScope>>, remaining: Set<Enum<ControlScope>> },
}
// One total, pure classifier over desired authority, lease ownership,
// and fresh observed realization. The ordering is deliberately
// resource-local: an unavailable later resource cannot stall an
// independent earlier obligation. Target observation versions and the
// write-authorizing intent/lease witness remain outside this helper in
// the actor's target-local actuation permit.
helper identity_reconcile_decision(
intent: Enum<IdentityAuthorityCondition>,
lease: Enum<IdentityLeaseCondition>,
external_binding_required: bool,
initial_delivery_required: bool,
session_creation_receipt: Enum<IdentityReceiptCondition>,
retirement_receipt: Enum<IdentityReceiptCondition>,
session: Enum<IdentitySessionCondition>,
runtime: Enum<IdentityResourceCondition>,
member: Enum<IdentityResourceCondition>,
external_binding_receipt: Enum<IdentityReceiptCondition>,
external_trust: Enum<IdentityExternalTrustCondition>,
external_ceremony: Enum<IdentityExternalCeremonyCondition>,
initial_delivery_receipt: Enum<IdentityReceiptCondition>,
initial_delivery: Enum<IdentityInitialDeliveryCondition>,
wiring: Enum<IdentityResourceCondition>
) -> Enum<IdentityReconcileDecision> {
if intent == IdentityAuthorityCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if intent == IdentityAuthorityCondition::Missing
|| intent == IdentityAuthorityCondition::Malformed
{
IdentityReconcileDecision::RepairBlocked
} else {
if lease == IdentityLeaseCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if lease == IdentityLeaseCondition::Missing
|| lease == IdentityLeaseCondition::HeldByExpiredIncarnation
{
IdentityReconcileDecision::AcquireLease
} else {
if lease == IdentityLeaseCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if lease == IdentityLeaseCondition::HeldByOtherLiveIncarnation {
IdentityReconcileDecision::AwaitLease
} else {
if intent == IdentityAuthorityCondition::Absent {
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Matching
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
if member == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if member == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Matching
|| member == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RetireMemberMaterialization
} else {
if runtime == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if runtime == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if runtime == IdentityResourceCondition::Matching
|| runtime == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RetireRuntimeRegistration
} else {
if session == IdentitySessionCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if session == IdentitySessionCondition::Malformed
|| session == IdentitySessionCondition::AmbiguousDivergence
{
IdentityReconcileDecision::RepairBlocked
} else {
if session == IdentitySessionCondition::Matching
|| session == IdentitySessionCondition::RecoverableDivergence
|| session == IdentitySessionCondition::IrrecoverablyCorrupt
{
IdentityReconcileDecision::ReleaseSessionAuthority
} else {
if retirement_receipt == IdentityReceiptCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if retirement_receipt == IdentityReceiptCondition::Missing {
IdentityReconcileDecision::SealRetirementProven
} else {
if retirement_receipt == IdentityReceiptCondition::Matching {
IdentityReconcileDecision::Tombstoned
} else {
IdentityReconcileDecision::RepairBlocked
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
} else {
if session == IdentitySessionCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if session == IdentitySessionCondition::Malformed
|| session == IdentitySessionCondition::IrrecoverablyCorrupt
|| session == IdentitySessionCondition::AmbiguousDivergence
|| (session == IdentitySessionCondition::Missing
&& intent == IdentityAuthorityCondition::PresentRequireExisting)
{
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Matching
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
if member == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if member == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Matching
|| member == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RetireMemberMaterialization
} else {
if runtime == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if runtime == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if runtime == IdentityResourceCondition::Matching
|| runtime == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RetireRuntimeRegistration
} else {
if session == IdentitySessionCondition::IrrecoverablyCorrupt {
IdentityReconcileDecision::Quarantined
} else {
IdentityReconcileDecision::RepairBlocked
}
}
}
}
}
}
}
}
}
}
} else {
if session == IdentitySessionCondition::Missing
|| session == IdentitySessionCondition::RecoverableDivergence
{
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& session_creation_receipt == IdentityReceiptCondition::Unavailable
{
IdentityReconcileDecision::Backoff
} else {
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& (session_creation_receipt == IdentityReceiptCondition::Conflicting
|| session_creation_receipt == IdentityReceiptCondition::Malformed
|| session_creation_receipt == IdentityReceiptCondition::NotRequired)
{
IdentityReconcileDecision::RepairBlocked
} else {
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& session_creation_receipt == IdentityReceiptCondition::Matching
&& session == IdentitySessionCondition::Missing
{
IdentityReconcileDecision::RepairBlocked
} else {
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& (session_creation_receipt == IdentityReceiptCondition::Missing
|| session_creation_receipt == IdentityReceiptCondition::Matching)
{
IdentityReconcileDecision::EnsureSessionAuthority
} else {
if intent == IdentityAuthorityCondition::PresentRequireExisting
&& session_creation_receipt == IdentityReceiptCondition::NotRequired
{
IdentityReconcileDecision::EnsureSessionAuthority
} else {
if intent == IdentityAuthorityCondition::PresentRequireExisting
&& session_creation_receipt == IdentityReceiptCondition::Unavailable
{
IdentityReconcileDecision::Backoff
} else {
IdentityReconcileDecision::RepairBlocked
}
}
}
}
}
}
} else {
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& session_creation_receipt == IdentityReceiptCondition::Unavailable
{
IdentityReconcileDecision::Backoff
} else {
if intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& session_creation_receipt == IdentityReceiptCondition::Missing
{
IdentityReconcileDecision::SealSessionCreationConsumed
} else {
if !((intent == IdentityAuthorityCondition::PresentCreateIfAbsent
&& session_creation_receipt == IdentityReceiptCondition::Matching)
|| (intent == IdentityAuthorityCondition::PresentRequireExisting
&& session_creation_receipt == IdentityReceiptCondition::NotRequired))
{
IdentityReconcileDecision::RepairBlocked
} else {
if runtime == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if runtime == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if runtime == IdentityResourceCondition::Missing
|| runtime == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::EnsureRuntimeRegistration
} else {
if external_binding_required == true {
if external_binding_receipt == IdentityReceiptCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if external_binding_receipt == IdentityReceiptCondition::Missing {
IdentityReconcileDecision::EnsureExternalBindingReceipt
} else {
if external_binding_receipt == IdentityReceiptCondition::Conflicting
|| external_binding_receipt == IdentityReceiptCondition::Malformed
|| external_binding_receipt == IdentityReceiptCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if external_trust == IdentityExternalTrustCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if external_trust == IdentityExternalTrustCondition::Absent {
if external_ceremony == IdentityExternalCeremonyCondition::FreshAvailable {
IdentityReconcileDecision::EnsureExternalBinding
} else {
if external_ceremony == IdentityExternalCeremonyCondition::AwaitFresh {
IdentityReconcileDecision::AwaitExternalBindingCeremony
} else {
if external_ceremony == IdentityExternalCeremonyCondition::TemporarilyUnavailable {
IdentityReconcileDecision::Backoff
} else {
IdentityReconcileDecision::RepairBlocked
}
}
}
} else {
if external_trust == IdentityExternalTrustCondition::Contradictory
|| external_trust == IdentityExternalTrustCondition::Indeterminate
|| external_trust == IdentityExternalTrustCondition::Malformed
|| external_trust == IdentityExternalTrustCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if member == IdentityResourceCondition::Malformed
|| member == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Missing {
IdentityReconcileDecision::EnsureMemberMaterialization
} else {
if initial_delivery_required == true {
if initial_delivery_receipt == IdentityReceiptCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if initial_delivery_receipt == IdentityReceiptCondition::Missing {
IdentityReconcileDecision::EnsureInitialDeliveryReceipt
} else {
if initial_delivery_receipt == IdentityReceiptCondition::Conflicting
|| initial_delivery_receipt == IdentityReceiptCondition::Malformed
|| initial_delivery_receipt == IdentityReceiptCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if initial_delivery == IdentityInitialDeliveryCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if initial_delivery == IdentityInitialDeliveryCondition::ProvenAbsent {
IdentityReconcileDecision::EnsureInitialDelivery
} else {
if initial_delivery == IdentityInitialDeliveryCondition::AcceptedPendingExact {
IdentityReconcileDecision::AwaitInitialDelivery
} else {
if initial_delivery == IdentityInitialDeliveryCondition::ContentOnlyMatch
|| initial_delivery == IdentityInitialDeliveryCondition::OperationCollision
|| initial_delivery == IdentityInitialDeliveryCondition::Contradictory
|| initial_delivery == IdentityInitialDeliveryCondition::Indeterminate
|| initial_delivery == IdentityInitialDeliveryCondition::Malformed
|| initial_delivery == IdentityInitialDeliveryCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if retirement_receipt != IdentityReceiptCondition::NotRequired {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Missing
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
IdentityReconcileDecision::Converged
}
}
}
}
}
}
}
}
}
}
}
} else {
if initial_delivery_receipt != IdentityReceiptCondition::NotRequired
|| initial_delivery != IdentityInitialDeliveryCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if retirement_receipt != IdentityReceiptCondition::NotRequired {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Missing
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
IdentityReconcileDecision::Converged
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
} else {
if external_binding_receipt != IdentityReceiptCondition::NotRequired
|| external_trust != IdentityExternalTrustCondition::NotRequired
|| external_ceremony != IdentityExternalCeremonyCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if member == IdentityResourceCondition::Malformed
|| member == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::RepairBlocked
} else {
if member == IdentityResourceCondition::Missing {
IdentityReconcileDecision::EnsureMemberMaterialization
} else {
if initial_delivery_required == true {
if initial_delivery_receipt == IdentityReceiptCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if initial_delivery_receipt == IdentityReceiptCondition::Missing {
IdentityReconcileDecision::EnsureInitialDeliveryReceipt
} else {
if initial_delivery_receipt == IdentityReceiptCondition::Conflicting
|| initial_delivery_receipt == IdentityReceiptCondition::Malformed
|| initial_delivery_receipt == IdentityReceiptCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if initial_delivery == IdentityInitialDeliveryCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if initial_delivery == IdentityInitialDeliveryCondition::ProvenAbsent {
IdentityReconcileDecision::EnsureInitialDelivery
} else {
if initial_delivery == IdentityInitialDeliveryCondition::AcceptedPendingExact {
IdentityReconcileDecision::AwaitInitialDelivery
} else {
if initial_delivery == IdentityInitialDeliveryCondition::ContentOnlyMatch
|| initial_delivery == IdentityInitialDeliveryCondition::OperationCollision
|| initial_delivery == IdentityInitialDeliveryCondition::Contradictory
|| initial_delivery == IdentityInitialDeliveryCondition::Indeterminate
|| initial_delivery == IdentityInitialDeliveryCondition::Malformed
|| initial_delivery == IdentityInitialDeliveryCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if retirement_receipt != IdentityReceiptCondition::NotRequired {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Missing
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
IdentityReconcileDecision::Converged
}
}
}
}
}
}
}
}
}
}
}
} else {
if initial_delivery_receipt != IdentityReceiptCondition::NotRequired
|| initial_delivery != IdentityInitialDeliveryCondition::NotRequired
{
IdentityReconcileDecision::RepairBlocked
} else {
if retirement_receipt != IdentityReceiptCondition::NotRequired {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Unavailable {
IdentityReconcileDecision::Backoff
} else {
if wiring == IdentityResourceCondition::Malformed {
IdentityReconcileDecision::RepairBlocked
} else {
if wiring == IdentityResourceCondition::Missing
|| wiring == IdentityResourceCondition::Divergent
{
IdentityReconcileDecision::ReconcileWiring
} else {
IdentityReconcileDecision::Converged
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
disposition RequestRuntimeBinding => routed [MeerkatMachine] seam NoOwnerRealization,
disposition SpawnProfileAuthorized => local seam NoOwnerRealization,
disposition RequestRuntimeIngress => routed [MeerkatMachine] seam NoOwnerRealization,
disposition RequestPeerRuntimeIngress => local seam SurfaceResultAlignment,
disposition SubmitWorkRejected => local seam SurfaceResultAlignment,
disposition CancelAllWorkRejected => local seam SurfaceResultAlignment,
disposition RequestRuntimeRetire => routed [MeerkatMachine] seam NoOwnerRealization,
disposition RequestRuntimeDestroy => routed [MeerkatMachine] seam NoOwnerRealization,
disposition RuntimeBindingRefusalClassified => local seam SurfaceResultAlignment,
disposition RuntimeIngressRefusalClassified => local seam SurfaceResultAlignment,
disposition RuntimeRetireRefusalClassified => local seam SurfaceResultAlignment,
disposition PendingSpawnOperationOwnerAuthorized => local seam NoOwnerRealization,
disposition RequestSessionIngressDetachForMobDestroy => external handoff mob_destroying_session_ingress seam NoOwnerRealization,
disposition AppendLifecycleJournal => local seam NoOwnerRealization,
// Local owner-realization authorization: the actor requires this exact
// effect, durably appends the typed marker store-first, and only then
// commits the prepared transition. Commit is conditional on successful
// realization, so no separate feedback input remains.
disposition PersistPlacedCompletionLifecycleIntent => local seam OwnerRealizationOnly,
disposition AppendOperatorActionProvenance => local seam NoOwnerRealization,
disposition EmitMemberLifecycleNotice => external seam SurfaceResultAlignment,
disposition EmitRunLifecycleNotice => external seam SurfaceResultAlignment,
disposition EmitFlowRunNotice => external seam SurfaceResultAlignment,
disposition AppendFailureLedger => local seam NoOwnerRealization,
disposition FlowTerminalized => external seam SurfaceResultAlignment,
disposition FlowRunTerminal => local seam SurfaceResultAlignment,
disposition FlowRunNonTerminal => local seam SurfaceResultAlignment,
disposition FlowStepTerminal => local seam SurfaceResultAlignment,
disposition FlowStepNonTerminal => local seam SurfaceResultAlignment,
disposition FlowFrameTerminalStatusClassified => local seam SurfaceResultAlignment,
disposition FlowFrameTerminalStatusUnavailable => local seam SurfaceResultAlignment,
disposition FlowRunPublicResultClassified => local seam SurfaceResultAlignment,
disposition EscalateSupervisor => external seam OwnerRealizationOnly,
disposition NotifyCoordinator => external seam OwnerRealizationOnly,
disposition ExposePendingSpawn => external seam OwnerRealizationOnly,
disposition EmitMemberTerminalNotice => external seam SurfaceResultAlignment,
disposition AdmitPeerInput => external seam OwnerRealizationOnly,
disposition EmitProgressNote => external seam OwnerRealizationOnly,
disposition PersistKickoffUpdate => local seam NoOwnerRealization,
disposition PersistKickoffFailureUpdate => local seam NoOwnerRealization,
disposition EmitKickoffLifecycleNotice => external seam OwnerRealizationOnly,
disposition PersistObjectiveOwnerBinding => local seam NoOwnerRealization,
disposition PersistObjectiveConclusion => local seam NoOwnerRealization,
// 0.7.2 L5 drain obligations: realized by the owning mob actor itself
// (same-machine effect→feedback shape; feedback inputs
// `KickoffQuiesced` / `CancelPendingSpawn` close them and teardown
// completion is guard-enforced on closure). Classified `local` like
// the sibling kickoff persistence effects; cross-machine C-F3 pairing
// is not required because no other machine participates.
disposition RequestKickoffQuiesce => local seam NoOwnerRealization,
disposition RequestPendingSpawnQuiesceForDestroy => local seam NoOwnerRealization,
disposition MemberAdmissionProbed => local seam SurfaceResultAlignment,
disposition RespawnGenerationComputed => local seam SurfaceResultAlignment,
disposition StepOutputFaultClassified => local seam SurfaceResultAlignment,
disposition SupervisorEscalationRequested => external seam OwnerRealizationOnly,
disposition SupervisorEscalationFailed => local seam SurfaceResultAlignment,
disposition TopologyEdgeVerdictResolved => local seam SurfaceResultAlignment,
disposition TurnTimeoutDispositionClassified => local seam SurfaceResultAlignment,
disposition MemberSpawnRequired => external seam OwnerRealizationOnly,
disposition MemberRetainRequired => local seam SurfaceResultAlignment,
disposition MemberRetireRequired => external seam OwnerRealizationOnly,
disposition AutonomousShutdownMemberActionResolved => local seam SurfaceResultAlignment,
disposition SpawnPolicyResolutionRecorded => local seam NoOwnerRealization,
disposition OwnerBridgeSessionBound => local seam SurfaceResultAlignment,
disposition RespawnTopologyRestoreResolved => local seam SurfaceResultAlignment,
disposition MemberLiveMaterializationClassified => local seam SurfaceResultAlignment,
disposition SpawnManyFailureClassified => local seam SurfaceResultAlignment,
disposition MemberWaitClassified => local seam SurfaceResultAlignment,
disposition FlowDelegationEdgeAdmissionResolved => local seam SurfaceResultAlignment,
disposition RemoteMemberRuntimeTerminalityClassified => local seam SurfaceResultAlignment,
disposition SpawnMemberAdmissionResolved => local seam SurfaceResultAlignment,
disposition CurrentMobAdmissionResolved => local seam SurfaceResultAlignment,
disposition SpawnToolAdmissionResolved => local seam SurfaceResultAlignment,
disposition CreateMobAdmissionResolved => local seam SurfaceResultAlignment,
disposition ProfileMutationAdmissionResolved => local seam SurfaceResultAlignment,
disposition MemberOperationEligibilityResolved => local seam SurfaceResultAlignment,
disposition RetirePendingSpawnCancellationAuthorized => local seam SurfaceResultAlignment,
disposition RetireCommittedIncarnationWithoutPendingSpawnResolved => local seam SurfaceResultAlignment,
disposition RetireAbsentPendingSpawnPreservationResolved => local seam SurfaceResultAlignment,
disposition BridgeRejectionRecoveryClassified => local seam SurfaceResultAlignment,
disposition PendingSupervisorAcceptanceClassified => local seam SurfaceResultAlignment,
disposition IdentityReconciliationClassified => local seam SurfaceResultAlignment,
disposition FrameSeedConfirmed => local seam SurfaceResultAlignment,
disposition WiringGraphChanged => external seam SurfaceResultAlignment,
disposition MemberSessionBindingChanged => external seam SurfaceResultAlignment,
disposition SessionProvisionOperationOwnerAuthorized => local seam NoOwnerRealization,
disposition MemberTrustWiringRequested => external handoff mob_member_trust_wiring seam OwnerRealizationOnly,
disposition MemberTrustUnwiringRequested => external handoff mob_member_trust_unwiring seam OwnerRealizationOnly,
disposition WiringTrustRepairRequested => local seam NoOwnerRealization,
disposition ExternalPeerTrustWiringRequested => external handoff mob_external_peer_trust_wiring seam OwnerRealizationOnly,
disposition ExternalPeerTrustUnwiringRequested => external handoff mob_external_peer_trust_unwiring seam OwnerRealizationOnly,
disposition ExternalPeerTrustRepairRequested => external handoff mob_external_peer_trust_repair seam OwnerRealizationOnly,
disposition MemberPeerRegistered => local seam NoOwnerRealization,
disposition MemberPeerRebindAuthorized => local seam NoOwnerRealization,
disposition MemberPeerOverlayAuthorized => external handoff mob_member_peer_overlay seam OwnerRealizationOnly,
disposition ExternalPeerReciprocalTrustRequested => external handoff mob_external_peer_reciprocal_trust seam OwnerRealizationOnly,
disposition PersistSupervisorAuthority => local seam SurfaceResultAlignment,
disposition DeleteSupervisorAuthority => local seam SurfaceResultAlignment,
disposition EmitWiringLifecycleNotice => external seam SurfaceResultAlignment,
disposition EmitExternalPeerWiringLifecycleNotice => external seam SurfaceResultAlignment,
disposition AuthorizeAgentEventSubscription => local seam SurfaceResultAlignment,
disposition RejectAgentEventSubscription => local seam SurfaceResultAlignment,
disposition AuthorizeAllAgentEventSubscription => local seam SurfaceResultAlignment,
disposition RejectAllAgentEventSubscription => local seam SurfaceResultAlignment,
disposition AuthorizeMobEventRouter => local seam SurfaceResultAlignment,
disposition AuthorizeMobEventRouterMemberSubscription => local seam SurfaceResultAlignment,
disposition AuthorizeMobEventRouterMemberRemoval => local seam SurfaceResultAlignment,
disposition AuthorizeStructuralEventSubscription => local seam SurfaceResultAlignment,
disposition RejectStructuralEventSubscription => local seam SurfaceResultAlignment,
disposition AuthorizeStrictEventPoll => local seam SurfaceResultAlignment,
disposition RejectStrictEventPoll => local seam SurfaceResultAlignment,
disposition WorkIntentRecorded => local seam NoOwnerRealization,
disposition ResourceClaimRecorded => local seam NoOwnerRealization,
disposition WorkIntentStatusChanged => local seam NoOwnerRealization,
disposition ResourceClaimStatusChanged => local seam NoOwnerRealization,
disposition ResourceClaimOverlapObserved => local seam NoOwnerRealization,
disposition AdaptiveRunInitialized => local seam NoOwnerRealization,
disposition AdaptivePlanningDecisionRecorded => local seam NoOwnerRealization,
disposition AdaptivePlanRejected => local seam NoOwnerRealization,
disposition AdaptiveLayerAdmissionResolved => local seam SurfaceResultAlignment,
disposition AdaptiveLayerProvisioned => local seam NoOwnerRealization,
disposition AdaptiveLayerRunStarted => local seam NoOwnerRealization,
disposition AdaptiveLayerTerminalIngested => local seam NoOwnerRealization,
disposition AdaptiveLayerSetupFaultRecorded => local seam NoOwnerRealization,
disposition AdaptiveLayerInterrupted => local seam NoOwnerRealization,
disposition AdaptiveLayerResultValidated => local seam NoOwnerRealization,
disposition AdaptiveLayerResultInvalid => local seam NoOwnerRealization,
disposition AdaptiveLayerCleanupObserved => local seam NoOwnerRealization,
disposition AdaptiveCleanupResolved => local seam NoOwnerRealization,
disposition AdaptiveBodyEvidenceMissing => local seam NoOwnerRealization,
disposition AdaptiveRunTerminalized => local seam SurfaceResultAlignment,
// Multi-host: cross-process bridge requests follow the
// EscalateSupervisor precedent (external, OwnerRealizationOnly, no
// handoff protocol). A named handoff protocol requires a composition
// EffectHandoffProtocol + generated extractor module whose realizing
// owner (the bridge dispatcher / host daemon) lands in phases 2-3 —
// the protocol upgrade lands in the same change-set as that owner.
disposition RequestHostBind => external seam OwnerRealizationOnly,
disposition HostRegistered => external seam SurfaceResultAlignment,
disposition HostReboundRecorded => external seam SurfaceResultAlignment,
disposition HostCapabilitiesRefreshed => external seam SurfaceResultAlignment,
disposition HostRevoked => external seam SurfaceResultAlignment,
disposition PersistPendingPlacedSpawn => local seam OwnerRealizationOnly,
disposition RequestMemberMaterialization => external seam OwnerRealizationOnly,
disposition CommitPlacedSpawnCarrier => local seam OwnerRealizationOnly,
disposition PromoteCommittedPlacedSpawnCarrierBinding => local seam OwnerRealizationOnly,
disposition PlacedCarrierCleanupRequested => local seam OwnerRealizationOnly,
disposition PlacedCarrierCleanupAuthorized => local seam OwnerRealizationOnly,
disposition PlacedCarrierCleanupResolved => local seam SurfaceResultAlignment,
disposition RequestMemberRelease => external seam OwnerRealizationOnly,
disposition RouteInstallRequested => external seam OwnerRealizationOnly,
disposition MemberOperatorAdmitted => local seam SurfaceResultAlignment,
disposition MemberOperatorRejected => local seam SurfaceResultAlignment,
disposition FlowStepDispatchClassified => local seam SurfaceResultAlignment,
disposition AuthorizeExternalAgentEventSubscription => local seam SurfaceResultAlignment,
disposition GrantRecorded => local seam SurfaceResultAlignment,
disposition GrantRevoked => local seam SurfaceResultAlignment,
// =====================================================================
// Invariants
// =====================================================================
// W3-H / dogma #4: "no zombie realtime binding" — every identity that
// has a bound session must also appear in `identity_to_runtime` (i.e.
// must be an identity MobMachine has spawned). Ensures the binding map
// cannot reference identities the machine has never admitted. Paired
// with the Retire transition's `member_session_bindings.remove` and
// Spawn's guard/state consistency: keys(bindings) ⊆ keys(identity_to_runtime).
invariant bindings_require_known_identity {
for_all(id in self.member_session_bindings.keys(), self.identity_to_runtime.contains_key(id))
}
invariant placed_spawn_pending_attempt_is_complete {
for_all(id in self.pending_placed_spawn_ids.keys(),
self.pending_placed_spawn_generations.contains_key(id)
&& self.pending_placed_spawn_fence_tokens.contains_key(id)
&& self.pending_placed_spawn_hosts.contains_key(id)
&& self.pending_placed_spawn_host_binding_generations.contains_key(id)
&& self.pending_placed_spawn_spec_digests.contains_key(id)
&& self.pending_placed_spawn_provision_operation_ids.contains_key(id)
&& self.pending_placed_spawn_operation_owner_session_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_generations.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_fence_tokens.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_hosts.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_host_binding_generations.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_spec_digests.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_provision_operation_ids.keys(), self.pending_placed_spawn_ids.contains_key(id))
&& for_all(id in self.pending_placed_spawn_operation_owner_session_ids.keys(), self.pending_placed_spawn_ids.contains_key(id))
}
invariant pending_autonomous_placed_spawn_is_an_exact_pending_attempt {
for_all(id in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_ids.contains_key(id)
&& self.pending_placed_spawn_hosts.contains_key(id))
}
invariant placed_spawn_committed_attempt_is_complete {
for_all(id in self.current_placed_spawn_ids.keys(),
self.current_placed_spawn_host_binding_generations.contains_key(id)
&& self.current_placed_spawn_host_binding_generations.get_copied(id).get("value") > 0
&& self.current_placed_spawn_provision_operation_ids.contains_key(id)
&& self.current_placed_spawn_operation_owner_session_ids.contains_key(id))
&& for_all(id in self.current_placed_spawn_host_binding_generations.keys(), self.current_placed_spawn_ids.contains_key(id))
&& for_all(id in self.current_placed_spawn_provision_operation_ids.keys(), self.current_placed_spawn_ids.contains_key(id))
&& for_all(id in self.current_placed_spawn_operation_owner_session_ids.keys(), self.current_placed_spawn_ids.contains_key(id))
}
invariant placed_spawn_attempt_is_not_both_pending_and_committed {
for_all(id in self.pending_placed_spawn_ids.keys(), self.current_placed_spawn_ids.contains_key(id) == false)
}
invariant identity_runtime_history_is_coherent {
for_all(id in self.identity_runtime_generations.keys(), self.identity_runtime_fence_tokens.contains_key(id))
&& for_all(id in self.identity_runtime_generations.keys(), self.member_profile_names.contains_key(id))
&& for_all(id in self.identity_runtime_generations.keys(), self.member_runtime_modes.contains_key(id))
&& for_all(id in self.identity_runtime_fence_tokens.keys(), self.identity_runtime_generations.contains_key(id))
&& for_all(id in self.member_profile_names.keys(), self.identity_runtime_generations.contains_key(id))
&& for_all(id in self.member_runtime_modes.keys(), self.identity_runtime_generations.contains_key(id))
}
// `identity_to_runtime` is current membership, while the four maps
// above are the durable incarnation high-water history used to mint
// and fence a later generation. Every current binding therefore has
// history, but a fully retired identity intentionally has history
// without a current binding.
invariant current_runtime_binding_has_history {
for_all(id in self.identity_to_runtime.keys(), self.member_profile_names.contains_key(id))
&& for_all(id in self.identity_to_runtime.keys(), self.member_runtime_modes.contains_key(id))
&& for_all(id in self.identity_to_runtime.keys(), self.identity_runtime_generations.contains_key(id))
&& for_all(id in self.identity_to_runtime.keys(), self.identity_runtime_fence_tokens.contains_key(id))
}
invariant pending_respawn_topology_has_no_current_runtime {
for_all(id in self.pending_respawn_topology,
self.identity_to_runtime.contains_key(id) == false
|| self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(id).get("value")) == Some(MobMemberState::Retiring))
}
invariant member_peer_endpoint_material_is_coherent {
for_all(id in self.member_peer_ids.keys(), self.member_peer_endpoints.contains_key(id))
&& for_all(id in self.member_peer_endpoints.keys(), self.member_peer_ids.contains_key(id))
&& for_all(id in self.member_peer_endpoints.keys(),
self.member_peer_ids.get_cloned(id) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(id).get("value"))))
}
invariant member_prior_peer_endpoints_are_generation_scoped {
for_all(id in self.member_prior_peer_endpoints.keys(),
self.identity_to_runtime.contains_key(id)
&& self.member_peer_endpoints.contains_key(id)
&& self.member_prior_peer_endpoints.get_cloned(id).get("value") != EmptySet
&& for_all(prior_endpoint in self.member_prior_peer_endpoints.get_cloned(id).get("value"),
mob_machine_member_peer_endpoint_peer_id(prior_endpoint) != mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(id).get("value"))
&& for_all(host in self.mob_hosts,
mob_machine_host_id_matches_peer_id(
host,
mob_machine_member_peer_endpoint_peer_id(prior_endpoint)
) == false)))
}
invariant member_peer_id_ownership_is_global_across_generations {
for_all(id in self.member_peer_endpoints.keys(),
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
id,
self.member_peer_endpoints.get_cloned(id).get("value")))
&& for_all(id in self.member_prior_peer_endpoints.keys(),
for_all(prior_endpoint in self.member_prior_peer_endpoints.get_cloned(id).get("value"),
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
id,
prior_endpoint)))
}
invariant pending_session_ingress_detach_has_session_correlation {
for_all(agent_runtime_id in self.pending_session_ingress_detach_runtime_ids,
self.runtime_retire_pending_sessions.contains_key(agent_runtime_id))
}
invariant remote_runtime_retired_is_still_retiring {
for_all(agent_runtime_id in self.remote_runtime_retired_ids,
self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring))
}
invariant remote_supervisor_revoked_has_retired_runtime_anchor {
for_all(agent_runtime_id in self.remote_supervisor_revoked_ids,
self.remote_runtime_retired_ids.contains(agent_runtime_id) == true
&& self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring))
}
// Spawn-exec phase ladder: once a spawn-exec has committed membership
// (phase == MembershipCommitted), the identity must already appear in
// identity_to_runtime (the membership commit inserts it in the same
// atomic step). The Opened phase precedes the membership commit, so it
// is exempt. This documents + verifies the ladder's commit ordering; it
// is NOT a duplicate of bindings_require_known_identity (which keys off
// member_session_bindings, not the spawn_exec phase).
invariant spawn_exec_membership_commit_requires_runtime {
for_all(id in self.spawn_exec_phase.keys(),
self.spawn_exec_phase.get_cloned(id) != Some(SpawnExecPhase::MembershipCommitted)
|| self.identity_to_runtime.contains_key(id))
}
invariant external_peer_edges_are_keyed_coherently {
for_all(key in self.external_peer_edges_by_key.keys(),
mob_machine_external_peer_key_matches_edge(key, self.external_peer_edges_by_key.get_cloned(key).get("value"))
&& self.external_peer_edges.contains(self.external_peer_edges_by_key.get_cloned(key).get("value")))
&& for_all(edge in self.external_peer_edges,
mob_machine_external_peer_edge_has_matching_key(self.external_peer_edges_by_key, edge))
}
invariant supervisor_authority_tuple_consistent {
(
self.supervisor_authority_peer_id == None
&& self.supervisor_authority_signing_key == None
&& self.supervisor_authority_epoch == None
&& self.supervisor_authority_protocol_version == None
)
|| (
self.supervisor_authority_peer_id != None
&& self.supervisor_authority_signing_key != None
&& self.supervisor_authority_epoch != None
&& self.supervisor_authority_protocol_version != None
)
}
invariant supervisor_pending_authority_tuple_consistent {
(
self.supervisor_pending_authority_peer_id == None
&& self.supervisor_pending_authority_signing_key == None
&& self.supervisor_pending_authority_epoch == None
&& self.supervisor_pending_authority_protocol_version == None
&& self.supervisor_pending_authority_operation_id == None
&& self.supervisor_pending_authority_accepted_peer_ids == EmptySet
&& self.supervisor_pending_authority_member_target_names == EmptyMap
&& self.supervisor_pending_authority_member_target_addresses == EmptyMap
)
|| (
self.supervisor_pending_authority_peer_id != None
&& self.supervisor_pending_authority_signing_key != None
&& self.supervisor_pending_authority_epoch != None
&& self.supervisor_pending_authority_protocol_version != None
)
}
invariant supervisor_pending_authority_member_targets_aligned {
self.supervisor_pending_authority_member_target_names.keys()
== self.supervisor_pending_authority_member_target_addresses.keys()
}
invariant supervisor_pending_authority_acceptance_has_target {
self.supervisor_pending_authority_operation_id == None
|| for_all(peer_id in self.supervisor_pending_authority_accepted_peer_ids,
self.supervisor_pending_authority_member_target_names.contains_key(peer_id)
&& self.supervisor_pending_authority_member_target_addresses.contains_key(peer_id))
}
invariant supervisor_pending_authority_requires_current {
self.supervisor_pending_authority_peer_id == None
|| self.supervisor_authority_peer_id != None
}
invariant owner_bridge_cleanup_requires_owner {
self.owner_bridge_destroy_on_archive == false
|| self.owner_bridge_session_id != None
}
invariant implicit_delegation_requires_owner {
self.implicit_delegation_mob == false
|| self.owner_bridge_session_id != None
}
invariant implicit_delegation_requires_cleanup {
self.implicit_delegation_mob == false
|| self.owner_bridge_destroy_on_archive == true
}
// RevokeHost deliberately KEEPS placement entries for the revival
// ladder. A replacement request stays in the disjoint request maps,
// leaving phase absent until CommitHostBind restores Bound.
invariant placement_never_targets_half_bound_host {
for_all(id in self.member_placement.keys(),
self.host_bind_phase.contains_key(self.member_placement.get_cloned(id).get("value")) == false
|| self.host_bind_phase.get_cloned(self.member_placement.get_cloned(id).get("value")) == Some(HostBindPhase::Bound))
}
// §19.L5: the legacy ops-owner None-skip never applies to placed
// members — remote placement requires the owner bridge session. The
// contains_key conjunct is tautological over keys(); it keeps the
// quantifier binding used so generated guard code stays lint-clean.
invariant placed_members_require_owner_bridge {
for_all(id in self.member_placement.keys(),
self.member_placement.contains_key(id) && self.owner_bridge_session_id != None)
}
// §16 DL5: live capability exists only for currently-bound hosts.
invariant live_endpoints_subset_of_bound_hosts {
for_all(host in self.host_live_endpoints.keys(),
self.host_bind_phase.get_cloned(host) == Some(HostBindPhase::Bound))
}
// Bound-host record completeness: mob_hosts membership, the epoch
// map, and every capability map share the same key set.
invariant host_epochs_present_for_hosts {
for_all(host in self.mob_hosts, self.host_authority_epochs.contains_key(host))
&& for_all(host in self.host_authority_epochs.keys(), self.mob_hosts.contains(host))
}
invariant host_binding_generations_cover_tracked_hosts {
for_all(host in self.host_bind_phase.keys(),
self.host_binding_generations.contains_key(host)
&& self.host_binding_generation_highwater.contains_key(host)
&& self.host_binding_generation_highwater.get_copied(host).get("value")
>= self.host_binding_generations.get_copied(host).get("value"))
&& for_all(host in self.host_binding_generations.keys(),
self.host_bind_phase.contains_key(host))
}
invariant replacement_host_bind_requests_are_exact_and_disjoint {
for_all(host in self.replacement_host_bind_endpoints.keys(),
self.replacement_host_binding_generations.contains_key(host)
&& self.host_bind_phase.contains_key(host) == false
&& self.host_binding_generations.contains_key(host) == false
&& self.host_binding_generation_highwater.contains_key(host)
&& self.host_binding_generation_highwater.get_copied(host)
== self.replacement_host_binding_generations.get_copied(host))
&& for_all(host in self.replacement_host_binding_generations.keys(),
self.replacement_host_bind_endpoints.contains_key(host))
}
invariant host_capability_maps_cover_bound_hosts {
for_all(host in self.mob_hosts,
self.host_public_keys.contains_key(host)
&& self.host_endpoints.contains_key(host)
&& self.host_protocol_min.contains_key(host)
&& self.host_protocol_max.contains_key(host)
&& self.host_engine_versions.contains_key(host)
&& self.host_durable_sessions.contains_key(host)
&& self.host_autonomous_members.contains_key(host)
&& self.host_hard_cancel_member.contains_key(host)
&& self.host_tracked_input_cancel.contains_key(host)
&& self.host_memory_store.contains_key(host)
&& self.host_mcp.contains_key(host)
&& self.host_resolvable_providers.contains_key(host)
&& self.host_approval_forwarding.contains_key(host))
&& for_all(host in self.host_public_keys.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_endpoints.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_protocol_min.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_protocol_max.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_engine_versions.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_durable_sessions.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_autonomous_members.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_hard_cancel_member.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_tracked_input_cancel.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_memory_store.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_mcp.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_resolvable_providers.keys(), self.mob_hosts.contains(host))
&& for_all(host in self.host_approval_forwarding.keys(), self.mob_hosts.contains(host))
}
// §6.1: a remote member whose roster truth was published (session
// binding present) carries the ack-derived peer endpoint.
invariant remote_committed_members_have_peer_endpoints {
for_all(id in self.member_placement.keys(),
self.member_session_bindings.contains_key(id) == false
|| self.member_peer_endpoints.contains_key(id))
}
// A peer id is the routing/authentication identity. Addresses may be
// shared by a multiplexing host, but one live peer id must never route
// two distinct mob identities.
invariant live_member_peer_ids_are_unique {
for_all(id in self.member_peer_endpoints.keys(),
for_all(other in self.member_peer_endpoints.keys(),
id == other
|| mob_machine_member_peer_endpoint_peer_id(
self.member_peer_endpoints.get_cloned(id).get("value")
) != mob_machine_member_peer_endpoint_peer_id(
self.member_peer_endpoints.get_cloned(other).get("value")
)))
}
invariant live_member_peer_ids_are_disjoint_from_hosts {
for_all(id in self.member_peer_endpoints.keys(),
for_all(host in self.mob_hosts,
mob_machine_host_id_matches_peer_id(
host,
mob_machine_member_peer_endpoint_peer_id(
self.member_peer_endpoints.get_cloned(id).get("value")
)
) == false))
}
invariant remote_turn_custody_sets_are_pairwise_disjoint {
for_all(obligation in self.pending_remote_turn_outcomes,
self.committed_remote_turn_outcomes.contains(obligation) == false
&& self.resolved_remote_turn_outcomes.contains(obligation) == false)
&& for_all(obligation in self.committed_remote_turn_outcomes,
self.resolved_remote_turn_outcomes.contains(obligation) == false)
}
invariant placed_completion_custody_is_well_partitioned {
for_all(obligation in self.pending_placed_completion_outcomes,
self.resolved_placed_completion_outcomes.contains(obligation) == false)
&& for_all(obligation in self.cancel_requested_placed_completion_outcomes,
self.pending_placed_completion_outcomes.contains(obligation) == true)
}
invariant placed_completion_lifecycle_intent_matches_quiesce {
(self.placed_completion_lifecycle_quiescing == true
&& self.placed_completion_lifecycle_intent != None)
|| (self.placed_completion_lifecycle_quiescing == false
&& self.placed_completion_lifecycle_intent == None)
}
invariant placed_completion_lifecycle_intent_owns_no_adaptive_custody {
self.placed_completion_lifecycle_quiescing == false
|| mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
invariant placed_completion_custody_is_input_and_sequence_injective {
for_all(left in self.pending_placed_completion_outcomes,
for_all(right in self.pending_placed_completion_outcomes,
left == right
|| (left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id))))
&& for_all(left in self.resolved_placed_completion_outcomes,
for_all(right in self.resolved_placed_completion_outcomes,
left == right
|| (left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id))))
&& for_all(left in self.pending_placed_completion_outcomes,
for_all(right in self.resolved_placed_completion_outcomes,
left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id)))
}
invariant placed_kickoff_custody_sets_are_disjoint {
for_all(obligation in self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes.contains(obligation) == false)
}
invariant placed_kickoff_custody_is_identity_and_input_injective {
for_all(left in self.pending_placed_kickoff_outcomes,
for_all(right in self.pending_placed_kickoff_outcomes,
left == right
|| left.agent_identity != right.agent_identity))
&& for_all(left in self.resolved_placed_kickoff_outcomes,
for_all(right in self.resolved_placed_kickoff_outcomes,
left == right
|| left.agent_identity != right.agent_identity))
&& for_all(left in self.pending_placed_kickoff_outcomes,
for_all(right in self.resolved_placed_kickoff_outcomes,
left.agent_identity != right.agent_identity))
}
invariant retained_placed_kickoff_correlations_are_injective_and_live {
for_all(identity in self.member_kickoff_input_ids.keys(),
self.retained_placed_kickoff_obligations.contains_key(identity)
&& self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id
== self.member_kickoff_input_ids.get_cloned(identity).get("value")
&& self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").objective_id
== self.member_kickoff_objective_ids.get_cloned(identity).get("value")
&& self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").agent_identity
== identity
&& (
self.member_kickoff_starting.contains(identity)
|| self.member_kickoff_callback_pending.contains(identity)
|| self.member_kickoff_started.contains(identity)
|| self.member_kickoff_failed.contains(identity)
|| self.member_kickoff_cancelled.contains(identity)))
&& for_all(identity in self.retained_placed_kickoff_obligations.keys(),
self.member_kickoff_input_ids.contains_key(identity))
&& for_all(identity in self.member_placed_kickoff_outcome_kinds.keys(),
self.retained_placed_kickoff_obligations.contains_key(identity))
&& for_all(identity in self.member_placed_kickoff_outcome_errors.keys(),
self.member_placed_kickoff_outcome_kinds.get_cloned(identity) == Some(PlacedKickoffOutcomeKind::Failed)
|| self.member_placed_kickoff_outcome_kinds.get_cloned(identity) == Some(PlacedKickoffOutcomeKind::RejectedNoEffect))
&& for_all(identity in self.member_placed_kickoff_closure_kinds.keys(),
self.retained_placed_kickoff_obligations.contains_key(identity)
&& (
(self.member_placed_kickoff_closure_kinds.get_cloned(identity) == Some(PlacedKickoffClosureKind::Acknowledged)
&& self.member_placed_kickoff_outcome_kinds.get_cloned(identity) != Some(PlacedKickoffOutcomeKind::RejectedNoEffect)
&& self.member_placed_kickoff_outcome_kinds.get_cloned(identity) != Some(PlacedKickoffOutcomeKind::Disposed))
|| self.member_placed_kickoff_closure_kinds.get_cloned(identity) == Some(PlacedKickoffClosureKind::Disposed)
|| (self.member_placed_kickoff_closure_kinds.get_cloned(identity) == Some(PlacedKickoffClosureKind::RejectedNoEffect)
&& self.member_placed_kickoff_outcome_kinds.get_cloned(identity) == Some(PlacedKickoffOutcomeKind::RejectedNoEffect))))
}
invariant placed_kickoff_and_flow_correlations_are_disjoint {
for_all(kickoff in self.pending_placed_kickoff_outcomes,
for_all(turn in self.pending_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id))
&& for_all(kickoff in self.resolved_placed_kickoff_outcomes,
for_all(turn in self.pending_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
kickoff.agent_identity != turn.agent_identity || kickoff.host_id != turn.host_id
|| kickoff.generation != turn.generation || kickoff.fence_token != turn.fence_token || kickoff.input_id != turn.input_id))
&& for_all(identity in self.retained_placed_kickoff_obligations.keys(),
for_all(turn in self.pending_remote_turn_outcomes,
identity != turn.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != turn.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != turn.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != turn.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != turn.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
identity != turn.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != turn.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != turn.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != turn.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != turn.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
identity != turn.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != turn.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != turn.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != turn.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != turn.input_id))
}
invariant placed_completion_correlations_are_disjoint {
for_all(completion in self.pending_placed_completion_outcomes,
for_all(turn in self.pending_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(kickoff in self.pending_placed_kickoff_outcomes,
completion.agent_identity != kickoff.agent_identity
|| completion.host_id != kickoff.host_id
|| completion.generation != kickoff.generation
|| completion.fence_token != kickoff.fence_token
|| completion.input_id != kickoff.input_id)
&& for_all(kickoff in self.resolved_placed_kickoff_outcomes,
completion.agent_identity != kickoff.agent_identity
|| completion.host_id != kickoff.host_id
|| completion.generation != kickoff.generation
|| completion.fence_token != kickoff.fence_token
|| completion.input_id != kickoff.input_id)
&& for_all(identity in self.retained_placed_kickoff_obligations.keys(),
identity != completion.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != completion.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != completion.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != completion.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != completion.input_id))
&& for_all(completion in self.resolved_placed_completion_outcomes,
for_all(turn in self.pending_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
completion.agent_identity != turn.agent_identity
|| completion.host_id != turn.host_id
|| completion.generation != turn.generation
|| completion.fence_token != turn.fence_token
|| completion.input_id != turn.input_id)
&& for_all(kickoff in self.pending_placed_kickoff_outcomes,
completion.agent_identity != kickoff.agent_identity
|| completion.host_id != kickoff.host_id
|| completion.generation != kickoff.generation
|| completion.fence_token != kickoff.fence_token
|| completion.input_id != kickoff.input_id)
&& for_all(kickoff in self.resolved_placed_kickoff_outcomes,
completion.agent_identity != kickoff.agent_identity
|| completion.host_id != kickoff.host_id
|| completion.generation != kickoff.generation
|| completion.fence_token != kickoff.fence_token
|| completion.input_id != kickoff.input_id)
&& for_all(identity in self.retained_placed_kickoff_obligations.keys(),
identity != completion.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != completion.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != completion.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != completion.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != completion.input_id))
}
invariant pending_route_ledger_is_install_only {
for_all(obligation in self.pending_route_installs,
obligation.kind == RouteObligationKind::Install)
}
invariant remote_turn_custody_requires_exact_current_placement {
for_all(obligation in self.pending_remote_turn_outcomes,
self.member_placement.contains_key(obligation.agent_identity)
&& self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token))
&& for_all(obligation in self.committed_remote_turn_outcomes,
self.member_placement.contains_key(obligation.agent_identity)
&& self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token))
&& for_all(obligation in self.resolved_remote_turn_outcomes,
self.member_placement.contains_key(obligation.agent_identity)
&& self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token))
}
invariant placed_completion_custody_requires_exact_current_placement {
for_all(obligation in self.pending_placed_completion_outcomes,
self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token))
&& for_all(obligation in self.resolved_placed_completion_outcomes,
self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token))
}
invariant placed_kickoff_custody_requires_exact_current_placement {
for_all(obligation in self.pending_placed_kickoff_outcomes,
self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token)
&& self.member_runtime_modes.get_cloned(obligation.agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
&& self.member_kickoff_objective_ids.get_cloned(obligation.agent_identity) == Some(obligation.objective_id)
&& self.member_kickoff_input_ids.get_cloned(obligation.agent_identity) == Some(obligation.input_id)
&& self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation)
&& (self.member_kickoff_starting.contains(obligation.agent_identity)
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)))
&& for_all(obligation in self.resolved_placed_kickoff_outcomes,
self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id)
&& self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
&& self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
&& self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id)
&& self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation)
&& self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token)
&& self.member_runtime_modes.get_cloned(obligation.agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
&& self.member_kickoff_objective_ids.get_cloned(obligation.agent_identity) == Some(obligation.objective_id)
&& self.member_kickoff_input_ids.get_cloned(obligation.agent_identity) == Some(obligation.input_id)
&& self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation)
&& self.member_placed_kickoff_outcome_kinds.contains_key(obligation.agent_identity)
&& (self.member_kickoff_started.contains(obligation.agent_identity)
|| self.member_kickoff_callback_pending.contains(obligation.agent_identity)
|| self.member_kickoff_failed.contains(obligation.agent_identity)
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)))
}
invariant remote_turn_custody_sequences_are_bounded_and_injective {
for_all(obligation in self.pending_remote_turn_outcomes,
obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence)
&& for_all(obligation in self.committed_remote_turn_outcomes,
obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence)
&& for_all(obligation in self.resolved_remote_turn_outcomes,
obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence)
&& for_all(left in self.pending_remote_turn_outcomes,
for_all(right in self.pending_remote_turn_outcomes,
left == right
|| (left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id))))
&& for_all(left in self.committed_remote_turn_outcomes,
for_all(right in self.committed_remote_turn_outcomes,
left == right
|| (left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id))))
&& for_all(left in self.resolved_remote_turn_outcomes,
for_all(right in self.resolved_remote_turn_outcomes,
left == right
|| (left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id))))
&& for_all(left in self.pending_remote_turn_outcomes,
for_all(right in self.committed_remote_turn_outcomes,
left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id)))
&& for_all(left in self.pending_remote_turn_outcomes,
for_all(right in self.resolved_remote_turn_outcomes,
left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id)))
&& for_all(left in self.committed_remote_turn_outcomes,
for_all(right in self.resolved_remote_turn_outcomes,
left.dispatch_sequence != right.dispatch_sequence
&& (left.agent_identity != right.agent_identity
|| left.host_id != right.host_id
|| left.generation != right.generation
|| left.fence_token != right.fence_token
|| left.input_id != right.input_id)))
}
invariant placed_completion_sequences_are_bounded {
for_all(obligation in self.pending_placed_completion_outcomes,
obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence)
&& for_all(obligation in self.resolved_placed_completion_outcomes,
obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence)
}
// =====================================================================
// Direct transitions
// =====================================================================
transition ClassifyFlowRunTerminalityTerminal {
per_phase [Running]
on input ClassifyFlowRunTerminality { run_id, status }
guard "run_status_terminal" {
status == FlowRunStatus::Completed
|| status == FlowRunStatus::Failed
|| status == FlowRunStatus::Canceled
}
update {}
to Running
emit FlowRunTerminal { run_id: run_id }
}
transition ClassifyFlowRunTerminalityNonTerminal {
per_phase [Running]
on input ClassifyFlowRunTerminality { run_id, status }
guard "run_status_non_terminal" {
status == FlowRunStatus::Absent
|| status == FlowRunStatus::Pending
|| status == FlowRunStatus::Running
}
update {}
to Running
emit FlowRunNonTerminal { run_id: run_id }
}
transition ClassifyFlowStepTerminalityTerminal {
per_phase [Running]
on input ClassifyFlowStepTerminality { run_id, step_id, status }
guard "step_status_terminal" {
status == StepRunStatus::Completed
|| status == StepRunStatus::Failed
|| status == StepRunStatus::Skipped
|| status == StepRunStatus::Canceled
}
update {}
to Running
emit FlowStepTerminal { run_id: run_id, step_id: step_id }
}
transition ClassifyFlowStepTerminalityNonTerminal {
per_phase [Running]
on input ClassifyFlowStepTerminality { run_id, step_id, status }
guard "step_status_non_terminal" { status == StepRunStatus::Dispatched }
update {}
to Running
emit FlowStepNonTerminal { run_id: run_id, step_id: step_id }
}
transition ClassifyFlowFrameTerminalStatusFailed {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowFrameTerminalStatus { frame_id }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_tracked_nodes_known" { self.frame_tracked_nodes.contains_key(frame_id) == true }
guard "frame_node_status_known" { self.frame_node_status.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "all_nodes_terminal" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Failed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Skipped)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Canceled))
}
guard "any_node_failed" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed)) == false
}
update {}
to Running
emit FlowFrameTerminalStatusClassified {
frame_id: frame_id,
terminal_status: FrameStatus::Failed
}
}
transition ClassifyFlowFrameTerminalStatusCanceled {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowFrameTerminalStatus { frame_id }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_tracked_nodes_known" { self.frame_tracked_nodes.contains_key(frame_id) == true }
guard "frame_node_status_known" { self.frame_node_status.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "all_nodes_terminal" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Failed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Skipped)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Canceled))
}
guard "no_node_failed" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed))
}
guard "any_node_canceled" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Canceled)) == false
}
update {}
to Running
emit FlowFrameTerminalStatusClassified {
frame_id: frame_id,
terminal_status: FrameStatus::Canceled
}
}
transition ClassifyFlowFrameTerminalStatusCompleted {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowFrameTerminalStatus { frame_id }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_tracked_nodes_known" { self.frame_tracked_nodes.contains_key(frame_id) == true }
guard "frame_node_status_known" { self.frame_node_status.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "all_nodes_terminal" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Failed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Skipped)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Canceled))
}
guard "no_node_failed" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed))
}
guard "no_node_canceled" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Canceled))
}
update {}
to Running
emit FlowFrameTerminalStatusClassified {
frame_id: frame_id,
terminal_status: FrameStatus::Completed
}
}
transition ClassifyFlowFrameTerminalStatusUnavailable {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowFrameTerminalStatus { frame_id }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_tracked_nodes_known" { self.frame_tracked_nodes.contains_key(frame_id) == true }
guard "frame_node_status_known" { self.frame_node_status.contains_key(frame_id) == true }
guard "terminal_status_unavailable" {
self.frame_phase.get_cloned(frame_id) != Some(FrameStatus::Running)
|| for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Failed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Skipped)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Canceled)) == false
}
update {}
to Running
emit FlowFrameTerminalStatusUnavailable { frame_id: frame_id }
}
transition ClassifyFlowRunPublicResultSuccess {
per_phase [Running]
on input ClassifyFlowRunPublicResult { run_id, status }
guard "run_status_success" { status == FlowRunStatus::Completed }
update {}
to Running
emit FlowRunPublicResultClassified {
run_id: run_id,
result: FlowRunPublicResultClassKind::Success
}
}
transition ClassifyFlowRunPublicResultFailure {
per_phase [Running]
on input ClassifyFlowRunPublicResult { run_id, status }
guard "run_status_failure" {
status == FlowRunStatus::Failed
|| status == FlowRunStatus::Canceled
}
update {}
to Running
emit FlowRunPublicResultClassified {
run_id: run_id,
result: FlowRunPublicResultClassKind::Failure
}
}
transition ClassifyMemberWaitRuntimeMaterialPresentRunning {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_material_present" {
self.identity_runtime_generations.contains_key(agent_identity) == true
&& self.identity_runtime_fence_tokens.contains_key(agent_identity) == true
}
update {}
to Running
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::RuntimeMaterialPresent }
}
transition ObserveMemberProgressChangedOpen {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_changed" { self.member_progress_tokens.get_cloned(agent_identity) != Some(progress_token) }
guard "run_open" { run_open == true }
update {
self.member_last_progress_at_ms.insert(agent_identity, observed_at_ms);
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::ExecutionAdvanced);
self.member_health_class.insert(agent_identity, MemberHealthClass::Healthy);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_progress_tokens.insert(agent_identity, progress_token);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressChangedIdle {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_changed" { self.member_progress_tokens.get_cloned(agent_identity) != Some(progress_token) }
guard "run_idle" { run_open == false }
update {
self.member_last_progress_at_ms.insert(agent_identity, observed_at_ms);
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::BecameIdle);
self.member_health_class.insert(agent_identity, MemberHealthClass::Healthy);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_progress_tokens.insert(agent_identity, progress_token);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressUnchangedIdle {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_unchanged" { self.member_progress_tokens.get_cloned(agent_identity) == Some(progress_token) }
guard "run_idle" { run_open == false }
update {
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::Unchanged);
self.member_health_class.insert(agent_identity, MemberHealthClass::Healthy);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressUnchangedOpenHealthy {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_unchanged" { self.member_progress_tokens.get_cloned(agent_identity) == Some(progress_token) }
guard "run_open" { run_open == true }
guard "progress_recent" { observed_at_ms - self.member_last_progress_at_ms.get_cloned(agent_identity).get("value") < 60000 }
update {
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::Unchanged);
self.member_health_class.insert(agent_identity, MemberHealthClass::Healthy);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressUnchangedOpenDegraded {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_unchanged" { self.member_progress_tokens.get_cloned(agent_identity) == Some(progress_token) }
guard "run_open" { run_open == true }
guard "progress_degraded" { observed_at_ms - self.member_last_progress_at_ms.get_cloned(agent_identity).get("value") >= 60000 && observed_at_ms - self.member_last_progress_at_ms.get_cloned(agent_identity).get("value") < 300000 }
update {
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::Unchanged);
self.member_health_class.insert(agent_identity, MemberHealthClass::Degraded);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressUnchangedOpenWedged {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_monotonic" { self.member_last_observed_at_ms.get_copied(agent_identity) <= Some(observed_at_ms) }
guard "member_progress_unchanged" { self.member_progress_tokens.get_cloned(agent_identity) == Some(progress_token) }
guard "run_open" { run_open == true }
guard "progress_wedged" { observed_at_ms - self.member_last_progress_at_ms.get_cloned(agent_identity).get("value") >= 300000 }
update {
self.member_last_progress_event.insert(agent_identity, MemberProgressEventKind::Unchanged);
self.member_health_class.insert(agent_identity, MemberHealthClass::Wedged);
self.member_run_open.insert(agent_identity, run_open);
self.member_in_flight_work.insert(agent_identity, in_flight_work);
self.member_last_observed_at_ms.insert(agent_identity, observed_at_ms);
}
to Running
}
transition ObserveMemberProgressStale {
per_phase [Running]
on input ObserveMemberProgress { agent_identity, run_open, in_flight_work, progress_token, observed_at_ms }
guard "observation_stale" { self.member_last_observed_at_ms.get_copied(agent_identity) > Some(observed_at_ms) }
update {}
to Running
}
transition ClassifyMemberWaitRuntimeMaterialPresentStopped {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "runtime_material_present" {
self.identity_runtime_generations.contains_key(agent_identity) == true
&& self.identity_runtime_fence_tokens.contains_key(agent_identity) == true
}
update {}
to Stopped
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::RuntimeMaterialPresent }
}
transition ClassifyMemberWaitRuntimeMaterialPresentCompleted {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "runtime_material_present" {
self.identity_runtime_generations.contains_key(agent_identity) == true
&& self.identity_runtime_fence_tokens.contains_key(agent_identity) == true
}
update {}
to Completed
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::RuntimeMaterialPresent }
}
transition ClassifyMemberWaitRuntimeMaterialPresentDestroyed {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "runtime_material_present" {
self.identity_runtime_generations.contains_key(agent_identity) == true
&& self.identity_runtime_fence_tokens.contains_key(agent_identity) == true
}
update {}
to Destroyed
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::RuntimeMaterialPresent }
}
transition ClassifyMemberWaitMissingRuntimeMaterialRunning {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_material_missing" {
self.identity_runtime_generations.contains_key(agent_identity) == false
|| self.identity_runtime_fence_tokens.contains_key(agent_identity) == false
}
update {}
to Running
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::MissingRuntimeMaterial }
}
transition ClassifyMemberWaitMissingRuntimeMaterialStopped {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "runtime_material_missing" {
self.identity_runtime_generations.contains_key(agent_identity) == false
|| self.identity_runtime_fence_tokens.contains_key(agent_identity) == false
}
update {}
to Stopped
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::MissingRuntimeMaterial }
}
transition ClassifyMemberWaitMissingRuntimeMaterialCompleted {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "runtime_material_missing" {
self.identity_runtime_generations.contains_key(agent_identity) == false
|| self.identity_runtime_fence_tokens.contains_key(agent_identity) == false
}
update {}
to Completed
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::MissingRuntimeMaterial }
}
transition ClassifyMemberWaitMissingRuntimeMaterialDestroyed {
on input ClassifyMemberWait { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "runtime_material_missing" {
self.identity_runtime_generations.contains_key(agent_identity) == false
|| self.identity_runtime_fence_tokens.contains_key(agent_identity) == false
}
update {}
to Destroyed
emit MemberWaitClassified { agent_identity: agent_identity, result: MemberWaitClassificationKind::MissingRuntimeMaterial }
}
// Autonomous shutdown classification is fail-closed. Only an exact
// current AutonomousHost incarnation may receive an action. A local
// member needs its exact retirement session plus absent executable
// carriers. A peer-only member needs machine-owned remote-retired and
// supervisor-revoked markers. A placed member needs its retained exact
// carrier plus the shell's current-epoch exact release terminal. These
// are terminal-journal retry anchors; all other current incarnations
// remain interruptible. A stale identity incarnation or runtime mode
// no-matches; incomplete carrier observations fail closed to
// Interrupt.
transition ResolveAutonomousShutdownMemberActionLocalTerminalRetryAnchor {
per_phase [Running, Stopped, Completed]
on input ResolveAutonomousShutdownMemberAction {
agent_identity,
agent_runtime_id,
fence_token,
generation,
session_id,
session_has_live_actor,
session_projection_visible,
runtime_residue_present,
archive_authority_known,
placed_release_confirmed
}
guard "exact_runtime" {
self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id)
}
guard "exact_generation" {
self.identity_runtime_generations.get_copied(agent_identity) == Some(generation)
}
guard "exact_fence" {
self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token)
}
guard "autonomous_member" {
self.member_runtime_modes.get_cloned(agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
guard "retirement_session_present" { session_id != None }
guard "retirement_session_exact" {
self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id
}
guard "retirement_session_binding_absent_or_exact" {
self.member_session_bindings.contains_key(agent_identity) == false
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "member_retiring" {
self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring)
}
guard "runtime_not_live" {
self.live_runtime_ids.contains(agent_runtime_id) == false
}
guard "session_ingress_detach_closed" {
self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
guard "member_disposal_complete" {
session_has_live_actor == false
&& runtime_residue_present == false
&& (archive_authority_known == false
|| session_projection_visible == false)
}
update {}
to Running
emit AutonomousShutdownMemberActionResolved {
action: AutonomousShutdownMemberActionKind::SkipTerminalRetirementAnchor,
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: generation,
session_id: session_id,
}
}
transition ResolveAutonomousShutdownMemberActionPeerOnlyTerminalRetryAnchor {
per_phase [Running, Stopped, Completed]
on input ResolveAutonomousShutdownMemberAction {
agent_identity,
agent_runtime_id,
fence_token,
generation,
session_id,
session_has_live_actor,
session_projection_visible,
runtime_residue_present,
archive_authority_known,
placed_release_confirmed
}
guard "exact_runtime" {
self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id)
}
guard "exact_generation" {
self.identity_runtime_generations.get_copied(agent_identity) == Some(generation)
}
guard "exact_fence" {
self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token)
}
guard "autonomous_member" {
self.member_runtime_modes.get_cloned(agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
guard "member_retiring" {
self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring)
}
guard "session_ingress_detach_closed" {
self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
guard "sessionless_peer_only_shape" {
session_id == None
&& self.member_session_bindings.contains_key(agent_identity) == false
&& self.member_placement.contains_key(agent_identity) == false
&& self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false
}
guard "remote_retirement_terminal" {
self.remote_runtime_retired_ids.contains(agent_runtime_id) == true
&& self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == true
}
update {}
to Running
emit AutonomousShutdownMemberActionResolved {
action: AutonomousShutdownMemberActionKind::SkipTerminalRetirementAnchor,
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: generation,
session_id: session_id,
}
}
transition ResolveAutonomousShutdownMemberActionPlacedTerminalRetryAnchor {
per_phase [Running, Stopped, Completed]
on input ResolveAutonomousShutdownMemberAction {
agent_identity,
agent_runtime_id,
fence_token,
generation,
session_id,
session_has_live_actor,
session_projection_visible,
runtime_residue_present,
archive_authority_known,
placed_release_confirmed
}
guard "exact_runtime" {
self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id)
}
guard "exact_generation" {
self.identity_runtime_generations.get_copied(agent_identity) == Some(generation)
}
guard "exact_fence" {
self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token)
}
guard "autonomous_member" {
self.member_runtime_modes.get_cloned(agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
guard "member_retiring" {
self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring)
}
guard "session_ingress_detach_closed" {
self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
guard "placed_session_shape" {
session_id != None
&& self.member_session_bindings.get_cloned(agent_identity) == session_id
&& self.member_placement.contains_key(agent_identity) == true
&& self.current_placed_spawn_ids.contains_key(agent_identity) == true
&& mob_machine_placed_cleanup_absent_for_identity(
self.pending_placed_carrier_cleanup,
agent_identity)
&& self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false
}
guard "placed_release_terminal" { placed_release_confirmed == true }
update {}
to Running
emit AutonomousShutdownMemberActionResolved {
action: AutonomousShutdownMemberActionKind::SkipTerminalRetirementAnchor,
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: generation,
session_id: session_id,
}
}
transition ResolveAutonomousShutdownMemberActionInterrupt {
per_phase [Running, Stopped, Completed]
on input ResolveAutonomousShutdownMemberAction {
agent_identity,
agent_runtime_id,
fence_token,
generation,
session_id,
session_has_live_actor,
session_projection_visible,
runtime_residue_present,
archive_authority_known,
placed_release_confirmed
}
guard "exact_runtime" {
self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id)
}
guard "exact_generation" {
self.identity_runtime_generations.get_copied(agent_identity) == Some(generation)
}
guard "exact_fence" {
self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token)
}
guard "autonomous_member" {
self.member_runtime_modes.get_cloned(agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
guard "not_local_terminal_retry_anchor" {
self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring)
|| self.live_runtime_ids.contains(agent_runtime_id) == true
|| self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true
|| self.member_kickoff_pending.contains(agent_identity)
|| self.member_kickoff_starting.contains(agent_identity)
|| self.member_kickoff_callback_pending.contains(agent_identity)
|| !mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
|| session_id == None
|| self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) != session_id
|| (self.member_session_bindings.contains_key(agent_identity) == true
&& self.member_session_bindings.get_cloned(agent_identity) != session_id)
|| session_has_live_actor == true
|| runtime_residue_present == true
|| (archive_authority_known == true
&& session_projection_visible == true)
}
guard "not_peer_only_terminal_retry_anchor" {
self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring)
|| self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true
|| self.member_kickoff_pending.contains(agent_identity)
|| self.member_kickoff_starting.contains(agent_identity)
|| self.member_kickoff_callback_pending.contains(agent_identity)
|| !mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
|| session_id != None
|| self.member_session_bindings.contains_key(agent_identity) == true
|| self.member_placement.contains_key(agent_identity) == true
|| self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == true
|| self.remote_runtime_retired_ids.contains(agent_runtime_id) == false
|| self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == false
}
guard "not_placed_terminal_retry_anchor" {
self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring)
|| self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true
|| self.member_kickoff_pending.contains(agent_identity)
|| self.member_kickoff_starting.contains(agent_identity)
|| self.member_kickoff_callback_pending.contains(agent_identity)
|| !mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
|| session_id == None
|| self.member_session_bindings.get_cloned(agent_identity) != session_id
|| self.member_placement.contains_key(agent_identity) == false
|| self.current_placed_spawn_ids.contains_key(agent_identity) == false
|| !mob_machine_placed_cleanup_absent_for_identity(
self.pending_placed_carrier_cleanup,
agent_identity)
|| self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == true
|| placed_release_confirmed == false
}
update {}
to Running
emit AutonomousShutdownMemberActionResolved {
action: AutonomousShutdownMemberActionKind::Interrupt,
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: generation,
session_id: session_id,
}
}
// Flow topology edge admission. The shell extracts the pure rule-match
// verdict (Allow/Deny) from declarative `TopologyRules` and the
// enforcement mode; the MobMachine decides the admission verdict the
// shell mirrors. No machine state is read or mutated — the rule-match
// is a config-only observation — so these are pure classification
// transitions across all lifecycle phases, like ClassifyMemberWait.
transition ResolveFlowDelegationEdgeAdmissionAllowed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveFlowDelegationEdgeAdmission { from_role, to_role, rule_verdict, mode }
guard "rule_allows_edge" { rule_verdict == MobFlowDelegationEdgeRuleVerdictKind::Allow }
update {}
to Running
emit FlowDelegationEdgeAdmissionResolved { from_role: from_role, to_role: to_role, admission: MobFlowDelegationEdgeAdmissionKind::Admitted }
}
transition ResolveFlowDelegationEdgeAdmissionDeniedStrict {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveFlowDelegationEdgeAdmission { from_role, to_role, rule_verdict, mode }
guard "rule_denies_edge_strict_mode" {
rule_verdict == MobFlowDelegationEdgeRuleVerdictKind::Deny
&& mode == MobFlowDelegationEdgeModeKind::Strict
}
update {}
to Running
emit FlowDelegationEdgeAdmissionResolved { from_role: from_role, to_role: to_role, admission: MobFlowDelegationEdgeAdmissionKind::DeniedStrict }
}
transition ResolveFlowDelegationEdgeAdmissionDeniedAdvisory {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveFlowDelegationEdgeAdmission { from_role, to_role, rule_verdict, mode }
guard "rule_denies_edge_advisory_mode" {
rule_verdict == MobFlowDelegationEdgeRuleVerdictKind::Deny
&& mode == MobFlowDelegationEdgeModeKind::Advisory
}
update {}
to Running
emit FlowDelegationEdgeAdmissionResolved { from_role: from_role, to_role: to_role, admission: MobFlowDelegationEdgeAdmissionKind::DeniedAdvisory }
}
// --- Remote-member runtime observation terminality ---
//
// The bridge consumer observes a remote member's runtime state during
// respawn/destroy cleanup. The observed state is a pure wire projection;
// MobMachine owns whether it is terminal. Pure classification across all
// lifecycle phases, like ClassifySpawnManyFailure.
transition ClassifyRemoteMemberRuntimeObservationTerminal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyRemoteMemberRuntimeObservation { observed_state }
guard "observed_state_terminal" {
observed_state == MobRemoteMemberRuntimeObservedState::Retired
|| observed_state == MobRemoteMemberRuntimeObservedState::Stopped
|| observed_state == MobRemoteMemberRuntimeObservedState::Destroyed
}
update {}
to Running
emit RemoteMemberRuntimeTerminalityClassified { observed_state: observed_state, terminality: MobRemoteMemberRuntimeTerminality::Terminal }
}
transition ClassifyRemoteMemberRuntimeObservationNonTerminal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyRemoteMemberRuntimeObservation { observed_state }
guard "observed_state_non_terminal" {
observed_state == MobRemoteMemberRuntimeObservedState::Initializing
|| observed_state == MobRemoteMemberRuntimeObservedState::Idle
|| observed_state == MobRemoteMemberRuntimeObservedState::Attached
|| observed_state == MobRemoteMemberRuntimeObservedState::Running
}
update {}
to Running
emit RemoteMemberRuntimeTerminalityClassified { observed_state: observed_state, terminality: MobRemoteMemberRuntimeTerminality::NonTerminal }
}
// --- Spawn-member operator admission ---
//
// The tool surface extracts RAW, atomic observations (manage scope, raw
// per-profile spawn-scope set membership, and the per-argument presence
// of every privileged spawn argument) and feeds them here WITHOUT
// pre-composing them; MobMachine owns the privileged-argument SET
// membership policy (OR-ing the presence facts) and the
// `manage_scope_present || profile_scope_contains` profile-scope
// disjunction, composing the Allow/Deny verdict. Pure classification
// across all phases.
//
// Verdict policy (composed entirely here):
// manage_scope_present -> Allowed
// !manage && any-privileged-arg -> Denied
// !manage && !privileged && profile_scope_contains -> Allowed
// !manage && !privileged && !profile_scope_contains -> Denied
transition ResolveSpawnMemberAdmissionManageScope {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnMemberAdmission {
manage_scope_present,
profile_scope_contains,
privileged_resume_bridge_session_present,
privileged_resume_session_present,
privileged_backend_present,
privileged_runtime_mode_present,
privileged_launch_mode_present,
privileged_tool_access_policy_present,
privileged_tooling_present,
privileged_auth_binding_present
}
guard "manage_scope_allows" { manage_scope_present == true }
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::Allowed }
}
transition ResolveSpawnMemberAdmissionPrivilegedArgsDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnMemberAdmission {
manage_scope_present,
profile_scope_contains,
privileged_resume_bridge_session_present,
privileged_resume_session_present,
privileged_backend_present,
privileged_runtime_mode_present,
privileged_launch_mode_present,
privileged_tool_access_policy_present,
privileged_tooling_present,
privileged_auth_binding_present
}
guard "privileged_args_without_manage_scope" {
manage_scope_present == false
&& (
privileged_resume_bridge_session_present == true
|| privileged_resume_session_present == true
|| privileged_backend_present == true
|| privileged_runtime_mode_present == true
|| privileged_launch_mode_present == true
|| privileged_tool_access_policy_present == true
|| privileged_tooling_present == true
|| privileged_auth_binding_present == true
)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::Denied }
}
transition ResolveSpawnMemberAdmissionProfileScope {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnMemberAdmission {
manage_scope_present,
profile_scope_contains,
privileged_resume_bridge_session_present,
privileged_resume_session_present,
privileged_backend_present,
privileged_runtime_mode_present,
privileged_launch_mode_present,
privileged_tool_access_policy_present,
privileged_tooling_present,
privileged_auth_binding_present
}
guard "profile_scope_allows" {
manage_scope_present == false
&& privileged_resume_bridge_session_present == false
&& privileged_resume_session_present == false
&& privileged_backend_present == false
&& privileged_runtime_mode_present == false
&& privileged_launch_mode_present == false
&& privileged_tool_access_policy_present == false
&& privileged_tooling_present == false
&& privileged_auth_binding_present == false
&& profile_scope_contains == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::Allowed }
}
transition ResolveSpawnMemberAdmissionDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnMemberAdmission {
manage_scope_present,
profile_scope_contains,
privileged_resume_bridge_session_present,
privileged_resume_session_present,
privileged_backend_present,
privileged_runtime_mode_present,
privileged_launch_mode_present,
privileged_tool_access_policy_present,
privileged_tooling_present,
privileged_auth_binding_present
}
guard "no_scope_denies" {
manage_scope_present == false
&& privileged_resume_bridge_session_present == false
&& privileged_resume_session_present == false
&& privileged_backend_present == false
&& privileged_runtime_mode_present == false
&& privileged_launch_mode_present == false
&& privileged_tool_access_policy_present == false
&& privileged_tooling_present == false
&& privileged_auth_binding_present == false
&& profile_scope_contains == false
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::Denied }
}
// --- Current-mob operator admission ---
//
// The tool surface extracts a single raw observation (whether the
// operator holds manage scope over the current mob) and feeds it here;
// MobMachine decides the Allow/Deny verdict. Pure classification across
// all phases.
transition ResolveCurrentMobAdmissionAllowed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveCurrentMobAdmission { can_manage_mob }
guard "manage_scope_allows" { can_manage_mob == true }
update {}
to Running
emit CurrentMobAdmissionResolved { admission: MobCurrentMobAdmissionKind::Allowed }
}
transition ResolveCurrentMobAdmissionDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveCurrentMobAdmission { can_manage_mob }
guard "no_manage_scope_denies" { can_manage_mob == false }
update {}
to Running
emit CurrentMobAdmissionResolved { admission: MobCurrentMobAdmissionKind::Denied }
}
// --- Coarse spawn-tool admission ---
//
// The tool surface extracts a single raw observation (whether the
// operator can spawn ANY profile in the current mob) and feeds it here;
// MobMachine decides the Allow/Deny verdict. This coarse gate uniquely
// covers the empty-specs spawn_many_members case (no per-member
// admission fires when zero specs are submitted). Pure classification
// across all phases.
transition ResolveSpawnToolAdmissionAllowed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnToolAdmission { can_manage_mob, spawn_profile_scope_present }
guard "spawn_scope_allows" {
can_manage_mob == true || spawn_profile_scope_present == true
}
update {}
to Running
emit SpawnToolAdmissionResolved { admission: MobSpawnToolAdmissionKind::Allowed }
}
transition ResolveSpawnToolAdmissionDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveSpawnToolAdmission { can_manage_mob, spawn_profile_scope_present }
guard "no_spawn_scope_denies" {
can_manage_mob == false && spawn_profile_scope_present == false
}
update {}
to Running
emit SpawnToolAdmissionResolved { admission: MobSpawnToolAdmissionKind::Denied }
}
// --- Operator create-mob admission ---
//
// The tool surface extracts a single raw observation (whether the
// operator holds the create-mobs capability bit) and feeds it here;
// MobMachine decides the Allow/Deny verdict. Pure classification across
// all phases.
transition ResolveCreateMobAdmissionAllowed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveCreateMobAdmission { can_create_mobs }
guard "create_capability_allows" { can_create_mobs == true }
update {}
to Running
emit CreateMobAdmissionResolved { admission: MobCreateMobAdmissionKind::Allowed }
}
transition ResolveCreateMobAdmissionDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveCreateMobAdmission { can_create_mobs }
guard "no_create_capability_denies" { can_create_mobs == false }
update {}
to Running
emit CreateMobAdmissionResolved { admission: MobCreateMobAdmissionKind::Denied }
}
transition InitializeAdaptiveRunRunning {
per_phase [Running]
on input InitializeAdaptiveRun {
adaptive_run_id,
max_depth,
max_total_decisions,
max_repair_attempts,
max_layer_failures,
max_attempts_per_layer,
max_members_per_layer,
max_total_spawned_members,
max_active_members,
max_retained_layer_mobs,
max_aggregate_tokens,
max_aggregate_tool_calls,
allowed_model_classes,
allowed_tool_classes,
allowed_skill_identities,
allowed_auth_binding_refs,
deadline_ms
}
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "no_active_adaptive_run" { self.adaptive_active_run == None }
guard "adaptive_run_id_unused" {
self.adaptive_run_phase.contains_key(adaptive_run_id) == false
}
guard "prior_adaptive_custody_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard "limits_complete" {
max_depth > 0
&& max_total_decisions > 0
&& max_repair_attempts > 0
&& max_layer_failures > 0
&& max_attempts_per_layer > 0
&& max_members_per_layer > 0
&& max_total_spawned_members > 0
&& max_active_members > 0
&& max_retained_layer_mobs > 0
&& max_aggregate_tokens > 0
&& max_aggregate_tool_calls > 0
&& deadline_ms > 0
}
update {
self.adaptive_active_run = Some(adaptive_run_id);
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Active);
self.adaptive_limit_max_depth.insert(adaptive_run_id, max_depth);
self.adaptive_limit_max_total_decisions.insert(adaptive_run_id, max_total_decisions);
self.adaptive_limit_max_repair_attempts.insert(adaptive_run_id, max_repair_attempts);
self.adaptive_limit_max_layer_failures.insert(adaptive_run_id, max_layer_failures);
self.adaptive_limit_max_attempts_per_layer.insert(adaptive_run_id, max_attempts_per_layer);
self.adaptive_limit_max_members_per_layer.insert(adaptive_run_id, max_members_per_layer);
self.adaptive_limit_max_total_spawned_members.insert(adaptive_run_id, max_total_spawned_members);
self.adaptive_limit_max_active_members.insert(adaptive_run_id, max_active_members);
self.adaptive_limit_max_retained_layer_mobs.insert(adaptive_run_id, max_retained_layer_mobs);
self.adaptive_limit_max_aggregate_tokens.insert(adaptive_run_id, max_aggregate_tokens);
self.adaptive_limit_max_aggregate_tool_calls.insert(adaptive_run_id, max_aggregate_tool_calls);
self.adaptive_limit_allowed_model_classes.insert(adaptive_run_id, allowed_model_classes);
self.adaptive_limit_allowed_tool_classes.insert(adaptive_run_id, allowed_tool_classes);
self.adaptive_limit_allowed_skill_identities.insert(adaptive_run_id, allowed_skill_identities);
self.adaptive_limit_allowed_auth_binding_refs.insert(adaptive_run_id, allowed_auth_binding_refs);
self.adaptive_deadline_ms.insert(adaptive_run_id, deadline_ms);
self.adaptive_depth.insert(adaptive_run_id, 0);
self.adaptive_total_decisions.insert(adaptive_run_id, 0);
self.adaptive_repair_attempts.insert(adaptive_run_id, 0);
self.adaptive_layer_failures.insert(adaptive_run_id, 0);
self.adaptive_total_spawned_members.insert(adaptive_run_id, 0);
self.adaptive_active_members.insert(adaptive_run_id, 0);
self.adaptive_retained_layer_mobs.insert(adaptive_run_id, 0);
self.adaptive_aggregate_token_reserved.insert(adaptive_run_id, 0);
self.adaptive_aggregate_token_actual.insert(adaptive_run_id, 0);
self.adaptive_aggregate_tool_call_reserved.insert(adaptive_run_id, 0);
self.adaptive_aggregate_tool_call_actual.insert(adaptive_run_id, 0);
}
to Running
emit AdaptiveRunInitialized { adaptive_run_id: adaptive_run_id }
}
transition InitializeAdaptiveRunReplay {
per_phase [Running]
on input InitializeAdaptiveRun {
adaptive_run_id,
max_depth,
max_total_decisions,
max_repair_attempts,
max_layer_failures,
max_attempts_per_layer,
max_members_per_layer,
max_total_spawned_members,
max_active_members,
max_retained_layer_mobs,
max_aggregate_tokens,
max_aggregate_tool_calls,
allowed_model_classes,
allowed_tool_classes,
allowed_skill_identities,
allowed_auth_binding_refs,
deadline_ms
}
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "same_active_run" { self.adaptive_active_run == Some(adaptive_run_id) }
guard "run_still_unstarted" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
&& self.adaptive_total_decisions.get_cloned(adaptive_run_id).get("value") == 0
&& self.adaptive_repair_attempts.get_cloned(adaptive_run_id).get("value") == 0
&& self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") == 0
&& self.adaptive_total_spawned_members.get_cloned(adaptive_run_id).get("value") == 0
&& self.adaptive_active_members.get_cloned(adaptive_run_id).get("value") == 0
&& self.adaptive_active_layer.contains_key(adaptive_run_id) == false
}
guard "exact_initialization_replay" {
self.adaptive_limit_max_depth.get_cloned(adaptive_run_id) == Some(max_depth)
&& self.adaptive_limit_max_total_decisions.get_cloned(adaptive_run_id) == Some(max_total_decisions)
&& self.adaptive_limit_max_repair_attempts.get_cloned(adaptive_run_id) == Some(max_repair_attempts)
&& self.adaptive_limit_max_layer_failures.get_cloned(adaptive_run_id) == Some(max_layer_failures)
&& self.adaptive_limit_max_attempts_per_layer.get_cloned(adaptive_run_id) == Some(max_attempts_per_layer)
&& self.adaptive_limit_max_members_per_layer.get_cloned(adaptive_run_id) == Some(max_members_per_layer)
&& self.adaptive_limit_max_total_spawned_members.get_cloned(adaptive_run_id) == Some(max_total_spawned_members)
&& self.adaptive_limit_max_active_members.get_cloned(adaptive_run_id) == Some(max_active_members)
&& self.adaptive_limit_max_retained_layer_mobs.get_cloned(adaptive_run_id) == Some(max_retained_layer_mobs)
&& self.adaptive_limit_max_aggregate_tokens.get_cloned(adaptive_run_id) == Some(max_aggregate_tokens)
&& self.adaptive_limit_max_aggregate_tool_calls.get_cloned(adaptive_run_id) == Some(max_aggregate_tool_calls)
&& self.adaptive_limit_allowed_model_classes.get_cloned(adaptive_run_id) == Some(allowed_model_classes)
&& self.adaptive_limit_allowed_tool_classes.get_cloned(adaptive_run_id) == Some(allowed_tool_classes)
&& self.adaptive_limit_allowed_skill_identities.get_cloned(adaptive_run_id) == Some(allowed_skill_identities)
&& self.adaptive_limit_allowed_auth_binding_refs.get_cloned(adaptive_run_id) == Some(allowed_auth_binding_refs)
&& self.adaptive_deadline_ms.get_cloned(adaptive_run_id) == Some(deadline_ms)
}
update {}
to Running
emit AdaptiveRunInitialized { adaptive_run_id: adaptive_run_id }
}
transition RecordAdaptivePlanningDecisionActive {
per_phase [Running]
on input RecordPlanningDecision { adaptive_run_id, decision_kind }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "decision_limit_available" {
self.adaptive_total_decisions.get_cloned(adaptive_run_id).get("value")
< self.adaptive_limit_max_total_decisions.get_cloned(adaptive_run_id).get("value")
}
update {
self.adaptive_total_decisions.insert(
adaptive_run_id,
self.adaptive_total_decisions.get_cloned(adaptive_run_id).get("value") + 1
);
}
to Running
emit AdaptivePlanningDecisionRecorded { adaptive_run_id: adaptive_run_id, decision_kind: decision_kind }
}
transition RecordAdaptivePlanningDecisionPlanLimit {
per_phase [Running]
on input RecordPlanningDecision { adaptive_run_id, decision_kind }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "decision_limit_exhausted" {
self.adaptive_total_decisions.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_limit_max_total_decisions.get_cloned(adaptive_run_id).get("value")
}
guard "adaptive_run_custody_drained" {
mob_machine_adaptive_run_custody_drained(
adaptive_run_id,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_adaptive_run,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Failed);
self.adaptive_stop_reason.insert(adaptive_run_id, AdaptiveStopReason::PlanLimit);
self.adaptive_active_run = None;
}
to Running
emit AdaptiveRunTerminalized { adaptive_run_id: adaptive_run_id, reason: AdaptiveStopReason::PlanLimit }
}
transition RecordAdaptivePlanRejectedActive {
per_phase [Running]
on input RecordPlanRejected { adaptive_run_id, layer_id }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "repair_limit_available" {
self.adaptive_repair_attempts.get_cloned(adaptive_run_id).get("value")
< self.adaptive_limit_max_repair_attempts.get_cloned(adaptive_run_id).get("value")
}
update {
self.adaptive_repair_attempts.insert(
adaptive_run_id,
self.adaptive_repair_attempts.get_cloned(adaptive_run_id).get("value") + 1
);
}
to Running
emit AdaptivePlanRejected { adaptive_run_id: adaptive_run_id, layer_id: layer_id }
}
transition RecordAdaptivePlanRejectedRepairLimit {
per_phase [Running]
on input RecordPlanRejected { adaptive_run_id, layer_id }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "repair_limit_exhausted" {
self.adaptive_repair_attempts.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_limit_max_repair_attempts.get_cloned(adaptive_run_id).get("value")
}
guard "adaptive_run_custody_drained" {
mob_machine_adaptive_run_custody_drained(
adaptive_run_id,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_adaptive_run,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Failed);
self.adaptive_stop_reason.insert(adaptive_run_id, AdaptiveStopReason::RepairLimit);
self.adaptive_active_run = None;
}
to Running
emit AdaptiveRunTerminalized { adaptive_run_id: adaptive_run_id, reason: AdaptiveStopReason::RepairLimit }
}
transition ResolveAdaptiveLayerAdmissionAllowed {
per_phase [Running]
on input ResolveLayerAdmission {
adaptive_run_id,
layer_id,
attempt,
plan_digest,
child_mob_id,
member_count,
token_reservation,
tool_call_reservation,
used_model_classes,
used_tool_classes,
used_skill_identities,
used_auth_binding_refs,
observed_at_ms
}
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "deadline_available" {
observed_at_ms <= self.adaptive_deadline_ms.get_cloned(adaptive_run_id).get("value")
}
guard "depth_available" {
self.adaptive_depth.get_cloned(adaptive_run_id).get("value")
< self.adaptive_limit_max_depth.get_cloned(adaptive_run_id).get("value")
}
guard "failure_limit_available" {
self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value")
< self.adaptive_limit_max_layer_failures.get_cloned(adaptive_run_id).get("value")
}
guard "member_count_available" {
member_count <= self.adaptive_limit_max_members_per_layer.get_cloned(adaptive_run_id).get("value")
}
guard "total_spawn_available" {
self.adaptive_total_spawned_members.get_cloned(adaptive_run_id).get("value") + member_count
<= self.adaptive_limit_max_total_spawned_members.get_cloned(adaptive_run_id).get("value")
}
guard "active_member_capacity_available" {
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value") + member_count
<= self.adaptive_limit_max_active_members.get_cloned(adaptive_run_id).get("value")
}
guard "token_reservation_available" {
self.adaptive_aggregate_token_reserved.get_cloned(adaptive_run_id).get("value") + token_reservation
<= self.adaptive_limit_max_aggregate_tokens.get_cloned(adaptive_run_id).get("value")
}
guard "tool_call_reservation_available" {
self.adaptive_aggregate_tool_call_reserved.get_cloned(adaptive_run_id).get("value") + tool_call_reservation
<= self.adaptive_limit_max_aggregate_tool_calls.get_cloned(adaptive_run_id).get("value")
}
guard "model_classes_allowed" {
for_all(class in used_model_classes, self.adaptive_limit_allowed_model_classes.get_cloned(adaptive_run_id).get("value").contains(class))
}
guard "tool_classes_allowed" {
for_all(class in used_tool_classes, self.adaptive_limit_allowed_tool_classes.get_cloned(adaptive_run_id).get("value").contains(class))
}
guard "skill_identities_allowed" {
for_all(skill in used_skill_identities, self.adaptive_limit_allowed_skill_identities.get_cloned(adaptive_run_id).get("value").contains(skill))
}
guard "auth_bindings_allowed" {
for_all(auth in used_auth_binding_refs, self.adaptive_limit_allowed_auth_binding_refs.get_cloned(adaptive_run_id).get("value").contains(auth))
}
guard "no_active_layer" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == None
}
guard "layer_not_previously_admitted" {
self.adaptive_layer_phase.get_cloned(layer_id) == None
}
update {
self.adaptive_depth.insert(
adaptive_run_id,
self.adaptive_depth.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_total_spawned_members.insert(
adaptive_run_id,
self.adaptive_total_spawned_members.get_cloned(adaptive_run_id).get("value") + member_count
);
self.adaptive_active_members.insert(
adaptive_run_id,
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value") + member_count
);
self.adaptive_aggregate_token_reserved.insert(
adaptive_run_id,
self.adaptive_aggregate_token_reserved.get_cloned(adaptive_run_id).get("value") + token_reservation
);
self.adaptive_aggregate_tool_call_reserved.insert(
adaptive_run_id,
self.adaptive_aggregate_tool_call_reserved.get_cloned(adaptive_run_id).get("value") + tool_call_reservation
);
self.adaptive_active_layer.insert(adaptive_run_id, layer_id);
self.adaptive_layer_adaptive_run.insert(layer_id, adaptive_run_id);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::Admitted);
self.adaptive_layer_attempt.insert(layer_id, attempt);
self.adaptive_layer_member_count.insert(layer_id, member_count);
self.adaptive_layer_plan_digest.insert(layer_id, plan_digest);
self.adaptive_layer_child_mob_id.insert(layer_id, child_mob_id);
self.adaptive_layer_token_reservation.insert(layer_id, token_reservation);
self.adaptive_layer_tool_call_reservation.insert(layer_id, tool_call_reservation);
}
to Running
emit AdaptiveLayerAdmissionResolved { adaptive_run_id: adaptive_run_id, layer_id: layer_id, admission: AdaptiveLayerAdmissionKind::Allowed }
}
transition ResolveAdaptiveLayerAdmissionRejected {
per_phase [Running]
on input ResolveLayerAdmission {
adaptive_run_id,
layer_id,
attempt,
plan_digest,
child_mob_id,
member_count,
token_reservation,
tool_call_reservation,
used_model_classes,
used_tool_classes,
used_skill_identities,
used_auth_binding_refs,
observed_at_ms
}
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "limit_exceeded" {
observed_at_ms > self.adaptive_deadline_ms.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_depth.get_cloned(adaptive_run_id).get("value") >= self.adaptive_limit_max_depth.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") >= self.adaptive_limit_max_layer_failures.get_cloned(adaptive_run_id).get("value")
|| member_count > self.adaptive_limit_max_members_per_layer.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_total_spawned_members.get_cloned(adaptive_run_id).get("value") + member_count > self.adaptive_limit_max_total_spawned_members.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_active_members.get_cloned(adaptive_run_id).get("value") + member_count > self.adaptive_limit_max_active_members.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_aggregate_token_reserved.get_cloned(adaptive_run_id).get("value") + token_reservation > self.adaptive_limit_max_aggregate_tokens.get_cloned(adaptive_run_id).get("value")
|| self.adaptive_aggregate_tool_call_reserved.get_cloned(adaptive_run_id).get("value") + tool_call_reservation > self.adaptive_limit_max_aggregate_tool_calls.get_cloned(adaptive_run_id).get("value")
|| for_all(class in used_model_classes, self.adaptive_limit_allowed_model_classes.get_cloned(adaptive_run_id).get("value").contains(class)) == false
|| for_all(class in used_tool_classes, self.adaptive_limit_allowed_tool_classes.get_cloned(adaptive_run_id).get("value").contains(class)) == false
|| for_all(skill in used_skill_identities, self.adaptive_limit_allowed_skill_identities.get_cloned(adaptive_run_id).get("value").contains(skill)) == false
|| for_all(auth in used_auth_binding_refs, self.adaptive_limit_allowed_auth_binding_refs.get_cloned(adaptive_run_id).get("value").contains(auth)) == false
|| self.adaptive_active_layer.get_cloned(adaptive_run_id) != None
}
update {
self.adaptive_repair_attempts.insert(
adaptive_run_id,
self.adaptive_repair_attempts.get_cloned(adaptive_run_id).get("value") + 1
);
}
to Running
emit AdaptiveLayerAdmissionResolved { adaptive_run_id: adaptive_run_id, layer_id: layer_id, admission: AdaptiveLayerAdmissionKind::Denied }
}
transition RecordAdaptiveLayerProvisioned {
per_phase [Running]
on input RecordLayerProvisioned { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_admitted" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Admitted)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::Provisioning);
}
to Running
emit AdaptiveLayerProvisioned { adaptive_run_id: adaptive_run_id, layer_id: layer_id, attempt: attempt }
}
transition RecordAdaptiveLayerRunStarted {
per_phase [Running]
on input RecordLayerRunStarted { adaptive_run_id, layer_id, attempt, child_run_id }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_provisioning" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Provisioning)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::Running);
self.adaptive_layer_run_id.insert(layer_id, child_run_id);
}
to Running
emit AdaptiveLayerRunStarted { adaptive_run_id: adaptive_run_id, layer_id: layer_id, attempt: attempt, child_run_id: child_run_id }
}
transition IngestAdaptiveLayerTerminalSuccess {
per_phase [Running]
on input IngestLayerTerminal { adaptive_run_id, layer_id, attempt, result_class, actual_tokens, actual_tool_calls }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_running" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Running)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "result_success" { result_class == FlowRunPublicResultClassKind::Success }
update {
self.adaptive_aggregate_token_actual.insert(
adaptive_run_id,
self.adaptive_aggregate_token_actual.get_cloned(adaptive_run_id).get("value") + actual_tokens
);
self.adaptive_aggregate_tool_call_actual.insert(
adaptive_run_id,
self.adaptive_aggregate_tool_call_actual.get_cloned(adaptive_run_id).get("value") + actual_tool_calls
);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::Collecting);
}
to Running
emit AdaptiveLayerTerminalIngested { adaptive_run_id: adaptive_run_id, layer_id: layer_id, result_class: result_class }
}
transition IngestAdaptiveLayerTerminalFailure {
per_phase [Running]
on input IngestLayerTerminal { adaptive_run_id, layer_id, attempt, result_class, actual_tokens, actual_tool_calls }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_running" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Running)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "result_failure" { result_class == FlowRunPublicResultClassKind::Failure }
update {
self.adaptive_aggregate_token_actual.insert(
adaptive_run_id,
self.adaptive_aggregate_token_actual.get_cloned(adaptive_run_id).get("value") + actual_tokens
);
self.adaptive_aggregate_tool_call_actual.insert(
adaptive_run_id,
self.adaptive_aggregate_tool_call_actual.get_cloned(adaptive_run_id).get("value") + actual_tool_calls
);
self.adaptive_layer_failures.insert(
adaptive_run_id,
self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::RunFailed);
self.adaptive_active_layer.remove(adaptive_run_id);
}
to Running
emit AdaptiveLayerTerminalIngested { adaptive_run_id: adaptive_run_id, layer_id: layer_id, result_class: result_class }
}
transition RecordAdaptiveLayerSetupFault {
per_phase [Running]
on input RecordLayerSetupFault { adaptive_run_id, layer_id, attempt, fault, spawned_members, requested_members }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_admitted_or_provisioning" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Admitted)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Provisioning)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "setup_counts_valid" {
requested_members == self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
&& spawned_members <= requested_members
}
update {
self.adaptive_layer_failures.insert(
adaptive_run_id,
self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::SetupFailed);
self.adaptive_layer_fault.insert(layer_id, fault);
self.adaptive_active_layer.remove(adaptive_run_id);
}
to Running
emit AdaptiveLayerSetupFaultRecorded { adaptive_run_id: adaptive_run_id, layer_id: layer_id, fault: fault }
}
// Driver or kernel failure after a layer mob has been acquired must
// terminalize the layer before physical cleanup can be recorded. This
// typed transition owns that interruption fact for every nonterminal
// post-acquisition phase.
transition RecordAdaptiveLayerInterruptedNonterminal {
per_phase [Running]
on input RecordLayerInterrupted { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "layer_nonterminal_after_acquisition" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Admitted)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Provisioning)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Running)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Collecting)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {
self.adaptive_layer_failures.insert(
adaptive_run_id,
self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::RunFailed);
self.adaptive_active_layer.remove(adaptive_run_id);
}
to Running
emit AdaptiveLayerInterrupted { adaptive_run_id: adaptive_run_id, layer_id: layer_id }
}
// Idempotent acknowledgement covers the case where the owning kernel
// committed a terminal transition but its response path failed. It
// never rewrites the more precise terminal fact.
transition RecordAdaptiveLayerInterruptedAlreadyTerminal {
per_phase [Running]
on input RecordLayerInterrupted { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "layer_already_terminal" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Completed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::SetupFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::RunFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::ResultInvalid)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Canceled)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {}
to Running
emit AdaptiveLayerInterrupted { adaptive_run_id: adaptive_run_id, layer_id: layer_id }
}
transition RecordAdaptiveLayerResultValidated {
per_phase [Running]
on input RecordLayerResultValidated { adaptive_run_id, layer_id, attempt, result_digest }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_collecting" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Collecting)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::Completed);
self.adaptive_layer_result_digest.insert(layer_id, result_digest);
self.adaptive_active_layer.remove(adaptive_run_id);
}
to Running
emit AdaptiveLayerResultValidated { adaptive_run_id: adaptive_run_id, layer_id: layer_id, result_digest: result_digest }
}
transition RecordAdaptiveLayerResultInvalid {
per_phase [Running]
on input RecordLayerResultInvalid { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "active_layer_matches" {
self.adaptive_active_layer.get_cloned(adaptive_run_id) == Some(layer_id)
}
guard "layer_collecting" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Collecting)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
update {
self.adaptive_layer_failures.insert(
adaptive_run_id,
self.adaptive_layer_failures.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_layer_phase.insert(layer_id, AdaptiveLayerPhase::ResultInvalid);
self.adaptive_active_layer.remove(adaptive_run_id);
}
to Running
emit AdaptiveLayerResultInvalid { adaptive_run_id: adaptive_run_id, layer_id: layer_id }
}
transition RecordAdaptiveLayerMobDestroyed {
per_phase [Running]
on input RecordLayerMobDestroyed { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "layer_terminal" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Completed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::SetupFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::RunFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::ResultInvalid)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Canceled)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "disposition_absent" {
self.adaptive_layer_disposition.contains_key(layer_id) == false
}
guard "active_member_debit_present" {
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
}
update {
self.adaptive_active_members.insert(
adaptive_run_id,
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
- self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
);
self.adaptive_layer_disposition.insert(layer_id, AdaptiveLayerDispositionKind::Destroyed);
}
to Running
emit AdaptiveLayerCleanupObserved { adaptive_run_id: adaptive_run_id, layer_id: layer_id, disposition: AdaptiveLayerDispositionKind::Destroyed }
}
transition RecordAdaptiveLayerMobDestroyedReplay {
per_phase [Running]
on input RecordLayerMobDestroyed { adaptive_run_id, layer_id, attempt }
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "exact_disposition_replay" {
self.adaptive_layer_disposition.get_cloned(layer_id)
== Some(AdaptiveLayerDispositionKind::Destroyed)
}
update {}
to Running
}
transition RecordAdaptiveLayerMobRetained {
per_phase [Running]
on input RecordLayerMobRetained { adaptive_run_id, layer_id, attempt, disposition }
guard "retained_disposition" {
disposition == AdaptiveLayerDispositionKind::Retained
|| disposition == AdaptiveLayerDispositionKind::RetainedAsEvidence
}
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "layer_terminal" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Completed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::SetupFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::RunFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::ResultInvalid)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Canceled)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "disposition_absent" {
self.adaptive_layer_disposition.contains_key(layer_id) == false
}
guard "retention_capacity_available" {
self.adaptive_retained_layer_mobs.get_cloned(adaptive_run_id).get("value")
< self.adaptive_limit_max_retained_layer_mobs.get_cloned(adaptive_run_id).get("value")
}
guard "active_member_debit_present" {
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
}
update {
self.adaptive_active_members.insert(
adaptive_run_id,
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
- self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
);
self.adaptive_retained_layer_mobs.insert(
adaptive_run_id,
self.adaptive_retained_layer_mobs.get_cloned(adaptive_run_id).get("value") + 1
);
self.adaptive_layer_disposition.insert(layer_id, disposition);
}
to Running
emit AdaptiveLayerCleanupObserved { adaptive_run_id: adaptive_run_id, layer_id: layer_id, disposition: disposition }
}
transition RecordAdaptiveLayerMobRetainedCleanupRequired {
per_phase [Running]
on input RecordLayerMobRetained { adaptive_run_id, layer_id, attempt, disposition }
guard "retained_disposition" {
disposition == AdaptiveLayerDispositionKind::Retained
|| disposition == AdaptiveLayerDispositionKind::RetainedAsEvidence
}
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "layer_terminal" {
self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Completed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::SetupFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::RunFailed)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::ResultInvalid)
|| self.adaptive_layer_phase.get_cloned(layer_id) == Some(AdaptiveLayerPhase::Canceled)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "disposition_absent" {
self.adaptive_layer_disposition.contains_key(layer_id) == false
}
guard "retention_capacity_exhausted" {
self.adaptive_retained_layer_mobs.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_limit_max_retained_layer_mobs.get_cloned(adaptive_run_id).get("value")
}
guard "active_member_debit_present" {
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
>= self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
}
update {
self.adaptive_active_members.insert(
adaptive_run_id,
self.adaptive_active_members.get_cloned(adaptive_run_id).get("value")
- self.adaptive_layer_member_count.get_cloned(layer_id).get("value")
);
// Cleanup observation may debit the final owned layer after
// the run has already terminalized (notably HostCancel). It
// must never reopen a terminal run as CleanupRequired.
if self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active) {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::CleanupRequired);
}
self.adaptive_layer_disposition.insert(layer_id, disposition);
}
to Running
emit AdaptiveLayerCleanupObserved { adaptive_run_id: adaptive_run_id, layer_id: layer_id, disposition: disposition }
}
transition RecordAdaptiveLayerMobRetainedReplay {
per_phase [Running]
on input RecordLayerMobRetained { adaptive_run_id, layer_id, attempt, disposition }
guard "retained_disposition" {
disposition == AdaptiveLayerDispositionKind::Retained
|| disposition == AdaptiveLayerDispositionKind::RetainedAsEvidence
}
guard "layer_owner_matches" {
self.adaptive_layer_adaptive_run.get_cloned(layer_id) == Some(adaptive_run_id)
}
guard "attempt_matches" {
self.adaptive_layer_attempt.get_cloned(layer_id).get("value") == attempt
}
guard "exact_disposition_replay" {
self.adaptive_layer_disposition.get_cloned(layer_id) == Some(disposition)
}
update {}
to Running
}
transition RecordAdaptiveCleanupResolved {
per_phase [Running]
on input RecordCleanupResolved { adaptive_run_id }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "cleanup_pause_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::CleanupRequired)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Active);
}
to Running
emit AdaptiveCleanupResolved { adaptive_run_id: adaptive_run_id }
}
transition RecordAdaptiveBodyEvidenceMissing {
per_phase [Running]
on input RecordBodyEvidenceMissing { adaptive_run_id, missing_digest }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "adaptive_run_custody_drained" {
mob_machine_adaptive_run_custody_drained(
adaptive_run_id,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_adaptive_run,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::EvidenceMissing);
self.adaptive_missing_body_digest.insert(adaptive_run_id, missing_digest);
self.adaptive_active_run = None;
}
to Running
emit AdaptiveBodyEvidenceMissing { adaptive_run_id: adaptive_run_id, missing_digest: missing_digest }
}
transition ResolveAdaptiveFinishRunning {
per_phase [Running]
on input ResolveAdaptiveFinish { adaptive_run_id, final_result_digest }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "adaptive_run_custody_drained" {
mob_machine_adaptive_run_custody_drained(
adaptive_run_id,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_adaptive_run,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Finished);
self.adaptive_stop_reason.insert(adaptive_run_id, AdaptiveStopReason::FinishDecision);
self.adaptive_active_run = None;
}
to Running
emit AdaptiveRunTerminalized { adaptive_run_id: adaptive_run_id, reason: AdaptiveStopReason::FinishDecision }
}
transition RequestAdaptiveCancelRunning {
per_phase [Running]
on input RequestAdaptiveCancel { adaptive_run_id }
guard "run_cancelable" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
|| self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::CleanupRequired)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Canceled);
self.adaptive_stop_reason.insert(adaptive_run_id, AdaptiveStopReason::HostCancel);
if self.adaptive_active_layer.contains_key(adaptive_run_id) {
self.adaptive_layer_phase.insert(
self.adaptive_active_layer.get_cloned(adaptive_run_id).get("value"),
AdaptiveLayerPhase::Canceled
);
self.adaptive_active_layer.remove(adaptive_run_id);
}
self.adaptive_active_run = None;
}
to Running
emit AdaptiveRunTerminalized { adaptive_run_id: adaptive_run_id, reason: AdaptiveStopReason::HostCancel }
}
transition RequestAdaptiveCancelReplay {
per_phase [Running]
on input RequestAdaptiveCancel { adaptive_run_id }
guard "already_terminal" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Canceled)
|| self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Finished)
|| self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Failed)
|| self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::EvidenceMissing)
}
update {}
to Running
}
transition RecordAdaptiveDeadlineObservedExpired {
per_phase [Running]
on input RecordDeadlineObserved { adaptive_run_id, observed_at_ms }
guard "run_active" {
self.adaptive_run_phase.get_cloned(adaptive_run_id) == Some(AdaptiveRunPhase::Active)
}
guard "deadline_expired" {
observed_at_ms > self.adaptive_deadline_ms.get_cloned(adaptive_run_id).get("value")
}
guard "adaptive_run_custody_drained" {
mob_machine_adaptive_run_custody_drained(
adaptive_run_id,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_adaptive_run,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.adaptive_run_phase.insert(adaptive_run_id, AdaptiveRunPhase::Failed);
self.adaptive_stop_reason.insert(adaptive_run_id, AdaptiveStopReason::DeadlineExceeded);
self.adaptive_active_run = None;
}
to Running
emit AdaptiveRunTerminalized { adaptive_run_id: adaptive_run_id, reason: AdaptiveStopReason::DeadlineExceeded }
}
// --- Operator profile-mutation admission ---
//
// The tool surface extracts a single raw observation (whether the
// operator holds the mutate-profiles capability bit) and feeds it here;
// MobMachine decides the Allow/Deny verdict. Pure classification across
// all phases.
transition ResolveProfileMutationAdmissionAllowed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveProfileMutationAdmission { can_mutate_profiles }
guard "mutate_capability_allows" { can_mutate_profiles == true }
update {}
to Running
emit ProfileMutationAdmissionResolved { admission: MobProfileMutationAdmissionKind::Allowed }
}
transition ResolveProfileMutationAdmissionDenied {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveProfileMutationAdmission { can_mutate_profiles }
guard "no_mutate_capability_denies" { can_mutate_profiles == false }
update {}
to Running
emit ProfileMutationAdmissionResolved { admission: MobProfileMutationAdmissionKind::Denied }
}
// --- Within-mob member-operation eligibility classification ---
//
// Spawn finalization, peer messaging, and respawn finalization require
// the mob to be live and running. MobMachine owns that eligibility over
// its own lifecycle phase plus the `destroy_admitted` marker: `Admitted`
// iff `Running` and destruction has not been admitted, `DeniedNotRunning`
// otherwise. The owning actor mirrors `DeniedNotRunning` to the same
// `InvalidTransition { from: self.state(), to: Running }` rejection it
// previously produced from the handwritten `require_state` pre-check.
transition ClassifyMemberOperationEligibilityAdmitted {
per_phase [Running]
on input ClassifyMemberOperationEligibility {}
guard "running_and_not_destroying_is_eligible" { self.destroy_admitted == false }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {}
to Running
emit MemberOperationEligibilityResolved { admission: MobMemberOperationEligibilityKind::Admitted }
}
transition ClassifyMemberOperationEligibilityRunningDestroyDenied {
per_phase [Running]
on input ClassifyMemberOperationEligibility {}
guard "running_but_destroying_is_denied" { self.destroy_admitted == true }
update {}
to Running
emit MemberOperationEligibilityResolved { admission: MobMemberOperationEligibilityKind::DeniedNotRunning }
}
transition ClassifyMemberOperationEligibilityRunningLifecycleDenied {
per_phase [Running]
on input ClassifyMemberOperationEligibility {}
guard "not_destroying" { self.destroy_admitted == false }
guard "lifecycle_origin_closed" { self.placed_completion_lifecycle_quiescing == true }
update {}
to Running
emit MemberOperationEligibilityResolved { admission: MobMemberOperationEligibilityKind::DeniedNotRunning }
}
transition ClassifyMemberOperationEligibilityNotRunning {
per_phase [Stopped, Completed, Destroyed]
on input ClassifyMemberOperationEligibility {}
update {}
to Running
emit MemberOperationEligibilityResolved { admission: MobMemberOperationEligibilityKind::DeniedNotRunning }
}
// --- Bridge-rejection recovery classification ---
//
// The mob bridge consumer receives a typed wire rejection cause when an
// `AuthorizeSupervisor` command is rejected. The cause is a pure wire
// projection; MobMachine owns whether it is recoverable by re-running
// `BindMember`. Pure classification across all lifecycle phases, like
// ClassifyRemoteMemberRuntimeObservation. NotBound / StaleSupervisor /
// SenderMismatch indicate the member is reachable but its supervisor
// authority is out of sync — a fresh bind reconciles. Every other cause
// is a hard contract violation that a rebind cannot fix.
transition ClassifyBridgeRejectionRecoveryRebind {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyBridgeRejectionRecovery { rejection_cause }
guard "rejection_recoverable_by_rebind" {
rejection_cause == MobBridgeRejectionCause::NotBound
|| rejection_cause == MobBridgeRejectionCause::StaleSupervisor
|| rejection_cause == MobBridgeRejectionCause::SenderMismatch
}
update {}
to Running
emit BridgeRejectionRecoveryClassified { rejection_cause: rejection_cause, recovery: MobBridgeRejectionRecovery::RebindRecover }
}
transition ClassifyBridgeRejectionRecoveryFatal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyBridgeRejectionRecovery { rejection_cause }
guard "rejection_fatal" {
rejection_cause == MobBridgeRejectionCause::AlreadyBound
|| rejection_cause == MobBridgeRejectionCause::InvalidBootstrapToken
|| rejection_cause == MobBridgeRejectionCause::UnsupportedProtocolVersion
|| rejection_cause == MobBridgeRejectionCause::InvalidSupervisorSpec
|| rejection_cause == MobBridgeRejectionCause::InvalidPeerSpec
|| rejection_cause == MobBridgeRejectionCause::AddressMismatch
|| rejection_cause == MobBridgeRejectionCause::Unsupported
|| rejection_cause == MobBridgeRejectionCause::Internal
}
update {}
to Running
emit BridgeRejectionRecoveryClassified { rejection_cause: rejection_cause, recovery: MobBridgeRejectionRecovery::FatalBubbleUp }
}
// --- Pending-supervisor-acceptance classification ---
//
// When a supervisor rotation already has accepted remote peers, the
// actor re-verifies a pending peer's acceptance by replaying the
// `AuthorizeSupervisor` command under the pending authority. The member
// may reply with a typed wire rejection cause (a pure wire projection);
// MobMachine — not a handwritten shell reducer — owns the acceptance /
// recovery verdict. Pure classification across all lifecycle phases,
// like ClassifyBridgeRejectionRecovery. NotBound / SenderMismatch mean
// the peer rebound to current authority so its prior acceptance is NOT
// confirmed and the rotation must re-attempt it. StaleSupervisor means
// the pending authority itself is stale. Every other cause is a hard
// fatal rejection.
transition ClassifyPendingSupervisorAcceptanceNotConfirmed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyPendingSupervisorAcceptance { rejection_cause }
guard "pending_acceptance_not_confirmed_reattempt" {
rejection_cause == MobBridgeRejectionCause::NotBound
|| rejection_cause == MobBridgeRejectionCause::SenderMismatch
}
update {}
to Running
emit PendingSupervisorAcceptanceClassified { rejection_cause: rejection_cause, verdict: MobPendingSupervisorAcceptanceKind::NotConfirmedReattempt }
}
transition ClassifyPendingSupervisorAcceptanceStale {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyPendingSupervisorAcceptance { rejection_cause }
guard "pending_acceptance_stale_authority" {
rejection_cause == MobBridgeRejectionCause::StaleSupervisor
}
update {}
to Running
emit PendingSupervisorAcceptanceClassified { rejection_cause: rejection_cause, verdict: MobPendingSupervisorAcceptanceKind::StalePendingAuthority }
}
transition ClassifyPendingSupervisorAcceptanceFatal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyPendingSupervisorAcceptance { rejection_cause }
guard "pending_acceptance_fatal" {
rejection_cause == MobBridgeRejectionCause::AlreadyBound
|| rejection_cause == MobBridgeRejectionCause::InvalidBootstrapToken
|| rejection_cause == MobBridgeRejectionCause::UnsupportedProtocolVersion
|| rejection_cause == MobBridgeRejectionCause::InvalidSupervisorSpec
|| rejection_cause == MobBridgeRejectionCause::InvalidPeerSpec
|| rejection_cause == MobBridgeRejectionCause::AddressMismatch
|| rejection_cause == MobBridgeRejectionCause::Unsupported
|| rejection_cause == MobBridgeRejectionCause::Internal
}
update {}
to Running
emit PendingSupervisorAcceptanceClassified { rejection_cause: rejection_cause, verdict: MobPendingSupervisorAcceptanceKind::Fatal }
}
// Stateless total identity classifier. This transition deliberately
// spans every phase and performs no update: lifecycle admission for a
// physical actuator remains an actor concern, while the desired-state
// decision itself depends only on the supplied fresh facts.
transition ClassifyIdentityReconciliation {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyIdentityReconciliation {
intent,
lease,
external_binding_required,
initial_delivery_required,
session_creation_receipt,
retirement_receipt,
session,
runtime,
member,
external_binding_receipt,
external_trust,
external_ceremony,
initial_delivery_receipt,
initial_delivery,
wiring
}
update {}
to Running
emit IdentityReconciliationClassified {
decision: identity_reconcile_decision(
intent,
lease,
external_binding_required,
initial_delivery_required,
session_creation_receipt,
retirement_receipt,
session,
runtime,
member,
external_binding_receipt,
external_trust,
external_ceremony,
initial_delivery_receipt,
initial_delivery,
wiring)
}
}
transition ClassifySpawnManyFailureProfileNotFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "profile_not_found" { observation == MobSpawnManyFailureObservationKind::ProfileNotFound }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::ProfileNotFound }
}
transition ClassifySpawnManyFailureMemberNotFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "member_not_found" { observation == MobSpawnManyFailureObservationKind::MemberNotFound }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::MemberNotFound }
}
transition ClassifySpawnManyFailureMemberAlreadyExists {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "member_already_exists" { observation == MobSpawnManyFailureObservationKind::MemberAlreadyExists }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::MemberAlreadyExists }
}
transition ClassifySpawnManyFailureNotExternallyAddressable {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "not_externally_addressable" { observation == MobSpawnManyFailureObservationKind::NotExternallyAddressable }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::NotExternallyAddressable }
}
transition ClassifySpawnManyFailureInvalidTransition {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "invalid_transition" { observation == MobSpawnManyFailureObservationKind::InvalidTransition }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::InvalidTransition }
}
transition ClassifySpawnManyFailureWiringError {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "wiring_error" {
observation == MobSpawnManyFailureObservationKind::WiringError
|| observation == MobSpawnManyFailureObservationKind::SupervisorRotationIncomplete
}
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::WiringError }
}
transition ClassifySpawnManyFailureBridgeCommandRejected {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "bridge_command_rejected" { observation == MobSpawnManyFailureObservationKind::BridgeCommandRejected }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::BridgeCommandRejected }
}
transition ClassifySpawnManyFailureMemberRestoreFailed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "member_restore_failed" { observation == MobSpawnManyFailureObservationKind::MemberRestoreFailed }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::MemberRestoreFailed }
}
transition ClassifySpawnManyFailureKickoffWaitTimedOut {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "kickoff_wait_timed_out" { observation == MobSpawnManyFailureObservationKind::KickoffWaitTimedOut }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::KickoffWaitTimedOut }
}
transition ClassifySpawnManyFailureReadyWaitTimedOut {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "ready_wait_timed_out" { observation == MobSpawnManyFailureObservationKind::ReadyWaitTimedOut }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::ReadyWaitTimedOut }
}
transition ClassifySpawnManyFailureDefinitionError {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "definition_error" { observation == MobSpawnManyFailureObservationKind::DefinitionError }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::DefinitionError }
}
transition ClassifySpawnManyFailureFlowNotFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "flow_not_found" { observation == MobSpawnManyFailureObservationKind::FlowNotFound }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::FlowNotFound }
}
transition ClassifySpawnManyFailureFlowFailed {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "flow_failed" { observation == MobSpawnManyFailureObservationKind::FlowFailed }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::FlowFailed }
}
transition ClassifySpawnManyFailureRunNotFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "run_not_found" { observation == MobSpawnManyFailureObservationKind::RunNotFound }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::RunNotFound }
}
transition ClassifySpawnManyFailureRunCanceled {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "run_canceled" { observation == MobSpawnManyFailureObservationKind::RunCanceled }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::RunCanceled }
}
transition ClassifySpawnManyFailureFlowTurnTimedOut {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "flow_turn_timed_out" { observation == MobSpawnManyFailureObservationKind::FlowTurnTimedOut }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::FlowTurnTimedOut }
}
transition ClassifySpawnManyFailureFrameDepthLimitExceeded {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "frame_depth_limit_exceeded" { observation == MobSpawnManyFailureObservationKind::FrameDepthLimitExceeded }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::FrameDepthLimitExceeded }
}
transition ClassifySpawnManyFailureFrameAtomicPersistenceUnavailable {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "frame_atomic_persistence_unavailable" { observation == MobSpawnManyFailureObservationKind::FrameAtomicPersistenceUnavailable }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::FrameAtomicPersistenceUnavailable }
}
transition ClassifySpawnManyFailureSpecRevisionConflict {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "spec_revision_conflict" { observation == MobSpawnManyFailureObservationKind::SpecRevisionConflict }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::SpecRevisionConflict }
}
transition ClassifySpawnManyFailureSchemaValidation {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "schema_validation" { observation == MobSpawnManyFailureObservationKind::SchemaValidation }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::SchemaValidation }
}
transition ClassifySpawnManyFailureInsufficientTargets {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "insufficient_targets" { observation == MobSpawnManyFailureObservationKind::InsufficientTargets }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::InsufficientTargets }
}
transition ClassifySpawnManyFailureTopologyViolation {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "topology_violation" { observation == MobSpawnManyFailureObservationKind::TopologyViolation }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::TopologyViolation }
}
transition ClassifySpawnManyFailureBridgeDeliveryRejected {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "bridge_delivery_rejected" { observation == MobSpawnManyFailureObservationKind::BridgeDeliveryRejected }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::BridgeDeliveryRejected }
}
transition ClassifySpawnManyFailureSupervisorEscalation {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "supervisor_escalation" { observation == MobSpawnManyFailureObservationKind::SupervisorEscalation }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::SupervisorEscalation }
}
transition ClassifySpawnManyFailureUnsupportedForMode {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "unsupported_for_mode" { observation == MobSpawnManyFailureObservationKind::UnsupportedForMode }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::UnsupportedForMode }
}
transition ClassifySpawnManyFailureMissingMemberCapability {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "missing_member_capability" { observation == MobSpawnManyFailureObservationKind::MissingMemberCapability }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::MissingMemberCapability }
}
transition ClassifySpawnManyFailureResetBarrier {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "reset_barrier" { observation == MobSpawnManyFailureObservationKind::ResetBarrier }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::ResetBarrier }
}
transition ClassifySpawnManyFailureStorageError {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "storage_error" { observation == MobSpawnManyFailureObservationKind::StorageError }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::StorageError }
}
transition ClassifySpawnManyFailureSessionError {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "session_error" { observation == MobSpawnManyFailureObservationKind::SessionError }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::SessionError }
}
transition ClassifySpawnManyFailureCommsError {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "comms_error" { observation == MobSpawnManyFailureObservationKind::CommsError }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::CommsError }
}
transition ClassifySpawnManyFailureCallbackPending {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "callback_pending" { observation == MobSpawnManyFailureObservationKind::CallbackPending }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::CallbackPending }
}
transition ClassifySpawnManyFailureStaleFenceToken {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "stale_fence_token" { observation == MobSpawnManyFailureObservationKind::StaleFenceToken }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::StaleFenceToken }
}
transition ClassifySpawnManyFailureStaleEventCursor {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "stale_event_cursor" { observation == MobSpawnManyFailureObservationKind::StaleEventCursor }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::StaleEventCursor }
}
transition ClassifySpawnManyFailureWorkNotFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "work_not_found" { observation == MobSpawnManyFailureObservationKind::WorkNotFound }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::WorkNotFound }
}
transition ClassifySpawnManyFailureInternal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifySpawnManyFailure { observation }
guard "internal" { observation == MobSpawnManyFailureObservationKind::Internal }
update {}
to Running
emit SpawnManyFailureClassified { observation: observation, cause: MobSpawnManyFailureCauseKind::Internal }
}
// W3-H: a spawn may only publish a membership for an identity with no
// current runtime or realtime binding. Respawn first completes the old
// retirement, then returns through this fresh commit at the exact next
// generation. Session-id rotation for an already-current runtime is a
// recovery/rebind concern, not a second spawn path; accepting it here
// would overwrite the current runtime without retiring its resources.
// CommitSpawnMembership{Fresh,FreshPeerOnly} form the local
// membership-commit rung. The original authority guards
// (coordinator_bound, addressability/digest authorization,
// identity_not_external_peer) live on the BeginSpawnExec opener; these
// commits guard on phase == Opened plus the local binding shape. The
// membership facts still mutate atomically and the update advances the
// phase to MembershipCommitted.
transition CommitSpawnMembershipFresh {
on input CommitSpawnMembership { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, member_peer_endpoint, spec_digest_echo, ack_engine_version, placed_spawn_id, provision_operation_id }
guard { self.lifecycle_phase == Phase::Running }
guard "spawn_exec_opened" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::Opened) }
guard "ack_fields_absent" {
member_peer_endpoint == None
&& spec_digest_echo == None
&& ack_engine_version == None
&& placed_spawn_id == None
&& provision_operation_id == None
}
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
guard "bridge_session_present" { bridge_session_id != None }
update {
// Spawn is the "member joined live_runtime_ids" fact. The
// pending_spawn_count lifecycle is owned by StageSpawn (+1)
// and CompleteSpawn (-1) signals; Spawn itself leaves the
// counter untouched. Concurrent spawn batches rely on that
// separation — zeroing or double-decrementing here breaks
// alignment between DSL pending_spawn_count and the actor's
// pending_spawns map
// (test_concurrent_spawns_parallelize_provisioning).
// active_run_count is unrelated to spawn and stays untouched
// (previously zeroed here by mistake).
self.live_runtime_ids.insert(agent_runtime_id);
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_profile_names.insert(agent_identity, self.spawn_profile_authority_profile_names.get_cloned(agent_identity).get("value"));
self.member_runtime_modes.insert(agent_identity, runtime_mode);
self.member_startup_binding_requested.insert(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_session_bindings.insert(agent_identity, bridge_session_id.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
// A locally-committed member is local truth: clear any
// placement/materialization residue from a prior remote
// generation so remote_committed_members_have_peer_endpoints
// cannot be violated by a local respawn.
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.spawn_profile_authority_profile_names.remove(agent_identity);
self.spawn_profile_authority_models.remove(agent_identity);
self.spawn_profile_authority_material_digests.remove(agent_identity);
self.spawn_profile_authority_tool_config_digests.remove(agent_identity);
self.spawn_profile_authority_skills_digests.remove(agent_identity);
self.spawn_profile_authority_provider_params_digests.remove(agent_identity);
self.spawn_profile_authority_output_schema_digests.remove(agent_identity);
self.spawn_profile_authority_resolved_spec_digests.remove(agent_identity);
self.spawn_profile_authority_external_addressable.remove(agent_identity);
self.topology_epoch += 1;
// Phase ladder: Opened -> MembershipCommitted.
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::MembershipCommitted);
}
to Running
emit RequestRuntimeBinding { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, fence_token: fence_token, generation: Some(generation), session_id: bridge_session_id.get("value") }
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberSpawned,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: bridge_session_id
}
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: None, new_session_id: bridge_session_id }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Spawned }
}
transition CommitSpawnMembershipFreshPeerOnly {
on input CommitSpawnMembership { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, member_peer_endpoint, spec_digest_echo, ack_engine_version, placed_spawn_id, provision_operation_id }
guard { self.lifecycle_phase == Phase::Running }
guard "spawn_exec_opened" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::Opened) }
guard "ack_fields_absent" {
member_peer_endpoint == None
&& spec_digest_echo == None
&& ack_engine_version == None
&& placed_spawn_id == None
&& provision_operation_id == None
}
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
guard "bridge_session_absent" { bridge_session_id == None }
update {
self.live_runtime_ids.insert(agent_runtime_id);
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_profile_names.insert(agent_identity, self.spawn_profile_authority_profile_names.get_cloned(agent_identity).get("value"));
self.member_runtime_modes.insert(agent_identity, runtime_mode);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_session_bindings.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.spawn_profile_authority_profile_names.remove(agent_identity);
self.spawn_profile_authority_models.remove(agent_identity);
self.spawn_profile_authority_material_digests.remove(agent_identity);
self.spawn_profile_authority_tool_config_digests.remove(agent_identity);
self.spawn_profile_authority_skills_digests.remove(agent_identity);
self.spawn_profile_authority_provider_params_digests.remove(agent_identity);
self.spawn_profile_authority_output_schema_digests.remove(agent_identity);
self.spawn_profile_authority_resolved_spec_digests.remove(agent_identity);
self.spawn_profile_authority_external_addressable.remove(agent_identity);
self.topology_epoch += 1;
// Phase ladder: Opened -> MembershipCommitted.
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::MembershipCommitted);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberSpawned,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Spawned }
}
// Multi-host (§6.1/§15.4) remote membership commit: guarded on the
// MaterializePending rung (disjoint from the Opened-rung local arms),
// carrying the materialization-ack facts. Roster truth — session
// binding AND peer endpoint (RegisterMemberPeer semantics folded) —
// is published only here, from the ack. No RequestRuntimeBinding: the
// member host owns the runtime binding. The ack-echoed spec digest
// must equal the machine-authorized resolved digest, and the ack
// engine version must equal the bound host record (a differing
// version is the HostEngineVersionChanged failure fed through
// RecordMemberMaterializationFailure instead).
transition CommitSpawnMembershipRemote {
on input CommitSpawnMembership { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, member_peer_endpoint, spec_digest_echo, ack_engine_version, placed_spawn_id, provision_operation_id }
guard { self.lifecycle_phase == Phase::Running }
guard "spawn_exec_materialize_pending" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MaterializePending) }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
guard "bridge_session_present" { bridge_session_id != None }
guard "ack_endpoint_present" { member_peer_endpoint != None }
guard "ack_peer_id_unowned" {
for_all(other in self.member_peer_endpoints.keys(),
other == agent_identity
|| mob_machine_member_peer_endpoint_peer_id(
self.member_peer_endpoints.get_cloned(other).get("value")
) != mob_machine_member_peer_endpoint_peer_id(
member_peer_endpoint.get("value")
))
}
guard "ack_peer_id_is_not_host" {
for_all(host in self.mob_hosts,
mob_machine_host_id_matches_peer_id(
host,
mob_machine_member_peer_endpoint_peer_id(
member_peer_endpoint.get("value")
)
) == false)
}
guard "placed_spawn_id_matches" {
placed_spawn_id != None
&& self.pending_placed_spawn_ids.get_cloned(agent_identity) == placed_spawn_id
}
guard "placed_generation_matches" { self.pending_placed_spawn_generations.get_cloned(agent_identity) == Some(generation) }
guard "placed_fence_matches" { self.pending_placed_spawn_fence_tokens.get_cloned(agent_identity) == Some(fence_token) }
guard "placed_host_matches" { self.pending_placed_spawn_hosts.get_cloned(agent_identity) == self.member_placement.get_cloned(agent_identity) }
guard "placed_host_binding_generation_current" {
self.pending_placed_spawn_host_binding_generations.get_copied(agent_identity)
== self.host_binding_generations.get_copied(self.pending_placed_spawn_hosts.get_cloned(agent_identity).get("value"))
}
guard "provision_operation_id_matches_pending" {
provision_operation_id != None
&& provision_operation_id == self.pending_placed_spawn_provision_operation_ids.get_cloned(agent_identity)
}
guard "spec_digest_echo_matches" {
spec_digest_echo != None
&& spec_digest_echo == self.spawn_profile_authority_resolved_spec_digests.get_cloned(agent_identity)
&& spec_digest_echo == self.pending_placed_spawn_spec_digests.get_cloned(agent_identity)
}
guard "engine_version_matches_bound_host" {
ack_engine_version == Some(self.host_engine_versions.get_cloned(self.member_placement.get_cloned(agent_identity).get("value")).get("value"))
}
update {
self.live_runtime_ids.insert(agent_runtime_id);
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_profile_names.insert(agent_identity, self.spawn_profile_authority_profile_names.get_cloned(agent_identity).get("value"));
self.member_runtime_modes.insert(agent_identity, runtime_mode);
// The member host owns the runtime binding, so no local
// startup-binding obligation is opened (PeerOnly shape).
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_session_bindings.insert(agent_identity, bridge_session_id.get("value"));
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(member_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, member_peer_endpoint.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
self.current_placed_spawn_ids.insert(agent_identity, placed_spawn_id.get("value"));
self.current_placed_spawn_host_binding_generations.insert(agent_identity, self.pending_placed_spawn_host_binding_generations.get_copied(agent_identity).get("value"));
self.current_placed_spawn_provision_operation_ids.insert(agent_identity, self.pending_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"));
self.current_placed_spawn_operation_owner_session_ids.insert(agent_identity, self.pending_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"));
self.pending_placed_spawn_ids.remove(agent_identity);
self.pending_placed_spawn_generations.remove(agent_identity);
self.pending_placed_spawn_fence_tokens.remove(agent_identity);
self.pending_placed_spawn_hosts.remove(agent_identity);
self.pending_autonomous_placed_spawns.remove(agent_identity);
self.pending_placed_spawn_host_binding_generations.remove(agent_identity);
self.pending_placed_spawn_spec_digests.remove(agent_identity);
self.pending_placed_spawn_provision_operation_ids.remove(agent_identity);
self.pending_placed_spawn_operation_owner_session_ids.remove(agent_identity);
self.spawn_profile_authority_profile_names.remove(agent_identity);
self.spawn_profile_authority_models.remove(agent_identity);
self.spawn_profile_authority_material_digests.remove(agent_identity);
self.spawn_profile_authority_tool_config_digests.remove(agent_identity);
self.spawn_profile_authority_skills_digests.remove(agent_identity);
self.spawn_profile_authority_provider_params_digests.remove(agent_identity);
self.spawn_profile_authority_output_schema_digests.remove(agent_identity);
self.spawn_profile_authority_resolved_spec_digests.remove(agent_identity);
self.spawn_profile_authority_external_addressable.remove(agent_identity);
self.topology_epoch += 1;
// Phase ladder: MaterializePending -> MembershipCommitted.
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::MembershipCommitted);
}
to Running
emit CommitPlacedSpawnCarrier {
spawn_id: placed_spawn_id.get("value"),
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
host: self.member_placement.get_cloned(agent_identity).get("value"),
host_binding_generation: self.current_placed_spawn_host_binding_generations.get_copied(agent_identity).get("value"),
spec_digest: spec_digest_echo.get("value"),
member_session_id: bridge_session_id.get("value"),
member_peer_endpoint: member_peer_endpoint.get("value"),
ack_engine_version: ack_engine_version.get("value"),
provision_operation_id: provision_operation_id.get("value"),
operation_owner_session_id: self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value")
}
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberSpawned,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: bridge_session_id
}
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: None, new_session_id: bridge_session_id }
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(member_peer_endpoint.get("value")) }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Spawned }
}
// =====================================================================
// Spawn-execution phase ladder: opener + final activation commit + abort.
// A lightweight 3-rung ladder (Begin -> Commit -> Activate). The machine
// OWNS + VALIDATES the phase ORDER; the shell still runs each individual
// finalization step. NO per-obligation tracking and NO per-step request
// effects (those exploded the mob x meerkat composition state space). The
// opener carries the original Spawn authority guards; activation/abort are
// total over an absent (Settled) phase entry via LateArrival/Destroyed
// no-op variants, mirroring KickoffQuiescedIdle/Destroyed.
// =====================================================================
// 1. Opener. Two local guarded variants carry the original Spawn authority
// guards (the guards the renamed CommitSpawnMembership* no longer carry) +
// a `spawn_exec_settled` guard (no window already open for this id). Sets
// ONLY spawn_exec_phase[id] = Opened; emits nothing. Does NOT mutate
// membership and does NOT consume the single-shot spawn_profile_authority_*
// material (that happens at CommitSpawnMembership). Self-loops to Running.
transition BeginSpawnExecFresh {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "placement_absent" { placement == None }
guard "placed_spawn_attempt_absent" {
placed_spawn_id == None
&& placed_provision_operation_id == None
&& placed_operation_owner_session_id == None
}
guard "effective_profile_override_presence_local" { effective_profile_override_present == false }
guard "effective_model_override_presence_local" { effective_model_override_present == false }
guard "no_pending_placed_spawn" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_current_placed_spawn" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_placed_carrier_cleanup" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "spawn_exec_settled" { self.spawn_exec_phase.contains_key(agent_identity) == false }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
guard "identity_not_external_peer" { mob_machine_external_peer_identity_absent(self.external_peer_edges, agent_identity) }
guard "spawn_profile_name_authorized" { self.spawn_profile_authority_profile_names.contains_key(agent_identity) == true }
guard "spawn_profile_authorized" { self.spawn_profile_authority_material_digests.get_cloned(agent_identity) == Some(profile_material_digest) }
guard "spawn_profile_addressability_authorized" { self.spawn_profile_authority_external_addressable.get_cloned(agent_identity) == Some(external_addressable) }
guard "bridge_session_present" { bridge_session_id != None }
update {
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::Opened);
}
to Running
}
transition BeginSpawnExecFreshPeerOnly {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "placement_absent" { placement == None }
guard "placed_spawn_attempt_absent" {
placed_spawn_id == None
&& placed_provision_operation_id == None
&& placed_operation_owner_session_id == None
}
guard "effective_profile_override_presence_local" { effective_profile_override_present == false }
guard "effective_model_override_presence_local" { effective_model_override_present == false }
guard "no_pending_placed_spawn" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_current_placed_spawn" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_placed_carrier_cleanup" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "spawn_exec_settled" { self.spawn_exec_phase.contains_key(agent_identity) == false }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
guard "identity_not_external_peer" { mob_machine_external_peer_identity_absent(self.external_peer_edges, agent_identity) }
guard "spawn_profile_name_authorized" { self.spawn_profile_authority_profile_names.contains_key(agent_identity) == true }
guard "spawn_profile_authorized" { self.spawn_profile_authority_material_digests.get_cloned(agent_identity) == Some(profile_material_digest) }
guard "spawn_profile_addressability_authorized" { self.spawn_profile_authority_external_addressable.get_cloned(agent_identity) == Some(external_addressable) }
guard "bridge_session_absent" { bridge_session_id == None }
update {
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::Opened);
}
to Running
}
// =====================================================================
// Multi-host spawn admission (§6.1/§15.4/§18.9/§19.L1/L5, A4).
// Placement/portability admission is enforced HERE, at the one
// choke-point every spawn path crosses. Each denial arm is a pure
// classification self-loop emitting the merged admission vocabulary
// (flat variants — the DSL emit grammar has no struct-variant
// construction, so `NonPortableResource { kind }` flattens to one
// variant per kind). The arms form a priority chain (each guard
// negates every earlier arm's discriminator) so exactly one fires.
// Local spawns pass `placement: None`, making every arm vacuous.
// =====================================================================
transition BeginSpawnExecDeniedNonPortableRustBundles {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "rust_bundles_present" { rust_bundles_present == true }
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableRustBundles }
}
transition BeginSpawnExecDeniedNonPortablePerSpawnExternalTools {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "per_spawn_external_tools_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortablePerSpawnExternalTools }
}
transition BeginSpawnExecDeniedNonPortableMobDefaultExternalTools {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "mob_default_external_tools_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableMobDefaultExternalTools }
}
transition BeginSpawnExecDeniedNonPortableDefaultLlmClientOverride {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "default_llm_client_override_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableDefaultLlmClientOverride }
}
transition BeginSpawnExecDeniedNonPortableHostSurfaceMcpAllowlist {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "host_surface_mcp_allowlist_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableHostSurfaceMcpAllowlist }
}
transition BeginSpawnExecDeniedNonPortableInheritedToolFilter {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "inherited_tool_filter_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableInheritedToolFilter }
}
transition BeginSpawnExecDeniedNonPortableWorkgraphTools {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "workgraph_required" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::NonPortableWorkgraphTools }
}
transition BeginSpawnExecDeniedSecretBearingShellEnv {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "shell_env_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::SecretBearingShellEnv }
}
transition BeginSpawnExecDeniedSecretBearingMcpStdioEnv {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "mcp_stdio_env_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::SecretBearingMcpStdioEnv }
}
transition BeginSpawnExecDeniedSecretBearingMcpHttpHeaders {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "mcp_http_headers_present" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == true
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::SecretBearingMcpHttpHeaders }
}
transition BeginSpawnExecDeniedHostNotBound {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_not_bound" { self.host_bind_phase.get_cloned(placement.get("value")) != Some(HostBindPhase::Bound) }
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::HostNotBound }
}
transition BeginSpawnExecDeniedMissingCapabilityAutonomousMembers {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "host_binding_generation_positive" { self.host_binding_generations.get_copied(placement.get("value")).get("value") > 0 }
guard "autonomous_members_missing" {
runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost
&& self.host_autonomous_members.get_copied(placement.get("value")) != Some(true)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityAutonomousMembers }
}
transition BeginSpawnExecDeniedMissingCapabilityDurableSessions {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
}
guard "durable_sessions_missing" {
runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost
&& self.host_durable_sessions.get_copied(placement.get("value")) != Some(true)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityDurableSessions }
}
transition BeginSpawnExecDeniedMissingCapabilityTrackedInputCancel {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true))
}
guard "tracked_input_cancel_missing" {
runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) != Some(true)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityTrackedInputCancel }
}
transition BeginSpawnExecDeniedMissingCapabilityProtocolV4 {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "tracked_turn_capabilities_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true))
}
guard "protocol_v4_missing" {
runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost
&& (self.host_protocol_min.get_copied(placement.get("value")).get("value") > 4
|| self.host_protocol_max.get_copied(placement.get("value")).get("value") < 4)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityProtocolV4 }
}
transition BeginSpawnExecDeniedMissingCapabilityMemoryStore {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_missing" {
memory_required == true
&& self.host_memory_store.get_copied(placement.get("value")) != Some(true)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityMemoryStore }
}
transition BeginSpawnExecDeniedMissingCapabilityMcp {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_satisfied" {
memory_required == false
|| self.host_memory_store.get_copied(placement.get("value")) == Some(true)
}
guard "mcp_missing" {
mcp_required == true
&& self.host_mcp.get_copied(placement.get("value")) != Some(true)
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::MissingHostCapabilityMcp }
}
transition BeginSpawnExecDeniedOwnerBridgeAbsent {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_satisfied" {
memory_required == false
|| self.host_memory_store.get_copied(placement.get("value")) == Some(true)
}
guard "mcp_satisfied" {
mcp_required == false
|| self.host_mcp.get_copied(placement.get("value")) == Some(true)
}
guard "owner_bridge_absent" { self.owner_bridge_session_id == None }
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::OwnerBridgeSessionAbsent }
}
transition BeginSpawnExecDeniedResumePlacementMismatch {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_satisfied" {
memory_required == false
|| self.host_memory_store.get_copied(placement.get("value")) == Some(true)
}
guard "mcp_satisfied" {
mcp_required == false
|| self.host_mcp.get_copied(placement.get("value")) == Some(true)
}
guard "owner_bridge_present" { self.owner_bridge_session_id != None }
// §19.L1 controlling-side check: the resume session id is bound in
// the machine to a DIFFERENT placement than the spawn requests
// (absence of a machine placement fact for a bound resume id is a
// mismatch too — the session is controlling-host-local).
guard "resume_placement_mismatch" {
resume_session_id != None
&& self.member_session_bindings.get_cloned(agent_identity) == resume_session_id
&& self.member_placement.get_cloned(agent_identity) != Some(placement.get("value"))
}
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::LaunchModePlacementMismatch }
}
transition BeginSpawnExecDeniedDigestAbsent {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { placement != None }
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_satisfied" {
memory_required == false
|| self.host_memory_store.get_copied(placement.get("value")) == Some(true)
}
guard "mcp_satisfied" {
mcp_required == false
|| self.host_mcp.get_copied(placement.get("value")) == Some(true)
}
guard "owner_bridge_present" { self.owner_bridge_session_id != None }
guard "resume_placement_consistent" {
resume_session_id == None
|| self.member_session_bindings.get_cloned(agent_identity) != resume_session_id
|| self.member_placement.get_cloned(agent_identity) == Some(placement.get("value"))
}
// §15.4 invariant: remote placement requires the resolved
// PortableMemberSpec digest before Spawn admits.
guard "resolved_spec_digest_absent" { self.spawn_profile_authority_resolved_spec_digests.contains_key(agent_identity) == false }
update {}
to Running
emit SpawnMemberAdmissionResolved { admission: MobSpawnMemberAdmissionKind::ResolvedSpecDigestAbsent }
}
// Remote opener: every denial discriminator clean, host bound and
// capable, owner bridge anchored, resolved digest authorized. Carries
// the same original Spawn authority guards as the local openers, then
// enters the MaterializePending rung, records placement, and hands
// the materialization request to the shell.
transition BeginSpawnExecRemote {
on input BeginSpawnExec { agent_identity, agent_runtime_id, fence_token, generation, profile_material_digest, external_addressable, runtime_mode, bridge_session_id, replacing, placement, workgraph_required, rust_bundles_present, per_spawn_external_tools_present, mob_default_external_tools_present, default_llm_client_override_present, host_surface_mcp_allowlist_present, inherited_tool_filter_present, shell_env_present, mcp_stdio_env_present, mcp_http_headers_present, memory_required, mcp_required, resume_session_id, placed_spawn_id, placed_provision_operation_id, placed_operation_owner_session_id, effective_profile_override_present, effective_model_override_present }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "placement_present" { placement != None }
guard "placed_spawn_id_present" { placed_spawn_id != None }
guard "placed_operation_owner_present" {
placed_provision_operation_id != None
&& placed_operation_owner_session_id != None
}
guard "portability_clean" {
rust_bundles_present == false
&& per_spawn_external_tools_present == false
&& mob_default_external_tools_present == false
&& default_llm_client_override_present == false
&& host_surface_mcp_allowlist_present == false
&& inherited_tool_filter_present == false
&& workgraph_required == false
&& shell_env_present == false
&& mcp_stdio_env_present == false
&& mcp_http_headers_present == false
}
guard "host_bound" { self.host_bind_phase.get_cloned(placement.get("value")) == Some(HostBindPhase::Bound) }
guard "autonomous_members_satisfied" {
runtime_mode != SpawnPolicyRuntimeMode::AutonomousHost
|| (self.host_autonomous_members.get_copied(placement.get("value")) == Some(true)
&& self.host_durable_sessions.get_copied(placement.get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(placement.get("value")) == Some(true)
&& self.host_protocol_min.get_copied(placement.get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(placement.get("value")).get("value") >= 4)
}
guard "memory_store_satisfied" {
memory_required == false
|| self.host_memory_store.get_copied(placement.get("value")) == Some(true)
}
guard "mcp_satisfied" {
mcp_required == false
|| self.host_mcp.get_copied(placement.get("value")) == Some(true)
}
guard "owner_bridge_present" { self.owner_bridge_session_id != None }
guard "operation_owner_is_owner_bridge" {
placed_operation_owner_session_id == self.owner_bridge_session_id
}
guard "resume_placement_consistent" {
resume_session_id == None
|| self.member_session_bindings.get_cloned(agent_identity) != resume_session_id
|| self.member_placement.get_cloned(agent_identity) == Some(placement.get("value"))
}
guard "resolved_spec_digest_present" { self.spawn_profile_authority_resolved_spec_digests.contains_key(agent_identity) == true }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "spawn_exec_settled" { self.spawn_exec_phase.contains_key(agent_identity) == false }
guard "no_pending_placed_spawn" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_current_placed_spawn" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "no_placed_carrier_cleanup" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "current_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "replacing_absent" { replacing == None }
// The member session id comes from the materialization ack at
// commit; a locally pre-provisioned session for a remote spawn is
// rejected fail-closed.
guard "bridge_session_absent" { bridge_session_id == None }
guard "identity_not_external_peer" { mob_machine_external_peer_identity_absent(self.external_peer_edges, agent_identity) }
guard "spawn_profile_name_authorized" { self.spawn_profile_authority_profile_names.contains_key(agent_identity) == true }
guard "spawn_profile_authorized" { self.spawn_profile_authority_material_digests.get_cloned(agent_identity) == Some(profile_material_digest) }
guard "spawn_profile_addressability_authorized" { self.spawn_profile_authority_external_addressable.get_cloned(agent_identity) == Some(external_addressable) }
update {
self.spawn_exec_phase.insert(agent_identity, SpawnExecPhase::MaterializePending);
self.member_placement.insert(agent_identity, placement.get("value"));
self.pending_placed_spawn_ids.insert(agent_identity, placed_spawn_id.get("value"));
self.pending_placed_spawn_generations.insert(agent_identity, generation);
self.pending_placed_spawn_fence_tokens.insert(agent_identity, fence_token);
self.pending_placed_spawn_hosts.insert(agent_identity, placement.get("value"));
if runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost {
self.pending_autonomous_placed_spawns.insert(agent_identity);
}
self.pending_placed_spawn_host_binding_generations.insert(agent_identity, self.host_binding_generations.get_copied(placement.get("value")).get("value"));
self.pending_placed_spawn_spec_digests.insert(agent_identity, self.spawn_profile_authority_resolved_spec_digests.get_cloned(agent_identity).get("value"));
self.pending_placed_spawn_provision_operation_ids.insert(agent_identity, placed_provision_operation_id.get("value"));
self.pending_placed_spawn_operation_owner_session_ids.insert(agent_identity, placed_operation_owner_session_id.get("value"));
self.member_materialization_failures.remove(agent_identity);
}
to Running
emit PersistPendingPlacedSpawn {
spawn_id: placed_spawn_id.get("value"),
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
spec_digest: self.pending_placed_spawn_spec_digests.get_cloned(agent_identity).get("value"),
host: placement.get("value"),
host_binding_generation: self.pending_placed_spawn_host_binding_generations.get_copied(agent_identity).get("value"),
effective_profile_override_present: effective_profile_override_present,
effective_model_override_present: effective_model_override_present,
provision_operation_id: placed_provision_operation_id.get("value"),
operation_owner_session_id: placed_operation_owner_session_id.get("value")
}
emit RequestMemberMaterialization {
spawn_id: placed_spawn_id.get("value"),
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
spec_digest: self.spawn_profile_authority_resolved_spec_digests.get_cloned(agent_identity).get("value"),
host: placement.get("value"),
host_binding_generation: self.pending_placed_spawn_host_binding_generations.get_copied(agent_identity).get("value"),
provision_operation_id: placed_provision_operation_id.get("value"),
operation_owner_session_id: placed_operation_owner_session_id.get("value")
}
}
// §6.1 materialization failure/retry recorder: the ladder rung stays
// MaterializePending so a retry with the same (identity, generation,
// fence) is idempotent; AbortSpawnExec clears on final abort.
transition RecordMemberMaterializationFailureRunning {
on input RecordMemberMaterializationFailure { agent_identity, kind }
guard { self.lifecycle_phase == Phase::Running }
guard "spawn_exec_materialize_pending" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MaterializePending) }
update {
self.member_materialization_failures.insert(agent_identity, kind);
}
to Running
}
// (removed) Per-step obligation feedback closers
// (SpawnTrustInstalled/SpawnOverlayUpserted/SpawnMemberEventAppended/
// SpawnPeerRegistered/SpawnKickoffMarked/SpawnWired/SpawnBindingDrained/
// SpawnActivated and their *Closed/*LateArrival/*Destroyed variants):
// the phase ladder tracks no per-step obligations, so the shell runs each
// step without a per-step machine handshake.
// 2. Final commit (Opened-membership -> Settled). Guarded ONLY on phase ==
// MembershipCommitted; removes the spawn_exec_phase entry (-> Settled),
// leaving no spawn-exec residue (membership facts persist independently).
// LateArrival/Destroyed keep the input total over an absent entry.
transition CommitSpawnActivationFinal {
per_phase [Running, Stopped, Completed]
on input CommitSpawnActivation { agent_identity }
guard "spawn_exec_membership_committed" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MembershipCommitted) }
update {
self.spawn_exec_phase.remove(agent_identity);
}
to Running
}
transition CommitSpawnActivationLateArrival {
per_phase [Running, Stopped, Completed]
on input CommitSpawnActivation { agent_identity }
// Exact complement of the Final guard: total over Settled (absent)
// AND a premature arrival while still Opened (membership not yet
// committed) — both are accepted no-ops.
guard "not_committed" { self.spawn_exec_phase.get_cloned(agent_identity) != Some(SpawnExecPhase::MembershipCommitted) }
update {}
to Running
}
transition CommitSpawnActivationDestroyed {
on input CommitSpawnActivation { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// 3. Abort (any non-Destroyed phase). Clears the spawn_exec_phase entry
// (-> Settled); the shell decides which compensator to run from its own
// step position. No machine-owned compensation routing or request effects.
// LateArrival (already Settled) + Destroyed keep the input total.
transition AbortSpawnExecActive {
per_phase [Running, Stopped, Completed]
on input AbortSpawnExec { agent_identity }
guard "spawn_exec_in_flight" { self.spawn_exec_phase.contains_key(agent_identity) == true }
guard "not_materialize_pending" { self.spawn_exec_phase.get_cloned(agent_identity) != Some(SpawnExecPhase::MaterializePending) }
update {
self.spawn_exec_phase.remove(agent_identity);
}
to Running
}
// Final abort of a remote materialization window: teardown
// completeness also clears the placement recorded by the remote
// opener and any recorded materialization failure.
transition AbortSpawnExecMaterializePending {
per_phase [Running, Stopped, Completed]
on input AbortSpawnExec { agent_identity }
guard "spawn_exec_materialize_pending" { self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MaterializePending) }
update {
self.spawn_exec_phase.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
self.pending_placed_spawn_ids.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_generations.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_fence_tokens.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Pending
));
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
self.pending_placed_spawn_ids.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_generations.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_fence_tokens.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.pending_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Pending
)
}
}
transition AbortSpawnExecLateArrival {
per_phase [Running, Stopped, Completed]
on input AbortSpawnExec { agent_identity }
guard "spawn_exec_settled" { self.spawn_exec_phase.contains_key(agent_identity) == false }
update {}
to Running
}
transition AbortSpawnExecDestroyed {
on input AbortSpawnExec { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// The machine first authorizes an exact compare-delete, then accepts
// resolution only for the same obligation. The carrier store remains
// fail-closed on Conflict; Phase B only feeds Resolve after Deleted or
// AlreadyAbsent.
transition AuthorizePlacedCarrierCleanupActive {
per_phase [Running, Stopped, Completed]
on input AuthorizePlacedCarrierCleanup { obligation }
guard "cleanup_pending" { self.pending_placed_carrier_cleanup.contains(obligation) == true }
update {}
to Running
emit PlacedCarrierCleanupAuthorized { obligation: obligation }
}
transition ResolvePlacedCarrierCleanupActive {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedCarrierCleanup { obligation }
guard "cleanup_pending" { self.pending_placed_carrier_cleanup.contains(obligation) == true }
update {
self.pending_placed_carrier_cleanup.remove(obligation);
if obligation.expected_phase == PlacedSpawnCarrierExpectedPhase::Pending {
self.pending_placed_spawn_ids.remove(obligation.agent_identity);
self.pending_placed_spawn_generations.remove(obligation.agent_identity);
self.pending_placed_spawn_fence_tokens.remove(obligation.agent_identity);
self.pending_placed_spawn_hosts.remove(obligation.agent_identity);
self.pending_autonomous_placed_spawns.remove(obligation.agent_identity);
self.pending_placed_spawn_host_binding_generations.remove(obligation.agent_identity);
self.pending_placed_spawn_spec_digests.remove(obligation.agent_identity);
self.pending_placed_spawn_provision_operation_ids.remove(obligation.agent_identity);
self.pending_placed_spawn_operation_owner_session_ids.remove(obligation.agent_identity);
self.member_placement.remove(obligation.agent_identity);
self.member_materialization_failures.remove(obligation.agent_identity);
} else {
self.current_placed_spawn_ids.remove(obligation.agent_identity);
self.current_placed_spawn_host_binding_generations.remove(obligation.agent_identity);
self.current_placed_spawn_provision_operation_ids.remove(obligation.agent_identity);
self.current_placed_spawn_operation_owner_session_ids.remove(obligation.agent_identity);
}
}
to Running
emit PlacedCarrierCleanupResolved { obligation: obligation }
}
transition ResolvePlacedCarrierCleanupLateArrival {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedCarrierCleanup { obligation }
guard "cleanup_absent" { self.pending_placed_carrier_cleanup.contains(obligation) == false }
update {}
to Running
}
transition AuthorizePlacedCarrierCleanupDestroyed {
on input AuthorizePlacedCarrierCleanup { obligation }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition ResolvePlacedCarrierCleanupDestroyed {
on input ResolvePlacedCarrierCleanup { obligation }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition AuthorizeSpawnProfileRunning {
on input AuthorizeSpawnProfile { agent_identity, profile_name, model, profile_material_digest, tool_config_digest, skills_digest, provider_params_digest, output_schema_digest, external_addressable, resolved_spec_digest }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "coordinator_bound" { self.coordinator_bound == true }
update {
self.spawn_profile_authority_profile_names.insert(agent_identity, profile_name);
self.spawn_profile_authority_models.insert(agent_identity, model);
self.spawn_profile_authority_material_digests.insert(agent_identity, profile_material_digest);
self.spawn_profile_authority_tool_config_digests.insert(agent_identity, tool_config_digest);
self.spawn_profile_authority_skills_digests.insert(agent_identity, skills_digest);
self.spawn_profile_authority_provider_params_digests.insert(agent_identity, provider_params_digest);
self.spawn_profile_authority_output_schema_digests.insert(agent_identity, output_schema_digest);
self.spawn_profile_authority_external_addressable.insert(agent_identity, external_addressable);
// §15.4: presence-based — a local authorization (None)
// clears any stale resolved digest for the identity.
if resolved_spec_digest != None {
self.spawn_profile_authority_resolved_spec_digests.insert(agent_identity, resolved_spec_digest.get("value"));
} else {
self.spawn_profile_authority_resolved_spec_digests.remove(agent_identity);
}
}
to Running
emit SpawnProfileAuthorized {
agent_identity: agent_identity,
profile_name: profile_name,
model: model,
profile_material_digest: profile_material_digest,
tool_config_digest: tool_config_digest,
skills_digest: skills_digest,
provider_params_digest: provider_params_digest,
output_schema_digest: output_schema_digest,
external_addressable: external_addressable,
resolved_spec_digest: resolved_spec_digest
}
}
transition EnsureMemberRunningExisting {
on input EnsureMember { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
update {
self.desired_members.insert(agent_identity);
self.members_to_spawn.remove(agent_identity);
self.members_to_retire.remove(agent_identity);
}
to Running
emit MemberRetainRequired { agent_identity: agent_identity }
}
transition EnsureMemberRunningMissing {
on input EnsureMember { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {
self.desired_members.insert(agent_identity);
self.members_to_spawn.insert(agent_identity);
self.members_to_retire.remove(agent_identity);
}
to Running
emit MemberSpawnRequired { agent_identity: agent_identity }
}
// Cold recovery of a Pending carrier never manufactures roster truth.
// It restores only the exact attempt plus a cleanup obligation; Phase B
// must compare-delete (or explicitly reconcile) it before any successor
// spawn for this identity can begin.
transition RecoverPendingPlacedSpawnRunning {
on signal RecoverPendingPlacedSpawn { spawn_id, agent_identity, generation, fence_token, host_id, host_binding_generation, spec_digest, runtime_mode, provision_operation_id, operation_owner_session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "owner_bridge_present" { self.owner_bridge_session_id == Some(operation_owner_session_id) }
guard "host_binding_generation_positive" { host_binding_generation > 0 }
guard "host_binding_generation_observed" {
self.host_binding_generation_highwater.contains_key(host_id) == true
&& self.host_binding_generation_highwater.get_copied(host_id).get("value") >= host_binding_generation
}
guard "identity_not_live" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "pending_attempt_absent" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "committed_attempt_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
update {
self.pending_placed_spawn_ids.insert(agent_identity, spawn_id);
self.pending_placed_spawn_generations.insert(agent_identity, generation);
self.pending_placed_spawn_fence_tokens.insert(agent_identity, fence_token);
self.pending_placed_spawn_hosts.insert(agent_identity, host_id);
if runtime_mode == SpawnPolicyRuntimeMode::AutonomousHost {
self.pending_autonomous_placed_spawns.insert(agent_identity);
}
self.pending_placed_spawn_host_binding_generations.insert(agent_identity, host_binding_generation);
self.pending_placed_spawn_spec_digests.insert(agent_identity, spec_digest);
self.pending_placed_spawn_provision_operation_ids.insert(agent_identity, provision_operation_id);
self.pending_placed_spawn_operation_owner_session_ids.insert(agent_identity, operation_owner_session_id);
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
spawn_id,
generation,
fence_token,
provision_operation_id,
operation_owner_session_id,
PlacedSpawnCarrierExpectedPhase::Pending
));
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
spawn_id,
generation,
fence_token,
provision_operation_id,
operation_owner_session_id,
PlacedSpawnCarrierExpectedPhase::Pending
)
}
}
// A Committed carrier is sufficient durable truth to rehydrate the
// exact placed member in one transition. In particular, recovery does
// not replay the Begin/Commit spawn ladder or create a new attempt.
transition RecoverCommittedPlacedSpawnRunning {
on signal RecoverCommittedPlacedSpawn { spawn_id, agent_identity, agent_runtime_id, generation, fence_token, host_id, host_binding_generation, member_session_id, member_peer_endpoint, profile_name, runtime_mode, external_addressable, provision_operation_id, operation_owner_session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "owner_bridge_present" { self.owner_bridge_session_id != None }
guard "operation_owner_is_owner_bridge" { self.owner_bridge_session_id == Some(operation_owner_session_id) }
guard "host_binding_generation_positive" { host_binding_generation > 0 }
guard "host_binding_generation_observed" {
self.host_binding_generation_highwater.contains_key(host_id) == true
&& self.host_binding_generation_highwater.get_copied(host_id).get("value") >= host_binding_generation
}
guard "identity_not_recovered" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "runtime_not_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "pending_attempt_absent" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "committed_attempt_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "member_peer_id_unowned" {
for_all(other in self.member_peer_endpoints.keys(),
other == agent_identity
|| mob_machine_member_peer_endpoint_peer_id(
self.member_peer_endpoints.get_cloned(other).get("value")
) != mob_machine_member_peer_endpoint_peer_id(member_peer_endpoint))
}
guard "member_peer_id_is_not_host" {
for_all(bound_host in self.mob_hosts,
mob_machine_host_id_matches_peer_id(
bound_host,
mob_machine_member_peer_endpoint_peer_id(member_peer_endpoint)
) == false)
}
update {
self.live_runtime_ids.insert(agent_runtime_id);
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_profile_names.insert(agent_identity, profile_name);
self.member_runtime_modes.insert(agent_identity, runtime_mode);
self.member_session_bindings.insert(agent_identity, member_session_id);
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(member_peer_endpoint));
self.member_peer_endpoints.insert(agent_identity, member_peer_endpoint);
self.member_placement.insert(agent_identity, host_id);
self.current_placed_spawn_ids.insert(agent_identity, spawn_id);
self.current_placed_spawn_host_binding_generations.insert(agent_identity, host_binding_generation);
self.current_placed_spawn_provision_operation_ids.insert(agent_identity, provision_operation_id);
self.current_placed_spawn_operation_owner_session_ids.insert(agent_identity, operation_owner_session_id);
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Active);
self.member_restore_failures.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
}
// A replacement host binding becomes carrier authority only after an
// authenticated materialization ACK or exact HostStatus presence. The
// shell prepares this transition, compare-and-swaps the durable v3
// carrier, and commits this machine generation update last.
transition PromoteCommittedPlacedSpawnCarrierBindingRunning {
on input PromoteCommittedPlacedSpawnCarrierBinding { spawn_id, agent_identity, generation, fence_token, host_id, expected_host_binding_generation, host_binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "committed_spawn_exact" { self.current_placed_spawn_ids.get_cloned(agent_identity) == Some(spawn_id) }
guard "identity_generation_exact" { self.identity_runtime_generations.get_cloned(agent_identity) == Some(generation) }
guard "identity_fence_exact" { self.identity_runtime_fence_tokens.get_cloned(agent_identity) == Some(fence_token) }
guard "placement_host_exact" { self.member_placement.get_cloned(agent_identity) == Some(host_id) }
guard "expected_carrier_binding_generation_exact" {
expected_host_binding_generation > 0
&& self.current_placed_spawn_host_binding_generations.get_copied(agent_identity) == Some(expected_host_binding_generation)
}
guard "replacement_binding_generation_advances" { host_binding_generation > expected_host_binding_generation }
guard "replacement_host_bound" { self.host_bind_phase.get_cloned(host_id) == Some(HostBindPhase::Bound) }
guard "replacement_binding_generation_exact" { self.host_binding_generations.get_copied(host_id) == Some(host_binding_generation) }
guard "pending_attempt_absent" { self.pending_placed_spawn_ids.contains_key(agent_identity) == false }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.current_placed_spawn_host_binding_generations.insert(agent_identity, host_binding_generation);
}
to Running
emit PromoteCommittedPlacedSpawnCarrierBinding {
spawn_id: spawn_id,
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
host: host_id,
expected_host_binding_generation: expected_host_binding_generation,
host_binding_generation: host_binding_generation
}
}
transition RecoverPlacedCarrierCleanupRunning {
on signal RecoverPlacedCarrierCleanup { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "operation_owner_is_owner_bridge" { self.owner_bridge_session_id == Some(obligation.operation_owner_session_id) }
guard "cleanup_exact_absent" { self.pending_placed_carrier_cleanup.contains(obligation) == false }
guard "cleanup_identity_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, obligation.agent_identity) }
update {
self.pending_placed_carrier_cleanup.insert(obligation);
}
to Running
emit PlacedCarrierCleanupRequested { obligation: obligation }
}
transition RecoverPlacedCarrierCleanupAlreadyRunning {
on signal RecoverPlacedCarrierCleanup { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "operation_owner_is_owner_bridge" { self.owner_bridge_session_id == Some(obligation.operation_owner_session_id) }
guard "cleanup_exact_present" { self.pending_placed_carrier_cleanup.contains(obligation) == true }
update {}
to Running
}
transition RecoverRosterMemberRunning {
on signal RecoverRosterMember { agent_identity, agent_runtime_id, fence_token, generation, profile_name, runtime_mode, external_addressable }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_not_recovered" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "runtime_not_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "generation_is_next" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
update {
self.live_runtime_ids.insert(agent_runtime_id);
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_profile_names.insert(agent_identity, profile_name);
self.member_runtime_modes.insert(agent_identity, runtime_mode);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
}
transition RecoverRosterMemberAddressabilityRunning {
on signal RecoverRosterMember { agent_identity, agent_runtime_id, fence_token, generation, profile_name, runtime_mode, external_addressable }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
update {
if external_addressable {
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.member_profile_names.insert(agent_identity, profile_name);
self.member_runtime_modes.insert(agent_identity, runtime_mode);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Running
}
transition RecoverMemberSessionBindingFreshRunning {
on signal RecoverMemberSessionBinding { agent_identity, agent_runtime_id, bridge_session_id, replacing }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "replacing_absent" { replacing == None }
update {
self.member_session_bindings.insert(agent_identity, bridge_session_id);
self.topology_epoch += 1;
}
to Running
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: None, new_session_id: Some(bridge_session_id) }
emit SessionProvisionOperationOwnerAuthorized { agent_identity: agent_identity, session_id: bridge_session_id }
}
transition RecoverMemberSessionBindingReplacingRunning {
on signal RecoverMemberSessionBinding { agent_identity, agent_runtime_id, bridge_session_id, replacing }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "replacing_present" { replacing != None }
guard "replacing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(replacing.get("value")) }
guard "replacement_changes_binding" { bridge_session_id != replacing.get("value") }
update {
self.member_session_bindings.insert(agent_identity, bridge_session_id);
self.topology_epoch += 1;
}
to Running
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: Some(replacing.get("value")), new_session_id: Some(bridge_session_id) }
emit SessionProvisionOperationOwnerAuthorized { agent_identity: agent_identity, session_id: bridge_session_id }
}
transition RecoverMemberSessionBindingAlreadyCurrentRunning {
on signal RecoverMemberSessionBinding { agent_identity, agent_runtime_id, bridge_session_id, replacing }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "binding_already_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(bridge_session_id) }
guard "replacing_absent_or_current" { replacing == None || replacing == Some(bridge_session_id) }
update {}
to Running
emit SessionProvisionOperationOwnerAuthorized { agent_identity: agent_identity, session_id: bridge_session_id }
}
// Replay-only endpoint recovery for the exact durable runtime/session
// binding. A legacy journal may not have registered an endpoint at
// spawn, so the fresh arm establishes the first endpoint without
// claiming a rotation. Replaying the exact same descriptor is a typed
// no-op. Only an actual descriptor change retains the previous
// generation endpoint, replaces current authority, and advances the
// topology epoch so every previously minted trust authority is stale.
transition RecoverSpawnedMemberPeerEndpointFreshRunning {
on signal RecoverSpawnedMemberPeerEndpoint { agent_identity, agent_runtime_id, fence_token, generation, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_peer_not_registered" { self.member_peer_ids.contains_key(agent_identity) == false }
guard "member_endpoint_not_registered" { self.member_peer_endpoints.contains_key(agent_identity) == false }
guard "prior_endpoint_history_absent" { self.member_prior_peer_endpoints.contains_key(agent_identity) == false }
guard "peer_id_available_for_identity" {
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
agent_identity,
peer_endpoint)
}
update {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(peer_endpoint));
self.member_peer_endpoints.insert(agent_identity, peer_endpoint);
}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RecoverSpawnedMemberPeerEndpointAlreadyCurrentRunning {
on signal RecoverSpawnedMemberPeerEndpoint { agent_identity, agent_runtime_id, fence_token, generation, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_endpoint_matches" { self.member_peer_endpoints.get_cloned(agent_identity) == Some(peer_endpoint) }
guard "current_peer_id_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(peer_endpoint)) }
update {}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RecoverMemberPeerEndpointFreshRunning {
on signal RecoverMemberPeerEndpoint { agent_identity, agent_runtime_id, bridge_session_id, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(bridge_session_id) }
guard "member_peer_not_registered" { self.member_peer_ids.contains_key(agent_identity) == false }
guard "member_endpoint_not_registered" { self.member_peer_endpoints.contains_key(agent_identity) == false }
guard "prior_endpoint_history_absent" { self.member_prior_peer_endpoints.contains_key(agent_identity) == false }
// With no durable baseline endpoint there is no exact old PeerId
// authority to remove from already-connected peers. New journals
// register before wiring; legacy journals with retained topology
// must fail closed instead of treating an arbitrary live
// observation as the historical baseline.
guard "no_member_wiring_edges" {
for_all(edge in self.wiring_edges,
mob_machine_wiring_edge_contains_identity(edge, agent_identity) == false)
}
guard "no_external_peer_edges" {
mob_machine_member_has_no_external_peer_edges(self.external_peer_edges, agent_identity)
}
guard "peer_id_available_for_identity" {
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
agent_identity,
peer_endpoint)
}
update {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(peer_endpoint));
self.member_peer_endpoints.insert(agent_identity, peer_endpoint);
}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RecoverMemberPeerEndpointAlreadyCurrentRunning {
on signal RecoverMemberPeerEndpoint { agent_identity, agent_runtime_id, bridge_session_id, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(bridge_session_id) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_endpoint_matches_recovered" { self.member_peer_endpoints.get_cloned(agent_identity) == Some(peer_endpoint) }
guard "current_peer_id_matches_recovered" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(peer_endpoint)) }
update {}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RecoverMemberPeerEndpointChangedRunning {
on signal RecoverMemberPeerEndpoint { agent_identity, agent_runtime_id, bridge_session_id, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(bridge_session_id) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_peer_id_matches_endpoint" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value"))) }
guard "recovered_endpoint_changed" { self.member_peer_endpoints.get_cloned(agent_identity) != Some(peer_endpoint) }
// Trust stores are keyed by PeerId and generated mutation
// preflight deliberately forbids rewriting descriptor material in
// place. Treat same-PeerId descriptor drift as corruption, not a
// migration; only a new cryptographic peer identity may rotate.
guard "recovered_peer_id_changed" {
mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value"))
!= mob_machine_member_peer_endpoint_peer_id(peer_endpoint)
}
guard "recovered_peer_id_available_for_identity" {
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
agent_identity,
peer_endpoint)
}
// External reciprocal trust does not yet have a generated
// historical-endpoint cleanup handoff. Refuse the migration rather
// than strand an old local PeerId in an external peer's trust
// store. Member-to-member edges are covered below.
guard "no_external_peer_edges" { mob_machine_member_has_no_external_peer_edges(self.external_peer_edges, agent_identity) }
update {
self.member_prior_peer_endpoints = mob_machine_member_prior_peer_endpoints_after_migration(
self.member_prior_peer_endpoints,
agent_identity,
self.member_peer_endpoints.get_cloned(agent_identity).get("value"),
peer_endpoint
);
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(peer_endpoint));
self.member_peer_endpoints.insert(agent_identity, peer_endpoint);
self.topology_epoch += 1;
}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RecoverRosterMemberResetRunning {
on signal RecoverRosterMemberReset { agent_identity, previous_agent_runtime_id, previous_generation, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "previous_runtime_recovered" { self.live_runtime_ids.contains(previous_agent_runtime_id) == true }
guard "identity_recovered" { self.identity_to_runtime.get_cloned(agent_identity) == Some(previous_agent_runtime_id) }
guard "previous_generation_matches_history" { self.identity_runtime_generations.get_copied(agent_identity) == Some(previous_generation) }
guard "generation_is_exact_successor" { Some(generation) == mob_machine_next_respawn_generation(self.identity_runtime_generations, agent_identity) }
guard "fence_token_changes" { self.identity_runtime_fence_tokens.get_copied(agent_identity) != Some(fence_token) }
guard "replacement_runtime_not_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "previous_runtime_session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(previous_agent_runtime_id) == false }
guard "previous_runtime_not_retiring" { self.member_state_markers.get_cloned(previous_agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "previous_runtime_retirement_closed" { self.runtime_retire_pending_sessions.contains_key(previous_agent_runtime_id) == false }
guard "previous_runtime_retire_refusal_closed" {
self.runtime_retire_refusal_codes.contains_key(previous_agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(previous_agent_runtime_id) == false
}
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.live_runtime_ids.remove(previous_agent_runtime_id);
self.runtime_fence_tokens.remove(previous_agent_runtime_id);
self.member_startup_binding_requested.remove(previous_agent_runtime_id);
self.member_startup_runtime_ready.remove(previous_agent_runtime_id);
self.member_startup_ready.remove(previous_agent_runtime_id);
self.member_state_markers.remove(previous_agent_runtime_id);
self.remote_runtime_retired_ids.remove(previous_agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(previous_agent_runtime_id);
self.runtime_retire_refusal_codes.remove(previous_agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(previous_agent_runtime_id);
self.runtime_retire_pending_sessions.remove(previous_agent_runtime_id);
self.live_runtime_ids.insert(agent_runtime_id);
if self.externally_addressable_runtime_ids.contains(previous_agent_runtime_id) {
self.externally_addressable_runtime_ids.remove(previous_agent_runtime_id);
self.externally_addressable_runtime_ids.insert(agent_runtime_id);
} else {
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
}
self.runtime_fence_tokens.insert(agent_runtime_id, fence_token);
self.identity_to_runtime.insert(agent_identity, agent_runtime_id);
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.remove(agent_identity);
self.identity_runtime_generations.insert(agent_identity, generation);
self.identity_runtime_fence_tokens.insert(agent_identity, fence_token);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
}
// A retirement-start journal is a durable in-flight obligation, not a
// completed roster removal. Replay keeps the member live-but-Retiring
// and restores the exact session correlation needed for a routed
// retire retry. The three arms mirror the releasing, preserving, and
// peer-only admission shapes without emitting live side effects during
// recovery.
transition RecoverRosterMemberRetirementStartedReleasing {
on signal RecoverRosterMemberRetirementStarted { agent_identity, agent_runtime_id, generation, releasing, session_id, retiring_peer_endpoint, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "releasing_present" { releasing != None }
guard "session_matches_releasing" { session_id == releasing }
guard "binding_matches_releasing" { self.member_session_bindings.get_cloned(agent_identity) == releasing }
guard "retiring_peer_endpoint_consistent" { retiring_peer_endpoint == None || self.member_peer_endpoints.contains_key(agent_identity) == false || self.member_peer_endpoints.get_cloned(agent_identity) == retiring_peer_endpoint }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_session_bindings.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_kickoff_pending.remove(agent_identity);
self.member_kickoff_starting.remove(agent_identity);
self.member_kickoff_callback_pending.remove(agent_identity);
self.member_kickoff_started.remove(agent_identity);
self.member_kickoff_failed.remove(agent_identity);
self.member_kickoff_cancelled.remove(agent_identity);
self.member_kickoff_error.remove(agent_identity);
self.member_kickoff_input_ids.remove(agent_identity);
self.retained_placed_kickoff_obligations.remove(agent_identity);
self.member_placed_kickoff_outcome_kinds.remove(agent_identity);
self.member_placed_kickoff_outcome_errors.remove(agent_identity);
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
self.member_placed_kickoff_closure_kinds.remove(agent_identity);
if retiring_peer_endpoint != None {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(retiring_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, retiring_peer_endpoint.get("value"));
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) && self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
self.topology_epoch += 1;
}
to Running
}
// Event replay may legitimately encounter the same start marker more
// than once (for example after an at-least-once journal copy). The
// releasing arm removed the binding on its first application, so make
// that already-applied shape explicitly idempotent instead of letting
// duplicate recovery fail closed as an invalid transition.
transition RecoverRosterMemberRetirementStartedReleasingAlreadyApplied {
on signal RecoverRosterMemberRetirementStarted { agent_identity, agent_runtime_id, generation, releasing, session_id, retiring_peer_endpoint, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches_retired_runtime" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "releasing_present" { releasing != None }
guard "session_matches_releasing" { session_id == releasing }
guard "binding_already_released" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "member_already_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_already_pending" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "ingress_detach_still_pending" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
guard "retiring_peer_endpoint_consistent" { retiring_peer_endpoint == None || self.member_peer_endpoints.contains_key(agent_identity) == false || self.member_peer_endpoints.get_cloned(agent_identity) == retiring_peer_endpoint }
update {
if retiring_peer_endpoint != None {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(retiring_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, retiring_peer_endpoint.get("value"));
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) && self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
transition RecoverRosterMemberRetirementStartedPreservingBinding {
on signal RecoverRosterMemberRetirementStarted { agent_identity, agent_runtime_id, generation, releasing, session_id, retiring_peer_endpoint, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "releasing_absent" { releasing == None }
guard "session_present" { session_id != None }
guard "binding_matches_session" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "retiring_peer_endpoint_consistent" { retiring_peer_endpoint == None || self.member_peer_endpoints.contains_key(agent_identity) == false || self.member_peer_endpoints.get_cloned(agent_identity) == retiring_peer_endpoint }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
if retiring_peer_endpoint != None {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(retiring_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, retiring_peer_endpoint.get("value"));
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) && self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
// The same durable journal kind is used for a placed release because
// the controlling session remains bound until the host acknowledges
// disposal. Recovery distinguishes that shape from local runtime
// retirement using the already-restored placement authority.
transition RecoverRosterMemberRetirementStartedPlaced {
on signal RecoverRosterMemberRetirementStarted { agent_identity, agent_runtime_id, generation, releasing, session_id, retiring_peer_endpoint, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "releasing_absent" { releasing == None }
guard "session_present" { session_id != None }
guard "binding_matches_session" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "retiring_peer_endpoint_consistent" { retiring_peer_endpoint == None || self.member_peer_endpoints.contains_key(agent_identity) == false || self.member_peer_endpoints.get_cloned(agent_identity) == retiring_peer_endpoint }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
if retiring_peer_endpoint != None {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(retiring_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, retiring_peer_endpoint.get("value"));
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) && self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
transition RecoverRosterMemberRetirementStartedPeerOnly {
on signal RecoverRosterMemberRetirementStarted { agent_identity, agent_runtime_id, generation, releasing, session_id, retiring_peer_endpoint, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "releasing_absent" { releasing == None }
guard "session_absent" { session_id == None }
guard "binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retiring_peer_endpoint_consistent" { retiring_peer_endpoint == None || self.member_peer_endpoints.contains_key(agent_identity) == false || self.member_peer_endpoints.get_cloned(agent_identity) == retiring_peer_endpoint }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
if retiring_peer_endpoint != None {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(retiring_peer_endpoint.get("value")));
self.member_peer_endpoints.insert(agent_identity, retiring_peer_endpoint.get("value"));
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) && self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
transition ObserveRespawnTopologyPreservationStartedFresh {
on signal ObserveRespawnTopologyPreservationStarted { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "preservation_not_recorded" { self.pending_respawn_topology.contains(agent_identity) == false }
guard "abandonment_not_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
update {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition ObserveRespawnTopologyPreservationStartedAlreadyRecorded {
on signal ObserveRespawnTopologyPreservationStarted { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "preservation_recorded" { self.pending_respawn_topology.contains(agent_identity) == true }
update {}
to Running
}
transition ObserveRespawnTopologyPreservationStartedAbandoned {
on signal ObserveRespawnTopologyPreservationStarted { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "preservation_not_recorded" { self.pending_respawn_topology.contains(agent_identity) == false }
guard "abandonment_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
update {}
to Running
}
transition ObserveRespawnTopologyAbandonedRetiringFresh {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "abandonment_not_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
update {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.topology_epoch += 1;
}
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.insert(agent_identity, generation);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RespawnTopologyAbandoned,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition ObserveRespawnTopologyAbandonedRetiringAlreadyRecorded {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "preservation_not_pending" { self.pending_respawn_topology.contains(agent_identity) == false }
guard "abandonment_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
update {}
to Running
}
transition ObserveRespawnTopologyAbandonedTerminalFresh {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_matches_terminal_history" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_terminal_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "preservation_pending" { self.pending_respawn_topology.contains(agent_identity) == true }
guard "abandonment_not_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
update {
self.pending_respawn_topology.remove(agent_identity);
self.abandoned_respawn_topology.insert(agent_identity, generation);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RespawnTopologyAbandoned,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition ObserveRespawnTopologyAbandonedTerminalAlreadyRecorded {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_matches_terminal_history" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_terminal_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "preservation_not_pending" { self.pending_respawn_topology.contains(agent_identity) == false }
guard "abandonment_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
update {}
to Running
}
// Replay of a marker that was already folded into a false-preserve
// terminal uses this no-journal arm to restore the exact generation
// tombstone without double-bumping the topology epoch.
transition ObserveRespawnTopologyAbandonedTerminalRecoveredFresh {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
guard "generation_matches_terminal_history" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_terminal_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "preservation_not_pending" { self.pending_respawn_topology.contains(agent_identity) == false }
guard "abandonment_not_recorded" { self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
update {
self.abandoned_respawn_topology.insert(agent_identity, generation);
}
to Running
}
transition ObserveRespawnTopologyAbandonedStaleSuccessor {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_rebound" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "different_runtime" { self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id) }
guard "successor_generation_differs" { self.identity_runtime_generations.get_copied(agent_identity) != Some(generation) }
update {}
to Running
}
transition ObserveRespawnTopologyAbandonedDestroyed {
on signal ObserveRespawnTopologyAbandoned { agent_identity, agent_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition RecoverRemoteMemberRuntimeRetiredFresh {
per_phase [Running, Stopped]
on signal RecoverRemoteMemberRuntimeRetired { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_not_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == false }
update {
self.remote_runtime_retired_ids.insert(agent_runtime_id);
}
to Running
}
transition RecoverRemoteMemberRuntimeRetiredAlreadyRecorded {
per_phase [Running, Stopped]
on signal RecoverRemoteMemberRuntimeRetired { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
update {}
to Running
}
transition RecoverRemoteMemberSupervisorRevokedFresh {
per_phase [Running, Stopped]
on signal RecoverRemoteMemberSupervisorRevoked { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
guard "remote_supervisor_not_recorded" { self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == false }
update {
self.remote_supervisor_revoked_ids.insert(agent_runtime_id);
}
to Running
}
transition RecoverRemoteMemberSupervisorRevokedAlreadyRecorded {
per_phase [Running, Stopped]
on signal RecoverRemoteMemberSupervisorRevoked { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
guard "remote_supervisor_recorded" { self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == true }
update {}
to Running
}
transition RecoverRosterMemberRetiredRunning {
on signal RecoverRosterMemberRetired { agent_identity, agent_runtime_id, generation, preserve_machine_topology, preservation_started }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
// Preserve a replacement spawn's pre-membership Opened phase;
// only the retired membership's committed phase is terminal.
if self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MembershipCommitted) {
self.spawn_exec_phase.remove(agent_identity);
}
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
// A durable MemberRetired event can only have been appended
// after the live detach handoff closed. Replay therefore
// consumes the transient obligation reopened by the earlier
// retirement-start event instead of attempting the external
// side effect again after terminal completion.
self.pending_session_ingress_detach_runtime_ids.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.external_member_rebind_capability.remove(agent_identity);
self.members_to_retire.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if preservation_started && preserve_machine_topology == false {
self.topology_epoch += 1;
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
} else {
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
transition RecoverRosterMemberRetiringRunning {
on signal RecoverRosterMemberRetiring { agent_identity, agent_runtime_id, fence_token, generation, session_id, host_id }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "identity_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "placement_matches" { self.member_placement.get_cloned(agent_identity) == host_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
}
to Running
}
transition RecoverRosterMemberRetiringReplay {
on signal RecoverRosterMemberRetiring { agent_identity, agent_runtime_id, fence_token, generation, session_id, host_id }
guard { self.lifecycle_phase == Phase::Running }
guard "already_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "identity_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "placement_matches" { self.member_placement.get_cloned(agent_identity) == host_id }
update {}
to Running
}
transition RecoverRosterMemberRetiredCurrentAlreadyAbsent {
on signal RecoverRosterMemberRetired { agent_identity, agent_runtime_id, generation, preserve_machine_topology, preservation_started }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_not_recovered" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "generation_matches_retired_runtime" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "current_binding_absent_or_matches" {
self.identity_to_runtime.contains_key(agent_identity) == false
|| self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id)
}
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
// A terminal for the current absent incarnation settles its
// committed pre-activation rung, but a delayed duplicate must
// not erase a successor spawn that has already opened.
if self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MembershipCommitted) {
self.spawn_exec_phase.remove(agent_identity);
}
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.pending_session_ingress_detach_runtime_ids.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.external_member_rebind_capability.remove(agent_identity);
self.members_to_retire.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if preservation_started && preserve_machine_topology == false {
self.topology_epoch += 1;
}
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
} else {
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
}
to Running
}
transition RecoverRosterMemberRetiredStaleGeneration {
on signal RecoverRosterMemberRetired { agent_identity, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_remapped" {
self.identity_to_runtime.contains_key(agent_identity) == true
&& self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
}
update {
// The identity belongs to a newer incarnation, so retain its
// identity-scoped facts while converging every runtime-scoped
// residue owned by the terminal event's older runtime.
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.pending_session_ingress_detach_runtime_ids.remove(agent_runtime_id);
}
to Running
}
// A delayed final for generation N must never clear generation N+1's
// identity, profile, session, placement, or wiring authority. Only
// stale runtime-keyed bookkeeping is safe to prune.
transition RecoverRosterMemberRetiredStaleIncarnation {
on signal RecoverRosterMemberRetired { agent_identity, agent_runtime_id, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_or_generation_advanced" {
self.identity_runtime_generations.get_copied(agent_identity) != Some(generation)
|| (
self.identity_to_runtime.contains_key(agent_identity)
&& self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
)
}
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
}
to Running
}
transition RecoverMemberKickoffPending {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_pending_phase" { phase == KickoffPhase::Pending }
guard "recover_pending_without_error" { error == None }
update {
self.member_kickoff_pending.insert(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
self.member_kickoff_input_ids.remove(member_id);
self.retained_placed_kickoff_obligations.remove(member_id);
self.member_placed_kickoff_outcome_kinds.remove(member_id);
self.member_placed_kickoff_outcome_errors.remove(member_id);
self.member_placed_kickoff_closure_kinds.remove(member_id);
}
to Running
}
transition RecoverMemberKickoffStarting {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_starting_phase" { phase == KickoffPhase::Starting }
guard "recover_starting_without_error" { error == None }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.insert(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
}
transition RecoverMemberKickoffCallbackPending {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_callback_pending_phase" { phase == KickoffPhase::CallbackPending }
guard "recover_callback_pending_without_error" { error == None }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.insert(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
}
transition RecoverMemberKickoffStarted {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_started_phase" { phase == KickoffPhase::Started }
guard "recover_started_without_error" { error == None }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.insert(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
}
transition RecoverMemberKickoffFailed {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_failed_phase" { phase == KickoffPhase::Failed }
guard "recover_failed_has_error" { error != None }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.insert(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.insert(member_id, error.get("value"));
}
to Running
}
transition RecoverMemberKickoffCancelled {
on signal RecoverMemberKickoff { member_id, phase, error }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent" { mob_machine_placed_kickoff_custody_absent_for_identity(self.pending_placed_kickoff_outcomes, self.resolved_placed_kickoff_outcomes, member_id) }
guard "placed_kickoff_tombstone_absent" { self.retained_placed_kickoff_obligations.contains_key(member_id) == false }
guard "recover_cancelled_phase" { phase == KickoffPhase::Cancelled }
guard "recover_cancelled_without_error" { error == None }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.insert(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
}
transition RecoverObjectiveBinding {
on signal RecoverObjectiveBinding { member_id, objective_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_kickoff_custody_absent_or_exact" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
&& self.retained_placed_kickoff_obligations.contains_key(member_id) == false
|| (self.member_kickoff_objective_ids.get_cloned(member_id) == Some(objective_id)
&& self.retained_placed_kickoff_obligations.get_cloned(member_id).get("value").objective_id == objective_id)
}
update {
self.member_kickoff_objective_ids.insert(member_id, objective_id);
if !self.objective_owner_ids.contains_key(objective_id) {
self.objective_owner_ids.insert(objective_id, member_id);
}
}
to Running
}
// Finalized kickoff custody is audit/tombstone truth, not live host
// custody. Recovery must be able to restore it while the committed
// carrier is dormant under a revoked or replacement host binding;
// routing guards belong only to Pending/Resolved send+ACK custody.
transition RecoverFinalizedPlacedKickoffRunning {
on signal RecoverFinalizedPlacedKickoff { obligation, outcome_kind, outcome_error, closure_kind }
guard { self.lifecycle_phase == Phase::Running }
guard "obligation_well_formed" { mob_machine_placed_kickoff_obligation_well_formed(obligation) }
guard "current_committed_carrier_present" { self.current_placed_spawn_ids.contains_key(obligation.agent_identity) == true }
guard "carrier_host_exact" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "carrier_binding_generation_exact" { self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation) }
guard "member_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "member_generation_exact" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "member_fence_exact" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
guard "member_autonomous" { self.member_runtime_modes.get_cloned(obligation.agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost) }
guard "objective_exact" { self.member_kickoff_objective_ids.get_cloned(obligation.agent_identity) == Some(obligation.objective_id) }
guard "custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
obligation.agent_identity)
}
guard "retained_obligation_absent" { self.retained_placed_kickoff_obligations.contains_key(obligation.agent_identity) == false }
guard "input_unbound" { self.member_kickoff_input_ids.contains_key(obligation.agent_identity) == false }
guard "finalized_chain_matches_public_terminal" {
mob_machine_finalized_placed_kickoff_recovery_well_formed(
self.member_kickoff_started,
self.member_kickoff_callback_pending,
self.member_kickoff_failed,
self.member_kickoff_cancelled,
self.member_kickoff_error,
obligation.agent_identity,
outcome_kind,
outcome_error,
closure_kind)
}
update {
self.member_kickoff_input_ids.insert(obligation.agent_identity, obligation.input_id);
self.retained_placed_kickoff_obligations.insert(obligation.agent_identity, obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, outcome_kind);
if outcome_error != None {
self.member_placed_kickoff_outcome_errors.insert(obligation.agent_identity, outcome_error.get("value"));
} else {
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
}
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, closure_kind);
}
to Running
}
transition BindObjectiveOwner {
per_phase [Running]
on input BindObjectiveOwner { owner_id, objective_id }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "objective_owner_unbound" { self.objective_owner_ids.contains_key(objective_id) == false }
update {
self.objective_owner_ids.insert(objective_id, owner_id);
}
to Running
emit PersistObjectiveOwnerBinding { owner_id: owner_id, objective_id: objective_id }
}
transition BindObjectiveOwnerIdempotent {
per_phase [Running]
on input BindObjectiveOwner { owner_id, objective_id }
guard "objective_owner_matches" { self.objective_owner_ids.get_cloned(objective_id) == Some(owner_id) }
update {}
to Running
}
transition RecoverObjectiveConclusion {
on signal RecoverObjectiveConclusion { member_id, objective_id, outcome }
guard { self.lifecycle_phase == Phase::Running }
guard "objective_belongs_to_lead" { self.objective_owner_ids.get_cloned(objective_id) == Some(member_id) }
update {
self.objective_outcomes.insert(objective_id, outcome);
self.concluded_objective_ids.insert(objective_id);
}
to Running
}
// Row #351: machine-owned membership reconciliation. The batch diff
// (desired-vs-current) is recomputed in-DSL from `identity_to_runtime`
// and stored into the membership-intent sets. The handle reads these
// sets from the returned snapshot and executes spawn/retire mechanically
// rather than computing the difference itself. Each ReconcileRunning
// fully recomputes the sets so successive reconciles stay self-fresh.
transition ReconcileRunning {
on input Reconcile { desired, retire_stale }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {
self.members_to_spawn = mob_machine_members_to_spawn(self.identity_to_runtime, desired);
self.members_to_retire = mob_machine_members_to_retire(self.identity_to_runtime, desired, retire_stale);
self.desired_members = desired;
}
to Running
}
transition ReconcileStopped {
on input Reconcile { desired, retire_stale }
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
}
transition ReconcileCompleted {
on input Reconcile { desired, retire_stale }
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Completed
}
transition ReconcileDestroyed {
on input Reconcile { desired, retire_stale }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition ObserveRuntimeReady {
on signal ObserveRuntimeReady { agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.insert(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
}
to Running
}
transition StartupMarkReady {
per_phase [Running, Stopped, Completed]
on input StartupMarkReady { agent_runtime_id, fence_token }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.insert(agent_runtime_id);
}
to Running
}
transition KickoffMarkPending {
on input KickoffMarkPending { member_id, objective_id }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
}
guard "kickoff_not_started" {
!self.member_kickoff_pending.contains(member_id)
&& !self.member_kickoff_starting.contains(member_id)
&& !self.member_kickoff_callback_pending.contains(member_id)
&& !self.member_kickoff_started.contains(member_id)
&& !self.member_kickoff_failed.contains(member_id)
&& !self.member_kickoff_cancelled.contains(member_id)
}
update {
self.member_kickoff_pending.insert(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
self.member_kickoff_input_ids.remove(member_id);
self.retained_placed_kickoff_obligations.remove(member_id);
self.member_placed_kickoff_outcome_kinds.remove(member_id);
self.member_placed_kickoff_outcome_errors.remove(member_id);
self.member_kickoff_objective_ids.insert(member_id, objective_id);
self.member_placed_kickoff_closure_kinds.remove(member_id);
if !self.objective_owner_ids.contains_key(objective_id) {
self.objective_owner_ids.insert(objective_id, member_id);
}
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::Pending }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Pending }
}
transition KickoffMarkPendingReplay {
per_phase [Running, Stopped, Completed]
on input KickoffMarkPending { member_id, objective_id }
guard "already_pending" { self.member_kickoff_pending.contains(member_id) }
guard "objective_exact" { self.member_kickoff_objective_ids.get_cloned(member_id) == Some(objective_id) }
update {}
to Running
}
transition ConcludeObjective {
per_phase [Running]
on input ConcludeObjective { member_id, objective_id, outcome }
guard "objective_belongs_to_lead" { self.objective_owner_ids.get_cloned(objective_id) == Some(member_id) }
guard "objective_not_concluded" { self.concluded_objective_ids.contains(objective_id) == false }
update {
self.objective_outcomes.insert(objective_id, outcome);
self.concluded_objective_ids.insert(objective_id);
}
to Running
emit PersistObjectiveConclusion { member_id: member_id, objective_id: objective_id, outcome: outcome }
}
transition ConcludeObjectiveIdempotent {
per_phase [Running]
on input ConcludeObjective { member_id, objective_id, outcome }
guard "objective_belongs_to_lead" { self.objective_owner_ids.get_cloned(objective_id) == Some(member_id) }
guard "objective_already_concluded" { self.concluded_objective_ids.contains(objective_id) == true }
guard "objective_outcome_matches" { self.objective_outcomes.get_cloned(objective_id) == Some(outcome) }
update {}
to Running
}
transition KickoffMarkStarting {
on input KickoffMarkStarting { member_id }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "kickoff_pending" { self.member_kickoff_pending.contains(member_id) }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.insert(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::Starting }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Starting }
}
transition KickoffMarkStartingReplay {
per_phase [Running, Stopped, Completed]
on input KickoffMarkStarting { member_id }
guard "already_starting" { self.member_kickoff_starting.contains(member_id) }
update {}
to Running
}
// =====================================================================
// Placed autonomous kickoff custody.
//
// Start is the record-before-send authority boundary: it binds one
// canonical input/interaction UUID to the exact current placed
// residency and atomically moves ordinary kickoff Pending->Starting.
// A host terminal moves Pending custody to Resolved/ACK-pending only
// while terminalizing the kickoff lifecycle. Certified rejection
// before runtime admission removes Pending without creating ACK
// custody. Dispose is reserved for exact host-row pruning on release,
// revoke, or superseding materialization.
// =====================================================================
transition StartPlacedKickoffFresh {
on input StartPlacedKickoff { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "obligation_well_formed" { mob_machine_placed_kickoff_obligation_well_formed(obligation) }
guard "target_placed" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "target_host_bound" { self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound) }
guard "target_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
}
guard "target_host_binding_generation_exact" {
self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
}
guard "target_host_supports_tracked_turns" {
self.host_durable_sessions.get_cloned(obligation.host_id) == Some(true)
&& self.host_autonomous_members.get_cloned(obligation.host_id) == Some(true)
&& self.host_tracked_input_cancel.get_cloned(obligation.host_id) == Some(true)
&& self.host_protocol_min.get_cloned(obligation.host_id).get("value") <= 4
&& self.host_protocol_max.get_cloned(obligation.host_id).get("value") >= 4
}
guard "target_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "target_runtime_present" { self.identity_to_runtime.contains_key(obligation.agent_identity) == true }
guard "target_runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) == true }
guard "target_not_retiring" { self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) != Some(MobMemberState::Retiring) }
guard "target_autonomous" { self.member_runtime_modes.get_cloned(obligation.agent_identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost) }
guard "target_spawn_settled" { self.spawn_exec_phase.contains_key(obligation.agent_identity) == false }
guard "target_not_reviving" { self.member_revival_pending.contains(obligation.agent_identity) == false }
guard "target_materialization_healthy" { self.member_materialization_failures.contains_key(obligation.agent_identity) == false }
guard "target_carrier_cleanup_absent" {
mob_machine_placed_cleanup_absent_for_identity(
self.pending_placed_carrier_cleanup,
obligation.agent_identity)
}
guard "current_generation" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "current_fence" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
guard "kickoff_pending" { self.member_kickoff_pending.contains(obligation.agent_identity) == true }
guard "objective_exact" { self.member_kickoff_objective_ids.get_cloned(obligation.agent_identity) == Some(obligation.objective_id) }
guard "input_unbound" { self.member_kickoff_input_ids.contains_key(obligation.agent_identity) == false }
guard "correlation_available" {
mob_machine_placed_kickoff_correlation_available(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
self.retained_placed_kickoff_obligations,
self.pending_remote_turn_outcomes,
self.committed_remote_turn_outcomes,
self.resolved_remote_turn_outcomes,
self.pending_placed_completion_outcomes,
self.resolved_placed_completion_outcomes,
obligation)
}
update {
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.insert(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.remove(obligation.agent_identity);
self.member_kickoff_cancelled.remove(obligation.agent_identity);
self.member_kickoff_error.remove(obligation.agent_identity);
self.member_kickoff_input_ids.insert(obligation.agent_identity, obligation.input_id);
self.retained_placed_kickoff_obligations.insert(obligation.agent_identity, obligation);
self.member_placed_kickoff_outcome_kinds.remove(obligation.agent_identity);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
self.member_placed_kickoff_closure_kinds.remove(obligation.agent_identity);
self.pending_placed_kickoff_outcomes.insert(obligation);
}
to Running
emit PersistKickoffUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Starting }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Starting }
}
transition StartPlacedKickoffPendingReplay {
per_phase [Running, Stopped, Completed]
on input StartPlacedKickoff { obligation }
guard "already_pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "input_exact" { self.member_kickoff_input_ids.get_cloned(obligation.agent_identity) == Some(obligation.input_id) }
guard "kickoff_active_or_cancelled" {
self.member_kickoff_starting.contains(obligation.agent_identity)
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)
}
update {}
to Running
}
transition StartPlacedKickoffResolvedReplay {
per_phase [Running, Stopped, Completed]
on input StartPlacedKickoff { obligation }
guard "already_resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "input_exact" { self.member_kickoff_input_ids.get_cloned(obligation.agent_identity) == Some(obligation.input_id) }
update {}
to Running
}
transition StartPlacedKickoffFinalReplay {
per_phase [Running, Stopped, Completed]
on input StartPlacedKickoff { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "retained_terminal_closure" { self.member_placed_kickoff_closure_kinds.contains_key(obligation.agent_identity) == true }
guard "kickoff_terminal" {
self.member_kickoff_started.contains(obligation.agent_identity)
|| self.member_kickoff_callback_pending.contains(obligation.agent_identity)
|| self.member_kickoff_failed.contains(obligation.agent_identity)
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)
}
update {}
to Running
}
transition ResolvePlacedKickoffStartedFresh {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffStarted { obligation }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Started);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.insert(obligation.agent_identity);
self.member_kickoff_failed.remove(obligation.agent_identity);
self.member_kickoff_cancelled.remove(obligation.agent_identity);
self.member_kickoff_error.remove(obligation.agent_identity);
}
to Running
emit PersistKickoffUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Started }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Started }
}
transition ResolvePlacedKickoffStartedAfterCancellation {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffStarted { obligation }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_cancelled" { self.member_kickoff_cancelled.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Started);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
}
to Running
}
transition ResolvePlacedKickoffStartedReplay {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffStarted { obligation }
guard "resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Started) }
update {}
to Running
}
transition ResolvePlacedKickoffStartedFinalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePlacedKickoffStarted { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Started) }
update {}
to Running
}
transition ResolvePlacedKickoffCallbackPendingFresh {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffCallbackPending { obligation }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::CallbackPending);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.insert(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.remove(obligation.agent_identity);
self.member_kickoff_cancelled.remove(obligation.agent_identity);
self.member_kickoff_error.remove(obligation.agent_identity);
}
to Running
emit PersistKickoffUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::CallbackPending }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::CallbackPending }
}
transition ResolvePlacedKickoffCallbackPendingAfterCancellation {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffCallbackPending { obligation }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_cancelled" { self.member_kickoff_cancelled.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::CallbackPending);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
}
to Running
}
transition ResolvePlacedKickoffCallbackPendingReplay {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffCallbackPending { obligation }
guard "resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::CallbackPending) }
update {}
to Running
}
transition ResolvePlacedKickoffCallbackPendingFinalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePlacedKickoffCallbackPending { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::CallbackPending) }
update {}
to Running
}
transition ResolvePlacedKickoffFailedFresh {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffFailed { obligation, error }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Failed);
self.member_placed_kickoff_outcome_errors.insert(obligation.agent_identity, error);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.insert(obligation.agent_identity);
self.member_kickoff_cancelled.remove(obligation.agent_identity);
self.member_kickoff_error.insert(obligation.agent_identity, error);
}
to Running
emit PersistKickoffFailureUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Failed, error: error }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Failed }
}
transition ResolvePlacedKickoffFailedAfterCancellation {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffFailed { obligation, error }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_cancelled" { self.member_kickoff_cancelled.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Failed);
self.member_placed_kickoff_outcome_errors.insert(obligation.agent_identity, error);
}
to Running
}
transition ResolvePlacedKickoffFailedReplay {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffFailed { obligation, error }
guard "resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" {
self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Failed)
&& self.member_placed_kickoff_outcome_errors.get_cloned(obligation.agent_identity) == Some(error)
}
update {}
to Running
}
transition ResolvePlacedKickoffFailedFinalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePlacedKickoffFailed { obligation, error }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" {
self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Failed)
&& self.member_placed_kickoff_outcome_errors.get_cloned(obligation.agent_identity) == Some(error)
}
update {}
to Running
}
transition ResolvePlacedKickoffCancelledFresh {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffCancelled { obligation }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_starting_or_cancelled" {
self.member_kickoff_starting.contains(obligation.agent_identity)
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)
}
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.insert(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Cancelled);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.remove(obligation.agent_identity);
self.member_kickoff_cancelled.insert(obligation.agent_identity);
self.member_kickoff_error.remove(obligation.agent_identity);
}
to Running
emit PersistKickoffUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Cancelled }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Cancelled }
}
transition ResolvePlacedKickoffCancelledReplay {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedKickoffCancelled { obligation }
guard "resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Cancelled) }
update {}
to Running
}
transition ResolvePlacedKickoffCancelledFinalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePlacedKickoffCancelled { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "host_outcome_exact" { self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::Cancelled) }
update {}
to Running
}
transition RejectPlacedKickoffBeforeAdmissionFresh {
per_phase [Running, Stopped, Completed]
on input RejectPlacedKickoffBeforeAdmission { obligation, error }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == true }
guard "error_nonempty" { error != "" }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::RejectedNoEffect);
self.member_placed_kickoff_outcome_errors.insert(obligation.agent_identity, error);
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, PlacedKickoffClosureKind::RejectedNoEffect);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.insert(obligation.agent_identity);
self.member_kickoff_cancelled.remove(obligation.agent_identity);
self.member_kickoff_error.insert(obligation.agent_identity, error);
}
to Running
emit PersistKickoffFailureUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Failed, error: error }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Failed }
}
// Cancellation wins the user-visible lifecycle race, while the
// authenticated no-effect proof still closes exact Pending custody.
// No resolved/ACK row is created because the host proved admission
// never occurred.
transition RejectPlacedKickoffBeforeAdmissionAfterCancellation {
per_phase [Running, Stopped, Completed]
on input RejectPlacedKickoffBeforeAdmission { obligation, error }
guard "pending" { self.pending_placed_kickoff_outcomes.contains(obligation) == true }
guard "kickoff_cancelled" { self.member_kickoff_cancelled.contains(obligation.agent_identity) == true }
guard "error_nonempty" { error != "" }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::RejectedNoEffect);
self.member_placed_kickoff_outcome_errors.insert(obligation.agent_identity, error);
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, PlacedKickoffClosureKind::RejectedNoEffect);
}
to Running
}
transition RejectPlacedKickoffBeforeAdmissionReplay {
per_phase [Running, Stopped, Completed]
on input RejectPlacedKickoffBeforeAdmission { obligation, error }
guard "error_nonempty" { error != "" }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "no_effect_outcome_exact" {
self.member_placed_kickoff_outcome_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffOutcomeKind::RejectedNoEffect)
&& self.member_placed_kickoff_outcome_errors.get_cloned(obligation.agent_identity) == Some(error)
}
guard "closure_exact" { self.member_placed_kickoff_closure_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffClosureKind::RejectedNoEffect) }
guard "terminal_matches" {
(self.member_kickoff_failed.contains(obligation.agent_identity)
&& self.member_kickoff_error.get_cloned(obligation.agent_identity) == Some(error))
|| self.member_kickoff_cancelled.contains(obligation.agent_identity)
}
update {}
to Running
}
transition AcknowledgePlacedKickoffOutcomePresent {
per_phase [Running, Stopped, Completed, Destroyed]
on input AcknowledgePlacedKickoffOutcome { obligation }
guard "resolved" { self.resolved_placed_kickoff_outcomes.contains(obligation) == true }
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
update {
self.resolved_placed_kickoff_outcomes.remove(obligation);
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, PlacedKickoffClosureKind::Acknowledged);
}
to Running
}
transition AcknowledgePlacedKickoffOutcomeReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input AcknowledgePlacedKickoffOutcome { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "closure_exact" { self.member_placed_kickoff_closure_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffClosureKind::Acknowledged) }
update {}
to Running
}
transition DisposePlacedKickoffObligationActive {
per_phase [Running, Stopped, Completed, Destroyed]
on input DisposePlacedKickoffObligation { obligation }
guard "custody_present" {
self.pending_placed_kickoff_outcomes.contains(obligation) == true
|| self.resolved_placed_kickoff_outcomes.contains(obligation) == true
}
guard "kickoff_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == true }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.remove(obligation);
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Disposed);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, PlacedKickoffClosureKind::Disposed);
self.member_kickoff_pending.remove(obligation.agent_identity);
self.member_kickoff_starting.remove(obligation.agent_identity);
self.member_kickoff_callback_pending.remove(obligation.agent_identity);
self.member_kickoff_started.remove(obligation.agent_identity);
self.member_kickoff_failed.remove(obligation.agent_identity);
self.member_kickoff_cancelled.insert(obligation.agent_identity);
self.member_kickoff_error.remove(obligation.agent_identity);
}
to Running
emit PersistKickoffUpdate { member_id: obligation.agent_identity, phase: KickoffPhase::Cancelled }
emit EmitKickoffLifecycleNotice { member_id: obligation.agent_identity, intent: KickoffIntent::Cancelled }
}
transition DisposePlacedKickoffObligationTerminal {
per_phase [Running, Stopped, Completed, Destroyed]
on input DisposePlacedKickoffObligation { obligation }
guard "custody_present" {
self.pending_placed_kickoff_outcomes.contains(obligation) == true
|| self.resolved_placed_kickoff_outcomes.contains(obligation) == true
}
guard "kickoff_not_starting" { self.member_kickoff_starting.contains(obligation.agent_identity) == false }
update {
self.pending_placed_kickoff_outcomes.remove(obligation);
self.resolved_placed_kickoff_outcomes.remove(obligation);
if !self.member_placed_kickoff_outcome_kinds.contains_key(obligation.agent_identity) {
self.member_placed_kickoff_outcome_kinds.insert(obligation.agent_identity, PlacedKickoffOutcomeKind::Disposed);
self.member_placed_kickoff_outcome_errors.remove(obligation.agent_identity);
}
self.member_placed_kickoff_closure_kinds.insert(obligation.agent_identity, PlacedKickoffClosureKind::Disposed);
}
to Running
}
transition DisposePlacedKickoffObligationReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input DisposePlacedKickoffObligation { obligation }
guard "custody_absent" {
self.pending_placed_kickoff_outcomes.contains(obligation) == false
&& self.resolved_placed_kickoff_outcomes.contains(obligation) == false
}
guard "retained_obligation_exact" { self.retained_placed_kickoff_obligations.get_cloned(obligation.agent_identity) == Some(obligation) }
guard "closure_exact" { self.member_placed_kickoff_closure_kinds.get_cloned(obligation.agent_identity) == Some(PlacedKickoffClosureKind::Disposed) }
update {}
to Running
}
transition KickoffResolveStarted {
per_phase [Running, Stopped, Completed]
on input KickoffResolveStarted { member_id }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
}
guard "kickoff_starting" { self.member_kickoff_starting.contains(member_id) }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.insert(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::Started }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Started }
}
transition KickoffResolveCallbackPending {
per_phase [Running, Stopped, Completed]
on input KickoffResolveCallbackPending { member_id }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
}
guard "kickoff_starting" { self.member_kickoff_starting.contains(member_id) }
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.insert(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::CallbackPending }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::CallbackPending }
}
transition KickoffResolveFailedFromStarting {
per_phase [Running, Stopped, Completed]
on input KickoffResolveFailed { member_id, error }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
}
guard "kickoff_active_failed" {
(self.member_kickoff_pending.contains(member_id)
|| self.member_kickoff_starting.contains(member_id)
|| self.member_kickoff_callback_pending.contains(member_id))
}
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.insert(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.insert(member_id, error);
}
to Running
emit PersistKickoffFailureUpdate { member_id: member_id, phase: KickoffPhase::Failed, error: error }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Failed }
}
transition KickoffCancelRequested {
per_phase [Running, Stopped, Completed]
on input KickoffCancelRequested { member_id }
guard "kickoff_cancellable" {
(self.member_kickoff_pending.contains(member_id)
|| self.member_kickoff_starting.contains(member_id)
|| self.member_kickoff_callback_pending.contains(member_id))
}
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.insert(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::Cancelled }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Cancelled }
}
transition KickoffClear {
per_phase [Running, Stopped, Completed]
on input KickoffClear { member_id }
guard "placed_kickoff_custody_absent" {
mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
member_id)
}
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.remove(member_id);
self.member_kickoff_error.remove(member_id);
self.member_kickoff_input_ids.remove(member_id);
self.retained_placed_kickoff_obligations.remove(member_id);
self.member_placed_kickoff_outcome_kinds.remove(member_id);
self.member_placed_kickoff_outcome_errors.remove(member_id);
self.member_placed_kickoff_closure_kinds.remove(member_id);
}
to Running
}
// =====================================================================
// 0.7.2 disciplined shell inputs — L5 (rows 12/13).
//
// `KickoffQuiesced` closes the kickoff-waiter drain obligation opened
// by the member retire / destroy-retire transitions (the
// `RequestKickoffQuiesce` effect). It is TOTAL over kickoff state and
// lifecycle phase: quiescing an in-flight kickoff is a machine-recorded
// cancellation; quiescing an idle or already-terminal kickoff is an
// accepted no-op; a post-destroy arrival is an accepted no-op. The
// shell aborts + awaits the waiter task and fires this input without
// probing machine state first.
// =====================================================================
transition KickoffQuiescedInFlight {
per_phase [Running, Stopped, Completed]
on input KickoffQuiesced { member_id }
guard "kickoff_in_flight" {
(self.member_kickoff_pending.contains(member_id)
|| self.member_kickoff_starting.contains(member_id)
|| self.member_kickoff_callback_pending.contains(member_id))
}
update {
self.member_kickoff_pending.remove(member_id);
self.member_kickoff_starting.remove(member_id);
self.member_kickoff_callback_pending.remove(member_id);
self.member_kickoff_started.remove(member_id);
self.member_kickoff_failed.remove(member_id);
self.member_kickoff_cancelled.insert(member_id);
self.member_kickoff_error.remove(member_id);
}
to Running
emit PersistKickoffUpdate { member_id: member_id, phase: KickoffPhase::Cancelled }
emit EmitKickoffLifecycleNotice { member_id: member_id, intent: KickoffIntent::Cancelled }
}
transition KickoffQuiescedIdle {
per_phase [Running, Stopped, Completed]
on input KickoffQuiesced { member_id }
guard "kickoff_not_in_flight" {
!self.member_kickoff_pending.contains(member_id)
&& !self.member_kickoff_starting.contains(member_id)
&& !self.member_kickoff_callback_pending.contains(member_id)
}
update {}
to Running
}
transition KickoffQuiescedDestroyed {
on input KickoffQuiesced { member_id }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// =====================================================================
// 0.7.2 L5 D2a — late kickoff resolutions are total typed no-ops.
//
// The autonomous-kickoff completion waiter is an in-process producer
// that can legitimately deliver its outcome after teardown quiesced
// the kickoff (or after the outcome was already in flight when
// teardown committed). A late `KickoffResolve*` / `KickoffCancel*`
// arrival must commit as an explicit no-op self-loop instead of a
// guard rejection the shell has to launder (`Err(_) => Ok(false)`).
// Precedent: `ObserveCredentialFreshnessValid` no-op self-loop
// (auth_machine.rs). The Destroyed-phase variants keep the inputs
// total even when the mob reached Destroyed without per-member
// quiesce (e.g. `ObserveRuntimeDestroyed` recovery).
// =====================================================================
transition KickoffResolveStartedLateArrival {
per_phase [Running, Stopped, Completed]
on input KickoffResolveStarted { member_id }
guard "kickoff_not_starting" { !self.member_kickoff_starting.contains(member_id) }
update {}
to Running
}
transition KickoffResolveStartedDestroyed {
on input KickoffResolveStarted { member_id }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition KickoffResolveCallbackPendingLateArrival {
per_phase [Running, Stopped, Completed]
on input KickoffResolveCallbackPending { member_id }
guard "kickoff_not_starting" { !self.member_kickoff_starting.contains(member_id) }
update {}
to Running
}
transition KickoffResolveCallbackPendingDestroyed {
on input KickoffResolveCallbackPending { member_id }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition KickoffResolveFailedLateArrival {
per_phase [Running, Stopped, Completed]
on input KickoffResolveFailed { member_id, error }
guard "kickoff_not_active" {
!self.member_kickoff_pending.contains(member_id)
&& !self.member_kickoff_starting.contains(member_id)
&& !self.member_kickoff_callback_pending.contains(member_id)
}
update {}
to Running
}
transition KickoffResolveFailedDestroyed {
on input KickoffResolveFailed { member_id, error }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition KickoffCancelRequestedLateArrival {
per_phase [Running, Stopped, Completed]
on input KickoffCancelRequested { member_id }
guard "kickoff_not_active" {
!self.member_kickoff_pending.contains(member_id)
&& !self.member_kickoff_starting.contains(member_id)
&& !self.member_kickoff_callback_pending.contains(member_id)
}
update {}
to Running
}
transition KickoffCancelRequestedDestroyed {
on input KickoffCancelRequested { member_id }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// =====================================================================
// Wave-G1 catalog folds: classification / probe / escalation transitions
// =====================================================================
// Row #14: duplicate-member admission probe. The verdict is read from
// machine-owned binding state, not the PendingSpawnLineage side-map.
// CRITICAL FIX (G1 regression): the Duplicate guard must also reject an
// in-flight pending spawn (pending_spawn_sessions) so a concurrent
// second spawn probing before the first records its binding still sees a
// duplicate. Admitted is the exact negation of all three presence facts.
transition ProbeMemberAdmissionDuplicate {
per_phase [Running, Stopped, Completed, Destroyed]
on input ProbeMemberAdmission { agent_identity }
guard "identity_already_bound_or_pending" {
self.identity_to_runtime.contains_key(agent_identity) == true
|| self.member_session_bindings.contains_key(agent_identity) == true
|| self.pending_spawn_sessions.contains_key(agent_identity) == true
}
update {}
to Running
emit MemberAdmissionProbed { agent_identity: agent_identity, verdict: MemberAdmissionVerdictKind::DuplicateRejected }
}
transition ProbeMemberAdmissionAdmitted {
per_phase [Running, Stopped, Completed, Destroyed]
on input ProbeMemberAdmission { agent_identity }
guard "identity_not_bound_and_not_pending" {
self.identity_to_runtime.contains_key(agent_identity) == false
&& self.member_session_bindings.contains_key(agent_identity) == false
&& self.pending_spawn_sessions.contains_key(agent_identity) == false
}
update {}
to Running
emit MemberAdmissionProbed { agent_identity: agent_identity, verdict: MemberAdmissionVerdictKind::Admitted }
}
// Row #181: compute the generation for the next incarnation. A fresh
// identity starts at the domain's initial generation zero; retained
// history advances by exactly one.
transition ComputeRespawnGeneration {
per_phase [Running, Stopped, Completed, Destroyed]
on input ComputeRespawnGeneration { agent_identity }
guard "generation_space_available" {
mob_machine_next_respawn_generation(
self.identity_runtime_generations,
agent_identity
) != None
}
update {}
to Running
emit RespawnGenerationComputed {
agent_identity: agent_identity,
next_generation: mob_machine_next_respawn_generation(
self.identity_runtime_generations,
agent_identity
).get("value")
}
}
// Row #260: classify a typed step-output fault into retry vs terminal.
// The retry-vs-fail decision is machine-owned; the typed terminal cause
// flows into terminalization. Fault detail strings stay shell-side.
transition ClassifyStepOutputFaultRetry {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyStepOutputFault { run_id, step_id, target_retry_key, fault, attempt, max_retries }
guard "attempts_remaining" { attempt < max_retries }
update {}
to Running
emit StepOutputFaultClassified {
run_id: run_id,
step_id: step_id,
target_retry_key: target_retry_key,
disposition: StepFaultDispositionKind::Retry,
terminal_cause: fault
}
}
transition ClassifyStepOutputFaultTerminal {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyStepOutputFault { run_id, step_id, target_retry_key, fault, attempt, max_retries }
guard "attempts_exhausted" { attempt >= max_retries }
update {}
to Running
emit StepOutputFaultClassified {
run_id: run_id,
step_id: step_id,
target_retry_key: target_retry_key,
disposition: StepFaultDispositionKind::Terminal,
terminal_cause: fault
}
}
// Row #261: supervisor escalation. Presence of an eligible target is
// structural — two inputs, not an Option<AgentIdentity>. Target
// selection, timeout policy, and escalation evidence are machine-owned;
// fail-closed is a typed terminal cause, not a free-form string.
transition EscalateToSupervisorTargetFound {
per_phase [Running, Stopped, Completed, Destroyed]
on input EscalateToSupervisor { run_id, step_id, supervisor_identity, turn_timeout_ms }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {}
to Running
emit SupervisorEscalationRequested {
run_id: run_id,
step_id: step_id,
supervisor_identity: supervisor_identity,
turn_timeout_ms: turn_timeout_ms
}
}
transition EscalateToSupervisorTargetMissing {
per_phase [Running, Stopped, Completed, Destroyed]
on input EscalateToSupervisorNoEligibleTarget { run_id, step_id }
update {}
to Running
emit SupervisorEscalationFailed {
run_id: run_id,
step_id: step_id,
cause: SupervisorEscalationFailureCause::NoEligibleSupervisor
}
}
// Row #293: topology-edge admission verdict. A matched declarative rule
// resolves directly; an unmatched edge applies the declared default
// policy field. Default policy is an explicit machine field, not a
// shell map_or(Allow, ..).
transition EvaluateTopologyEdgeRuleAllow {
per_phase [Running, Stopped, Completed, Destroyed]
on input EvaluateTopologyEdge { from_role, to_role, rule_match }
guard "rule_allows_edge" { rule_match == Some(PolicyDecision::Allow) }
update {}
to Running
emit TopologyEdgeVerdictResolved { from_role: from_role, to_role: to_role, verdict: PolicyDecision::Allow }
}
transition EvaluateTopologyEdgeRuleDeny {
per_phase [Running, Stopped, Completed, Destroyed]
on input EvaluateTopologyEdge { from_role, to_role, rule_match }
guard "rule_denies_edge" { rule_match == Some(PolicyDecision::Deny) }
update {}
to Running
emit TopologyEdgeVerdictResolved { from_role: from_role, to_role: to_role, verdict: PolicyDecision::Deny }
}
transition EvaluateTopologyEdgeDefaultAllow {
per_phase [Running, Stopped, Completed, Destroyed]
on input EvaluateTopologyEdge { from_role, to_role, rule_match }
guard "no_rule_and_default_allow" {
rule_match == None
&& self.topology_default_policy == PolicyDecision::Allow
}
update {}
to Running
emit TopologyEdgeVerdictResolved { from_role: from_role, to_role: to_role, verdict: PolicyDecision::Allow }
}
transition EvaluateTopologyEdgeDefaultDeny {
per_phase [Running, Stopped, Completed, Destroyed]
on input EvaluateTopologyEdge { from_role, to_role, rule_match }
guard "no_rule_and_default_deny" {
rule_match == None
&& self.topology_default_policy == PolicyDecision::Deny
}
update {}
to Running
emit TopologyEdgeVerdictResolved { from_role: from_role, to_role: to_role, verdict: PolicyDecision::Deny }
}
// Row #314: external-member rebind capability. The bridge supplies the
// typed capability bit; the projection reads the machine map directly.
transition SetExternalMemberRebindCapability {
per_phase [Running, Stopped, Completed, Destroyed]
on input SetExternalMemberRebindCapability { agent_identity, capability }
update {
self.external_member_rebind_capability.insert(agent_identity, capability);
}
to Running
}
// Row #320: one-time orphan-budget seed. Dispatched once at actor build
// from definition.limits.max_orphaned_turns (default 8). Without this,
// every non-retryable timeout would classify Canceled.
transition SeedOrphanBudget {
per_phase [Running, Stopped, Completed, Destroyed]
on input SeedOrphanBudget { budget }
update {
self.orphan_budget = budget;
}
to Running
}
// Row #320: turn-timeout disposition. A retryable timeout is Retryable;
// a non-retryable timeout detaches while orphan_budget > 0 (decrementing
// it), otherwise cancels. The detach/cancel verdict and the orphan
// budget are machine-owned.
transition ClassifyTurnTimeoutDispositionRetryable {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyTurnTimeoutDisposition { timed_out_run_id, retryable }
guard "timeout_is_retryable" { retryable == true }
update {}
to Running
emit TurnTimeoutDispositionClassified {
timed_out_run_id: timed_out_run_id,
disposition: TurnTimeoutDisposition::Retryable
}
}
transition ClassifyTurnTimeoutDispositionDetached {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyTurnTimeoutDisposition { timed_out_run_id, retryable }
guard "non_retryable_with_budget" {
retryable == false
&& self.orphan_budget > 0
}
update {
self.orphan_budget -= 1;
}
to Running
emit TurnTimeoutDispositionClassified {
timed_out_run_id: timed_out_run_id,
disposition: TurnTimeoutDisposition::Detached
}
}
transition ClassifyTurnTimeoutDispositionCanceled {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClassifyTurnTimeoutDisposition { timed_out_run_id, retryable }
guard "non_retryable_without_budget" {
retryable == false
&& self.orphan_budget == 0
}
update {}
to Running
emit TurnTimeoutDispositionClassified {
timed_out_run_id: timed_out_run_id,
disposition: TurnTimeoutDisposition::Canceled
}
}
transition SubmitWorkRunningExternal {
on input SubmitWork { agent_identity, agent_runtime_id, fence_token, work_id, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_binding_present" { self.identity_runtime_generations.get_copied(agent_identity) != None }
guard "session_binding_present" { self.member_session_bindings.get_cloned(agent_identity) != None }
guard "placed_carrier_binding_active_or_local" {
self.member_placement.contains_key(agent_identity) == false
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "external_origin" { origin == WorkOrigin::External }
guard "runtime_externally_addressable" { self.externally_addressable_runtime_ids.contains(agent_runtime_id) }
update {}
to Running
emit RequestRuntimeIngress {
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: self.identity_runtime_generations.get_copied(agent_identity),
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value"),
work_id: work_id,
origin: origin
}
}
transition SubmitWorkRunningExternalPeerOnly {
on input SubmitWork { agent_identity, agent_runtime_id, fence_token, work_id, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_binding_present" { self.identity_runtime_generations.get_copied(agent_identity) != None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "external_origin" { origin == WorkOrigin::External }
guard "runtime_externally_addressable" { self.externally_addressable_runtime_ids.contains(agent_runtime_id) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) }
update {}
to Running
emit RequestPeerRuntimeIngress {
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: self.identity_runtime_generations.get_copied(agent_identity),
work_id: work_id,
origin: origin
}
}
transition SubmitWorkRunningInternal {
on input SubmitWork { agent_identity, agent_runtime_id, fence_token, work_id, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_binding_present" { self.identity_runtime_generations.get_copied(agent_identity) != None }
guard "session_binding_present" { self.member_session_bindings.get_cloned(agent_identity) != None }
guard "placed_carrier_binding_active_or_local" {
self.member_placement.contains_key(agent_identity) == false
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "internal_origin" { origin == WorkOrigin::Internal }
update {}
to Running
emit RequestRuntimeIngress {
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: self.identity_runtime_generations.get_copied(agent_identity),
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value"),
work_id: work_id,
origin: origin
}
}
transition SubmitWorkRunningInternalPeerOnly {
on input SubmitWork { agent_identity, agent_runtime_id, fence_token, work_id, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_binding_present" { self.identity_runtime_generations.get_copied(agent_identity) != None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "internal_origin" { origin == WorkOrigin::Internal }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) }
update {}
to Running
emit RequestPeerRuntimeIngress {
agent_runtime_id: agent_runtime_id,
fence_token: fence_token,
generation: self.identity_runtime_generations.get_copied(agent_identity),
work_id: work_id,
origin: origin
}
}
transition ResolveSubmitWorkRejectionStopped {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionCompleted {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Completed
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionDestroyed {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionMemberNotFound {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_absent" { !self.identity_to_runtime.contains_key(agent_identity) }
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MemberNotFound,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionCurrentRuntimeNotLive {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) }
guard "current_runtime_not_live" { !self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MemberNotFound,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionStaleFenceToken {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) }
guard "current_runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "runtime_or_fence_stale" {
self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
|| self.runtime_fence_tokens.get_copied(self.identity_to_runtime.get_cloned(agent_identity).get("value")) != Some(fence_token)
}
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::StaleFenceToken,
expected_fence_token: self.runtime_fence_tokens.get_copied(self.identity_to_runtime.get_cloned(agent_identity).get("value")),
actual_fence_token: Some(fence_token)
}
}
transition ResolveSubmitWorkRejectionRetiringAsMemberNotFound {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::MemberNotFound,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionNotExternallyAddressable {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "external_origin" { origin == WorkOrigin::External }
guard "runtime_not_externally_addressable" { !self.externally_addressable_runtime_ids.contains(agent_runtime_id) }
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::NotExternallyAddressable,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveSubmitWorkRejectionPeerOnlyNotExternallyAddressable {
on input ResolveSubmitWorkRejection { agent_identity, agent_runtime_id, fence_token, origin }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "internal_origin" { origin == WorkOrigin::Internal }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "member_peer_absent" { !self.member_peer_ids.contains_key(agent_identity) }
update {}
to Running
emit SubmitWorkRejected {
agent_runtime_id: agent_runtime_id,
origin: origin,
reason: SubmitWorkRejectReasonKind::NotExternallyAddressable,
expected_fence_token: None,
actual_fence_token: None
}
}
// Generated routed-effect refusal closure. The composition binds each
// consumer refusal back to one of these typed inputs. The shell never
// chooses terminality from a generic dispatch error:
//
// * binding refusal is the only arm that records Broken/restore
// terminality for the affected identity;
// * ingress refusal terminates only that work delivery;
// * retire refusal preserves a retry anchor while the member remains
// Retiring.
transition RetireMember {
on signal RetireMember { agent_identity, agent_runtime_id, fence_token, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(self.identity_runtime_generations.get_copied(agent_identity).get("value")),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireMemberRemote {
on signal RetireMember { agent_identity, agent_runtime_id, fence_token, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(self.identity_runtime_generations.get_copied(agent_identity).get("value")),
session_id: session_id
}
emit RequestMemberRelease {
agent_identity: agent_identity,
generation: self.identity_runtime_generations.get_copied(agent_identity).get("value"),
fence_token: fence_token,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// Authenticated revoke already terminalized the exact host-side G.
// Ordinary retirement keeps the logical member/carrier as its local
// cleanup anchor but emits no ReleaseMember under absent/new authority.
transition RetireMemberRemoteConfirmedRevoked {
on signal RetireMember { agent_identity, agent_runtime_id, fence_token, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_confirmed_revoked" {
mob_machine_placed_carrier_binding_confirmed_revoked(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.confirmed_host_binding_revocations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(self.identity_runtime_generations.get_copied(agent_identity).get("value")),
session_id: session_id
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireMemberPeerOnly {
on signal RetireMember { agent_identity, agent_runtime_id, fence_token, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_absent" { session_id == None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPeerOnly,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(self.identity_runtime_generations.get_copied(agent_identity).get("value")),
session_id: None
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition ResolveRuntimeBindingRefusalRunning {
on input ResolveRuntimeBindingRefusal { agent_identity, agent_runtime_id, session_id, refusal_code, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(session_id) }
update {
self.member_restore_failures.insert(agent_identity, reason);
self.member_restore_failure_codes.insert(agent_identity, refusal_code);
}
to Running
emit RuntimeBindingRefusalClassified {
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
session_id: session_id,
refusal_code: refusal_code,
reason: reason
}
}
transition ResolveRuntimeIngressRefusalRunning {
on input ResolveRuntimeIngressRefusal { agent_runtime_id, fence_token, session_id, work_id, origin, refusal_code, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {}
to Running
emit RuntimeIngressRefusalClassified {
agent_runtime_id: agent_runtime_id,
session_id: session_id,
work_id: work_id,
origin: origin,
refusal_code: refusal_code,
reason: reason
}
}
transition ResolveRuntimeRetireRefusalRunning {
on input ResolveRuntimeRetireRefusal { agent_identity, agent_runtime_id, session_id, refusal_code, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {
self.runtime_retire_refusal_codes.insert(agent_runtime_id, refusal_code);
self.runtime_retire_refusal_reasons.insert(agent_runtime_id, reason);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id);
}
to Running
emit RuntimeRetireRefusalClassified {
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
session_id: session_id,
refusal_code: refusal_code,
reason: reason
}
}
transition ResolveRuntimeRetireRefusalStopped {
on input ResolveRuntimeRetireRefusal { agent_identity, agent_runtime_id, session_id, refusal_code, reason }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {
self.runtime_retire_refusal_codes.insert(agent_runtime_id, refusal_code);
self.runtime_retire_refusal_reasons.insert(agent_runtime_id, reason);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id);
}
to Stopped
emit RuntimeRetireRefusalClassified {
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
session_id: session_id,
refusal_code: refusal_code,
reason: reason
}
}
transition RetryRuntimeRetireRunning {
on input RetryRuntimeRetire { agent_identity, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_pending" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == true }
update {}
to Running
emit RequestRuntimeRetire {
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
session_id: self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id).get("value")
}
}
transition RetryRuntimeRetireStopped {
on input RetryRuntimeRetire { agent_identity, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_pending" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == true }
update {}
to Stopped
emit RequestRuntimeRetire {
agent_identity: agent_identity,
agent_runtime_id: agent_runtime_id,
session_id: self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id).get("value")
}
}
transition RecordRemoteMemberRuntimeRetiredFresh {
per_phase [Running, Stopped]
on input RecordRemoteMemberRuntimeRetired { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_not_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == false }
update {
self.remote_runtime_retired_ids.insert(agent_runtime_id);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RemoteMemberRuntimeRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition RecordRemoteMemberRuntimeRetiredAlreadyRecorded {
per_phase [Running, Stopped]
on input RecordRemoteMemberRuntimeRetired { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
update {}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RemoteMemberRuntimeRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition RecordRemoteMemberSupervisorRevokedFresh {
per_phase [Running, Stopped]
on input RecordRemoteMemberSupervisorRevoked { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
guard "remote_supervisor_not_recorded" { self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == false }
update {
self.remote_supervisor_revoked_ids.insert(agent_runtime_id);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RemoteMemberSupervisorRevoked,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition RecordRemoteMemberSupervisorRevokedAlreadyRecorded {
per_phase [Running, Stopped]
on input RecordRemoteMemberSupervisorRevoked { agent_identity, agent_runtime_id, fence_token, generation }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_runtime_recorded" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
guard "remote_supervisor_recorded" { self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == true }
update {}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::RemoteMemberSupervisorRevoked,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: Some(fence_token),
generation: Some(generation),
session_id: None
}
}
transition AdmitDestroyMemberRetireLiveRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireLiveStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// Placed members retire through the host-owned release seam. This arm
// is intentionally idempotent over an already-Retiring member so a
// destroy retry re-submits the same fenced release instead of falling
// into the local runtime-retire route.
transition AdmitDestroyMemberRetireRemoteRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestMemberRelease {
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireRemoteStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestMemberRelease {
agent_identity: agent_identity,
generation: generation,
fence_token: fence_token,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// Destroy may converge a logical placed member after the exact host
// binding was already authenticated-revoked. These arms intentionally
// emit no ReleaseMember; the shell certifies the exact tombstone,
// disposes controller custody/ops, and publishes normal retirement.
transition AdmitDestroyMemberRetireConfirmedRevokedRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_confirmed_revoked" {
mob_machine_placed_carrier_binding_confirmed_revoked(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.confirmed_host_binding_revocations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireConfirmedRevokedStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_confirmed_revoked" {
mob_machine_placed_carrier_binding_confirmed_revoked(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.confirmed_host_binding_revocations, agent_identity)
}
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetirePeerOnlyRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
guard "session_absent" { session_id == None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPeerOnly,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetirePeerOnlyStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
guard "session_absent" { session_id == None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPeerOnly,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyRetiringSessionRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
update {
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Running
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyRetiringSessionStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
update {
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Stopped
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// Ordinary releasing retirement consumes the live session binding as
// soon as detach authority opens. A later destroy takeover therefore
// proves session ownership through the still-durable pending retire
// correlation, not through the already-released binding.
transition AdmitDestroyMemberRetireAlreadyRetiringReleasedSessionRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_released" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
update {
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Running
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyRetiringReleasedSessionStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_released" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
update {
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
}
to Stopped
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyRetiringPeerOnlyRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_absent" { session_id == None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
update {}
to Running
// Idempotent re-admission still re-requests the kickoff quiesce so
// a destroy retry can re-discharge a previously dropped obligation.
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyRetiringPeerOnlyStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_absent" { session_id == None }
guard "session_binding_absent" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "session_ingress_detach_absent" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "retire_refusal_absent" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
update {}
to Stopped
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition AdmitDestroyMemberRetireAlreadyArchivedRunning {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_cleared" { self.identity_to_runtime.get_cloned(agent_identity) == None }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_cleared" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retry_observes_cleared_session" { session_id == None }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "runtime_retirement_closed" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "runtime_retire_refusal_closed" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
update {}
to Running
}
transition AdmitDestroyMemberRetireAlreadyArchivedStopped {
on signal AdmitDestroyMemberRetire { mob_id, agent_identity, agent_runtime_id, fence_token, generation, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_cleared" { self.identity_to_runtime.get_cloned(agent_identity) == None }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_cleared" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retry_observes_cleared_session" { session_id == None }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "runtime_retirement_closed" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "runtime_retire_refusal_closed" {
self.runtime_retire_refusal_codes.contains_key(agent_runtime_id) == false
&& self.runtime_retire_refusal_reasons.contains_key(agent_runtime_id) == false
}
update {}
to Stopped
}
transition ObserveRuntimeRetired {
on signal ObserveRuntimeRetired { agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.active_run_count = 0;
}
to Running
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveRuntimeRetiredStopped {
on signal ObserveRuntimeRetired { agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Stopped }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.active_run_count = 0;
}
to Stopped
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
// Peer-only terminality is a distinct exact proof path. The shell may
// emit this signal only after the remote retirement checkpoint is
// durable and direct supervisor revocation has acknowledged (or
// returned the typed idempotent NotBound result). Generic session
// archive observations cannot terminalize this sessionless shape.
transition ObserveRemoteMemberRetirementArchivedAndSupervisorRevoked {
per_phase [Running, Stopped]
on signal ObserveRemoteMemberRetirementArchivedAndSupervisorRevoked { agent_identity, agent_runtime_id, fence_token, generation, preserve_machine_topology }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_runtime_retired" { self.remote_runtime_retired_ids.contains(agent_runtime_id) == true }
guard "remote_supervisor_revoked" { self.remote_supervisor_revoked_ids.contains(agent_runtime_id) == true }
guard "remote_member_session_absent" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "remote_retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
} else {
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
self.active_run_count = 0;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveMemberRetirementArchivedLive {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "topology_not_preserved" { preserve_machine_topology == false || self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
// 0.7.2 L5: retirement archival is the member-level teardown
// completion; it may only commit after the kickoff-waiter drain
// obligation closed (`KickoffQuiesced` / a natural `KickoffResolve*`
// moved the kickoff out of the in-flight states).
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_session_bindings.remove(agent_identity);
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
self.active_run_count = 0;
}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
emit WiringGraphChanged { epoch: self.topology_epoch }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveMemberRetirementArchivedLivePreservingTopology {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "topology_preserved" { preserve_machine_topology == true && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_session_bindings.remove(agent_identity);
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
self.active_run_count = 0;
}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveMemberRetirementArchivedLiveStopped {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Stopped }
guard "topology_not_preserved" { preserve_machine_topology == false || self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_session_bindings.remove(agent_identity);
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
self.active_run_count = 0;
}
to Stopped
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
emit WiringGraphChanged { epoch: self.topology_epoch }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveMemberRetirementArchivedRetired {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "topology_not_preserved" { preserve_machine_topology == false || self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition ObserveMemberRetirementArchivedRetiredPreservingTopology {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Running }
guard "topology_preserved" { preserve_machine_topology == true && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedRetiredStopped {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard { self.lifecycle_phase == Phase::Stopped }
guard "topology_not_preserved" { preserve_machine_topology == false || self.abandoned_respawn_topology.get_copied(agent_identity) == Some(generation) }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition ObserveMemberRetirementArchivedPlacedLive {
per_phase [Running, Stopped]
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_present" { self.current_placed_spawn_ids.contains_key(agent_identity) == true }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "remote_retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
));
self.member_session_bindings.remove(agent_identity);
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
} else {
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
self.active_run_count = 0;
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
)
}
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit WiringGraphChanged { epoch: self.topology_epoch }
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
}
transition ObserveMemberRetirementArchivedPlacedRetired {
per_phase [Running, Stopped]
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal, preserve_machine_topology }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_present" { self.current_placed_spawn_ids.contains_key(agent_identity) == true }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "remote_retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "session_binding_matches_or_cleared" {
self.member_session_bindings.get_cloned(agent_identity) == None
|| self.member_session_bindings.get_cloned(agent_identity) == session_id
}
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
));
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
if preserve_machine_topology && self.abandoned_respawn_topology.get_copied(agent_identity) != Some(generation) {
if self.pending_respawn_topology.contains(agent_identity) == false {
self.pending_respawn_topology.insert(agent_identity);
self.topology_epoch += 1;
}
} else {
self.pending_respawn_topology.remove(agent_identity);
self.wiring_edges = mob_machine_wiring_edges_without_identity(self.wiring_edges, agent_identity);
self.external_peer_edges = mob_machine_external_peer_edges_without_identity(self.external_peer_edges, agent_identity);
self.external_peer_edges_by_key = mob_machine_external_peer_edges_by_key_without_identity(self.external_peer_edges_by_key, agent_identity);
self.topology_epoch += 1;
}
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
)
}
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition ObserveMemberRetirementArchivedStaleRuntime {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_remapped" { self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedStaleRuntimeStopped {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_remapped" { self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "session_present" { session_id != None }
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
}
to Stopped
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedAlreadyCleared {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
update {}
to Running
// Re-emit durable-write authority for a retry that landed after
// the first transition committed but before the shell released
// its retained roster anchor. The event store remains the
// idempotency owner and skips an already-present exact event.
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedAlreadyClearedStopped {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
update {}
to Stopped
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedStaleRuntimeAlreadyCleared {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_remapped" {
self.identity_to_runtime.contains_key(agent_identity) == true
&& self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
}
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
update {}
to Running
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveMemberRetirementArchivedStaleRuntimeAlreadyClearedStopped {
on signal ObserveMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_remapped" {
self.identity_to_runtime.contains_key(agent_identity) == true
&& self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
}
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
update {}
to Stopped
emit AppendLifecycleJournal { kind: MobLifecycleJournalKind::MemberRetired, agent_identity: Some(agent_identity), agent_runtime_id: Some(agent_runtime_id), fence_token: None, generation: Some(generation), session_id: session_id }
}
transition ObserveDestroyMemberRetirementArchivedLiveRunning {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "session_present" { session_id != None }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
// §19.L4 teardown completeness: destroy-retirement clears the
// placement and materialization-failure facts too.
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.active_run_count = 0;
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedLiveStopped {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "session_present" { session_id != None }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
// §19.L4 teardown completeness: destroy-retirement clears the
// placement and materialization-failure facts too.
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.active_run_count = 0;
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedRetiredRunning {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "session_present" { session_id != None }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
// §19.L4 teardown completeness: destroy-retirement clears the
// placement and materialization-failure facts too.
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedRetiredStopped {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_absent" { self.current_placed_spawn_ids.contains_key(agent_identity) == false }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "session_present" { session_id != None }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retirement_session_matches" { self.runtime_retire_pending_sessions.get_cloned(agent_runtime_id) == session_id }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
// §19.L4 teardown completeness: destroy-retirement clears the
// placement and materialization-failure facts too.
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedPlacedLive {
per_phase [Running, Stopped]
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_present" { self.current_placed_spawn_ids.contains_key(agent_identity) == true }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "remote_retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
));
self.live_runtime_ids.remove(agent_runtime_id);
self.externally_addressable_runtime_ids.remove(agent_runtime_id);
self.runtime_fence_tokens.remove(agent_runtime_id);
self.member_startup_binding_requested.remove(agent_runtime_id);
self.member_startup_runtime_ready.remove(agent_runtime_id);
self.member_startup_ready.remove(agent_runtime_id);
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.active_run_count = 0;
self.topology_epoch += 1;
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
)
}
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retired }
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedPlacedRetired {
per_phase [Running, Stopped]
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "placed_carrier_present" { self.current_placed_spawn_ids.contains_key(agent_identity) == true }
guard "cleanup_absent" { mob_machine_placed_cleanup_absent_for_identity(self.pending_placed_carrier_cleanup, agent_identity) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches_history" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "session_present" { session_id != None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
guard "remote_retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "kickoff_quiesced" {
!self.member_kickoff_pending.contains(agent_identity)
&& !self.member_kickoff_starting.contains(agent_identity)
&& !self.member_kickoff_callback_pending.contains(agent_identity)
&& mob_machine_placed_kickoff_custody_absent_for_identity(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
agent_identity)
}
update {
self.pending_placed_carrier_cleanup.insert(mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
));
self.member_state_markers.remove(agent_runtime_id);
self.remote_runtime_retired_ids.remove(agent_runtime_id);
self.remote_supervisor_revoked_ids.remove(agent_runtime_id);
self.runtime_retire_refusal_codes.remove(agent_runtime_id);
self.runtime_retire_refusal_reasons.remove(agent_runtime_id);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.identity_to_runtime.remove(agent_identity);
self.spawn_exec_phase.remove(agent_identity);
self.member_session_bindings.remove(agent_identity);
self.member_peer_ids.remove(agent_identity);
self.member_peer_endpoints.remove(agent_identity);
self.member_prior_peer_endpoints.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.member_placement.remove(agent_identity);
self.member_materialization_failures.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
emit PlacedCarrierCleanupRequested {
obligation: mob_machine_placed_cleanup_obligation(
agent_identity,
self.current_placed_spawn_ids.get_cloned(agent_identity).get("value"),
generation,
fence_token,
self.current_placed_spawn_provision_operation_ids.get_cloned(agent_identity).get("value"),
self.current_placed_spawn_operation_owner_session_ids.get_cloned(agent_identity).get("value"),
PlacedSpawnCarrierExpectedPhase::Committed
)
}
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: session_id, new_session_id: None }
}
transition ObserveDestroyMemberRetirementArchivedAlreadyClearedRunning {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Running }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_cleared" { self.identity_to_runtime.get_cloned(agent_identity) == None }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_cleared" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retry_observes_cleared_session" { session_id == None }
update {}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
}
transition ObserveDestroyMemberRetirementArchivedAlreadyClearedStopped {
on signal ObserveDestroyMemberRetirementArchived { agent_identity, agent_runtime_id, fence_token, generation, session_id, disposal }
guard { self.lifecycle_phase == Phase::Stopped }
guard "destroy_admitted" { self.destroy_admitted == true }
guard "session_ingress_detach_closed" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == false }
guard "identity_binding_cleared" { self.identity_to_runtime.get_cloned(agent_identity) == None }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_not_live" { self.live_runtime_ids.contains(agent_runtime_id) == false }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "session_binding_cleared" { self.member_session_bindings.get_cloned(agent_identity) == None }
guard "retry_observes_cleared_session" { session_id == None }
update {}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetired,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
}
transition ResolveRespawnTopologyRestoreCompleted {
on signal ResolveRespawnTopologyRestore { agent_identity, failed_peer_ids }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "no_failed_peers" { failed_peer_ids == EmptySeq }
update {}
to Running
emit RespawnTopologyRestoreResolved {
agent_identity: agent_identity,
result: RespawnTopologyRestoreResultKind::Completed,
failed_peer_ids: failed_peer_ids
}
}
transition ResolveRespawnTopologyRestoreFailed {
on signal ResolveRespawnTopologyRestore { agent_identity, failed_peer_ids }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "failed_peers_present" { failed_peer_ids != EmptySeq }
update {}
to Running
emit RespawnTopologyRestoreResolved {
agent_identity: agent_identity,
result: RespawnTopologyRestoreResultKind::TopologyRestoreFailed,
failed_peer_ids: failed_peer_ids
}
}
transition RecoverMemberRestoreFailureRunning {
on signal RecoverMemberRestoreFailure { agent_identity, reason }
guard { self.lifecycle_phase == Phase::Running }
update {
self.member_restore_failures.insert(agent_identity, reason);
self.member_restore_failure_codes.remove(agent_identity);
}
to Running
}
// Post-discard member revival seam (#37). The shell observes "the
// member's current bridge session has no live materialization" at the
// dispatch boundary and feeds the raw observation (durable snapshot
// present or missing) here; MobMachine — never the session-registry
// cache — owns the verdict. A durable snapshot makes the member
// revivable: the machine records the revival obligation and authorizes
// exactly one shell materialization attempt via the emitted
// ReviveAuthorized verdict. A missing durable snapshot is a terminal
// restore failure (existing Broken classification). Resolution comes
// back as a typed signal: success clears the obligation; failure
// converts it into the Broken classification, whose `not_broken`
// guard below refuses any further revival authorization — fail-closed,
// no retry loop.
transition ClassifyMemberLiveMaterializationRevivable {
on signal ClassifyMemberLiveMaterialization { agent_identity, observation, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "not_broken" { self.member_restore_failures.contains_key(agent_identity) == false }
guard "durable_snapshot_present" { observation == MemberLiveMaterializationObservationKind::DurableSnapshotPresent }
update {
self.member_revival_pending.insert(agent_identity);
}
to Running
emit MemberLiveMaterializationClassified {
agent_identity: agent_identity,
observation: observation,
verdict: MemberRevivalVerdictKind::ReviveAuthorized,
reason: reason
}
}
transition ClassifyMemberLiveMaterializationTerminal {
on signal ClassifyMemberLiveMaterialization { agent_identity, observation, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "not_broken" { self.member_restore_failures.contains_key(agent_identity) == false }
guard "durable_snapshot_missing" { observation == MemberLiveMaterializationObservationKind::DurableSnapshotMissing }
update {
self.member_revival_pending.remove(agent_identity);
self.member_restore_failures.insert(agent_identity, reason);
self.member_restore_failure_codes.remove(agent_identity);
}
to Running
emit MemberLiveMaterializationClassified {
agent_identity: agent_identity,
observation: observation,
verdict: MemberRevivalVerdictKind::BrokenRecorded,
reason: reason
}
}
transition ResolveMemberRevivalSucceededRunning {
on signal ResolveMemberRevivalSucceeded { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "revival_pending" { self.member_revival_pending.contains(agent_identity) == true }
guard "placed_carrier_binding_active_or_local" {
self.member_placement.contains_key(agent_identity) == false
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {
self.member_revival_pending.remove(agent_identity);
}
to Running
}
transition ResolveMemberRevivalFailedRunning {
on signal ResolveMemberRevivalFailed { agent_identity, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "revival_pending" { self.member_revival_pending.contains(agent_identity) == true }
update {
self.member_revival_pending.remove(agent_identity);
self.member_restore_failures.insert(agent_identity, reason);
self.member_restore_failure_codes.remove(agent_identity);
}
to Running
}
transition AdmitDestroyCleanup {
on signal AdmitDestroyCleanup
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard {
self.lifecycle_phase == Phase::Running
|| self.lifecycle_phase == Phase::Stopped
|| self.lifecycle_phase == Phase::Completed
}
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_destroy_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Destroy) }
update {
self.destroy_admitted = true;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::Destroying,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
// 0.7.2 L5 (row 14): destroy admission opens the pending-spawn
// drain obligation. The shell aborts + awaits every in-flight
// spawn-provisioning task, fails its waiters with a typed
// cancellation, and closes each machine obligation with
// `CancelPendingSpawn` before the `Destroy` transition (guarded on
// the drained pending-spawn table) can commit.
emit RequestPendingSpawnQuiesceForDestroy
}
transition AdmitDestroyStorageFinalizing {
on signal AdmitDestroyStorageFinalizing
guard { self.lifecycle_phase == Phase::Destroyed }
guard "destroy_admitted" { self.destroy_admitted == true }
update {}
to Destroyed
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::DestroyStorageFinalizing,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
}
transition MarkCompleted {
on signal MarkCompleted
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped }
guard "no_active_runs" { self.active_run_count == 0 }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_complete_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {}
to Completed
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Completed }
}
transition DestroyMob {
on signal DestroyMob { session_id }
guard {
self.lifecycle_phase == Phase::Running
|| self.lifecycle_phase == Phase::Stopped
|| self.lifecycle_phase == Phase::Completed
}
guard "session_ingress_detaches_closed" { self.pending_session_ingress_detach_runtime_ids == EmptySet }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_destroy_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Destroy) }
guard "remote_turn_pending_drained" { self.pending_remote_turn_outcomes == EmptySet }
guard "remote_turn_committed_drained" { self.committed_remote_turn_outcomes == EmptySet }
guard "remote_turn_resolved_drained" { self.resolved_remote_turn_outcomes == EmptySet }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
guard "placed_kickoff_pending_drained" { self.pending_placed_kickoff_outcomes == EmptySet }
guard "placed_kickoff_resolved_drained" { self.resolved_placed_kickoff_outcomes == EmptySet }
guard "host_bind_phases_drained" { self.host_bind_phase == EmptyMap }
guard "replacement_host_bind_requests_drained" {
self.replacement_host_bind_endpoints == EmptyMap
&& self.replacement_host_binding_generations == EmptyMap
}
guard "bound_hosts_drained" { self.mob_hosts == EmptySet }
guard "host_authority_epochs_drained" { self.host_authority_epochs == EmptyMap }
guard "host_public_keys_drained" { self.host_public_keys == EmptyMap }
guard "host_endpoints_drained" { self.host_endpoints == EmptyMap }
guard "host_live_endpoints_drained" { self.host_live_endpoints == EmptyMap }
guard "placed_carrier_cleanup_drained" { self.pending_placed_carrier_cleanup == EmptySet }
guard "pending_placed_spawns_drained" { self.pending_placed_spawn_ids == EmptyMap }
guard "committed_placed_spawns_drained" { self.current_placed_spawn_ids == EmptyMap }
// 0.7.2 L5: destroy is the final teardown transition; it may only
// commit after every kickoff-waiter drain obligation closed (no
// member kickoff left in flight) and the pending-spawn table was
// drained via typed `CancelPendingSpawn` closures (instead of the
// former silent wipe, which erased open obligations).
guard "kickoff_waiters_quiesced" {
self.member_kickoff_pending == EmptySet
&& self.member_kickoff_starting == EmptySet
&& self.member_kickoff_callback_pending == EmptySet
}
guard "pending_spawns_drained" {
self.pending_spawn_count == 0
&& self.pending_spawn_sessions == EmptyMap
}
update {
self.destroy_admitted = true;
self.live_runtime_ids = EmptySet;
self.externally_addressable_runtime_ids = EmptySet;
self.runtime_fence_tokens = EmptyMap;
self.wiring_edges = EmptySet;
self.pending_respawn_topology = EmptySet;
self.abandoned_respawn_topology = EmptyMap;
self.external_peer_edges = EmptySet;
self.external_peer_edges_by_key = EmptyMap;
self.identity_to_runtime = EmptyMap;
self.identity_runtime_generations = EmptyMap;
self.identity_runtime_fence_tokens = EmptyMap;
self.member_session_bindings = EmptyMap;
self.member_profile_names = EmptyMap;
self.member_runtime_modes = EmptyMap;
self.member_peer_ids = EmptyMap;
self.member_peer_endpoints = EmptyMap;
self.member_prior_peer_endpoints = EmptyMap;
self.member_startup_binding_requested = EmptySet;
self.member_startup_runtime_ready = EmptySet;
self.member_startup_ready = EmptySet;
self.member_state_markers = EmptyMap;
self.member_restore_failures = EmptyMap;
self.member_restore_failure_codes = EmptyMap;
self.runtime_retire_refusal_codes = EmptyMap;
self.runtime_retire_refusal_reasons = EmptyMap;
self.runtime_retire_pending_sessions = EmptyMap;
self.remote_runtime_retired_ids = EmptySet;
self.remote_supervisor_revoked_ids = EmptySet;
self.member_revival_pending = EmptySet;
// Spawn-exec phase ladder: total teardown — clear the whole phase
// map so no in-flight spawn-exec survives into Destroyed (every
// late CommitSpawnActivation/AbortSpawnExec becomes a Settled no-op).
self.spawn_exec_phase = EmptyMap;
self.pending_session_ingress_detach_runtime_ids = EmptySet;
self.active_run_count = 0;
self.coordinator_bound = false;
}
to Destroyed
emit RequestRuntimeDestroy { session_id: session_id }
}
transition ObserveRuntimeDestroyed {
on signal ObserveRuntimeDestroyed { agent_runtime_id, fence_token }
guard {
self.lifecycle_phase == Phase::Running
|| self.lifecycle_phase == Phase::Stopped
|| self.lifecycle_phase == Phase::Completed
|| self.lifecycle_phase == Phase::Destroyed
}
guard "session_ingress_detaches_closed" { self.pending_session_ingress_detach_runtime_ids == EmptySet }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.live_runtime_ids = EmptySet;
self.runtime_fence_tokens = EmptyMap;
self.member_state_markers = EmptyMap;
self.member_restore_failures = EmptyMap;
self.member_restore_failure_codes = EmptyMap;
self.runtime_retire_refusal_codes = EmptyMap;
self.runtime_retire_refusal_reasons = EmptyMap;
self.runtime_retire_pending_sessions = EmptyMap;
self.remote_runtime_retired_ids = EmptySet;
self.remote_supervisor_revoked_ids = EmptySet;
self.member_revival_pending = EmptySet;
// Spawn-exec phase ladder: total teardown (see DestroyMob).
self.spawn_exec_phase = EmptyMap;
self.active_run_count = 0;
self.pending_spawn_count = 0;
self.pending_spawn_sessions = EmptyMap;
self.coordinator_bound = false;
}
to Destroyed
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Destroyed }
}
// =====================================================================
// Absorbed transitions: per-phase self-loops
// =====================================================================
transition RecordOperatorActionProvenanceRunning {
on input RecordOperatorActionProvenance { tool_name, principal_token, caller_provenance, audit_invocation_id }
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit AppendOperatorActionProvenance {
tool_name: tool_name,
principal_token: principal_token,
caller_provenance: caller_provenance,
audit_invocation_id: audit_invocation_id
}
}
transition RecordOperatorActionProvenanceStopped {
on input RecordOperatorActionProvenance { tool_name, principal_token, caller_provenance, audit_invocation_id }
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit AppendOperatorActionProvenance {
tool_name: tool_name,
principal_token: principal_token,
caller_provenance: caller_provenance,
audit_invocation_id: audit_invocation_id
}
}
transition RecordOperatorActionProvenanceCompleted {
on input RecordOperatorActionProvenance { tool_name, principal_token, caller_provenance, audit_invocation_id }
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Completed
emit AppendOperatorActionProvenance {
tool_name: tool_name,
principal_token: principal_token,
caller_provenance: caller_provenance,
audit_invocation_id: audit_invocation_id
}
}
transition RecordOperatorActionProvenanceDestroyed {
on input RecordOperatorActionProvenance { tool_name, principal_token, caller_provenance, audit_invocation_id }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
emit AppendOperatorActionProvenance {
tool_name: tool_name,
principal_token: principal_token,
caller_provenance: caller_provenance,
audit_invocation_id: audit_invocation_id
}
}
transition SetSpawnPolicyRunning {
on input SetSpawnPolicy { enabled }
guard { self.lifecycle_phase == Phase::Running }
update {
self.spawn_policy_enabled = enabled;
self.spawn_policy_revision += 1;
self.spawn_policy_resolution_revision = EmptyMap;
self.spawn_policy_resolution_profiles = EmptyMap;
self.spawn_policy_resolution_runtime_modes = EmptyMap;
self.spawn_policy_resolution_absent = EmptySet;
}
to Running
}
transition SetSpawnPolicyStopped {
on input SetSpawnPolicy { enabled }
guard { self.lifecycle_phase == Phase::Stopped }
update {
self.spawn_policy_enabled = enabled;
self.spawn_policy_revision += 1;
self.spawn_policy_resolution_revision = EmptyMap;
self.spawn_policy_resolution_profiles = EmptyMap;
self.spawn_policy_resolution_runtime_modes = EmptyMap;
self.spawn_policy_resolution_absent = EmptySet;
}
to Stopped
}
transition SetSpawnPolicyCompleted {
on input SetSpawnPolicy { enabled }
guard { self.lifecycle_phase == Phase::Completed }
update {
self.spawn_policy_enabled = enabled;
self.spawn_policy_revision += 1;
self.spawn_policy_resolution_revision = EmptyMap;
self.spawn_policy_resolution_profiles = EmptyMap;
self.spawn_policy_resolution_runtime_modes = EmptyMap;
self.spawn_policy_resolution_absent = EmptySet;
}
to Completed
}
transition SetSpawnPolicyDestroyed {
on input SetSpawnPolicy { enabled }
guard { self.lifecycle_phase == Phase::Destroyed }
update {
self.spawn_policy_enabled = enabled;
self.spawn_policy_revision += 1;
self.spawn_policy_resolution_revision = EmptyMap;
self.spawn_policy_resolution_profiles = EmptyMap;
self.spawn_policy_resolution_runtime_modes = EmptyMap;
self.spawn_policy_resolution_absent = EmptySet;
}
to Destroyed
}
transition ResolveSpawnPolicyAdmitted {
on input ResolveSpawnPolicy { agent_identity, revision, profile_name, runtime_mode }
guard { self.lifecycle_phase == Phase::Running }
guard "policy_enabled" { self.spawn_policy_enabled }
guard "revision_matches" { revision == self.spawn_policy_revision }
guard "identity_absent" { !self.identity_to_runtime.contains_key(agent_identity) }
guard "profile_present" { profile_name != None }
update {
self.spawn_policy_resolution_revision.insert(agent_identity, revision);
self.spawn_policy_resolution_profiles.insert(agent_identity, profile_name.get("value"));
self.spawn_policy_resolution_runtime_modes.insert(agent_identity, runtime_mode);
self.spawn_policy_resolution_absent.remove(agent_identity);
}
to Running
emit SpawnPolicyResolutionRecorded {
agent_identity: agent_identity,
revision: revision,
profile_name: profile_name,
runtime_mode: runtime_mode
}
}
transition ResolveSpawnPolicyNoMatch {
on input ResolveSpawnPolicy { agent_identity, revision, profile_name, runtime_mode }
guard { self.lifecycle_phase == Phase::Running }
guard "policy_enabled" { self.spawn_policy_enabled }
guard "revision_matches" { revision == self.spawn_policy_revision }
guard "identity_absent" { !self.identity_to_runtime.contains_key(agent_identity) }
guard "profile_absent" { profile_name == None }
guard "runtime_mode_absent" { runtime_mode == None }
update {
self.spawn_policy_resolution_revision.insert(agent_identity, revision);
self.spawn_policy_resolution_profiles.remove(agent_identity);
self.spawn_policy_resolution_runtime_modes.remove(agent_identity);
self.spawn_policy_resolution_absent.insert(agent_identity);
}
to Running
emit SpawnPolicyResolutionRecorded {
agent_identity: agent_identity,
revision: revision,
profile_name: None,
runtime_mode: None
}
}
// Owner bridge-session authority. The runtime shell may observe the
// owner session that requested creation, but this transition owns the
// facts that later drive lookup, archive cleanup, and implicit-mob
// admission.
transition BindOwnerBridgeSessionRunning {
on input BindOwnerBridgeSession { bridge_session_id, destroy_on_owner_archive, implicit_delegation_mob }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "owner_bridge_session_absent" { self.owner_bridge_session_id == None }
guard "implicit_delegation_requires_cleanup" { implicit_delegation_mob == false || destroy_on_owner_archive == true }
update {
self.owner_bridge_session_id = Some(bridge_session_id);
self.owner_bridge_destroy_on_archive = destroy_on_owner_archive;
self.implicit_delegation_mob = implicit_delegation_mob;
}
to Running
emit OwnerBridgeSessionBound {
bridge_session_id: bridge_session_id,
destroy_on_owner_archive: destroy_on_owner_archive,
implicit_delegation_mob: implicit_delegation_mob
}
}
transition RecoverOwnerBridgeSessionRunning {
on signal RecoverOwnerBridgeSession { bridge_session_id, destroy_on_owner_archive, implicit_delegation_mob }
guard { self.lifecycle_phase == Phase::Running }
guard "owner_bridge_session_absent" { self.owner_bridge_session_id == None }
guard "implicit_delegation_requires_cleanup" { implicit_delegation_mob == false || destroy_on_owner_archive == true }
update {
self.owner_bridge_session_id = Some(bridge_session_id);
self.owner_bridge_destroy_on_archive = destroy_on_owner_archive;
self.implicit_delegation_mob = implicit_delegation_mob;
}
to Running
}
transition RecoverOwnerBridgeSessionAlreadyCurrent {
on signal RecoverOwnerBridgeSession { bridge_session_id, destroy_on_owner_archive, implicit_delegation_mob }
guard { self.lifecycle_phase == Phase::Running }
guard "owner_bridge_session_current" { self.owner_bridge_session_id == Some(bridge_session_id) }
guard "cleanup_policy_current" { self.owner_bridge_destroy_on_archive == destroy_on_owner_archive }
guard "implicit_classification_current" { self.implicit_delegation_mob == implicit_delegation_mob }
guard "implicit_delegation_requires_cleanup" { implicit_delegation_mob == false || destroy_on_owner_archive == true }
update {}
to Running
}
// =====================================================================
// Phase-changing transitions
// =====================================================================
transition StopRunning {
on input Stop
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Running }
guard "no_active_runs" { self.active_run_count == 0 }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_stop_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Stop) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {
self.coordinator_bound = false;
self.active_run_count = 0;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::Stopped,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
emit EmitRunLifecycleNotice
}
transition ResumeStopped {
on input Resume
guard { self.lifecycle_phase == Phase::Stopped }
guard "placed_completion_stop_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Stop) }
update {
self.coordinator_bound = true;
self.placed_completion_lifecycle_quiescing = false;
self.placed_completion_lifecycle_intent = None;
}
to Running
emit PersistPlacedCompletionLifecycleIntent { intent: PlacedCompletionLifecycleIntentKind::Stop, active: false }
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::Resumed,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
emit EmitRunLifecycleNotice
}
transition CompleteRunning {
on input Complete
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_complete_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {
self.active_run_count = 0;
}
to Completed
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::Completed,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
emit EmitRunLifecycleNotice
}
transition ResetToRunning {
on input Reset
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard {
self.lifecycle_phase == Phase::Running
|| self.lifecycle_phase == Phase::Stopped
|| self.lifecycle_phase == Phase::Completed
}
guard "remote_turn_pending_drained" { self.pending_remote_turn_outcomes == EmptySet }
guard "remote_turn_committed_drained" { self.committed_remote_turn_outcomes == EmptySet }
guard "remote_turn_resolved_drained" { self.resolved_remote_turn_outcomes == EmptySet }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
guard "placed_completion_reset_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Reset) }
guard "placed_kickoff_pending_drained" { self.pending_placed_kickoff_outcomes == EmptySet }
guard "placed_kickoff_resolved_drained" { self.resolved_placed_kickoff_outcomes == EmptySet }
update {
self.active_run_count = 0;
self.pending_spawn_count = 0;
self.pending_spawn_sessions = EmptyMap;
self.coordinator_bound = true;
self.remote_turn_dispatch_sequence = 0;
self.placed_completion_dispatch_sequence = 0;
self.placed_completion_lifecycle_quiescing = false;
self.placed_completion_lifecycle_intent = None;
self.wiring_edges = EmptySet;
self.pending_respawn_topology = EmptySet;
self.abandoned_respawn_topology = EmptyMap;
self.external_peer_edges = EmptySet;
self.external_peer_edges_by_key = EmptyMap;
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::Reset,
agent_identity: None,
agent_runtime_id: None,
fence_token: None,
generation: None,
session_id: None
}
emit EmitRunLifecycleNotice
emit WiringGraphChanged { epoch: self.topology_epoch }
}
// =====================================================================
// Running self-loops (inputs)
// =====================================================================
// =====================================================================
// Track-B (R5): identity-level wiring mutations.
//
// `WireMembers`/`UnwireMembers` mutate `wiring_edges` at DSL
// authority and bump `topology_epoch`. The `WiringGraphChanged`
// effect lets the `RecomputeMobPeerOverlay` composition driver
// linearize peer-overlay recomputation against graph changes.
// =====================================================================
transition WireMembersRunning {
on input WireMembers { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "edge_not_already_wired" { self.wiring_edges.contains(edge) == false }
update {
self.wiring_edges.insert(edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit EmitWiringLifecycleNotice { kind: WiringLifecycleKind::Wired, edge: edge }
}
transition WireMembersWithTrustRunning {
on input WireMembersWithTrust { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "edge_not_already_wired" { self.wiring_edges.contains(edge) == false }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
guard "a_member_endpoint_registered" { self.member_peer_endpoints.contains_key(a_identity) == true }
guard "b_member_endpoint_registered" { self.member_peer_endpoints.contains_key(b_identity) == true }
update {
self.wiring_edges.insert(edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit MemberTrustWiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
a_endpoint: self.member_peer_endpoints.get_cloned(a_identity).get("value"),
b_endpoint: self.member_peer_endpoints.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch
}
emit EmitWiringLifecycleNotice { kind: WiringLifecycleKind::Wired, edge: edge }
}
transition WireMembersWithTrustAlreadyWired {
on input WireMembersWithTrust { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_already_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
update {}
to Running
emit WiringTrustRepairRequested { edge: edge }
}
transition WireMembersAlreadyWired {
on input WireMembers { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_already_wired" { self.wiring_edges.contains(edge) == true }
update {}
to Running
emit WiringTrustRepairRequested { edge: edge }
}
transition RecoverRosterWiringRunning {
on signal RecoverRosterWiring { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_not_already_recovered" { self.wiring_edges.contains(edge) == false }
update {
self.wiring_edges.insert(edge);
self.topology_epoch += 1;
}
to Running
}
transition RecoverRosterWiringAlreadyRecovered {
on signal RecoverRosterWiring { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_already_recovered" { self.wiring_edges.contains(edge) == true }
update {}
to Running
}
transition RecoverRosterUnwireRunning {
on signal RecoverRosterUnwire { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_recovered" { self.wiring_edges.contains(edge) == true }
update {
self.wiring_edges.remove(edge);
self.topology_epoch += 1;
}
to Running
}
transition RecoverRosterUnwireAlreadyAbsent {
on signal RecoverRosterUnwire { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_not_recovered" { self.wiring_edges.contains(edge) == false }
update {}
to Running
}
// Durable wiring events describe historical intent, while terminal
// member events decide which identity incarnations survived replay.
// Prune only after the full event stream so a later respawn of the
// same identity retains its topology and a finally-absent identity
// cannot resurrect stale trust on the next fresh spawn.
transition ConvergeRecoveredRosterTopologyPrune {
on signal ConvergeRecoveredRosterTopology { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_recovered" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "edge_has_absent_endpoint" {
self.identity_to_runtime.contains_key(a_identity) == false
|| self.identity_to_runtime.contains_key(b_identity) == false
}
update {
self.wiring_edges.remove(edge);
if self.identity_to_runtime.contains_key(a_identity) == false {
self.pending_respawn_topology.remove(a_identity);
}
if self.identity_to_runtime.contains_key(b_identity) == false {
self.pending_respawn_topology.remove(b_identity);
}
self.topology_epoch += 1;
}
to Running
}
transition ConvergeRecoveredRosterTopologyRetain {
on signal ConvergeRecoveredRosterTopology { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_recovered" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "edge_endpoints_present" {
self.identity_to_runtime.contains_key(a_identity) == true
&& self.identity_to_runtime.contains_key(b_identity) == true
}
update {}
to Running
}
transition ConvergeRecoveredRosterTopologyDestroyed {
on signal ConvergeRecoveredRosterTopology { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// A retirement-start marker is not a durable replacement operation:
// if replay reaches the end without a successor membership, abandon
// the transient hold after all incident topology has been pruned.
transition ConvergeRecoveredRespawnTopologyAbandoned {
on signal ConvergeRecoveredRespawnTopology { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "respawn_topology_pending" { self.pending_respawn_topology.contains(agent_identity) == true }
guard "successor_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {
self.pending_respawn_topology.remove(agent_identity);
}
to Running
}
transition ConvergeRecoveredRespawnTopologyDestroyed {
on signal ConvergeRecoveredRespawnTopology { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
transition UnwireMembersRunning {
on input UnwireMembers { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
update {
self.wiring_edges.remove(edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit EmitWiringLifecycleNotice { kind: WiringLifecycleKind::Unwired, edge: edge }
}
transition UnwireMembersAlreadyAbsent {
on input UnwireMembers { edge }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_already_absent" { self.wiring_edges.contains(edge) == false }
update {}
to Running
}
transition CleanupRetiringMemberWiring {
per_phase [Running, Stopped]
on input CleanupRetiringMemberWiring { edge, a_identity, b_identity, agent_identity, agent_runtime_id, fence_token, generation }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "retiring_identity_is_endpoint" { agent_identity == a_identity || agent_identity == b_identity }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {
self.wiring_edges.remove(edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition CleanupRetiringMemberWiringAlreadyAbsent {
per_phase [Running, Stopped]
on input CleanupRetiringMemberWiring { edge, a_identity, b_identity, agent_identity, agent_runtime_id, fence_token, generation }
guard "edge_absent" { self.wiring_edges.contains(edge) == false }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "retiring_identity_is_endpoint" { agent_identity == a_identity || agent_identity == b_identity }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {}
to Running
}
transition RestoreRetiringMemberWiring {
per_phase [Running, Stopped]
on input RestoreRetiringMemberWiring { edge, a_identity, b_identity, agent_identity, agent_runtime_id, fence_token, generation }
guard "edge_absent" { self.wiring_edges.contains(edge) == false }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "retiring_identity_is_endpoint" { agent_identity == a_identity || agent_identity == b_identity }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {
self.wiring_edges.insert(edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition WireExternalPeerRunning {
on input WireExternalPeer { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_not_already_wired" { self.external_peer_edges_by_key.contains_key(key) == false }
guard "external_peer_edge_not_already_wired" { self.external_peer_edges.contains(edge) == false }
guard "local_member_peer_registered" { self.member_peer_ids.contains_key(mob_machine_external_peer_edge_local(edge)) == true }
update {
self.external_peer_edges.insert(edge);
self.external_peer_edges_by_key.insert(key, edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit ExternalPeerTrustWiringRequested {
edge: edge,
local_peer_id: self.member_peer_ids.get_cloned(mob_machine_external_peer_edge_local(edge)).get("value"),
peer_id: mob_machine_external_peer_edge_peer_id(edge),
epoch: self.topology_epoch
}
emit EmitExternalPeerWiringLifecycleNotice { kind: WiringLifecycleKind::Wired, edge: edge }
}
transition WireExternalPeerAlreadyWired {
on input WireExternalPeer { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_already_wired" { self.external_peer_edges_by_key.get_cloned(key) == Some(edge) }
guard "external_peer_edge_already_wired" { self.external_peer_edges.contains(edge) == true }
guard "local_member_peer_registered" { self.member_peer_ids.contains_key(mob_machine_external_peer_edge_local(edge)) == true }
update {}
to Running
emit ExternalPeerTrustRepairRequested {
edge: edge,
local_peer_id: self.member_peer_ids.get_cloned(mob_machine_external_peer_edge_local(edge)).get("value"),
peer_id: mob_machine_external_peer_edge_peer_id(edge),
epoch: self.topology_epoch
}
}
transition RegisterMemberPeerRunning {
on input RegisterMemberPeer { agent_identity, agent_runtime_id, generation, fence_token, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "identity_fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring) }
guard "member_peer_not_registered" { self.member_peer_ids.contains_key(agent_identity) == false }
guard "member_endpoint_not_registered" { self.member_peer_endpoints.contains_key(agent_identity) == false }
guard "fresh_spawn_or_no_retained_topology" {
self.spawn_exec_phase.get_cloned(agent_identity) == Some(SpawnExecPhase::MembershipCommitted)
|| (
for_all(edge in self.wiring_edges,
mob_machine_wiring_edge_contains_identity(edge, agent_identity) == false)
&& mob_machine_member_has_no_external_peer_edges(self.external_peer_edges, agent_identity)
)
}
guard "peer_id_available_for_identity" {
mob_machine_member_peer_id_available_for_identity(
self.member_peer_endpoints,
self.member_prior_peer_endpoints,
agent_identity,
peer_endpoint)
}
guard "member_peer_id_is_not_host" {
for_all(host in self.mob_hosts,
mob_machine_host_id_matches_peer_id(
host,
mob_machine_member_peer_endpoint_peer_id(peer_endpoint)
) == false)
}
update {
self.member_peer_ids.insert(agent_identity, mob_machine_member_peer_endpoint_peer_id(peer_endpoint));
self.member_peer_endpoints.insert(agent_identity, peer_endpoint);
}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
transition RegisterMemberPeerAlreadyCurrentRunning {
on input RegisterMemberPeer { agent_identity, agent_runtime_id, generation, fence_token, peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) == true }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "identity_fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "runtime_fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_endpoint_matches" { self.member_peer_endpoints.get_cloned(agent_identity) == Some(peer_endpoint) }
guard "current_peer_id_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(peer_endpoint)) }
update {}
to Running
emit MemberPeerRegistered { agent_identity: agent_identity, peer_id: mob_machine_member_peer_endpoint_peer_id(peer_endpoint) }
}
// A durable endpoint recovery may leave stale reciprocal trust on
// each still-wired peer. This authorization is deliberately separate
// from ordinary cleanup: the exact current runtime, exact retained
// descriptor, live edge, and the other endpoint's current descriptor
// all come from MobMachine state. The effect carries the historical
// peer id only on the migrated side and the current peer id on the
// other side; the existing generated member-unwiring handoff then
// mints the reciprocal PublicRemove authority without removing the
// topology edge.
transition AuthorizeMemberEndpointMigrationTrustCleanupRunning {
per_phase [Running, Stopped]
on input AuthorizeMemberEndpointMigrationTrustCleanup { edge, agent_identity, agent_runtime_id, retained_peer_endpoint }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
// Normal resume cleans history while the runtime is live. A
// retirement retry may already have observed the runtime as gone,
// but its exact Retiring tuple remains the durable cleanup anchor
// until MemberRetired clears the generation.
guard "runtime_live_or_retiring" {
self.live_runtime_ids.contains(agent_runtime_id) == true
|| self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring)
}
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_contains_migrated_member" { mob_machine_wiring_edge_contains_identity(edge, agent_identity) }
guard "retained_endpoint_history_present" {
self.member_prior_peer_endpoints.contains_key(agent_identity) == true
&& self.member_prior_peer_endpoints.get_cloned(agent_identity).get("value").contains(retained_peer_endpoint) == true
}
guard "migrated_current_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "migrated_current_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "migrated_current_endpoint_changed" { self.member_peer_endpoints.get_cloned(agent_identity) != Some(retained_peer_endpoint) }
guard "migrated_current_peer_id_changed" {
mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value"))
!= mob_machine_member_peer_endpoint_peer_id(retained_peer_endpoint)
}
guard "migrated_current_peer_id_matches_endpoint" {
self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value")))
}
guard "edge_a_current_peer_registered" { self.member_peer_ids.contains_key(mob_machine_wiring_edge_a(edge)) == true }
guard "edge_b_current_peer_registered" { self.member_peer_ids.contains_key(mob_machine_wiring_edge_b(edge)) == true }
guard "edge_a_current_endpoint_registered" { self.member_peer_endpoints.contains_key(mob_machine_wiring_edge_a(edge)) == true }
guard "edge_b_current_endpoint_registered" { self.member_peer_endpoints.contains_key(mob_machine_wiring_edge_b(edge)) == true }
guard "edge_a_current_peer_id_matches_endpoint" {
self.member_peer_ids.get_cloned(mob_machine_wiring_edge_a(edge)) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(mob_machine_wiring_edge_a(edge)).get("value")))
}
guard "edge_b_current_peer_id_matches_endpoint" {
self.member_peer_ids.get_cloned(mob_machine_wiring_edge_b(edge)) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(mob_machine_wiring_edge_b(edge)).get("value")))
}
update {}
to Running
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: mob_machine_member_endpoint_migration_cleanup_peer_id(mob_machine_wiring_edge_a(edge), agent_identity, retained_peer_endpoint, self.member_peer_ids),
b_peer_id: mob_machine_member_endpoint_migration_cleanup_peer_id(mob_machine_wiring_edge_b(edge), agent_identity, retained_peer_endpoint, self.member_peer_ids),
epoch: self.topology_epoch
}
}
transition AuthorizeMemberPeerRebindRunning {
on input AuthorizeMemberPeerRebind { agent_identity, expected_peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_endpoint_matches_expected" { self.member_peer_endpoints.get_cloned(agent_identity) == Some(expected_peer_endpoint) }
guard "current_peer_id_matches_expected" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(expected_peer_endpoint)) }
update {}
to Running
emit MemberPeerRebindAuthorized {
agent_identity: agent_identity,
peer_id: mob_machine_member_peer_endpoint_peer_id(expected_peer_endpoint),
peer_endpoint: expected_peer_endpoint
}
}
transition AuthorizeMemberPeerOverlayRunning {
on input AuthorizeMemberPeerOverlay { agent_identity, expected_peer_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "current_endpoint_matches_expected" { self.member_peer_endpoints.get_cloned(agent_identity) == Some(expected_peer_endpoint) }
guard "current_peer_id_matches_expected" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(expected_peer_endpoint)) }
guard "overlay_member_endpoints_complete" { mob_machine_member_peer_overlay_complete(self.wiring_edges, self.member_peer_endpoints, agent_identity) == true }
guard "overlay_peer_ids_unique" { mob_machine_member_peer_overlay_peer_ids_unique(self.wiring_edges, self.member_peer_endpoints, self.external_peer_edges, agent_identity) == true }
update {}
to Running
emit MemberPeerOverlayAuthorized {
agent_identity: agent_identity,
peer_id: mob_machine_member_peer_endpoint_peer_id(expected_peer_endpoint),
peer_overlay_endpoints: mob_machine_member_peer_overlay(self.wiring_edges, self.member_peer_endpoints, self.external_peer_edges, agent_identity),
epoch: self.topology_epoch
}
}
transition AuthorizeRetiringMemberPeerOverlayCleanupRunning {
on input AuthorizeRetiringMemberPeerOverlayCleanup { recipient_identity, expected_recipient_endpoint, retiring_identity, retiring_runtime_id, fence_token, generation }
guard { self.lifecycle_phase == Phase::Running }
guard "recipient_present" { self.identity_to_runtime.contains_key(recipient_identity) == true }
guard "recipient_endpoint_registered" { self.member_peer_endpoints.contains_key(recipient_identity) == true }
guard "recipient_endpoint_matches" { self.member_peer_endpoints.get_cloned(recipient_identity) == Some(expected_recipient_endpoint) }
guard "recipient_peer_id_matches" { self.member_peer_ids.get_cloned(recipient_identity) == Some(mob_machine_member_peer_endpoint_peer_id(expected_recipient_endpoint)) }
guard "retiring_binding_matches" { self.identity_to_runtime.get_cloned(retiring_identity) == Some(retiring_runtime_id) }
guard "retiring_generation_matches" { self.identity_runtime_generations.get_copied(retiring_identity) == Some(generation) }
guard "retiring_fence_matches" { self.identity_runtime_fence_tokens.get_copied(retiring_identity) == Some(fence_token) }
guard "retiring_member_marked" { self.member_state_markers.get_cloned(retiring_runtime_id) == Some(MobMemberState::Retiring) }
guard "respawn_topology_preservation_recorded" { self.pending_respawn_topology.contains(retiring_identity) == true }
guard "recipient_wired_to_retiring" { mob_machine_wiring_contains_pair(self.wiring_edges, recipient_identity, retiring_identity) }
guard "filtered_overlay_member_endpoints_complete" { mob_machine_member_peer_overlay_without_identity_complete(self.wiring_edges, self.member_peer_endpoints, recipient_identity, retiring_identity) == true }
guard "filtered_overlay_peer_ids_unique" { mob_machine_member_peer_overlay_without_identity_peer_ids_unique(self.wiring_edges, self.member_peer_endpoints, self.external_peer_edges, recipient_identity, retiring_identity) == true }
update {}
to Running
emit MemberPeerOverlayAuthorized {
agent_identity: recipient_identity,
peer_id: mob_machine_member_peer_endpoint_peer_id(expected_recipient_endpoint),
peer_overlay_endpoints: mob_machine_member_peer_overlay_without_identity(self.wiring_edges, self.member_peer_endpoints, self.external_peer_edges, recipient_identity, retiring_identity),
epoch: self.topology_epoch
}
}
transition AuthorizeMemberTrustWiringRunning {
on input AuthorizeMemberTrustWiring { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
guard "a_member_endpoint_registered" { self.member_peer_endpoints.contains_key(a_identity) == true }
guard "b_member_endpoint_registered" { self.member_peer_endpoints.contains_key(b_identity) == true }
update {}
to Running
emit MemberTrustWiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
a_endpoint: self.member_peer_endpoints.get_cloned(a_identity).get("value"),
b_endpoint: self.member_peer_endpoints.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch
}
}
transition AuthorizeMemberTrustUnwiringRunning {
on input AuthorizeMemberTrustUnwiring { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
update {}
to Running
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch + 1
}
}
transition AuthorizeMemberTrustUnwiringStopped {
on input AuthorizeMemberTrustUnwiring { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
update {}
to Stopped
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch + 1
}
}
transition AuthorizeMemberTrustCleanupRunning {
on input AuthorizeMemberTrustCleanup { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
update {}
to Running
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch
}
}
transition AuthorizeMemberTrustCleanupStopped {
on input AuthorizeMemberTrustCleanup { edge, a_identity, b_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "a_member_peer_registered" { self.member_peer_ids.contains_key(a_identity) == true }
guard "b_member_peer_registered" { self.member_peer_ids.contains_key(b_identity) == true }
update {}
to Stopped
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: self.member_peer_ids.get_cloned(a_identity).get("value"),
b_peer_id: self.member_peer_ids.get_cloned(b_identity).get("value"),
epoch: self.topology_epoch
}
}
transition AuthorizeMemberTrustCleanupObservedRunning {
on input AuthorizeMemberTrustCleanupObserved { edge, a_identity, a_peer_id, b_identity, b_peer_id }
guard { self.lifecycle_phase == Phase::Running }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "cleanup_has_restore_failure" { self.member_restore_failures.contains_key(a_identity) == true || self.member_restore_failures.contains_key(b_identity) == true }
update {}
to Running
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: a_peer_id,
b_peer_id: b_peer_id,
epoch: self.topology_epoch
}
}
transition AuthorizeMemberTrustCleanupObservedStopped {
on input AuthorizeMemberTrustCleanupObserved { edge, a_identity, a_peer_id, b_identity, b_peer_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "cleanup_has_restore_failure" { self.member_restore_failures.contains_key(a_identity) == true || self.member_restore_failures.contains_key(b_identity) == true }
update {}
to Stopped
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: a_peer_id,
b_peer_id: b_peer_id,
epoch: self.topology_epoch
}
}
// Cold retirement retry may have only observed trust rows left: the
// retirement-start journal deliberately clears restore diagnostics,
// while peer endpoint registration can be unavailable after the
// crashed runtime vanished. The exact current runtime binding, fence,
// generation, and Retiring marker are the machine-owned authority for
// accepting those observed peer ids. This path never authorizes an
// active or stale runtime to remove trust.
transition AuthorizeRetiringMemberTrustCleanupObserved {
per_phase [Running, Stopped]
on input AuthorizeRetiringMemberTrustCleanupObserved { edge, a_identity, a_peer_id, b_identity, b_peer_id, agent_identity, agent_runtime_id, fence_token, generation }
guard "edge_matches_members" { mob_machine_wiring_edge_matches_members(edge, a_identity, b_identity) }
guard "edge_currently_wired" { self.wiring_edges.contains(edge) == true }
guard "retiring_identity_is_endpoint" { agent_identity == a_identity || agent_identity == b_identity }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
update {}
to Running
emit MemberTrustUnwiringRequested {
edge: edge,
a_peer_id: a_peer_id,
b_peer_id: b_peer_id,
epoch: self.topology_epoch
}
}
transition AuthorizeExternalPeerReciprocalTrustRunning {
on input AuthorizeExternalPeerReciprocalTrust { key, agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_already_wired" { self.external_peer_edges_by_key.contains_key(key) == true }
guard "external_peer_key_matches_member" { mob_machine_external_peer_key_matches_local(key, agent_identity) }
guard "member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
guard "member_endpoint_registered" { self.member_peer_endpoints.contains_key(agent_identity) == true }
update {}
to Running
emit ExternalPeerReciprocalTrustRequested {
key: key,
edge: self.external_peer_edges_by_key.get_cloned(key).get("value"),
peer_id: self.member_peer_ids.get_cloned(agent_identity).get("value"),
peer_endpoint: self.member_peer_endpoints.get_cloned(agent_identity).get("value"),
epoch: self.topology_epoch
}
}
transition RecoverExternalPeerWiringRunning {
on signal RecoverExternalPeerWiring { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_not_already_recovered" { self.external_peer_edges_by_key.contains_key(key) == false }
guard "external_peer_edge_not_already_recovered" { self.external_peer_edges.contains(edge) == false }
update {
self.external_peer_edges.insert(edge);
self.external_peer_edges_by_key.insert(key, edge);
self.topology_epoch += 1;
}
to Running
}
transition RecoverExternalPeerWiringAlreadyRecovered {
on signal RecoverExternalPeerWiring { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_already_recovered" { self.external_peer_edges_by_key.get_cloned(key) == Some(edge) }
guard "external_peer_edge_already_recovered" { self.external_peer_edges.contains(edge) == true }
update {}
to Running
}
transition RecoverExternalPeerUnwireRunning {
on signal RecoverExternalPeerUnwire { key }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_recovered" { self.external_peer_edges_by_key.contains_key(key) == true }
update {
self.external_peer_edges.remove(self.external_peer_edges_by_key.get_cloned(key).get("value"));
self.external_peer_edges_by_key.remove(key);
self.topology_epoch += 1;
}
to Running
}
transition RecoverExternalPeerUnwireAlreadyAbsent {
on signal RecoverExternalPeerUnwire { key }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_not_recovered" { self.external_peer_edges_by_key.contains_key(key) == false }
update {}
to Running
}
transition UnwireExternalPeerRunning {
on input UnwireExternalPeer { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_currently_wired" { self.external_peer_edges_by_key.get_cloned(key) == Some(edge) }
guard "external_peer_edge_currently_wired" { self.external_peer_edges.contains(edge) == true }
guard "local_member_peer_registered" { self.member_peer_ids.contains_key(mob_machine_external_peer_edge_local(edge)) == true }
update {
self.external_peer_edges.remove(edge);
self.external_peer_edges_by_key.remove(key);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit ExternalPeerTrustUnwiringRequested {
edge: edge,
local_peer_id: self.member_peer_ids.get_cloned(mob_machine_external_peer_edge_local(edge)).get("value"),
peer_id: mob_machine_external_peer_edge_peer_id(edge),
epoch: self.topology_epoch
}
emit EmitExternalPeerWiringLifecycleNotice { kind: WiringLifecycleKind::Unwired, edge: edge }
}
transition UnwireExternalPeerAlreadyAbsent {
on input UnwireExternalPeer { key, edge }
guard { self.lifecycle_phase == Phase::Running }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_already_absent" { self.external_peer_edges_by_key.contains_key(key) == false }
guard "external_peer_edge_already_absent" { self.external_peer_edges.contains(edge) == false }
update {}
to Running
}
transition CleanupRetiringExternalPeer {
per_phase [Running, Stopped]
on input CleanupRetiringExternalPeer { key, edge, agent_identity, agent_runtime_id, fence_token, generation }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_matches_member" { mob_machine_external_peer_key_matches_local(key, agent_identity) }
guard "external_peer_key_currently_wired" { self.external_peer_edges_by_key.get_cloned(key) == Some(edge) }
guard "external_peer_edge_currently_wired" { self.external_peer_edges.contains(edge) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "local_member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
update {
self.external_peer_edges.remove(edge);
self.external_peer_edges_by_key.remove(key);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit ExternalPeerTrustUnwiringRequested {
edge: edge,
local_peer_id: self.member_peer_ids.get_cloned(agent_identity).get("value"),
peer_id: mob_machine_external_peer_edge_peer_id(edge),
epoch: self.topology_epoch
}
}
transition RestoreRetiringExternalPeer {
per_phase [Running, Stopped]
on input RestoreRetiringExternalPeer { key, edge, agent_identity, agent_runtime_id, fence_token, generation }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_matches_member" { mob_machine_external_peer_key_matches_local(key, agent_identity) }
guard "external_peer_key_absent" { self.external_peer_edges_by_key.contains_key(key) == false }
guard "external_peer_edge_absent" { self.external_peer_edges.contains(edge) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "local_member_peer_registered" { self.member_peer_ids.contains_key(agent_identity) == true }
update {
self.external_peer_edges.insert(edge);
self.external_peer_edges_by_key.insert(key, edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
emit ExternalPeerTrustWiringRequested {
edge: edge,
local_peer_id: self.member_peer_ids.get_cloned(agent_identity).get("value"),
peer_id: mob_machine_external_peer_edge_peer_id(edge),
epoch: self.topology_epoch
}
}
// A cold retirement retry can prove that the retiring runtime no
// longer has a live comms owner. In that shape there is no trust store
// on which to realize an ExternalPeerTrustUnwiringRequested effect.
// The durable retiring endpoint plus exact runtime/fence/generation
// authorizes topology convergence without publishing an unrealizable
// trust obligation. A failed event append uses the symmetric restore
// transition, which likewise emits no live trust effect.
transition CleanupRetiringExternalPeerObservedAbsent {
per_phase [Running, Stopped]
on input CleanupRetiringExternalPeerObservedAbsent { key, edge, agent_identity, agent_runtime_id, fence_token, generation }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_matches_member" { mob_machine_external_peer_key_matches_local(key, agent_identity) }
guard "external_peer_key_currently_wired" { self.external_peer_edges_by_key.get_cloned(key) == Some(edge) }
guard "external_peer_edge_currently_wired" { self.external_peer_edges.contains(edge) == true }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retiring_peer_endpoint_retained" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "retiring_peer_id_retained" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value"))) }
update {
self.external_peer_edges.remove(edge);
self.external_peer_edges_by_key.remove(key);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
}
transition RestoreRetiringExternalPeerObservedAbsent {
per_phase [Running, Stopped]
on input RestoreRetiringExternalPeerObservedAbsent { key, edge, agent_identity, agent_runtime_id, fence_token, generation }
guard "external_peer_key_matches_edge" { mob_machine_external_peer_key_matches_edge(key, edge) }
guard "external_peer_key_matches_member" { mob_machine_external_peer_key_matches_local(key, agent_identity) }
guard "external_peer_key_absent" { self.external_peer_edges_by_key.contains_key(key) == false }
guard "external_peer_edge_absent" { self.external_peer_edges.contains(edge) == false }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "fence_token_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(fence_token) }
guard "member_retiring" { self.member_state_markers.get_cloned(agent_runtime_id) == Some(MobMemberState::Retiring) }
guard "retiring_peer_endpoint_retained" { self.member_peer_endpoints.contains_key(agent_identity) == true }
guard "retiring_peer_id_retained" { self.member_peer_ids.get_cloned(agent_identity) == Some(mob_machine_member_peer_endpoint_peer_id(self.member_peer_endpoints.get_cloned(agent_identity).get("value"))) }
update {
self.external_peer_edges.insert(edge);
self.external_peer_edges_by_key.insert(key, edge);
self.topology_epoch += 1;
}
to Running
emit WiringGraphChanged { epoch: self.topology_epoch }
}
// Mob-wide supervisor authority. The shell may generate key material,
// but MobMachine owns whether the current/pending authority tuple is
// admitted and which exact tuple may be persisted or used by the
// bridge.
transition AdmitSupervisorRotation {
per_phase [Running, Stopped]
on input AdmitSupervisorRotation
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "destroy_not_admitted" { self.destroy_admitted == false }
guard "no_member_retiring" {
for_all(agent_runtime_id in self.member_state_markers.keys(),
self.member_state_markers.get_cloned(agent_runtime_id) != Some(MobMemberState::Retiring))
}
update {}
to Running
}
transition ProvisionSupervisorAuthority {
per_phase [Running, Stopped, Completed, Destroyed]
on input ProvisionSupervisorAuthority { peer_id, signing_key, epoch, protocol_version }
guard "supervisor_authority_absent" {
self.supervisor_authority_peer_id == None
&& self.supervisor_authority_signing_key == None
&& self.supervisor_authority_epoch == None
&& self.supervisor_authority_protocol_version == None
}
guard "initial_epoch" { epoch == 0 }
update {
self.supervisor_authority_peer_id = Some(peer_id);
self.supervisor_authority_signing_key = Some(signing_key);
self.supervisor_authority_epoch = Some(epoch);
self.supervisor_authority_protocol_version = Some(protocol_version);
self.supervisor_pending_authority_peer_id = None;
self.supervisor_pending_authority_signing_key = None;
self.supervisor_pending_authority_epoch = None;
self.supervisor_pending_authority_protocol_version = None;
self.supervisor_pending_authority_operation_id = None;
self.supervisor_pending_authority_accepted_peer_ids = EmptySet;
self.supervisor_pending_authority_member_target_names = EmptyMap;
self.supervisor_pending_authority_member_target_addresses = EmptyMap;
}
to Running
emit PersistSupervisorAuthority {
peer_id: peer_id,
signing_key: signing_key,
epoch: epoch,
protocol_version: protocol_version,
pending_operation_id: None,
pending_peer_id: None,
pending_signing_key: None,
pending_epoch: None,
pending_protocol_version: None,
pending_accepted_peer_ids: EmptySet,
pending_member_target_names: EmptyMap,
pending_member_target_addresses: EmptyMap
}
}
transition RecoverSupervisorAuthority {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverSupervisorAuthority {
peer_id,
signing_key,
epoch,
protocol_version,
pending_operation_id,
pending_peer_id,
pending_signing_key,
pending_epoch,
pending_protocol_version,
pending_accepted_peer_ids,
pending_member_target_names,
pending_member_target_addresses
}
guard "supervisor_authority_absent" {
self.supervisor_authority_peer_id == None
&& self.supervisor_authority_signing_key == None
&& self.supervisor_authority_epoch == None
&& self.supervisor_authority_protocol_version == None
}
guard "pending_shape_consistent" {
(
pending_peer_id == None
&& pending_signing_key == None
&& pending_epoch == None
&& pending_protocol_version == None
&& pending_operation_id == None
&& pending_accepted_peer_ids == EmptySet
&& pending_member_target_names == EmptyMap
&& pending_member_target_addresses == EmptyMap
)
|| (
pending_peer_id != None
&& pending_signing_key != None
&& pending_epoch != None
&& pending_protocol_version != None
&& pending_peer_id != Some(peer_id)
&& mob_machine_optional_u64_is_exact_successor(epoch, pending_epoch)
)
}
guard "pending_member_targets_aligned" {
pending_member_target_names.keys() == pending_member_target_addresses.keys()
}
update {
self.supervisor_authority_peer_id = Some(peer_id);
self.supervisor_authority_signing_key = Some(signing_key);
self.supervisor_authority_epoch = Some(epoch);
self.supervisor_authority_protocol_version = Some(protocol_version);
self.supervisor_pending_authority_peer_id = pending_peer_id;
self.supervisor_pending_authority_signing_key = pending_signing_key;
self.supervisor_pending_authority_epoch = pending_epoch;
self.supervisor_pending_authority_protocol_version = pending_protocol_version;
self.supervisor_pending_authority_operation_id = pending_operation_id;
self.supervisor_pending_authority_accepted_peer_ids = pending_accepted_peer_ids;
self.supervisor_pending_authority_member_target_names = pending_member_target_names;
self.supervisor_pending_authority_member_target_addresses = pending_member_target_addresses;
}
to Running
}
transition RecordSupervisorPendingRotation {
per_phase [Running, Stopped, Completed]
on input RecordSupervisorPendingRotation {
current_peer_id,
current_epoch,
current_protocol_version,
operation_id,
pending_peer_id,
pending_signing_key,
pending_epoch,
pending_protocol_version,
accepted_peer_ids,
active_peer_ids,
member_target_names,
member_target_addresses
}
guard "current_supervisor_matches" {
self.supervisor_authority_peer_id == Some(current_peer_id)
&& self.supervisor_authority_signing_key != None
&& self.supervisor_authority_epoch == Some(current_epoch)
&& self.supervisor_authority_protocol_version == Some(current_protocol_version)
}
guard "pending_authority_changes_peer" { pending_peer_id != current_peer_id }
guard "pending_epoch_is_successor" { mob_machine_u64_is_exact_successor(current_epoch, pending_epoch) }
guard "operation_id_not_empty" { operation_id != "" }
guard "member_targets_aligned" {
member_target_names.keys() == member_target_addresses.keys()
}
guard "accepted_peers_have_targets" {
for_all(peer_id in accepted_peer_ids,
member_target_names.contains_key(peer_id)
&& member_target_addresses.contains_key(peer_id))
}
guard "pending_slot_empty_legacy_reconciled_or_exact_retry" {
(
self.supervisor_pending_authority_operation_id == None
&& self.supervisor_pending_authority_peer_id == None
&& accepted_peer_ids == EmptySet
)
|| (
self.supervisor_pending_authority_operation_id == None
&& self.supervisor_pending_authority_peer_id == Some(pending_peer_id)
&& self.supervisor_pending_authority_signing_key == Some(pending_signing_key)
&& self.supervisor_pending_authority_epoch == Some(pending_epoch)
// Legacy V2/V3 records predate operation ids and exact
// targets. The shell supplies the current active-peer set;
// the machine admits exactly old-accepted intersect active,
// deterministically dropping retired/missing peer ids before
// installing the first operation id.
&& for_all(peer_id in accepted_peer_ids,
self.supervisor_pending_authority_accepted_peer_ids.contains(peer_id)
&& active_peer_ids.contains(peer_id))
&& for_all(peer_id in self.supervisor_pending_authority_accepted_peer_ids,
accepted_peer_ids.contains(peer_id) == active_peer_ids.contains(peer_id))
)
|| (
self.supervisor_pending_authority_operation_id == Some(operation_id)
&& self.supervisor_pending_authority_peer_id == Some(pending_peer_id)
&& self.supervisor_pending_authority_signing_key == Some(pending_signing_key)
&& self.supervisor_pending_authority_epoch == Some(pending_epoch)
&& self.supervisor_pending_authority_protocol_version == Some(pending_protocol_version)
&& for_all(peer_id in self.supervisor_pending_authority_accepted_peer_ids,
accepted_peer_ids.contains(peer_id))
&& for_all(peer_id in self.supervisor_pending_authority_member_target_names.keys(),
member_target_names.get_cloned(peer_id)
== self.supervisor_pending_authority_member_target_names.get_cloned(peer_id))
&& for_all(peer_id in self.supervisor_pending_authority_member_target_addresses.keys(),
member_target_addresses.get_cloned(peer_id)
== self.supervisor_pending_authority_member_target_addresses.get_cloned(peer_id))
)
}
update {
self.supervisor_pending_authority_peer_id = Some(pending_peer_id);
self.supervisor_pending_authority_signing_key = Some(pending_signing_key);
self.supervisor_pending_authority_epoch = Some(pending_epoch);
self.supervisor_pending_authority_protocol_version = Some(pending_protocol_version);
self.supervisor_pending_authority_operation_id = Some(operation_id);
self.supervisor_pending_authority_accepted_peer_ids = accepted_peer_ids;
self.supervisor_pending_authority_member_target_names = member_target_names;
self.supervisor_pending_authority_member_target_addresses = member_target_addresses;
}
to Running
emit PersistSupervisorAuthority {
peer_id: current_peer_id,
signing_key: self.supervisor_authority_signing_key.get("value"),
epoch: current_epoch,
protocol_version: current_protocol_version,
pending_operation_id: Some(operation_id),
pending_peer_id: Some(pending_peer_id),
pending_signing_key: Some(pending_signing_key),
pending_epoch: Some(pending_epoch),
pending_protocol_version: Some(pending_protocol_version),
pending_accepted_peer_ids: accepted_peer_ids,
pending_member_target_names: member_target_names,
pending_member_target_addresses: member_target_addresses
}
}
// --- Recipient-trust obligation window (dogma row R044) ---
//
// The comms router refuses to route to untrusted peers, so the shell
// must install recipient trust BEFORE the AuthorizeSupervisor /
// BindMember terminality verdict. That trust-install-to-terminality
// window is a machine fact, mirroring the pending-rotation metadata
// pattern: Record before trust install, Resolve on confirmed-accept
// terminality, Rollback after the shell removes the installed trust
// on a failure path (send error, terminal rejection, decode error).
// No guards beyond phase: set insert/remove are idempotent so nested
// authorize-then-bind windows for the same peer compose. The state is
// volatile exactly like the trust it tracks (recovery seeds empty).
transition RecordPendingRecipientTrust {
per_phase [Running, Stopped, Completed, Destroyed]
on input RecordPendingRecipientTrust { peer_id }
update {
self.pending_recipient_trust.insert(peer_id);
}
to Running
}
transition ResolvePendingRecipientTrust {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePendingRecipientTrust { peer_id }
update {
self.pending_recipient_trust.remove(peer_id);
}
to Running
}
transition RollbackPendingRecipientTrust {
per_phase [Running, Stopped, Completed, Destroyed]
on input RollbackPendingRecipientTrust { peer_id }
update {
self.pending_recipient_trust.remove(peer_id);
}
to Running
}
// =====================================================================
// Multi-host mobs (§6.1): host bind lifecycle.
// =====================================================================
transition BeginHostBindFreshUnplaced {
on input BeginHostBind { host_id, expected_endpoint, binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "host_untracked" { self.host_bind_phase.contains_key(host_id) == false }
guard "no_replacement_request" { self.replacement_host_bind_endpoints.contains_key(host_id) == false }
guard "no_retained_placement" {
for_all(id in self.member_placement.keys(), self.member_placement.get_cloned(id) != Some(host_id))
}
guard "binding_generation_positive" { binding_generation > 0 }
guard "binding_generation_advances" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation > self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.host_bind_phase.insert(host_id, HostBindPhase::Requested);
self.host_binding_generations.insert(host_id, binding_generation);
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
to Running
emit RequestHostBind { host_id: host_id, endpoint: expected_endpoint, binding_generation: binding_generation }
}
// A revoked host can retain placement rows for revival. Opening its
// replacement ceremony must leave host_bind_phase absent so no
// remote-action transition mistakes Requested for live authority.
transition BeginHostBindFreshReplacement {
on input BeginHostBind { host_id, expected_endpoint, binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "host_untracked" { self.host_bind_phase.contains_key(host_id) == false }
guard "no_replacement_request" { self.replacement_host_bind_endpoints.contains_key(host_id) == false }
guard "retained_placement_present" {
exists(id in self.member_placement.keys(), self.member_placement.get_cloned(id) == Some(host_id))
}
guard "binding_generation_positive" { binding_generation > 0 }
guard "binding_generation_advances" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation > self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.replacement_host_bind_endpoints.insert(host_id, expected_endpoint);
self.replacement_host_binding_generations.insert(host_id, binding_generation);
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
to Running
emit RequestHostBind { host_id: host_id, endpoint: expected_endpoint, binding_generation: binding_generation }
}
// Idempotent re-request while the window is open (bind retry).
transition BeginHostBindRequested {
on input BeginHostBind { host_id, expected_endpoint, binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "host_requested" { self.host_bind_phase.get_cloned(host_id) == Some(HostBindPhase::Requested) }
guard "binding_generation_exact" { self.host_binding_generations.get_copied(host_id) == Some(binding_generation) }
update {}
to Running
emit RequestHostBind { host_id: host_id, endpoint: expected_endpoint, binding_generation: binding_generation }
}
transition BeginHostBindReplacementRequested {
on input BeginHostBind { host_id, expected_endpoint, binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "host_phase_absent" { self.host_bind_phase.contains_key(host_id) == false }
guard "replacement_endpoint_exact" { self.replacement_host_bind_endpoints.get_cloned(host_id) == Some(expected_endpoint) }
guard "binding_generation_exact" { self.replacement_host_binding_generations.get_copied(host_id) == Some(binding_generation) }
update {}
to Running
emit RequestHostBind { host_id: host_id, endpoint: expected_endpoint, binding_generation: binding_generation }
}
transition CommitHostBind {
on input CommitHostBind { host_id, pubkey, endpoint, epoch, binding_generation, protocol_min, protocol_max, engine_version, durable_sessions, autonomous_members, hard_cancel_member, tracked_input_cancel, memory_store, mcp, resolvable_providers, approval_forwarding, live_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "bind_requested" {
self.host_bind_phase.get_cloned(host_id) == Some(HostBindPhase::Requested)
|| self.replacement_host_bind_endpoints.contains_key(host_id) == true
}
guard "binding_generation_exact" {
self.host_binding_generations.get_copied(host_id) == Some(binding_generation)
|| self.replacement_host_binding_generations.get_copied(host_id) == Some(binding_generation)
}
guard "replacement_endpoint_exact" {
self.replacement_host_bind_endpoints.contains_key(host_id) == false
|| self.replacement_host_bind_endpoints.get_cloned(host_id) == Some(endpoint)
}
guard "active_capability_contract_preserved" {
(
!exists(turn in self.pending_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.committed_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.resolved_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(completion in self.pending_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(completion in self.resolved_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(kickoff in self.pending_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(kickoff in self.resolved_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
)
|| (
durable_sessions == true
&& tracked_input_cancel == true
&& protocol_min <= 4
&& protocol_max >= 4
&& (
!exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
|| autonomous_members == true
)
)
}
update {
self.replacement_host_bind_endpoints.remove(host_id);
self.replacement_host_binding_generations.remove(host_id);
self.mob_hosts.insert(host_id);
self.host_public_keys.insert(host_id, pubkey);
self.host_endpoints.insert(host_id, endpoint);
self.host_authority_epochs.insert(host_id, epoch);
self.host_binding_generations.insert(host_id, binding_generation);
self.host_bind_phase.insert(host_id, HostBindPhase::Bound);
self.host_protocol_min.insert(host_id, protocol_min);
self.host_protocol_max.insert(host_id, protocol_max);
self.host_engine_versions.insert(host_id, engine_version);
self.host_durable_sessions.insert(host_id, durable_sessions);
self.host_autonomous_members.insert(host_id, autonomous_members);
self.host_hard_cancel_member.insert(host_id, hard_cancel_member);
self.host_tracked_input_cancel.insert(host_id, tracked_input_cancel);
self.host_memory_store.insert(host_id, memory_store);
self.host_mcp.insert(host_id, mcp);
self.host_resolvable_providers.insert(host_id, resolvable_providers);
self.host_approval_forwarding.insert(host_id, approval_forwarding);
if live_endpoint != None {
self.host_live_endpoints.insert(host_id, live_endpoint.get("value"));
} else {
self.host_live_endpoints.remove(host_id);
}
}
to Running
emit HostRegistered { host_id: host_id, epoch: epoch, binding_generation: binding_generation }
}
// Epoch monotonicity is strict here: a rebind at or below the
// recorded epoch fires no transition (typed machine rejection).
transition HostRebound {
on input HostRebound { host_id, epoch, binding_generation, protocol_min, protocol_max, engine_version, durable_sessions, autonomous_members, hard_cancel_member, tracked_input_cancel, memory_store, mcp, resolvable_providers, approval_forwarding, live_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "host_bound" { self.host_bind_phase.get_cloned(host_id) == Some(HostBindPhase::Bound) }
guard "binding_generation_exact" { self.host_binding_generations.get_copied(host_id) == Some(binding_generation) }
guard "epoch_advances" { self.host_authority_epochs.get_copied(host_id).get("value") < epoch }
guard "active_capability_contract_preserved" {
(
!exists(turn in self.pending_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.committed_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.resolved_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(completion in self.pending_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(completion in self.resolved_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(kickoff in self.pending_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(kickoff in self.resolved_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
)
|| (
durable_sessions == true
&& tracked_input_cancel == true
&& protocol_min <= 4
&& protocol_max >= 4
&& (
!exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
|| autonomous_members == true
)
)
}
update {
self.host_authority_epochs.insert(host_id, epoch);
self.host_protocol_min.insert(host_id, protocol_min);
self.host_protocol_max.insert(host_id, protocol_max);
self.host_engine_versions.insert(host_id, engine_version);
self.host_durable_sessions.insert(host_id, durable_sessions);
self.host_autonomous_members.insert(host_id, autonomous_members);
self.host_hard_cancel_member.insert(host_id, hard_cancel_member);
self.host_tracked_input_cancel.insert(host_id, tracked_input_cancel);
self.host_memory_store.insert(host_id, memory_store);
self.host_mcp.insert(host_id, mcp);
self.host_resolvable_providers.insert(host_id, resolvable_providers);
self.host_approval_forwarding.insert(host_id, approval_forwarding);
if live_endpoint != None {
self.host_live_endpoints.insert(host_id, live_endpoint.get("value"));
} else {
self.host_live_endpoints.remove(host_id);
}
}
to Running
emit HostReboundRecorded { host_id: host_id, epoch: epoch, binding_generation: binding_generation }
}
transition RefreshHostCapabilities {
on input RefreshHostCapabilities { host_id, epoch, binding_generation, protocol_min, protocol_max, engine_version, durable_sessions, autonomous_members, hard_cancel_member, tracked_input_cancel, memory_store, mcp, resolvable_providers, approval_forwarding, live_endpoint }
guard { self.lifecycle_phase == Phase::Running }
guard "host_bound" { self.host_bind_phase.get_cloned(host_id) == Some(HostBindPhase::Bound) }
guard "host_epoch_exact" { self.host_authority_epochs.get_copied(host_id) == Some(epoch) }
guard "binding_generation_exact" { self.host_binding_generations.get_copied(host_id) == Some(binding_generation) }
guard "active_capability_contract_preserved" {
(
!exists(turn in self.pending_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.committed_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(turn in self.resolved_remote_turn_outcomes, turn.host_id == host_id)
&& !exists(completion in self.pending_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(completion in self.resolved_placed_completion_outcomes, completion.host_id == host_id)
&& !exists(kickoff in self.pending_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(kickoff in self.resolved_placed_kickoff_outcomes, kickoff.host_id == host_id)
&& !exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
)
|| (
durable_sessions == true
&& tracked_input_cancel == true
&& protocol_min <= 4
&& protocol_max >= 4
&& (
!exists(identity in self.member_placement.keys(),
self.member_placement.get_cloned(identity) == Some(host_id)
&& self.member_runtime_modes.get_cloned(identity) == Some(SpawnPolicyRuntimeMode::AutonomousHost))
&& !exists(identity in self.pending_autonomous_placed_spawns,
self.pending_placed_spawn_hosts.get_cloned(identity) == Some(host_id))
|| autonomous_members == true
)
)
}
update {
self.host_protocol_min.insert(host_id, protocol_min);
self.host_protocol_max.insert(host_id, protocol_max);
self.host_engine_versions.insert(host_id, engine_version);
self.host_durable_sessions.insert(host_id, durable_sessions);
self.host_autonomous_members.insert(host_id, autonomous_members);
self.host_hard_cancel_member.insert(host_id, hard_cancel_member);
self.host_tracked_input_cancel.insert(host_id, tracked_input_cancel);
self.host_memory_store.insert(host_id, memory_store);
self.host_mcp.insert(host_id, mcp);
self.host_resolvable_providers.insert(host_id, resolvable_providers);
self.host_approval_forwarding.insert(host_id, approval_forwarding);
if live_endpoint != None {
self.host_live_endpoints.insert(host_id, live_endpoint.get("value"));
} else {
self.host_live_endpoints.remove(host_id);
}
}
to Running
emit HostCapabilitiesRefreshed { host_id: host_id, epoch: epoch, binding_generation: binding_generation }
}
transition RevokeHost {
on input RevokeHost { host_id, binding_generation }
guard { self.lifecycle_phase == Phase::Running }
guard "host_tracked" {
self.host_bind_phase.contains_key(host_id) == true
|| self.replacement_host_bind_endpoints.contains_key(host_id) == true
}
guard "binding_generation_exact" {
self.host_binding_generations.get_copied(host_id) == Some(binding_generation)
|| self.replacement_host_binding_generations.get_copied(host_id) == Some(binding_generation)
}
guard "placed_kickoff_custody_drained_for_host" {
mob_machine_placed_kickoff_custody_absent_for_host(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
host_id)
}
update {
self.confirmed_host_binding_revocations.insert(mob_machine_host_binding_generation_tombstone(host_id, binding_generation));
self.replacement_host_bind_endpoints.remove(host_id);
self.replacement_host_binding_generations.remove(host_id);
self.mob_hosts.remove(host_id);
self.host_public_keys.remove(host_id);
self.host_endpoints.remove(host_id);
self.host_authority_epochs.remove(host_id);
self.host_binding_generations.remove(host_id);
self.host_bind_phase.remove(host_id);
self.host_protocol_min.remove(host_id);
self.host_protocol_max.remove(host_id);
self.host_engine_versions.remove(host_id);
self.host_durable_sessions.remove(host_id);
self.host_autonomous_members.remove(host_id);
self.host_hard_cancel_member.remove(host_id);
self.host_tracked_input_cancel.remove(host_id);
self.host_memory_store.remove(host_id);
self.host_mcp.remove(host_id);
self.host_resolvable_providers.remove(host_id);
self.host_approval_forwarding.remove(host_id);
self.host_live_endpoints.remove(host_id);
}
to Running
emit HostRevoked { host_id: host_id, binding_generation: binding_generation }
}
// Restore an unfinished pre-ACK bind request from its structural
// Started anchor. `replacement` is durable event truth: recovery must
// not reclassify the request from a partially rebuilt placement map.
transition RecoverOrdinaryHostBindRequest {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverHostBindRequest { host_id, expected_endpoint, binding_generation, replacement }
guard "ordinary_request" { replacement == false }
guard "host_untracked" { self.host_bind_phase.contains_key(host_id) == false }
guard "host_generation_absent" { self.host_binding_generations.contains_key(host_id) == false }
guard "replacement_absent" {
self.replacement_host_bind_endpoints.contains_key(host_id) == false
&& self.replacement_host_binding_generations.contains_key(host_id) == false
}
guard "binding_generation_positive" { binding_generation > 0 }
guard "binding_generation_not_regressed" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation >= self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.host_bind_phase.insert(host_id, HostBindPhase::Requested);
self.host_binding_generations.insert(host_id, binding_generation);
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
to Running
}
transition RecoverReplacementHostBindRequest {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverHostBindRequest { host_id, expected_endpoint, binding_generation, replacement }
guard "replacement_request" { replacement == true }
guard "host_untracked" { self.host_bind_phase.contains_key(host_id) == false }
guard "host_generation_absent" { self.host_binding_generations.contains_key(host_id) == false }
guard "replacement_absent" {
self.replacement_host_bind_endpoints.contains_key(host_id) == false
&& self.replacement_host_binding_generations.contains_key(host_id) == false
}
guard "binding_generation_positive" { binding_generation > 0 }
guard "binding_generation_not_regressed" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation >= self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.replacement_host_bind_endpoints.insert(host_id, expected_endpoint);
self.replacement_host_binding_generations.insert(host_id, binding_generation);
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
to Running
}
// FLAG-3 (§9 controlling-host restart): restore one bound host from
// its durable MobHostAuthorityRecord at builder recovery — the
// RecoverSupervisorAuthority posture (per_phase self-loops across
// every recoverable phase; a double-apply for the same host fails
// loud on the guard instead of silently overwriting). Records exist
// only for Bound hosts, so recovery restores the full Bound fact set:
// membership, key, endpoint, epoch, phase, every capability map, and
// the live endpoint (absent = live-incapable, no shadow boolean).
transition RecoverHostBinding {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverHostBinding { host_id, pubkey, endpoint, epoch, binding_generation, protocol_min, protocol_max, engine_version, durable_sessions, autonomous_members, hard_cancel_member, tracked_input_cancel, memory_store, mcp, resolvable_providers, approval_forwarding, live_endpoint }
guard "host_untracked" { self.host_bind_phase.contains_key(host_id) == false }
guard "binding_generation_not_regressed" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation >= self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.mob_hosts.insert(host_id);
self.host_public_keys.insert(host_id, pubkey);
self.host_endpoints.insert(host_id, endpoint);
self.host_authority_epochs.insert(host_id, epoch);
self.host_binding_generations.insert(host_id, binding_generation);
self.host_binding_generation_highwater.insert(host_id, binding_generation);
self.host_bind_phase.insert(host_id, HostBindPhase::Bound);
self.host_protocol_min.insert(host_id, protocol_min);
self.host_protocol_max.insert(host_id, protocol_max);
self.host_engine_versions.insert(host_id, engine_version);
self.host_durable_sessions.insert(host_id, durable_sessions);
self.host_autonomous_members.insert(host_id, autonomous_members);
self.host_hard_cancel_member.insert(host_id, hard_cancel_member);
self.host_tracked_input_cancel.insert(host_id, tracked_input_cancel);
self.host_memory_store.insert(host_id, memory_store);
self.host_mcp.insert(host_id, mcp);
self.host_resolvable_providers.insert(host_id, resolvable_providers);
self.host_approval_forwarding.insert(host_id, approval_forwarding);
if live_endpoint != None {
self.host_live_endpoints.insert(host_id, live_endpoint.get("value"));
} else {
self.host_live_endpoints.remove(host_id);
}
}
to Running
}
transition RecoverHostBindingGenerationHighwater {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverHostBindingGenerationHighwater { host_id, binding_generation }
guard "binding_generation_positive" { binding_generation > 0 }
guard "binding_generation_not_regressed" {
self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation >= self.host_binding_generation_highwater.get_copied(host_id).get("value")
}
update {
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
to Running
}
transition RecoverConfirmedHostBindingRevocation {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverConfirmedHostBindingRevocation { host_id, binding_generation }
guard "binding_generation_positive" { binding_generation > 0 }
update {
self.confirmed_host_binding_revocations.insert(mob_machine_host_binding_generation_tombstone(host_id, binding_generation));
if self.host_binding_generation_highwater.contains_key(host_id) == false
|| binding_generation > self.host_binding_generation_highwater.get_copied(host_id).get("value") {
self.host_binding_generation_highwater.insert(host_id, binding_generation);
}
}
to Running
}
// =====================================================================
// Multi-host mobs (§6.2, D4): route install obligations. The machine
// revalidates each proposed obligation against its own wiring/host
// facts; Resolve/Rollback are idempotent set removals mirroring the
// pending_recipient_trust trio.
// =====================================================================
transition RecordRouteInstallInstall {
on input RecordRouteInstall { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "obligation_is_install" { obligation.kind == RouteObligationKind::Install }
guard "edge_currently_wired" { self.wiring_edges.contains(obligation.edge) == true }
guard "host_bound" { self.host_bind_phase.get_cloned(obligation.host) == Some(HostBindPhase::Bound) }
guard "placed_endpoints_binding_active" {
(self.member_placement.get_cloned(obligation.edge.a) != Some(obligation.host)
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.edge.a))
&& (self.member_placement.get_cloned(obligation.edge.b) != Some(obligation.host)
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.edge.b))
}
update {
self.pending_route_installs.insert(obligation);
}
to Running
emit RouteInstallRequested { obligation: obligation }
}
transition AuthorizeRouteRemovalBeforeUnwire {
on input AuthorizeRouteRemovalBeforeUnwire { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "obligation_is_remove" { obligation.kind == RouteObligationKind::Remove }
guard "edge_currently_wired" { self.wiring_edges.contains(obligation.edge) == true }
guard "host_bound" { self.host_bind_phase.get_cloned(obligation.host) == Some(HostBindPhase::Bound) }
guard "placed_endpoints_binding_active" {
(self.member_placement.get_cloned(obligation.edge.a) == Some(obligation.host)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.edge.a))
|| (self.member_placement.get_cloned(obligation.edge.b) == Some(obligation.host)
&& mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.edge.b))
}
guard "host_owns_edge_endpoint" {
self.member_placement.get_cloned(obligation.edge.a) == Some(obligation.host)
|| self.member_placement.get_cloned(obligation.edge.b) == Some(obligation.host)
}
guard "edge_endpoints_published" {
self.member_peer_endpoints.contains_key(obligation.edge.a) == true
&& self.member_peer_endpoints.contains_key(obligation.edge.b) == true
}
update {}
to Running
emit RouteInstallRequested { obligation: obligation }
}
transition ResolveRouteInstall {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveRouteInstall { obligation }
guard "obligation_is_install" { obligation.kind == RouteObligationKind::Install }
update {
self.pending_route_installs.remove(obligation);
}
to Running
}
transition RollbackRouteInstall {
per_phase [Running, Stopped, Completed, Destroyed]
on input RollbackRouteInstall { obligation }
guard "obligation_is_install" { obligation.kind == RouteObligationKind::Install }
update {
self.pending_route_installs.remove(obligation);
}
to Running
}
// =====================================================================
// Multi-host mobs (§18 O2): remote turn-outcome obligations.
// Recorded before the directed send. Commit is admitted only after a
// durable StepTargetCompleted/StepTargetFailed row names the exact
// obligation. Resolve moves the exact host row into ACK-pending
// custody; Acknowledge removes it only after a poll response proves
// that the host applied that exact ACK.
// =====================================================================
transition RecoverRemoteTurnDispatchSequenceAdvance {
on signal RecoverRemoteTurnDispatchSequence { dispatch_sequence }
guard { self.lifecycle_phase == Phase::Running }
guard "newer_dispatch_sequence" { dispatch_sequence > self.remote_turn_dispatch_sequence }
update {
self.remote_turn_dispatch_sequence = dispatch_sequence;
}
to Running
}
transition RecoverRemoteTurnDispatchSequenceReplay {
on signal RecoverRemoteTurnDispatchSequence { dispatch_sequence }
guard { self.lifecycle_phase == Phase::Running }
guard "historical_dispatch_sequence" { dispatch_sequence <= self.remote_turn_dispatch_sequence }
update {}
to Running
}
transition RecordRemoteTurnObligationFresh {
on input RecordRemoteTurnObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "target_placed" { self.member_placement.contains_key(obligation.agent_identity) == true }
guard "target_host_exact" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "target_host_bound" { self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound) }
guard "target_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
}
guard "target_host_binding_generation_exact" {
self.current_placed_spawn_host_binding_generations.get_cloned(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_cloned(obligation.host_id) == Some(obligation.host_binding_generation)
}
guard "target_host_durable_sessions" { self.host_durable_sessions.get_cloned(obligation.host_id) == Some(true) }
guard "target_host_supports_tracked_input_cancel" {
self.host_tracked_input_cancel.get_cloned(obligation.host_id) == Some(true)
}
guard "target_host_supports_v4" {
self.host_protocol_min.get_cloned(obligation.host_id).get("value") <= 4
&& self.host_protocol_max.get_cloned(obligation.host_id).get("value") >= 4
}
guard "target_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "target_runtime_present" { self.identity_to_runtime.contains_key(obligation.agent_identity) == true }
guard "target_runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) == true }
// Placed members are host-owned PeerOnly runtimes: remote
// membership commit intentionally carries no LOCAL
// member_startup_ready fact. The committed host session + exact
// placement/incarnation + settled materialization facts below are
// their readiness authority.
guard "target_not_retiring" { self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) != Some(MobMemberState::Retiring) }
guard "target_not_reviving" { self.member_revival_pending.contains(obligation.agent_identity) == false }
guard "target_spawn_settled" { self.spawn_exec_phase.contains_key(obligation.agent_identity) == false }
guard "target_materialization_healthy" { self.member_materialization_failures.contains_key(obligation.agent_identity) == false }
guard "custody_quota_and_correlation_available" {
mob_machine_remote_turn_custody_admits(
self.pending_remote_turn_outcomes,
self.committed_remote_turn_outcomes,
self.resolved_remote_turn_outcomes,
obligation)
}
guard "placed_kickoff_correlation_available" {
mob_machine_remote_turn_input_id_available_to_kickoff(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
self.retained_placed_kickoff_obligations,
obligation)
}
guard "placed_completion_correlation_available" {
for_all(completion in self.pending_placed_completion_outcomes,
completion.agent_identity != obligation.agent_identity
|| completion.host_id != obligation.host_id
|| completion.generation != obligation.generation
|| completion.fence_token != obligation.fence_token
|| completion.input_id != obligation.input_id)
&& for_all(completion in self.resolved_placed_completion_outcomes,
completion.agent_identity != obligation.agent_identity
|| completion.host_id != obligation.host_id
|| completion.generation != obligation.generation
|| completion.fence_token != obligation.fence_token
|| completion.input_id != obligation.input_id)
}
guard "current_generation" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "current_fence" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
// Recovery may legitimately observe a gap: machine admission can
// reserve N, crash before its record-before-send carrier, while a
// concurrently admitted N+1 durably records and sends. No carrier
// means N had no external effect, so any strictly newer sequence
// advances the bounded watermark safely.
guard "newer_dispatch_sequence" { obligation.dispatch_sequence > self.remote_turn_dispatch_sequence }
guard "not_pending" { self.pending_remote_turn_outcomes.contains(obligation) == false }
guard "not_committed" { self.committed_remote_turn_outcomes.contains(obligation) == false }
guard "not_resolved" { self.resolved_remote_turn_outcomes.contains(obligation) == false }
update {
self.remote_turn_dispatch_sequence = obligation.dispatch_sequence;
self.pending_remote_turn_outcomes.insert(obligation);
}
to Running
}
transition RecordRemoteTurnObligationPendingReplay {
on input RecordRemoteTurnObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "already_pending" { self.pending_remote_turn_outcomes.contains(obligation) == true }
update {}
to Running
}
transition RecordRemoteTurnObligationCommittedReplay {
on input RecordRemoteTurnObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "already_committed" { self.committed_remote_turn_outcomes.contains(obligation) == true }
update {}
to Running
}
transition RecordRemoteTurnObligationResolvedReplay {
on input RecordRemoteTurnObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "already_resolved" { self.resolved_remote_turn_outcomes.contains(obligation) == true }
update {}
to Running
}
// Bounded negative memory: the global dispatch high-watermark makes
// an acknowledged obligation's delayed Record replay a no-op even
// after all custody sets release its full payload. Fresh sends carry
// a sequence strictly above the watermark, so no per-turn tombstone
// grows forever and crash-before-carrier gaps remain recoverable.
transition RecordRemoteTurnObligationHistoricalReplay {
on input RecordRemoteTurnObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "historical_sequence" { obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence }
guard "placed_kickoff_correlation_available" {
mob_machine_remote_turn_input_id_available_to_kickoff(
self.pending_placed_kickoff_outcomes,
self.resolved_placed_kickoff_outcomes,
self.retained_placed_kickoff_obligations,
obligation)
}
guard "not_pending" { self.pending_remote_turn_outcomes.contains(obligation) == false }
guard "not_committed" { self.committed_remote_turn_outcomes.contains(obligation) == false }
guard "not_resolved" { self.resolved_remote_turn_outcomes.contains(obligation) == false }
update {}
to Running
}
// Pre-effect rollback only: if the durable record-before-send carrier
// cannot be appended, no remote delivery occurred and pending custody
// can be closed without fabricating a downstream step terminal.
transition AbortRemoteTurnObligationPresent {
per_phase [Running, Stopped, Completed, Destroyed]
on input AbortRemoteTurnObligation { obligation }
guard "pending" { self.pending_remote_turn_outcomes.contains(obligation) == true }
update {
self.pending_remote_turn_outcomes.remove(obligation);
}
to Running
}
transition AbortRemoteTurnObligationReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input AbortRemoteTurnObligation { obligation }
guard "already_absent" { self.pending_remote_turn_outcomes.contains(obligation) == false }
update {}
to Running
}
transition CommitRemoteTurnOutcomePending {
per_phase [Running, Stopped, Completed, Destroyed]
on input CommitRemoteTurnOutcome { obligation }
guard "pending" { self.pending_remote_turn_outcomes.contains(obligation) == true }
update {
self.pending_remote_turn_outcomes.remove(obligation);
self.committed_remote_turn_outcomes.insert(obligation);
}
to Running
}
transition CommitRemoteTurnOutcomeReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input CommitRemoteTurnOutcome { obligation }
guard "already_committed_or_resolved" {
self.committed_remote_turn_outcomes.contains(obligation) == true
|| self.resolved_remote_turn_outcomes.contains(obligation) == true
}
update {}
to Running
}
transition CommitRemoteTurnOutcomeDisposedReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input CommitRemoteTurnOutcome { obligation }
guard "historical_sequence" { obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence }
guard "already_absent" {
self.pending_remote_turn_outcomes.contains(obligation) == false
&& self.committed_remote_turn_outcomes.contains(obligation) == false
&& self.resolved_remote_turn_outcomes.contains(obligation) == false
}
update {}
to Running
}
transition ResolveRemoteTurnObligationCommitted {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveRemoteTurnObligation { obligation }
guard "committed" { self.committed_remote_turn_outcomes.contains(obligation) == true }
update {
self.committed_remote_turn_outcomes.remove(obligation);
self.resolved_remote_turn_outcomes.insert(obligation);
}
to Running
}
transition ResolveRemoteTurnObligationReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveRemoteTurnObligation { obligation }
guard "already_resolved" { self.resolved_remote_turn_outcomes.contains(obligation) == true }
update {}
to Running
}
transition ResolveRemoteTurnObligationDisposedReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveRemoteTurnObligation { obligation }
guard "historical_sequence" { obligation.dispatch_sequence <= self.remote_turn_dispatch_sequence }
guard "already_absent" {
self.pending_remote_turn_outcomes.contains(obligation) == false
&& self.committed_remote_turn_outcomes.contains(obligation) == false
&& self.resolved_remote_turn_outcomes.contains(obligation) == false
}
update {}
to Running
}
transition AcknowledgeRemoteTurnOutcomePresent {
per_phase [Running, Stopped, Completed, Destroyed]
on input AcknowledgeRemoteTurnOutcome { obligation }
guard "resolved" { self.resolved_remote_turn_outcomes.contains(obligation) == true }
update {
self.resolved_remote_turn_outcomes.remove(obligation);
}
to Running
}
transition AcknowledgeRemoteTurnOutcomeReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input AcknowledgeRemoteTurnOutcome { obligation }
guard "already_absent" {
self.pending_remote_turn_outcomes.contains(obligation) == false
&& self.committed_remote_turn_outcomes.contains(obligation) == false
&& self.resolved_remote_turn_outcomes.contains(obligation) == false
}
update {}
to Running
}
// Host release/superseding materialization or an authenticated exact
// tracked-input cancellation durably closes the host key. Only after
// one of those external terminals may teardown close controller
// custody without a turn-outcome ACK.
transition DisposeRemoteTurnObligation {
per_phase [Running, Stopped, Completed, Destroyed]
on input DisposeRemoteTurnObligation { obligation }
update {
self.pending_remote_turn_outcomes.remove(obligation);
self.committed_remote_turn_outcomes.remove(obligation);
self.resolved_remote_turn_outcomes.remove(obligation);
}
to Running
}
// =====================================================================
// Ordinary placed TurnCompleted host-row cleanup. The RPC promise is
// deliberately absent from this state. Pending means a delivery may
// have happened; cancellation_requested means timeout/restart closed
// the caller but exact host convergence is still required; Resolved
// means the one pump must resend the exact ACK until confirmation.
// =====================================================================
transition BeginPlacedCompletionLifecycleQuiesceFresh {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_intent_admissible" {
intent != PlacedCompletionLifecycleIntentKind::Stop
|| self.active_run_count == 0
}
guard "not_quiescing" { self.placed_completion_lifecycle_quiescing == false }
update {
self.placed_completion_lifecycle_quiescing = true;
self.placed_completion_lifecycle_intent = Some(intent);
}
to Running
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition BeginPlacedCompletionLifecycleQuiesceReplay {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_intent_admissible" {
intent != PlacedCompletionLifecycleIntentKind::Stop
|| self.active_run_count == 0
}
guard "already_quiescing" { self.placed_completion_lifecycle_quiescing == true }
guard "compatible_lifecycle_intent_takeover" {
self.placed_completion_lifecycle_intent == Some(intent)
|| self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::RetireAll)
|| (self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Stop)
&& (intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::Complete
|| intent == PlacedCompletionLifecycleIntentKind::Destroy))
|| (self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Reset)
&& (intent == PlacedCompletionLifecycleIntentKind::Stop
|| intent == PlacedCompletionLifecycleIntentKind::Complete
|| intent == PlacedCompletionLifecycleIntentKind::Destroy))
|| (self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete)
&& intent == PlacedCompletionLifecycleIntentKind::Destroy)
}
update { self.placed_completion_lifecycle_intent = Some(intent); }
to Running
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition BeginPlacedCompletionLifecycleQuiesceStoppedFresh {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Stopped }
guard "lifecycle_intent_admissible" {
intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy
}
guard "not_quiescing" { self.placed_completion_lifecycle_quiescing == false }
update {
self.placed_completion_lifecycle_quiescing = true;
self.placed_completion_lifecycle_intent = Some(intent);
}
to Stopped
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition BeginPlacedCompletionLifecycleQuiesceStoppedReplay {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Stopped }
guard "lifecycle_intent_admissible" {
intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy
}
guard "already_quiescing" { self.placed_completion_lifecycle_quiescing == true }
guard "compatible_lifecycle_intent_takeover" {
self.placed_completion_lifecycle_intent == Some(intent)
|| ((self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Stop)
|| self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::RetireAll))
&& (intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy))
|| (self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Reset)
&& intent == PlacedCompletionLifecycleIntentKind::Destroy)
}
update { self.placed_completion_lifecycle_intent = Some(intent); }
to Stopped
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition BeginPlacedCompletionLifecycleQuiesceCompletedFresh {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Completed }
guard "lifecycle_intent_admissible" {
intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy
}
guard "not_quiescing" { self.placed_completion_lifecycle_quiescing == false }
update {
self.placed_completion_lifecycle_quiescing = true;
self.placed_completion_lifecycle_intent = Some(intent);
}
to Completed
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition BeginPlacedCompletionLifecycleQuiesceCompletedReplay {
on input BeginPlacedCompletionLifecycleQuiesce { intent }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Completed }
guard "lifecycle_intent_admissible" {
intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy
}
guard "already_quiescing" { self.placed_completion_lifecycle_quiescing == true }
guard "compatible_lifecycle_intent_takeover" {
self.placed_completion_lifecycle_intent == Some(intent)
|| ((self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete)
|| self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::RetireAll))
&& (intent == PlacedCompletionLifecycleIntentKind::Reset
|| intent == PlacedCompletionLifecycleIntentKind::RetireAll
|| intent == PlacedCompletionLifecycleIntentKind::Destroy))
|| (self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Reset)
&& intent == PlacedCompletionLifecycleIntentKind::Destroy)
}
update { self.placed_completion_lifecycle_intent = Some(intent); }
to Completed
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: true }
}
transition EndPlacedCompletionLifecycleQuiesceRunningFresh {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Running }
guard "quiescing" { self.placed_completion_lifecycle_quiescing == true }
guard "same_lifecycle_intent" { self.placed_completion_lifecycle_intent == Some(intent) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {
self.placed_completion_lifecycle_quiescing = false;
self.placed_completion_lifecycle_intent = None;
}
to Running
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: false }
}
transition EndPlacedCompletionLifecycleQuiesceRunningReplay {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Running }
guard "already_open" { self.placed_completion_lifecycle_quiescing == false }
guard "no_lifecycle_intent" { self.placed_completion_lifecycle_intent == None }
update {}
to Running
emit PersistPlacedCompletionLifecycleIntent { intent: intent, active: false }
}
transition EndPlacedCompletionLifecycleQuiesceStoppedRetireAll {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Stopped }
guard "retire_all_intent" { intent == PlacedCompletionLifecycleIntentKind::RetireAll }
guard "retire_all_active" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::RetireAll) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {
self.placed_completion_lifecycle_quiescing = true;
self.placed_completion_lifecycle_intent = Some(PlacedCompletionLifecycleIntentKind::Stop);
}
to Stopped
emit PersistPlacedCompletionLifecycleIntent { intent: PlacedCompletionLifecycleIntentKind::Stop, active: true }
}
transition EndPlacedCompletionLifecycleQuiesceStoppedRetireAllReplay {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Stopped }
guard "retire_all_intent" { intent == PlacedCompletionLifecycleIntentKind::RetireAll }
guard "stop_baseline_restored" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Stop) }
update {}
to Stopped
emit PersistPlacedCompletionLifecycleIntent { intent: PlacedCompletionLifecycleIntentKind::Stop, active: true }
}
transition EndPlacedCompletionLifecycleQuiesceCompletedRetireAll {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Completed }
guard "retire_all_intent" { intent == PlacedCompletionLifecycleIntentKind::RetireAll }
guard "retire_all_active" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::RetireAll) }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
update {
self.placed_completion_lifecycle_quiescing = true;
self.placed_completion_lifecycle_intent = Some(PlacedCompletionLifecycleIntentKind::Complete);
}
to Completed
emit PersistPlacedCompletionLifecycleIntent { intent: PlacedCompletionLifecycleIntentKind::Complete, active: true }
}
transition EndPlacedCompletionLifecycleQuiesceCompletedRetireAllReplay {
on input EndPlacedCompletionLifecycleQuiesce { intent }
guard { self.lifecycle_phase == Phase::Completed }
guard "retire_all_intent" { intent == PlacedCompletionLifecycleIntentKind::RetireAll }
guard "complete_baseline_restored" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete) }
update {}
to Completed
emit PersistPlacedCompletionLifecycleIntent { intent: PlacedCompletionLifecycleIntentKind::Complete, active: true }
}
transition RecoverPlacedCompletionDispatchSequenceAdvance {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverPlacedCompletionDispatchSequence { dispatch_sequence }
guard "newer_dispatch_sequence" { dispatch_sequence > self.placed_completion_dispatch_sequence }
update { self.placed_completion_dispatch_sequence = dispatch_sequence; }
to Running
}
transition RecoverPlacedCompletionDispatchSequenceReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on signal RecoverPlacedCompletionDispatchSequence { dispatch_sequence }
guard "historical_dispatch_sequence" { dispatch_sequence <= self.placed_completion_dispatch_sequence }
update {}
to Running
}
transition RecoverPendingPlacedCompletion {
per_phase [Running, Stopped, Completed]
on signal RecoverPendingPlacedCompletion { obligation, cancellation_requested }
guard "obligation_well_formed" { mob_machine_placed_completion_obligation_well_formed(obligation) }
guard "target_host_exact" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "target_host_binding_generation_exact" {
self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
}
guard "target_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "current_generation" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "current_fence" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
guard "newer_dispatch_sequence" { obligation.dispatch_sequence > self.placed_completion_dispatch_sequence }
guard "custody_available" {
mob_machine_placed_completion_custody_admits(
self.pending_placed_completion_outcomes,
self.resolved_placed_completion_outcomes,
obligation)
}
update {
self.placed_completion_dispatch_sequence = obligation.dispatch_sequence;
self.pending_placed_completion_outcomes.insert(obligation);
if cancellation_requested {
self.cancel_requested_placed_completion_outcomes.insert(obligation);
}
}
to Running
}
transition RecoverResolvedPlacedCompletion {
per_phase [Running, Stopped, Completed]
on signal RecoverResolvedPlacedCompletion { obligation }
guard "obligation_well_formed" { mob_machine_placed_completion_obligation_well_formed(obligation) }
guard "target_host_exact" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "target_host_binding_generation_exact" {
self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
}
guard "target_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "current_generation" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "current_fence" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
guard "newer_dispatch_sequence" { obligation.dispatch_sequence > self.placed_completion_dispatch_sequence }
guard "custody_available" {
mob_machine_placed_completion_custody_admits(
self.pending_placed_completion_outcomes,
self.resolved_placed_completion_outcomes,
obligation)
}
update {
self.placed_completion_dispatch_sequence = obligation.dispatch_sequence;
self.resolved_placed_completion_outcomes.insert(obligation);
}
to Running
}
transition RecoverCompletedWithCleanupCustody {
on signal RecoverCompletedWithCleanupCustody
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_complete_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Complete) }
guard "cleanup_custody_present" {
self.pending_remote_turn_outcomes != EmptySet
|| self.committed_remote_turn_outcomes != EmptySet
|| self.resolved_remote_turn_outcomes != EmptySet
|| self.pending_placed_completion_outcomes != EmptySet
|| self.resolved_placed_completion_outcomes != EmptySet
|| self.pending_placed_kickoff_outcomes != EmptySet
|| self.resolved_placed_kickoff_outcomes != EmptySet
}
update { self.active_run_count = 0; }
to Completed
}
transition RecordPlacedCompletionObligationFresh {
on input RecordPlacedCompletionObligation { obligation }
guard { self.lifecycle_phase == Phase::Running }
guard "placed_completion_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "obligation_well_formed" { mob_machine_placed_completion_obligation_well_formed(obligation) }
guard "target_host_exact" { self.member_placement.get_cloned(obligation.agent_identity) == Some(obligation.host_id) }
guard "target_host_bound" { self.host_bind_phase.get_cloned(obligation.host_id) == Some(HostBindPhase::Bound) }
guard "target_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, obligation.agent_identity)
}
guard "target_host_binding_generation_exact" {
self.current_placed_spawn_host_binding_generations.get_copied(obligation.agent_identity) == Some(obligation.host_binding_generation)
&& self.host_binding_generations.get_copied(obligation.host_id) == Some(obligation.host_binding_generation)
}
guard "target_host_supports_tracked_cancel" {
self.host_durable_sessions.get_copied(obligation.host_id) == Some(true)
&& self.host_tracked_input_cancel.get_copied(obligation.host_id) == Some(true)
&& self.host_protocol_min.get_copied(obligation.host_id).get("value") <= 4
&& self.host_protocol_max.get_copied(obligation.host_id).get("value") >= 4
}
guard "target_session_exact" { self.member_session_bindings.get_cloned(obligation.agent_identity) == Some(obligation.member_session_id) }
guard "target_runtime_present" { self.identity_to_runtime.contains_key(obligation.agent_identity) == true }
guard "target_runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) == true }
guard "target_not_retiring" { self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(obligation.agent_identity).get("value")) != Some(MobMemberState::Retiring) }
guard "target_not_reviving" { self.member_revival_pending.contains(obligation.agent_identity) == false }
guard "target_spawn_settled" { self.spawn_exec_phase.contains_key(obligation.agent_identity) == false }
guard "target_materialization_healthy" { self.member_materialization_failures.contains_key(obligation.agent_identity) == false }
guard "current_generation" { self.identity_runtime_generations.get_cloned(obligation.agent_identity) == Some(obligation.generation) }
guard "current_fence" { self.identity_runtime_fence_tokens.get_cloned(obligation.agent_identity) == Some(obligation.fence_token) }
guard "custody_quota_and_correlation_available" {
mob_machine_placed_completion_custody_admits(
self.pending_placed_completion_outcomes,
self.resolved_placed_completion_outcomes,
obligation)
}
guard "flow_correlation_available" {
for_all(turn in self.pending_remote_turn_outcomes,
turn.agent_identity != obligation.agent_identity
|| turn.host_id != obligation.host_id
|| turn.generation != obligation.generation
|| turn.fence_token != obligation.fence_token
|| turn.input_id != obligation.input_id)
&& for_all(turn in self.committed_remote_turn_outcomes,
turn.agent_identity != obligation.agent_identity
|| turn.host_id != obligation.host_id
|| turn.generation != obligation.generation
|| turn.fence_token != obligation.fence_token
|| turn.input_id != obligation.input_id)
&& for_all(turn in self.resolved_remote_turn_outcomes,
turn.agent_identity != obligation.agent_identity
|| turn.host_id != obligation.host_id
|| turn.generation != obligation.generation
|| turn.fence_token != obligation.fence_token
|| turn.input_id != obligation.input_id)
}
guard "kickoff_correlation_available" {
for_all(kickoff in self.pending_placed_kickoff_outcomes,
kickoff.agent_identity != obligation.agent_identity
|| kickoff.host_id != obligation.host_id
|| kickoff.generation != obligation.generation
|| kickoff.fence_token != obligation.fence_token
|| kickoff.input_id != obligation.input_id)
&& for_all(kickoff in self.resolved_placed_kickoff_outcomes,
kickoff.agent_identity != obligation.agent_identity
|| kickoff.host_id != obligation.host_id
|| kickoff.generation != obligation.generation
|| kickoff.fence_token != obligation.fence_token
|| kickoff.input_id != obligation.input_id)
&& for_all(identity in self.retained_placed_kickoff_obligations.keys(),
identity != obligation.agent_identity
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").host_id != obligation.host_id
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").generation != obligation.generation
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").fence_token != obligation.fence_token
|| self.retained_placed_kickoff_obligations.get_cloned(identity).get("value").input_id != obligation.input_id)
}
guard "newer_dispatch_sequence" { obligation.dispatch_sequence > self.placed_completion_dispatch_sequence }
update {
self.placed_completion_dispatch_sequence = obligation.dispatch_sequence;
self.pending_placed_completion_outcomes.insert(obligation);
}
to Running
}
transition RecordPlacedCompletionObligationPendingReplay {
per_phase [Running, Stopped, Completed]
on input RecordPlacedCompletionObligation { obligation }
guard "already_pending" { self.pending_placed_completion_outcomes.contains(obligation) == true }
update {}
to Running
}
transition RecordPlacedCompletionObligationResolvedReplay {
per_phase [Running, Stopped, Completed]
on input RecordPlacedCompletionObligation { obligation }
guard "already_resolved" { self.resolved_placed_completion_outcomes.contains(obligation) == true }
update {}
to Running
}
// Bounded sequence memory makes a delayed exact Record harmless after
// ACK/close. The sealed actor additionally rejects any caller reuse of
// a historical input id before this input can be reached.
transition RecordPlacedCompletionObligationHistoricalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input RecordPlacedCompletionObligation { obligation }
guard "historical_sequence" { obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence }
guard "custody_absent" {
self.pending_placed_completion_outcomes.contains(obligation) == false
&& self.resolved_placed_completion_outcomes.contains(obligation) == false
}
update {}
to Running
}
transition RequestPlacedCompletionCancellationPending {
per_phase [Running, Stopped, Completed]
on input RequestPlacedCompletionCancellation { obligation }
guard "pending" { self.pending_placed_completion_outcomes.contains(obligation) == true }
guard "not_requested" { self.cancel_requested_placed_completion_outcomes.contains(obligation) == false }
update { self.cancel_requested_placed_completion_outcomes.insert(obligation); }
to Running
}
transition RequestPlacedCompletionCancellationReplay {
per_phase [Running, Stopped, Completed]
on input RequestPlacedCompletionCancellation { obligation }
guard "already_requested" { self.cancel_requested_placed_completion_outcomes.contains(obligation) == true }
update {}
to Running
}
transition RequestPlacedCompletionCancellationTerminalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input RequestPlacedCompletionCancellation { obligation }
guard "not_pending" { self.pending_placed_completion_outcomes.contains(obligation) == false }
guard "historical_or_resolved" {
self.resolved_placed_completion_outcomes.contains(obligation) == true
|| obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence
}
update {}
to Running
}
transition ResolvePlacedCompletionOutcomePending {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedCompletionOutcome { obligation }
guard "pending" { self.pending_placed_completion_outcomes.contains(obligation) == true }
update {
self.pending_placed_completion_outcomes.remove(obligation);
self.cancel_requested_placed_completion_outcomes.remove(obligation);
self.resolved_placed_completion_outcomes.insert(obligation);
}
to Running
}
transition ResolvePlacedCompletionOutcomeReplay {
per_phase [Running, Stopped, Completed]
on input ResolvePlacedCompletionOutcome { obligation }
guard "already_resolved" { self.resolved_placed_completion_outcomes.contains(obligation) == true }
update {}
to Running
}
transition ResolvePlacedCompletionOutcomeHistoricalReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolvePlacedCompletionOutcome { obligation }
guard "custody_absent" {
self.pending_placed_completion_outcomes.contains(obligation) == false
&& self.resolved_placed_completion_outcomes.contains(obligation) == false
}
guard "historical_sequence" { obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence }
update {}
to Running
}
transition ClosePlacedCompletionOutcomePending {
per_phase [Running, Stopped, Completed]
on input ClosePlacedCompletionOutcome { obligation }
guard "pending" { self.pending_placed_completion_outcomes.contains(obligation) == true }
update {
self.pending_placed_completion_outcomes.remove(obligation);
self.cancel_requested_placed_completion_outcomes.remove(obligation);
}
to Running
}
transition ClosePlacedCompletionOutcomeReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input ClosePlacedCompletionOutcome { obligation }
guard "custody_absent" {
self.pending_placed_completion_outcomes.contains(obligation) == false
&& self.resolved_placed_completion_outcomes.contains(obligation) == false
}
guard "historical_sequence" { obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence }
update {}
to Running
}
transition AcknowledgePlacedCompletionOutcomePresent {
per_phase [Running, Stopped, Completed]
on input AcknowledgePlacedCompletionOutcome { obligation }
guard "resolved" { self.resolved_placed_completion_outcomes.contains(obligation) == true }
update { self.resolved_placed_completion_outcomes.remove(obligation); }
to Running
}
transition AcknowledgePlacedCompletionOutcomeReplay {
per_phase [Running, Stopped, Completed, Destroyed]
on input AcknowledgePlacedCompletionOutcome { obligation }
guard "custody_absent" {
self.pending_placed_completion_outcomes.contains(obligation) == false
&& self.resolved_placed_completion_outcomes.contains(obligation) == false
}
guard "historical_sequence" { obligation.dispatch_sequence <= self.placed_completion_dispatch_sequence }
update {}
to Running
}
transition DisposePlacedCompletionOutcome {
per_phase [Running, Stopped, Completed, Destroyed]
on input DisposePlacedCompletionOutcome { obligation }
update {
self.pending_placed_completion_outcomes.remove(obligation);
self.cancel_requested_placed_completion_outcomes.remove(obligation);
self.resolved_placed_completion_outcomes.remove(obligation);
}
to Running
}
// =====================================================================
// Multi-host mobs (§6.5/§8): principal control-scope grants. The
// machine owns grant lifecycle; scope enforcement lives in the sealed
// policy at command dispatch. Expiry is data — the machine never
// reads a clock.
// =====================================================================
transition GrantOperatorScopes {
on input GrantOperatorScopes { principal, scopes, expires_at_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "scopes_nonempty" { scopes != EmptySet }
update {
self.operator_grant_scopes.insert(principal, scopes);
self.operator_grant_expiries.insert(principal, expires_at_ms);
}
to Running
emit GrantRecorded { principal: principal, scopes: scopes, expires_at_ms: expires_at_ms }
}
// Full revocation: the proposed partition covers the recorded grant
// and nothing remains.
transition RevokeOperatorScopesAll {
on input RevokeOperatorScopes { principal, revoked, remaining }
guard { self.lifecycle_phase == Phase::Running }
guard "grant_present" { self.operator_grant_scopes.contains_key(principal) == true }
guard "revoked_nonempty" { revoked != EmptySet }
guard "remaining_empty" { remaining == EmptySet }
guard "revoked_are_granted" { for_all(scope in revoked, self.operator_grant_scopes.get_cloned(principal).get("value").contains(scope)) }
guard "partition_covers_grant" { for_all(scope in self.operator_grant_scopes.get_cloned(principal).get("value"), revoked.contains(scope)) }
update {
self.operator_grant_scopes.remove(principal);
self.operator_grant_expiries.remove(principal);
}
to Running
emit GrantRevoked { principal: principal, revoked: revoked, remaining: remaining }
}
// Partial revocation: the machine revalidates the proposed
// (revoked, remaining) partition of the recorded grant, then replaces
// the scope set (expiry retained).
transition RevokeOperatorScopesPartial {
on input RevokeOperatorScopes { principal, revoked, remaining }
guard { self.lifecycle_phase == Phase::Running }
guard "grant_present" { self.operator_grant_scopes.contains_key(principal) == true }
guard "revoked_nonempty" { revoked != EmptySet }
guard "remaining_nonempty" { remaining != EmptySet }
guard "revoked_are_granted" { for_all(scope in revoked, self.operator_grant_scopes.get_cloned(principal).get("value").contains(scope)) }
guard "remaining_are_granted" { for_all(scope in remaining, self.operator_grant_scopes.get_cloned(principal).get("value").contains(scope)) }
guard "revoked_disjoint_from_remaining" { for_all(scope in revoked, remaining.contains(scope) == false) }
guard "partition_covers_grant" { for_all(scope in self.operator_grant_scopes.get_cloned(principal).get("value"), revoked.contains(scope) || remaining.contains(scope)) }
update {
self.operator_grant_scopes.insert(principal, remaining);
}
to Running
emit GrantRevoked { principal: principal, revoked: revoked, remaining: remaining }
}
// Idempotent no-op: revoking an absent grant with an empty partition
// (the surfaced absent=all revoke of a principal with no grant).
transition RevokeOperatorScopesAbsent {
on input RevokeOperatorScopes { principal, revoked, remaining }
guard { self.lifecycle_phase == Phase::Running }
guard "grant_absent" { self.operator_grant_scopes.contains_key(principal) == false }
guard "revoked_empty" { revoked == EmptySet }
guard "remaining_empty" { remaining == EmptySet }
update {}
to Running
}
// =====================================================================
// Multi-host mobs (§15 R6): member-operator upcall admission. Ten
// disjoint arms — one admit, one per typed reject cause. The signed
// requester generation+fence must match the current identity binding;
// peer-key equality alone is insufficient because Resume may reuse it.
// =====================================================================
transition ResolveMemberOperatorAdmissionAdmitted {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(requester_member_session_id) }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "requester_host_matches" { self.member_placement.get_cloned(agent_identity) == Some(requester_host_id) }
guard "host_binding_generation_matches" { self.current_placed_spawn_host_binding_generations.get_copied(agent_identity) == Some(requester_host_binding_generation) }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {}
to Running
emit MemberOperatorAdmitted { agent_identity: agent_identity, request_id: request_id }
}
transition ResolveMemberOperatorAdmissionUnknownIdentity {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_unknown" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::UnknownIdentity }
}
transition ResolveMemberOperatorAdmissionSenderKeyMismatch {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_mismatch" { self.member_peer_ids.get_cloned(agent_identity) != Some(sender_peer_id) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::SenderKeyMismatch }
}
transition ResolveMemberOperatorAdmissionStaleGeneration {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_mismatch" { self.identity_runtime_generations.get_copied(agent_identity) != Some(requester_generation) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::StaleGeneration }
}
transition ResolveMemberOperatorAdmissionStaleFence {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_mismatch" { self.identity_runtime_fence_tokens.get_copied(agent_identity) != Some(requester_fence_token) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::StaleFence }
}
transition ResolveMemberOperatorAdmissionStaleSession {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_mismatch" { self.member_session_bindings.get_cloned(agent_identity) != Some(requester_member_session_id) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::StaleSession }
}
transition ResolveMemberOperatorAdmissionNoPlacement {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(requester_member_session_id) }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::NoPlacement }
}
transition ResolveMemberOperatorAdmissionStaleHost {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(requester_member_session_id) }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "requester_host_mismatch" { self.member_placement.get_cloned(agent_identity) != Some(requester_host_id) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::StaleHost }
}
transition ResolveMemberOperatorAdmissionStaleHostBindingGeneration {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(requester_member_session_id) }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "requester_host_matches" { self.member_placement.get_cloned(agent_identity) == Some(requester_host_id) }
guard "host_binding_generation_mismatch" { self.current_placed_spawn_host_binding_generations.get_copied(agent_identity) != Some(requester_host_binding_generation) }
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::StaleHostBindingGeneration }
}
transition ResolveMemberOperatorAdmissionHostRevoked {
per_phase [Running, Stopped, Completed, Destroyed]
on input ResolveMemberOperatorAdmission { agent_identity, requester_generation, requester_fence_token, requester_host_id, requester_host_binding_generation, requester_member_session_id, sender_peer_id, request_id }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "sender_key_matches" { self.member_peer_ids.get_cloned(agent_identity) == Some(sender_peer_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(requester_generation) }
guard "fence_matches" { self.identity_runtime_fence_tokens.get_copied(agent_identity) == Some(requester_fence_token) }
guard "member_session_matches" { self.member_session_bindings.get_cloned(agent_identity) == Some(requester_member_session_id) }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "requester_host_matches" { self.member_placement.get_cloned(agent_identity) == Some(requester_host_id) }
guard "host_binding_generation_matches" { self.current_placed_spawn_host_binding_generations.get_copied(agent_identity) == Some(requester_host_binding_generation) }
guard "placed_carrier_binding_inactive" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity) == false
}
update {}
to Running
emit MemberOperatorRejected { agent_identity: agent_identity, request_id: request_id, cause: MemberOperatorRejectKind::HostRevoked }
}
// =====================================================================
// Multi-host mobs (§18.9): flow step dispatch classification. Four
// disjoint arms over machine facts; the FlowFrameTerminalStatus
// classification precedent (per_phase, pure self-loop).
// =====================================================================
transition ClassifyFlowStepDispatchLocal {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowStepDispatch { run_id, step_id, target, overlay_present }
guard "placement_absent" { self.member_placement.contains_key(target) == false }
guard "not_overlay_autonomous" {
overlay_present == false
|| self.member_runtime_modes.get_cloned(target) != Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
update {}
to Running
emit FlowStepDispatchClassified { run_id: run_id, step_id: step_id, target: target, dispatch: FlowStepDispatchKind::Local }
}
transition ClassifyFlowStepDispatchRemoteTurnDirective {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowStepDispatch { run_id, step_id, target, overlay_present }
guard "placement_present" { self.member_placement.contains_key(target) == true }
guard "host_supports_tracked_turns" {
self.host_durable_sessions.get_copied(self.member_placement.get_cloned(target).get("value")) == Some(true)
&& self.host_tracked_input_cancel.get_copied(self.member_placement.get_cloned(target).get("value")) == Some(true)
&& self.host_protocol_min.get_copied(self.member_placement.get_cloned(target).get("value")).get("value") <= 4
&& self.host_protocol_max.get_copied(self.member_placement.get_cloned(target).get("value")).get("value") >= 4
}
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, target)
}
guard "not_overlay_autonomous" {
overlay_present == false
|| self.member_runtime_modes.get_cloned(target) != Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
update {}
to Running
emit FlowStepDispatchClassified { run_id: run_id, step_id: step_id, target: target, dispatch: FlowStepDispatchKind::RemoteTurnDirective }
}
// Overlay-bearing steps cannot target autonomous-host members,
// regardless of placement.
transition ClassifyFlowStepDispatchRejectedOverlayAutonomous {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowStepDispatch { run_id, step_id, target, overlay_present }
guard "overlay_autonomous" {
overlay_present == true
&& self.member_runtime_modes.get_cloned(target) == Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
update {}
to Running
emit FlowStepDispatchClassified { run_id: run_id, step_id: step_id, target: target, dispatch: FlowStepDispatchKind::RejectedOverlayAutonomous }
}
// A flow-step turn requires the complete tracked-turn bundle. The
// classification predicate intentionally matches the later Record
// custody predicate so dispatch can never authorize work that the
// machine then refuses to journal.
transition ClassifyFlowStepDispatchRejectedHostIncapable {
per_phase [Running, Stopped, Completed]
on input ClassifyFlowStepDispatch { run_id, step_id, target, overlay_present }
guard "placement_present" { self.member_placement.contains_key(target) == true }
guard "host_lacks_tracked_turn_support" {
self.host_durable_sessions.get_copied(self.member_placement.get_cloned(target).get("value")) != Some(true)
|| self.host_tracked_input_cancel.get_copied(self.member_placement.get_cloned(target).get("value")) != Some(true)
|| self.host_protocol_min.get_copied(self.member_placement.get_cloned(target).get("value")).get("value") > 4
|| self.host_protocol_max.get_copied(self.member_placement.get_cloned(target).get("value")).get("value") < 4
}
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, target)
}
guard "not_overlay_autonomous" {
overlay_present == false
|| self.member_runtime_modes.get_cloned(target) != Some(SpawnPolicyRuntimeMode::AutonomousHost)
}
update {}
to Running
emit FlowStepDispatchClassified { run_id: run_id, step_id: step_id, target: target, dispatch: FlowStepDispatchKind::RejectedHostIncapable }
}
transition CommitSupervisorRotation {
per_phase [Running, Stopped, Completed]
on input CommitSupervisorRotation { current_peer_id, current_epoch, current_protocol_version, operation_id, next_peer_id, next_signing_key, next_epoch, next_protocol_version }
guard "current_supervisor_matches" {
self.supervisor_authority_peer_id == Some(current_peer_id)
&& self.supervisor_authority_signing_key != None
&& self.supervisor_authority_epoch == Some(current_epoch)
&& self.supervisor_authority_protocol_version == Some(current_protocol_version)
}
guard "next_epoch_is_successor" { mob_machine_u64_is_exact_successor(current_epoch, next_epoch) }
guard "next_authority_changes_peer" { next_peer_id != current_peer_id }
guard "pending_operation_matches" {
self.supervisor_pending_authority_operation_id == Some(operation_id)
}
guard "pending_authority_matches_next" {
self.supervisor_pending_authority_peer_id == Some(next_peer_id)
&& self.supervisor_pending_authority_signing_key == Some(next_signing_key)
&& self.supervisor_pending_authority_epoch == Some(next_epoch)
&& self.supervisor_pending_authority_protocol_version == Some(next_protocol_version)
}
update {
self.supervisor_authority_peer_id = Some(next_peer_id);
self.supervisor_authority_signing_key = Some(next_signing_key);
self.supervisor_authority_epoch = Some(next_epoch);
self.supervisor_authority_protocol_version = Some(next_protocol_version);
self.supervisor_pending_authority_peer_id = None;
self.supervisor_pending_authority_signing_key = None;
self.supervisor_pending_authority_epoch = None;
self.supervisor_pending_authority_protocol_version = None;
self.supervisor_pending_authority_operation_id = None;
self.supervisor_pending_authority_accepted_peer_ids = EmptySet;
self.supervisor_pending_authority_member_target_names = EmptyMap;
self.supervisor_pending_authority_member_target_addresses = EmptyMap;
}
to Running
emit PersistSupervisorAuthority {
peer_id: next_peer_id,
signing_key: next_signing_key,
epoch: next_epoch,
protocol_version: next_protocol_version,
pending_operation_id: None,
pending_peer_id: None,
pending_signing_key: None,
pending_epoch: None,
pending_protocol_version: None,
pending_accepted_peer_ids: EmptySet,
pending_member_target_names: EmptyMap,
pending_member_target_addresses: EmptyMap
}
}
transition ClearSupervisorAuthorityForDestroy {
on input ClearSupervisorAuthorityForDestroy { current_peer_id, current_signing_key, current_epoch, protocol_version }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "current_supervisor_matches" {
self.supervisor_authority_peer_id == Some(current_peer_id)
&& self.supervisor_authority_signing_key == Some(current_signing_key)
&& self.supervisor_authority_epoch == Some(current_epoch)
&& self.supervisor_authority_protocol_version == Some(protocol_version)
}
update {
self.supervisor_authority_peer_id = None;
self.supervisor_authority_signing_key = None;
self.supervisor_authority_epoch = None;
self.supervisor_authority_protocol_version = None;
self.supervisor_pending_authority_peer_id = None;
self.supervisor_pending_authority_signing_key = None;
self.supervisor_pending_authority_epoch = None;
self.supervisor_pending_authority_protocol_version = None;
self.supervisor_pending_authority_operation_id = None;
self.supervisor_pending_authority_accepted_peer_ids = EmptySet;
self.supervisor_pending_authority_member_target_names = EmptyMap;
self.supervisor_pending_authority_member_target_addresses = EmptyMap;
}
to Destroyed
emit DeleteSupervisorAuthority {
peer_id: current_peer_id,
signing_key: current_signing_key,
epoch: current_epoch,
protocol_version: protocol_version
}
}
transition RestoreSupervisorAuthorityAfterDestroyRollback {
on input RestoreSupervisorAuthorityAfterDestroyRollback {
peer_id,
signing_key,
epoch,
protocol_version,
pending_operation_id,
pending_peer_id,
pending_signing_key,
pending_epoch,
pending_protocol_version,
pending_accepted_peer_ids,
pending_member_target_names,
pending_member_target_addresses
}
guard { self.lifecycle_phase == Phase::Destroyed }
guard "supervisor_authority_absent" {
self.supervisor_authority_peer_id == None
&& self.supervisor_authority_signing_key == None
&& self.supervisor_authority_epoch == None
&& self.supervisor_authority_protocol_version == None
}
guard "pending_shape_consistent" {
(
pending_peer_id == None
&& pending_signing_key == None
&& pending_epoch == None
&& pending_protocol_version == None
&& pending_operation_id == None
&& pending_accepted_peer_ids == EmptySet
&& pending_member_target_names == EmptyMap
&& pending_member_target_addresses == EmptyMap
)
|| (
pending_peer_id != None
&& pending_signing_key != None
&& pending_epoch != None
&& pending_protocol_version != None
&& pending_peer_id != Some(peer_id)
&& mob_machine_optional_u64_is_exact_successor(epoch, pending_epoch)
)
}
guard "pending_member_targets_aligned" {
pending_member_target_names.keys() == pending_member_target_addresses.keys()
}
update {
self.supervisor_authority_peer_id = Some(peer_id);
self.supervisor_authority_signing_key = Some(signing_key);
self.supervisor_authority_epoch = Some(epoch);
self.supervisor_authority_protocol_version = Some(protocol_version);
self.supervisor_pending_authority_peer_id = pending_peer_id;
self.supervisor_pending_authority_signing_key = pending_signing_key;
self.supervisor_pending_authority_epoch = pending_epoch;
self.supervisor_pending_authority_protocol_version = pending_protocol_version;
self.supervisor_pending_authority_operation_id = pending_operation_id;
self.supervisor_pending_authority_accepted_peer_ids = pending_accepted_peer_ids;
self.supervisor_pending_authority_member_target_names = pending_member_target_names;
self.supervisor_pending_authority_member_target_addresses = pending_member_target_addresses;
}
to Destroyed
emit PersistSupervisorAuthority {
peer_id: peer_id,
signing_key: signing_key,
epoch: epoch,
protocol_version: protocol_version,
pending_operation_id: pending_operation_id,
pending_peer_id: pending_peer_id,
pending_signing_key: pending_signing_key,
pending_epoch: pending_epoch,
pending_protocol_version: pending_protocol_version,
pending_accepted_peer_ids: pending_accepted_peer_ids,
pending_member_target_names: pending_member_target_names,
pending_member_target_addresses: pending_member_target_addresses
}
}
transition ForceCancelRunning {
on input ForceCancel { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "member_not_retiring" { self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(agent_identity).get("value")) != Some(MobMemberState::Retiring) }
guard "placed_carrier_binding_active_or_local" {
self.member_placement.contains_key(agent_identity) == false
|| mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {
self.active_run_count = 0;
}
to Running
emit FlowTerminalized
}
// Force-cancel is the operator remedy for a wedged member, so a KNOWN
// member identity must never be refused from Running. When the
// member's current runtime is no longer live (e.g. the runtime retired
// out from under the identity binding via ObserveRuntimeRetired),
// there is no executor to interrupt: the cancel converges as an
// idempotent no-op instead of an admission rejection (which the shell
// surfaced as `invalid state transition: Running -> Running`). No
// emit: `FlowTerminalized` on the active arm above is the sole
// ForceCancel emission, and the shell dispatches the mechanical
// interrupt only when it is present.
transition ForceCancelRunningRuntimeNotLive {
on input ForceCancel { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { !self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
update {}
to Running
}
// A retiring member is already draining under cancel authority; a
// repeated cancel converges as a no-op success, never an error.
transition ForceCancelRunningAlreadyRetiring {
on input ForceCancel { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_known" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "member_retiring" { self.member_state_markers.get_cloned(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == Some(MobMemberState::Retiring) }
update {}
to Running
}
// =====================================================================
// Subscribe commands
// =====================================================================
transition SubscribeAgentEventsRunning {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
update {}
to Running
emit AuthorizeAgentEventSubscription {
agent_identity: agent_identity,
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsStopped {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
update {}
to Stopped
emit AuthorizeAgentEventSubscription {
agent_identity: agent_identity,
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsCompleted {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
update {}
to Completed
emit AuthorizeAgentEventSubscription {
agent_identity: agent_identity,
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsDestroyed {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
update {}
to Destroyed
emit AuthorizeAgentEventSubscription {
agent_identity: agent_identity,
session_id: self.member_session_bindings.get_cloned(agent_identity).get("value")
}
}
// Multi-host (§6.5) third outcome: the member is real, live, and
// session-bound, but its event stream lives on a member host. The
// shell realizes the subscription remotely instead of opening a
// local stream; peer-only members (no session binding) still reject.
transition SubscribeAgentEventsExternalRunning {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {}
to Running
emit AuthorizeExternalAgentEventSubscription {
agent_identity: agent_identity,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsExternalStopped {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {}
to Stopped
emit AuthorizeExternalAgentEventSubscription {
agent_identity: agent_identity,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsExternalCompleted {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {}
to Completed
emit AuthorizeExternalAgentEventSubscription {
agent_identity: agent_identity,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsExternalDestroyed {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
update {}
to Destroyed
emit AuthorizeExternalAgentEventSubscription {
agent_identity: agent_identity,
host: self.member_placement.get_cloned(agent_identity).get("value")
}
}
transition SubscribeAgentEventsMissingMemberRunning {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Running
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsMissingMemberStopped {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Stopped
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsMissingMemberCompleted {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Completed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsMissingMemberDestroyed {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Destroyed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsMissingSessionRunning {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Running
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAgentEventsMissingSessionStopped {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Stopped
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAgentEventsMissingSessionCompleted {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Completed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAgentEventsMissingSessionDestroyed {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Destroyed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAgentEventsRuntimeNotLiveRunning {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Running
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsRuntimeNotLiveStopped {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Stopped
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsRuntimeNotLiveCompleted {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Completed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAgentEventsRuntimeNotLiveDestroyed {
on input SubscribeAgentEvents { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Destroyed
emit RejectAgentEventSubscription { agent_identity: agent_identity, reason: EventSubscriptionRejectReasonKind::MemberNotFound }
}
transition SubscribeAllAgentEventsRunning {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Running }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
guard "session_bound_or_no_live_members" { session_bound_runtimes != EmptySet || self.live_runtime_ids == EmptySet }
update {}
to Running
emit AuthorizeAllAgentEventSubscription { session_bound_runtimes: session_bound_runtimes, external_members: external_members }
}
transition SubscribeAllAgentEventsStopped {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
guard "session_bound_or_no_live_members" { session_bound_runtimes != EmptySet || self.live_runtime_ids == EmptySet }
update {}
to Stopped
emit AuthorizeAllAgentEventSubscription { session_bound_runtimes: session_bound_runtimes, external_members: external_members }
}
transition SubscribeAllAgentEventsCompleted {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Completed }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
guard "session_bound_or_no_live_members" { session_bound_runtimes != EmptySet || self.live_runtime_ids == EmptySet }
update {}
to Completed
emit AuthorizeAllAgentEventSubscription { session_bound_runtimes: session_bound_runtimes, external_members: external_members }
}
transition SubscribeAllAgentEventsDestroyed {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
guard "session_bound_or_no_live_members" { session_bound_runtimes != EmptySet || self.live_runtime_ids == EmptySet }
update {}
to Destroyed
emit AuthorizeAllAgentEventSubscription { session_bound_runtimes: session_bound_runtimes, external_members: external_members }
}
transition SubscribeAllAgentEventsNoSessionBindingsRunning {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Running }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "no_session_bound_runtime" { session_bound_runtimes == EmptySet }
guard "live_members_present" { self.live_runtime_ids != EmptySet }
update {}
to Running
emit RejectAllAgentEventSubscription { reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAllAgentEventsNoSessionBindingsStopped {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Stopped }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "no_session_bound_runtime" { session_bound_runtimes == EmptySet }
guard "live_members_present" { self.live_runtime_ids != EmptySet }
update {}
to Stopped
emit RejectAllAgentEventSubscription { reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAllAgentEventsNoSessionBindingsCompleted {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Completed }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "no_session_bound_runtime" { session_bound_runtimes == EmptySet }
guard "live_members_present" { self.live_runtime_ids != EmptySet }
update {}
to Completed
emit RejectAllAgentEventSubscription { reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeAllAgentEventsNoSessionBindingsDestroyed {
on input SubscribeAllAgentEvents { session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "no_session_bound_runtime" { session_bound_runtimes == EmptySet }
guard "live_members_present" { self.live_runtime_ids != EmptySet }
update {}
to Destroyed
emit RejectAllAgentEventSubscription { reason: EventSubscriptionRejectReasonKind::NoSessionBinding }
}
transition SubscribeMobEventsRunning {
on input SubscribeMobEvents { initial_cursor, channel_capacity, poll_interval_ms, session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Running }
guard "channel_capacity_positive" { channel_capacity > 0 }
guard "poll_interval_positive" { poll_interval_ms > 0 }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
update {}
to Running
emit AuthorizeMobEventRouter { initial_cursor: initial_cursor, channel_capacity: channel_capacity, poll_interval_ms: poll_interval_ms, session_bound_runtimes: session_bound_runtimes }
}
transition SubscribeMobEventsStopped {
on input SubscribeMobEvents { initial_cursor, channel_capacity, poll_interval_ms, session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Stopped }
guard "channel_capacity_positive" { channel_capacity > 0 }
guard "poll_interval_positive" { poll_interval_ms > 0 }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
update {}
to Stopped
emit AuthorizeMobEventRouter { initial_cursor: initial_cursor, channel_capacity: channel_capacity, poll_interval_ms: poll_interval_ms, session_bound_runtimes: session_bound_runtimes }
}
transition SubscribeMobEventsCompleted {
on input SubscribeMobEvents { initial_cursor, channel_capacity, poll_interval_ms, session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Completed }
guard "channel_capacity_positive" { channel_capacity > 0 }
guard "poll_interval_positive" { poll_interval_ms > 0 }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
update {}
to Completed
emit AuthorizeMobEventRouter { initial_cursor: initial_cursor, channel_capacity: channel_capacity, poll_interval_ms: poll_interval_ms, session_bound_runtimes: session_bound_runtimes }
}
transition SubscribeMobEventsDestroyed {
on input SubscribeMobEvents { initial_cursor, channel_capacity, poll_interval_ms, session_bound_runtimes, external_members }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "channel_capacity_positive" { channel_capacity > 0 }
guard "poll_interval_positive" { poll_interval_ms > 0 }
guard "session_bound_runtimes_match" { mob_machine_session_bound_live_runtime_ids_match(self.identity_to_runtime, self.member_session_bindings, self.live_runtime_ids, session_bound_runtimes) }
guard "external_members_match" {
for_all(id in external_members, self.member_placement.contains_key(id))
&& for_all(id in self.member_placement.keys(), external_members.contains(id))
}
guard "external_carrier_bindings_active" {
for_all(id in external_members, mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, id))
}
update {}
to Destroyed
emit AuthorizeMobEventRouter { initial_cursor: initial_cursor, channel_capacity: channel_capacity, poll_interval_ms: poll_interval_ms, session_bound_runtimes: session_bound_runtimes }
}
transition SubscribeStructuralEventsRunning {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Running }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
guard "batch_limit_positive" { batch_limit > 0 }
guard "channel_capacity_positive" { channel_capacity > 0 }
update {}
to Running
emit AuthorizeStructuralEventSubscription { after_cursor: after_cursor, explicit_after_cursor: explicit_after_cursor, batch_limit: batch_limit, channel_capacity: channel_capacity }
}
transition SubscribeStructuralEventsStopped {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
guard "batch_limit_positive" { batch_limit > 0 }
guard "channel_capacity_positive" { channel_capacity > 0 }
update {}
to Stopped
emit AuthorizeStructuralEventSubscription { after_cursor: after_cursor, explicit_after_cursor: explicit_after_cursor, batch_limit: batch_limit, channel_capacity: channel_capacity }
}
transition SubscribeStructuralEventsCompleted {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Completed }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
guard "batch_limit_positive" { batch_limit > 0 }
guard "channel_capacity_positive" { channel_capacity > 0 }
update {}
to Completed
emit AuthorizeStructuralEventSubscription { after_cursor: after_cursor, explicit_after_cursor: explicit_after_cursor, batch_limit: batch_limit, channel_capacity: channel_capacity }
}
transition SubscribeStructuralEventsDestroyed {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
guard "batch_limit_positive" { batch_limit > 0 }
guard "channel_capacity_positive" { channel_capacity > 0 }
update {}
to Destroyed
emit AuthorizeStructuralEventSubscription { after_cursor: after_cursor, explicit_after_cursor: explicit_after_cursor, batch_limit: batch_limit, channel_capacity: channel_capacity }
}
transition SubscribeStructuralEventsStaleRunning {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Running }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Running
emit RejectStructuralEventSubscription { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition SubscribeStructuralEventsStaleStopped {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Stopped
emit RejectStructuralEventSubscription { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition SubscribeStructuralEventsStaleCompleted {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Completed }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Completed
emit RejectStructuralEventSubscription { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition SubscribeStructuralEventsStaleDestroyed {
on input SubscribeStructuralEvents { after_cursor, latest_cursor, explicit_after_cursor, batch_limit, channel_capacity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Destroyed
emit RejectStructuralEventSubscription { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition PollEventsStrictRunning {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Running }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
update {}
to Running
emit AuthorizeStrictEventPoll { after_cursor: after_cursor, limit: limit }
}
transition PollEventsStrictStopped {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Stopped }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
update {}
to Stopped
emit AuthorizeStrictEventPoll { after_cursor: after_cursor, limit: limit }
}
transition PollEventsStrictCompleted {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Completed }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
update {}
to Completed
emit AuthorizeStrictEventPoll { after_cursor: after_cursor, limit: limit }
}
transition PollEventsStrictDestroyed {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "cursor_not_stale" { after_cursor <= latest_cursor }
update {}
to Destroyed
emit AuthorizeStrictEventPoll { after_cursor: after_cursor, limit: limit }
}
transition PollEventsStrictStaleRunning {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Running }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Running
emit RejectStrictEventPoll { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition PollEventsStrictStaleStopped {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Stopped }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Stopped
emit RejectStrictEventPoll { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition PollEventsStrictStaleCompleted {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Completed }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Completed
emit RejectStrictEventPoll { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition PollEventsStrictStaleDestroyed {
on input PollEventsStrict { after_cursor, latest_cursor, limit }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "cursor_stale" { after_cursor > latest_cursor }
update {}
to Destroyed
emit RejectStrictEventPoll { after_cursor: after_cursor, latest_cursor: latest_cursor }
}
transition AuthorizeMobEventRouterMemberSubscriptionRunning {
on input AuthorizeMobEventRouterMemberSubscription { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
update {}
to Running
emit AuthorizeMobEventRouterMemberSubscription { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, fence_token: fence_token, session_id: self.member_session_bindings.get_cloned(agent_identity).get("value") }
}
transition AuthorizeMobEventRouterMemberSubscriptionStopped {
on input AuthorizeMobEventRouterMemberSubscription { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
update {}
to Stopped
emit AuthorizeMobEventRouterMemberSubscription { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, fence_token: fence_token, session_id: self.member_session_bindings.get_cloned(agent_identity).get("value") }
}
transition AuthorizeMobEventRouterMemberSubscriptionCompleted {
on input AuthorizeMobEventRouterMemberSubscription { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
update {}
to Completed
emit AuthorizeMobEventRouterMemberSubscription { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, fence_token: fence_token, session_id: self.member_session_bindings.get_cloned(agent_identity).get("value") }
}
transition AuthorizeMobEventRouterMemberSubscriptionDestroyed {
on input AuthorizeMobEventRouterMemberSubscription { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_runtime_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "runtime_live" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
guard "session_bound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == true }
update {}
to Destroyed
emit AuthorizeMobEventRouterMemberSubscription { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, fence_token: fence_token, session_id: self.member_session_bindings.get_cloned(agent_identity).get("value") }
}
transition AuthorizeMobEventRouterMemberRemovalMissingRunning {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Running
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalMissingStopped {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Stopped
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalMissingCompleted {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Completed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalMissingDestroyed {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Destroyed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalUnboundRunning {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Running
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalUnboundStopped {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Stopped
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalUnboundCompleted {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Completed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalUnboundDestroyed {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "session_unbound" { mob_machine_identity_has_session_binding(self.member_session_bindings, agent_identity) == false }
update {}
to Destroyed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalRuntimeNotLiveRunning {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Running
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalRuntimeNotLiveStopped {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Stopped
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalRuntimeNotLiveCompleted {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Completed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Completed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
transition AuthorizeMobEventRouterMemberRemovalRuntimeNotLiveDestroyed {
on input AuthorizeMobEventRouterMemberRemoval { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "runtime_not_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) == false }
update {}
to Destroyed
emit AuthorizeMobEventRouterMemberRemoval { agent_identity: agent_identity }
}
// =====================================================================
// Shutdown: from any non-Destroyed state
// =====================================================================
transition ShutdownRunning {
on input Shutdown
guard { self.lifecycle_phase == Phase::Running }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.coordinator_bound = false;
self.active_run_count = 0;
}
to Stopped
emit EmitRunLifecycleNotice
}
transition ShutdownStopped {
on input Shutdown
guard { self.lifecycle_phase == Phase::Stopped }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.coordinator_bound = false;
self.active_run_count = 0;
}
to Stopped
emit EmitRunLifecycleNotice
}
transition ShutdownCompleted {
on input Shutdown
guard { self.lifecycle_phase == Phase::Completed }
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
update {
self.coordinator_bound = false;
self.active_run_count = 0;
}
to Completed
emit EmitRunLifecycleNotice
}
// =====================================================================
// Signal-driven Running self-loops
// =====================================================================
transition CancelFlowRunning {
on input CancelFlow { run_id }
guard { self.lifecycle_phase == Phase::Running }
guard "run_known" { self.run_status.contains_key(run_id) == true }
update {}
to Running
emit NotifyCoordinator
}
transition InitializeOrchestratorRunning {
on signal InitializeOrchestrator
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {
self.coordinator_bound = true;
}
to Running
emit NotifyCoordinator
}
transition BindCoordinatorRunning {
on signal BindCoordinator
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {
self.coordinator_bound = true;
}
to Running
emit NotifyCoordinator
}
transition UnbindCoordinatorRunning {
on signal UnbindCoordinator
guard { self.lifecycle_phase == Phase::Running }
update {
self.coordinator_bound = false;
}
to Running
emit NotifyCoordinator
}
transition StageSpawnRunning {
on signal StageSpawn { agent_identity, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "pending_identity_unused" { self.pending_spawn_sessions.contains_key(agent_identity) == false }
update {
self.pending_spawn_count += 1;
self.pending_spawn_sessions.insert(agent_identity, session_id);
}
to Running
emit ExposePendingSpawn
emit PendingSpawnOperationOwnerAuthorized { agent_identity: agent_identity, session_id: session_id }
}
transition StopOrchestratorRunning {
on signal StopOrchestrator
guard { self.lifecycle_phase == Phase::Running }
update { self.coordinator_bound = false; }
to Running
emit NotifyCoordinator
}
transition StopOrchestratorStopped {
on signal StopOrchestrator
guard { self.lifecycle_phase == Phase::Stopped }
update { self.coordinator_bound = false; }
to Stopped
emit NotifyCoordinator
}
transition StopOrchestratorCompleted {
on signal StopOrchestrator
guard { self.lifecycle_phase == Phase::Completed }
update { self.coordinator_bound = false; }
to Completed
emit NotifyCoordinator
}
transition ResumeOrchestratorRunning {
on signal ResumeOrchestrator
guard { self.lifecycle_phase == Phase::Running }
update { self.coordinator_bound = true; }
to Running
emit NotifyCoordinator
}
transition ResumeOrchestratorStopped {
on signal ResumeOrchestrator
guard { self.lifecycle_phase == Phase::Stopped }
update { self.coordinator_bound = true; }
to Stopped
emit NotifyCoordinator
}
transition ResumeOrchestratorCompleted {
on signal ResumeOrchestrator
guard { self.lifecycle_phase == Phase::Completed }
update { self.coordinator_bound = true; }
to Completed
emit NotifyCoordinator
}
transition DestroyOrchestratorRunning {
on signal DestroyOrchestrator
guard { self.lifecycle_phase == Phase::Running }
update { self.coordinator_bound = false; }
to Running
emit NotifyCoordinator
}
transition DestroyOrchestratorStopped {
on signal DestroyOrchestrator
guard { self.lifecycle_phase == Phase::Stopped }
update { self.coordinator_bound = false; }
to Stopped
emit NotifyCoordinator
}
transition DestroyOrchestratorCompleted {
on signal DestroyOrchestrator
guard { self.lifecycle_phase == Phase::Completed }
update { self.coordinator_bound = false; }
to Completed
emit NotifyCoordinator
}
transition ForceCancelMemberRunning {
on signal ForceCancelMember
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit EmitMemberTerminalNotice
}
transition MemberPeerExposedRunning {
on signal MemberPeerExposed
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit AdmitPeerInput
}
transition MemberTerminalizedRunning {
on signal MemberTerminalized
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit EmitMemberTerminalNotice
}
transition OperationPeerTrustedRunning {
on signal OperationPeerTrusted
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit AdmitPeerInput
}
transition PeerInputAdmittedRunning {
on signal PeerInputAdmitted
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit AdmitPeerInput
}
// =====================================================================
// BeginCleanup / FinishCleanup
// =====================================================================
transition BeginCleanupStopped {
on signal BeginCleanup
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit EmitRunLifecycleNotice
}
transition BeginCleanupCompleted {
on signal BeginCleanup
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Stopped
emit EmitRunLifecycleNotice
}
transition FinishCleanupStopped {
on signal FinishCleanup
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit EmitRunLifecycleNotice
}
transition FinishCleanupCompleted {
on signal FinishCleanup
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Stopped
emit EmitRunLifecycleNotice
}
// =====================================================================
// RunFlow / StartFlow / CreateRun / StartRun
// =====================================================================
transition RunFlowRunning {
on input RunFlow { run_id, step_ids, ordered_steps, step_status, output_recorded, step_condition_results, step_has_conditions, step_dependencies, step_dependency_modes, step_branches, step_collection_policies, step_quorum_thresholds, step_target_counts, step_target_success_counts, step_target_terminal_failure_counts, escalation_threshold, max_step_retries, max_active_nodes, max_active_frames, max_frame_depth }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "coordinator_bound" { self.coordinator_bound == true }
guard "run_seed_is_new" { self.run_status.contains_key(run_id) == false }
guard "run_seed_ordered_steps_match_tracked_steps" {
for_all(candidate in step_ids, ordered_steps.contains(candidate))
&& for_all(candidate in ordered_steps, step_ids.contains(candidate))
}
guard "run_seed_defaults_cover_tracked_steps" {
for_all(candidate in step_ids,
step_status.get_cloned(candidate) == Some(None)
&& output_recorded.get_cloned(candidate) == Some(false)
&& step_condition_results.get_cloned(candidate) == Some(None)
&& step_target_counts.get_cloned(candidate) == Some(0)
&& step_target_success_counts.get_cloned(candidate) == Some(0)
&& step_target_terminal_failure_counts.get_cloned(candidate) == Some(0))
}
guard "run_seed_maps_cover_tracked_steps" {
for_all(candidate in step_ids,
step_has_conditions.contains_key(candidate)
&& step_dependencies.contains_key(candidate)
&& step_dependency_modes.contains_key(candidate)
&& step_branches.contains_key(candidate)
&& step_collection_policies.contains_key(candidate)
&& step_quorum_thresholds.contains_key(candidate))
}
guard "run_seed_map_keys_are_tracked" {
for_all(candidate in step_status.keys(), step_ids.contains(candidate))
&& for_all(candidate in output_recorded.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_condition_results.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_has_conditions.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_dependencies.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_dependency_modes.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_branches.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_collection_policies.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_quorum_thresholds.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_counts.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_success_counts.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_terminal_failure_counts.keys(), step_ids.contains(candidate))
}
guard "run_seed_dependency_targets_are_tracked" {
for_all(candidate in step_dependencies.keys(),
for_all(dependency in step_dependencies.get_cloned(candidate).get("value"),
step_ids.contains(dependency)))
}
update {
self.run_status.insert(run_id, FlowRunStatus::Pending);
self.run_tracked_steps.insert(run_id, step_ids);
self.run_ordered_steps.insert(run_id, ordered_steps);
self.run_step_status.insert(run_id, step_status);
self.run_output_recorded.insert(run_id, output_recorded);
self.run_step_condition_results.insert(run_id, step_condition_results);
self.run_step_has_conditions.insert(run_id, step_has_conditions);
self.run_step_dependencies.insert(run_id, step_dependencies);
self.run_step_dependency_modes.insert(run_id, step_dependency_modes);
self.run_step_branches.insert(run_id, step_branches);
self.run_step_collection_policies.insert(run_id, step_collection_policies);
self.run_step_quorum_thresholds.insert(run_id, step_quorum_thresholds);
self.run_step_target_counts.insert(run_id, step_target_counts);
self.run_step_target_success_counts.insert(run_id, step_target_success_counts);
self.run_step_target_terminal_failure_counts.insert(run_id, step_target_terminal_failure_counts);
self.run_target_retry_counts.insert(run_id, EmptyMap);
self.run_failure_count.insert(run_id, 0);
self.run_consecutive_failure_count.insert(run_id, 0);
self.run_escalation_threshold.insert(run_id, escalation_threshold);
self.run_max_step_retries.insert(run_id, max_step_retries);
self.run_ready_frames.insert(run_id, EmptySeq);
self.run_ready_frame_membership.insert(run_id, EmptySet);
self.run_pending_body_frame_loops.insert(run_id, EmptySeq);
self.run_pending_body_frame_loop_membership.insert(run_id, EmptySet);
self.run_active_node_count.insert(run_id, 0);
self.run_active_frame_count.insert(run_id, 0);
self.run_last_granted_frame.insert(run_id, None);
self.run_last_granted_loop.insert(run_id, None);
self.run_max_active_nodes.insert(run_id, max_active_nodes);
self.run_max_active_frames.insert(run_id, max_active_frames);
self.run_max_frame_depth.insert(run_id, max_frame_depth);
self.active_run_count += 1;
}
to Running
emit EmitFlowRunNotice
}
transition CreateRunSeedRunning {
on input CreateRunSeed { run_id, step_ids, ordered_steps, step_status, output_recorded, step_condition_results, step_has_conditions, step_dependencies, step_dependency_modes, step_branches, step_collection_policies, step_quorum_thresholds, step_target_counts, step_target_success_counts, step_target_terminal_failure_counts, escalation_threshold, max_step_retries, max_active_nodes, max_active_frames, max_frame_depth }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "run_seed_is_new" { self.run_status.contains_key(run_id) == false }
guard "run_seed_ordered_steps_match_tracked_steps" {
for_all(candidate in step_ids, ordered_steps.contains(candidate))
&& for_all(candidate in ordered_steps, step_ids.contains(candidate))
}
guard "run_seed_defaults_cover_tracked_steps" {
for_all(candidate in step_ids,
step_status.get_cloned(candidate) == Some(None)
&& output_recorded.get_cloned(candidate) == Some(false)
&& step_condition_results.get_cloned(candidate) == Some(None)
&& step_target_counts.get_cloned(candidate) == Some(0)
&& step_target_success_counts.get_cloned(candidate) == Some(0)
&& step_target_terminal_failure_counts.get_cloned(candidate) == Some(0))
}
guard "run_seed_maps_cover_tracked_steps" {
for_all(candidate in step_ids,
step_has_conditions.contains_key(candidate)
&& step_dependencies.contains_key(candidate)
&& step_dependency_modes.contains_key(candidate)
&& step_branches.contains_key(candidate)
&& step_collection_policies.contains_key(candidate)
&& step_quorum_thresholds.contains_key(candidate))
}
guard "run_seed_map_keys_are_tracked" {
for_all(candidate in step_status.keys(), step_ids.contains(candidate))
&& for_all(candidate in output_recorded.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_condition_results.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_has_conditions.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_dependencies.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_dependency_modes.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_branches.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_collection_policies.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_quorum_thresholds.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_counts.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_success_counts.keys(), step_ids.contains(candidate))
&& for_all(candidate in step_target_terminal_failure_counts.keys(), step_ids.contains(candidate))
}
guard "run_seed_dependency_targets_are_tracked" {
for_all(candidate in step_dependencies.keys(),
for_all(dependency in step_dependencies.get_cloned(candidate).get("value"),
step_ids.contains(dependency)))
}
update {
self.run_status.insert(run_id, FlowRunStatus::Pending);
self.run_tracked_steps.insert(run_id, step_ids);
self.run_ordered_steps.insert(run_id, ordered_steps);
self.run_step_status.insert(run_id, step_status);
self.run_output_recorded.insert(run_id, output_recorded);
self.run_step_condition_results.insert(run_id, step_condition_results);
self.run_step_has_conditions.insert(run_id, step_has_conditions);
self.run_step_dependencies.insert(run_id, step_dependencies);
self.run_step_dependency_modes.insert(run_id, step_dependency_modes);
self.run_step_branches.insert(run_id, step_branches);
self.run_step_collection_policies.insert(run_id, step_collection_policies);
self.run_step_quorum_thresholds.insert(run_id, step_quorum_thresholds);
self.run_step_target_counts.insert(run_id, step_target_counts);
self.run_step_target_success_counts.insert(run_id, step_target_success_counts);
self.run_step_target_terminal_failure_counts.insert(run_id, step_target_terminal_failure_counts);
self.run_target_retry_counts.insert(run_id, EmptyMap);
self.run_failure_count.insert(run_id, 0);
self.run_consecutive_failure_count.insert(run_id, 0);
self.run_escalation_threshold.insert(run_id, escalation_threshold);
self.run_max_step_retries.insert(run_id, max_step_retries);
self.run_ready_frames.insert(run_id, EmptySeq);
self.run_ready_frame_membership.insert(run_id, EmptySet);
self.run_pending_body_frame_loops.insert(run_id, EmptySeq);
self.run_pending_body_frame_loop_membership.insert(run_id, EmptySet);
self.run_active_node_count.insert(run_id, 0);
self.run_active_frame_count.insert(run_id, 0);
self.run_last_granted_frame.insert(run_id, None);
self.run_last_granted_loop.insert(run_id, None);
self.run_max_active_nodes.insert(run_id, max_active_nodes);
self.run_max_active_frames.insert(run_id, max_active_frames);
self.run_max_frame_depth.insert(run_id, max_frame_depth);
}
to Running
emit EmitRunLifecycleNotice
}
transition CreateFrameSeedRunning {
on input CreateFrameSeed { run_id, frame_id, frame_scope, loop_instance_id, iteration, tracked_nodes, ordered_nodes, node_kind, node_dependencies, node_dependency_modes, node_branches, node_step_ids, node_loop_ids, node_status, ready_queue, output_recorded, node_condition_results, last_admitted_node }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "frame_seed_is_new" { self.frame_phase.contains_key(frame_id) == false }
guard "run_known" { self.run_status.contains_key(run_id) == true }
guard "body_frame_has_parent_loop" { frame_scope != FrameScope::Body || loop_instance_id != None }
guard "frame_seed_has_no_last_admitted_node" { last_admitted_node == None }
guard "frame_seed_ordered_nodes_match_tracked_nodes" {
for_all(candidate in tracked_nodes, ordered_nodes.contains(candidate))
&& for_all(candidate in ordered_nodes, tracked_nodes.contains(candidate))
}
guard "frame_seed_status_covers_tracked_nodes" {
for_all(candidate in tracked_nodes,
node_status.contains_key(candidate))
}
guard "frame_seed_defaults_cover_tracked_nodes" {
for_all(candidate in tracked_nodes,
output_recorded.get_cloned(candidate) == Some(false)
&& node_condition_results.get_cloned(candidate) == Some(None))
}
guard "frame_seed_maps_cover_tracked_nodes" {
for_all(candidate in tracked_nodes,
node_dependencies.contains_key(candidate)
&& node_dependency_modes.contains_key(candidate)
&& node_branches.contains_key(candidate))
}
guard "frame_seed_map_keys_are_tracked" {
for_all(candidate in node_status.keys(), tracked_nodes.contains(candidate))
&& for_all(candidate in output_recorded.keys(), tracked_nodes.contains(candidate))
&& for_all(candidate in node_condition_results.keys(), tracked_nodes.contains(candidate))
&& for_all(candidate in node_dependencies.keys(), tracked_nodes.contains(candidate))
&& for_all(candidate in node_dependency_modes.keys(), tracked_nodes.contains(candidate))
&& for_all(candidate in node_branches.keys(), tracked_nodes.contains(candidate))
}
guard "frame_seed_ready_queue_nodes_are_tracked" {
for_all(candidate in ready_queue, tracked_nodes.contains(candidate))
}
guard "frame_seed_dependency_targets_are_tracked" {
for_all(candidate in node_dependencies.keys(),
for_all(dependency in node_dependencies.get_cloned(candidate).get("value"),
tracked_nodes.contains(dependency)))
}
guard "frame_seed_node_kind_covers_tracked_nodes" {
for_all(candidate in tracked_nodes,
node_kind.contains_key(candidate))
}
guard "frame_seed_node_kind_keys_are_tracked" {
for_all(candidate in node_kind.keys(),
tracked_nodes.contains(candidate))
}
guard "frame_seed_ready_queue_matches_dependency_roots" {
for_all(candidate in tracked_nodes,
(node_dependencies.get_cloned(candidate).get("value") == EmptySeq
&& node_status.get_cloned(candidate) == Some(NodeRunStatus::Ready)
&& ready_queue.contains(candidate))
|| (node_dependencies.get_cloned(candidate).get("value") != EmptySeq
&& node_status.get_cloned(candidate) == Some(NodeRunStatus::Pending)
&& ready_queue.contains(candidate) == false))
}
guard "frame_seed_step_nodes_have_exact_step_ids" {
for_all(candidate in tracked_nodes,
(node_kind.get_cloned(candidate) == Some(FlowNodeKind::Step)
&& node_step_ids.contains_key(candidate)
&& node_loop_ids.contains_key(candidate) == false)
|| node_kind.get_cloned(candidate) != Some(FlowNodeKind::Step))
}
guard "frame_seed_loop_nodes_have_exact_loop_ids" {
for_all(candidate in tracked_nodes,
(node_kind.get_cloned(candidate) == Some(FlowNodeKind::Loop)
&& node_loop_ids.contains_key(candidate)
&& node_step_ids.contains_key(candidate) == false)
|| node_kind.get_cloned(candidate) != Some(FlowNodeKind::Loop))
}
guard "frame_seed_step_id_keys_are_tracked_steps" {
for_all(candidate in node_step_ids.keys(),
tracked_nodes.contains(candidate)
&& node_kind.get_cloned(candidate) == Some(FlowNodeKind::Step))
}
guard "frame_seed_loop_id_keys_are_tracked_loops" {
for_all(candidate in node_loop_ids.keys(),
tracked_nodes.contains(candidate)
&& node_kind.get_cloned(candidate) == Some(FlowNodeKind::Loop))
}
update {
self.frame_scope.insert(frame_id, frame_scope);
self.frame_phase.insert(frame_id, FrameStatus::Running);
self.frame_run.insert(frame_id, run_id);
self.frame_parent_loop.insert(frame_id, loop_instance_id);
self.frame_iteration.insert(frame_id, iteration);
self.frame_tracked_nodes.insert(frame_id, tracked_nodes);
self.frame_ordered_nodes.insert(frame_id, ordered_nodes);
self.frame_node_kind.insert(frame_id, node_kind);
self.frame_node_dependencies.insert(frame_id, node_dependencies);
self.frame_node_dependency_modes.insert(frame_id, node_dependency_modes);
self.frame_node_branches.insert(frame_id, node_branches);
self.frame_node_step_ids.insert(frame_id, node_step_ids);
self.frame_node_loop_ids.insert(frame_id, node_loop_ids);
self.frame_node_status.insert(frame_id, node_status);
self.frame_ready_queue.insert(frame_id, ready_queue);
self.frame_output_recorded.insert(frame_id, output_recorded);
self.frame_node_condition_results.insert(frame_id, node_condition_results);
self.frame_last_admitted_node.insert(frame_id, last_admitted_node);
if frame_scope == FrameScope::Body {
self.loop_stage.insert(loop_instance_id.get("value"), LoopIterationStage::BodyFrameActive);
self.loop_active_body_frame.insert(loop_instance_id.get("value"), Some(frame_id));
}
}
to Running
emit EmitRunLifecycleNotice
emit FrameSeedConfirmed { frame_id: frame_id, disposition: MobFrameSeedDisposition::Seeded }
}
// Idempotent re-seed: when the frame is already tracked, `CreateFrameSeed`
// is a no-op that emits `AlreadySeeded` instead of being rejected by the
// `frame_seed_is_new` guard. This is the machine-owned idempotency
// disposition the flow shell mirrors (replacing the former
// `error.to_string().contains("frame_seed_is_new")` string folklore).
transition CreateFrameSeedAlreadySeeded {
per_phase [Running, Stopped, Completed, Destroyed]
on input CreateFrameSeed { run_id, frame_id, frame_scope, loop_instance_id, iteration, tracked_nodes, ordered_nodes, node_kind, node_dependencies, node_dependency_modes, node_branches, node_step_ids, node_loop_ids, node_status, ready_queue, output_recorded, node_condition_results, last_admitted_node }
guard "frame_seed_already_tracked" { self.frame_phase.contains_key(frame_id) == true }
update {}
to Running
emit FrameSeedConfirmed { frame_id: frame_id, disposition: MobFrameSeedDisposition::AlreadySeeded }
}
transition CreateLoopSeedRunning {
on input CreateLoopSeed { loop_instance_id, parent_frame_id, parent_node_id, loop_id, depth, max_iterations }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "loop_seed_is_new" { self.loop_phase.contains_key(loop_instance_id) == false }
guard "parent_frame_known" { self.frame_run.contains_key(parent_frame_id) == true }
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Running);
self.loop_parent_frame.insert(loop_instance_id, parent_frame_id);
self.loop_parent_node.insert(loop_instance_id, parent_node_id);
self.loop_definition.insert(loop_instance_id, loop_id);
self.loop_depth.insert(loop_instance_id, depth);
self.loop_stage.insert(loop_instance_id, LoopIterationStage::AwaitingBodyFrame);
self.loop_current_iteration.insert(loop_instance_id, 0u64);
self.loop_last_completed_iteration.insert(loop_instance_id, 0u64);
self.loop_max_iterations.insert(loop_instance_id, max_iterations);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition RecordLoopBodyFrameCompletedRunning {
on input RecordLoopBodyFrameCompleted { loop_instance_id, iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "body_frame_active" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::BodyFrameActive) }
guard "iteration_matches_current" { self.loop_current_iteration.get_cloned(loop_instance_id) == Some(iteration) }
update {
self.loop_stage.insert(loop_instance_id, LoopIterationStage::AwaitingUntilEvaluation);
self.loop_last_completed_iteration.insert(loop_instance_id, iteration);
self.loop_current_iteration.insert(loop_instance_id, iteration + 1u64);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition RecordLoopUntilConditionMetRunning {
on input RecordLoopUntilConditionMet { loop_instance_id, iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "awaiting_until_evaluation" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::AwaitingUntilEvaluation) }
guard "iteration_matches_last_completed" { self.loop_last_completed_iteration.get_cloned(loop_instance_id) == Some(iteration) }
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Completed);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition RecordLoopUntilConditionFailedRunning {
on input RecordLoopUntilConditionFailed { loop_instance_id, iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "awaiting_until_evaluation" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::AwaitingUntilEvaluation) }
guard "iteration_matches_last_completed" { self.loop_last_completed_iteration.get_cloned(loop_instance_id) == Some(iteration) }
guard "iterations_remaining" {
self.loop_current_iteration.get_cloned(loop_instance_id).get("value")
< self.loop_max_iterations.get_cloned(loop_instance_id).get("value")
}
update {
self.loop_stage.insert(loop_instance_id, LoopIterationStage::AwaitingBodyFrame);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition RecordLoopUntilConditionFailedExhausted {
on input RecordLoopUntilConditionFailed { loop_instance_id, iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "awaiting_until_evaluation" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::AwaitingUntilEvaluation) }
guard "iteration_matches_last_completed" { self.loop_last_completed_iteration.get_cloned(loop_instance_id) == Some(iteration) }
guard "iterations_exhausted" {
self.loop_current_iteration.get_cloned(loop_instance_id).get("value")
>= self.loop_max_iterations.get_cloned(loop_instance_id).get("value")
}
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Exhausted);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandStartRun {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "start_run_command" { command == FlowRunReducerCommandKind::StartRun }
guard "run_pending" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Pending) }
update {
self.run_status.insert(run_id, FlowRunStatus::Running);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandDispatchStep {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "dispatch_step_command" { command == FlowRunReducerCommandKind::DispatchStep }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "dispatched_step_status" { step_status == Some(StepRunStatus::Dispatched) }
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Dispatched);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandCompleteStep {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "complete_step_command" { command == FlowRunReducerCommandKind::CompleteStep }
guard "has_step_id" { step_id != None }
guard "completed_step_status" { step_status == Some(StepRunStatus::Completed) }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Completed);
self.run_consecutive_failure_count.insert(run_id, 0);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRecordStepOutput {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "record_step_output_command" { command == FlowRunReducerCommandKind::RecordStepOutput }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_output_recorded = mob_machine_run_step_bool_after_set(self.run_output_recorded, run_id, step_id.get("value"), true);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandConditionPassed {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "condition_passed_command" { command == FlowRunReducerCommandKind::ConditionPassed }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_condition_results = mob_machine_run_step_condition_result_after_set(self.run_step_condition_results, run_id, step_id.get("value"), true);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandConditionRejected {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "condition_rejected_command" { command == FlowRunReducerCommandKind::ConditionRejected }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_condition_results = mob_machine_run_step_condition_result_after_set(self.run_step_condition_results, run_id, step_id.get("value"), false);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandFailStep {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "fail_step_command" { command == FlowRunReducerCommandKind::FailStep }
guard "has_step_id" { step_id != None }
guard "failed_step_status" { step_status == Some(StepRunStatus::Failed) }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "supervisor_escalation_not_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") == 0
|| self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
< self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
}
transition AuthorizeFlowRunReducerCommandFailStepEscalating {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "fail_step_command" { command == FlowRunReducerCommandKind::FailStep }
guard "has_step_id" { step_id != None }
guard "failed_step_status" { step_status == Some(StepRunStatus::Failed) }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "supervisor_escalation_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") > 0
&& self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
>= self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
emit EscalateSupervisor
}
// Terminal failure folding must remain available while lifecycle
// cleanup is quiescing work origin, but crossing an escalation
// threshold must not originate a new supervisor turn in that window.
transition AuthorizeFlowRunReducerCommandFailStepEscalationSuppressedByLifecycle {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_closed" { self.placed_completion_lifecycle_quiescing == true }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "fail_step_command" { command == FlowRunReducerCommandKind::FailStep }
guard "has_step_id" { step_id != None }
guard "failed_step_status" { step_status == Some(StepRunStatus::Failed) }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "supervisor_escalation_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") > 0
&& self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
>= self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
}
transition AuthorizeFlowRunReducerCommandSkipStep {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "skip_step_command" { command == FlowRunReducerCommandKind::SkipStep }
guard "has_step_id" { step_id != None }
guard "skipped_step_status" { step_status == Some(StepRunStatus::Skipped) }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Skipped);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandProjectFrameStepStatus {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "project_frame_step_status_command" { command == FlowRunReducerCommandKind::ProjectFrameStepStatus }
guard "has_step_id" { step_id != None }
guard "has_frame_id" { frame_id != None }
guard "has_node_id" { node_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "frame_belongs_to_run" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id.get("value")).get("value").contains(node_id.get("value")) }
guard "frame_node_maps_to_step" { self.frame_node_step_ids.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(step_id.get("value")) }
guard "run_step_not_already_terminal_projected" {
self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == None
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(None)
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(Some(StepRunStatus::Dispatched))
}
guard "frame_node_completed_or_skipped" {
self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Skipped)
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(
self.run_step_status,
run_id,
step_id.get("value"),
mob_machine_step_status_from_frame_node_status(
self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")).get("value")
)
);
if self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Completed) {
self.run_consecutive_failure_count.insert(run_id, 0);
}
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandProjectFrameStepStatusFailed {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "project_frame_step_status_command" { command == FlowRunReducerCommandKind::ProjectFrameStepStatus }
guard "has_step_id" { step_id != None }
guard "has_frame_id" { frame_id != None }
guard "has_node_id" { node_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "frame_belongs_to_run" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id.get("value")).get("value").contains(node_id.get("value")) }
guard "frame_node_maps_to_step" { self.frame_node_step_ids.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(step_id.get("value")) }
guard "run_step_not_already_terminal_projected" {
self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == None
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(None)
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(Some(StepRunStatus::Dispatched))
}
guard "frame_node_failed" {
self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Failed)
}
guard "supervisor_escalation_not_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") == 0
|| self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
< self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
}
transition AuthorizeFlowRunReducerCommandProjectFrameStepStatusFailedEscalating {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "project_frame_step_status_command" { command == FlowRunReducerCommandKind::ProjectFrameStepStatus }
guard "has_step_id" { step_id != None }
guard "has_frame_id" { frame_id != None }
guard "has_node_id" { node_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "frame_belongs_to_run" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id.get("value")).get("value").contains(node_id.get("value")) }
guard "frame_node_maps_to_step" { self.frame_node_step_ids.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(step_id.get("value")) }
guard "run_step_not_already_terminal_projected" {
self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == None
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(None)
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(Some(StepRunStatus::Dispatched))
}
guard "frame_node_failed" {
self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Failed)
}
guard "supervisor_escalation_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") > 0
&& self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
>= self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
emit EscalateSupervisor
}
transition AuthorizeFlowRunReducerCommandProjectFrameStepStatusFailedEscalationSuppressedByLifecycle {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_closed" { self.placed_completion_lifecycle_quiescing == true }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "project_frame_step_status_command" { command == FlowRunReducerCommandKind::ProjectFrameStepStatus }
guard "has_step_id" { step_id != None }
guard "has_frame_id" { frame_id != None }
guard "has_node_id" { node_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "frame_belongs_to_run" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id.get("value")).get("value").contains(node_id.get("value")) }
guard "frame_node_maps_to_step" { self.frame_node_step_ids.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(step_id.get("value")) }
guard "run_step_not_already_terminal_projected" {
self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == None
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(None)
|| self.run_step_status.get_cloned(run_id).get("value").get_cloned(step_id.get("value")) == Some(Some(StepRunStatus::Dispatched))
}
guard "frame_node_failed" {
self.frame_node_status.get_cloned(frame_id.get("value")).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Failed)
}
guard "supervisor_escalation_due" {
self.run_escalation_threshold.get_cloned(run_id).get("value") > 0
&& self.run_consecutive_failure_count.get_cloned(run_id).get("value") + 1
>= self.run_escalation_threshold.get_cloned(run_id).get("value")
}
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Failed);
self.run_failure_count.increment(run_id, 1);
self.run_consecutive_failure_count.increment(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
emit AppendFailureLedger
}
transition AuthorizeFlowRunReducerCommandCancelStep {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "cancel_step_command" { command == FlowRunReducerCommandKind::CancelStep }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
guard "canceled_step_status" { step_status == Some(StepRunStatus::Canceled) }
update {
self.run_step_status = mob_machine_run_step_status_after_set(self.run_step_status, run_id, step_id.get("value"), StepRunStatus::Canceled);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRegisterTargets {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "register_targets_command" { command == FlowRunReducerCommandKind::RegisterTargets }
guard "has_step_id" { step_id != None }
guard "has_target_count" { target_count != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_target_counts = mob_machine_run_step_u64_after_set(self.run_step_target_counts, run_id, step_id.get("value"), target_count.get("value"));
self.run_step_target_success_counts = mob_machine_run_step_u64_after_set(self.run_step_target_success_counts, run_id, step_id.get("value"), 0);
self.run_step_target_terminal_failure_counts = mob_machine_run_step_u64_after_set(self.run_step_target_terminal_failure_counts, run_id, step_id.get("value"), 0);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRecordTargetSuccess {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "record_target_success_command" { command == FlowRunReducerCommandKind::RecordTargetSuccess }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_target_success_counts = mob_machine_run_step_u64_after_increment(self.run_step_target_success_counts, run_id, step_id.get("value"), 1);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRecordTargetTerminalFailure {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "record_target_terminal_failure_command" { command == FlowRunReducerCommandKind::RecordTargetTerminalFailure }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_step_target_terminal_failure_counts = mob_machine_run_step_u64_after_increment(self.run_step_target_terminal_failure_counts, run_id, step_id.get("value"), 1);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRecordTargetCanceled {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "record_target_canceled_command" { command == FlowRunReducerCommandKind::RecordTargetCanceled }
guard "has_step_id" { step_id != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRecordTargetFailure {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "record_target_failure_command" { command == FlowRunReducerCommandKind::RecordTargetFailure }
guard "has_step_id" { step_id != None }
guard "has_retry_key" { retry_key != None }
guard "step_tracked" { self.run_tracked_steps.get_cloned(run_id).get("value").contains(step_id.get("value")) }
update {
self.run_target_retry_counts = mob_machine_run_retry_count_after_increment(self.run_target_retry_counts, run_id, retry_key.get("value"), 1);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRegisterReadyFrame {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "register_ready_frame_command" { command == FlowRunReducerCommandKind::RegisterReadyFrame }
guard "has_frame_id" { frame_id != None }
guard "known_frame" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_not_already_ready" { self.run_ready_frame_membership_flat.contains(frame_id.get("value")) == false }
update {
self.run_ready_frame_membership_flat.insert(frame_id.get("value"));
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRegisterReadyFrameAlreadyReady {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "register_ready_frame_command" { command == FlowRunReducerCommandKind::RegisterReadyFrame }
guard "has_frame_id" { frame_id != None }
guard "known_frame" { self.frame_run.get_cloned(frame_id.get("value")) == Some(run_id) }
guard "frame_already_ready" { self.run_ready_frame_membership_flat.contains(frame_id.get("value")) == true }
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandPumpNodeScheduler {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "pump_node_scheduler_command" { command == FlowRunReducerCommandKind::PumpNodeScheduler }
guard "has_frame_id" { frame_id != None }
guard "ready_frame_registered" { self.run_ready_frame_membership_flat.contains(frame_id.get("value")) == true }
guard "machine_selected_ready_frame" {
for_all(candidate in self.run_ready_frame_membership_flat,
self.frame_run.get_cloned(candidate) != Some(run_id)
|| frame_id.get("value") <= candidate)
}
guard "node_capacity_available" {
self.run_max_active_nodes.get_cloned(run_id).get("value") == 0
|| self.run_active_node_count.get_cloned(run_id).get("value") < self.run_max_active_nodes.get_cloned(run_id).get("value")
}
update {
self.run_ready_frame_membership_flat.remove(frame_id.get("value"));
self.run_active_node_count.increment(run_id, 1);
self.run_last_granted_frame.insert(run_id, Some(frame_id.get("value")));
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandRegisterPendingBodyFrame {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "register_pending_body_frame_command" { command == FlowRunReducerCommandKind::RegisterPendingBodyFrame }
guard "has_loop_instance_id" { loop_instance_id != None }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id.get("value")) == true }
guard "loop_not_already_pending_body_frame" { self.run_pending_body_frame_loop_membership_flat.contains(loop_instance_id.get("value")) == false }
update {
self.run_pending_body_frame_loop_membership_flat.insert(loop_instance_id.get("value"));
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandPumpFrameScheduler {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "pump_frame_scheduler_command" { command == FlowRunReducerCommandKind::PumpFrameScheduler }
guard "has_loop_instance_id" { loop_instance_id != None }
guard "pending_body_frame_registered" { self.run_pending_body_frame_loop_membership_flat.contains(loop_instance_id.get("value")) == true }
guard "machine_selected_pending_body_frame_loop" {
for_all(candidate in self.run_pending_body_frame_loop_membership_flat,
self.loop_parent_frame.contains_key(candidate) == false
|| self.frame_run.get_cloned(self.loop_parent_frame.get_cloned(candidate).get("value")) != Some(run_id)
|| loop_instance_id.get("value") <= candidate)
}
guard "frame_capacity_available" {
self.run_max_active_frames.get_cloned(run_id).get("value") == 0
|| self.run_active_frame_count.get_cloned(run_id).get("value") < self.run_max_active_frames.get_cloned(run_id).get("value")
}
update {
self.run_pending_body_frame_loop_membership_flat.remove(loop_instance_id.get("value"));
self.run_active_frame_count.increment(run_id, 1);
self.run_last_granted_loop.insert(run_id, Some(loop_instance_id.get("value")));
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandNodeExecutionReleased {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "node_execution_released_command" { command == FlowRunReducerCommandKind::NodeExecutionReleased }
guard "active_node_count_present" { self.run_active_node_count.contains_key(run_id) == true }
guard "active_node_count_positive" { self.run_active_node_count.get_cloned(run_id).get("value") > 0 }
update {
self.run_active_node_count.decrement(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandFrameTerminated {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "frame_terminated_command" { command == FlowRunReducerCommandKind::FrameTerminated }
guard "active_frame_count_present" { self.run_active_frame_count.contains_key(run_id) == true }
guard "active_frame_count_positive" { self.run_active_frame_count.get_cloned(run_id).get("value") > 0 }
update {
self.run_active_frame_count.decrement(run_id, 1);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandFrameTerminatedNoActiveFrame {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "frame_terminated_command" { command == FlowRunReducerCommandKind::FrameTerminated }
guard "active_frame_count_present" { self.run_active_frame_count.contains_key(run_id) == true }
guard "active_frame_count_zero" { self.run_active_frame_count.get_cloned(run_id).get("value") == 0 }
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandTerminalCompleted {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "terminal_completed_command" { command == FlowRunReducerCommandKind::TerminalizeCompleted }
update {
self.run_status.insert(run_id, FlowRunStatus::Completed);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandTerminalFailed {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "terminal_failed_command" { command == FlowRunReducerCommandKind::TerminalizeFailed }
update {
self.run_status.insert(run_id, FlowRunStatus::Failed);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowRunReducerCommandTerminalCanceled {
on input AuthorizeFlowRunReducerCommand { run_id, command, step_id, step_status, target_count, frame_id, node_id, loop_instance_id, retry_key }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_run" { self.run_status.contains_key(run_id) == true }
guard "run_running" { self.run_status.get_cloned(run_id) == Some(FlowRunStatus::Running) }
guard "terminal_canceled_command" { command == FlowRunReducerCommandKind::TerminalizeCanceled }
update {
self.run_status.insert(run_id, FlowRunStatus::Canceled);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandAdmitNextReadyNode {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "admit_next_ready_node_command" { command == FlowFrameReducerCommandKind::AdmitNextReadyNode }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "running_node_status" { node_status == Some(NodeRunStatus::Running) }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
guard "node_currently_ready" { self.frame_ready_queue.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
update {
self.frame_node_status = mob_machine_frame_node_status_after_admit(self.frame_node_status, self.frame_node_branches, self.frame_ordered_nodes, frame_id, node_id.get("value"));
self.frame_last_admitted_node.insert(frame_id, Some(node_id.get("value")));
self.frame_ready_queue = mob_machine_frame_ready_queue_after_admit(self.frame_ready_queue, self.frame_node_status, self.frame_ordered_nodes, frame_id);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandCompleteNode {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "complete_node_command" { command == FlowFrameReducerCommandKind::CompleteNode }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "completed_node_status" { node_status == Some(NodeRunStatus::Completed) }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
guard "node_currently_running" { self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Running) }
update {
self.frame_node_status = mob_machine_frame_node_status_after_terminal(self.frame_node_status, self.frame_node_branches, self.frame_ordered_nodes, self.frame_node_dependencies, self.frame_node_dependency_modes, frame_id, node_id.get("value"), NodeRunStatus::Completed);
self.frame_ready_queue = mob_machine_frame_ready_queue_after_terminal(self.frame_ready_queue, self.frame_node_status, self.frame_ordered_nodes, frame_id);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandRecordNodeOutput {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "record_node_output_command" { command == FlowFrameReducerCommandKind::RecordNodeOutput }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
update {
self.frame_output_recorded = mob_machine_frame_node_bool_after_set(self.frame_output_recorded, frame_id, node_id.get("value"), true);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandFailNode {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "fail_node_command" { command == FlowFrameReducerCommandKind::FailNode }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "failed_node_status" { node_status == Some(NodeRunStatus::Failed) }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
guard "node_currently_running" { self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Running) }
update {
self.frame_node_status = mob_machine_frame_node_status_after_terminal(self.frame_node_status, self.frame_node_branches, self.frame_ordered_nodes, self.frame_node_dependencies, self.frame_node_dependency_modes, frame_id, node_id.get("value"), NodeRunStatus::Failed);
self.frame_ready_queue = mob_machine_frame_ready_queue_after_terminal(self.frame_ready_queue, self.frame_node_status, self.frame_ordered_nodes, frame_id);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandSkipNode {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "skip_node_command" { command == FlowFrameReducerCommandKind::SkipNode }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "skipped_node_status" { node_status == Some(NodeRunStatus::Skipped) }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
guard "node_currently_running" { self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Running) }
update {
self.frame_node_status = mob_machine_frame_node_status_after_terminal(self.frame_node_status, self.frame_node_branches, self.frame_ordered_nodes, self.frame_node_dependencies, self.frame_node_dependency_modes, frame_id, node_id.get("value"), NodeRunStatus::Skipped);
self.frame_ready_queue = mob_machine_frame_ready_queue_after_terminal(self.frame_ready_queue, self.frame_node_status, self.frame_ordered_nodes, frame_id);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandCancelNode {
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "cancel_node_command" { command == FlowFrameReducerCommandKind::CancelNode }
guard "no_terminal_status" { terminal_status == None }
guard "has_node_id" { node_id != None }
guard "canceled_node_status" { node_status == Some(NodeRunStatus::Canceled) }
guard "node_tracked" { self.frame_tracked_nodes.get_cloned(frame_id).get("value").contains(node_id.get("value")) }
guard "node_currently_running" { self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(node_id.get("value")) == Some(NodeRunStatus::Running) }
update {
self.frame_node_status = mob_machine_frame_node_status_after_terminal(self.frame_node_status, self.frame_node_branches, self.frame_ordered_nodes, self.frame_node_dependencies, self.frame_node_dependency_modes, frame_id, node_id.get("value"), NodeRunStatus::Canceled);
self.frame_ready_queue = mob_machine_frame_ready_queue_after_terminal(self.frame_ready_queue, self.frame_node_status, self.frame_ordered_nodes, frame_id);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeFlowFrameReducerCommandSealFrame {
per_phase [Running, Stopped, Completed]
on input AuthorizeFlowFrameReducerCommand { frame_id, command, node_id, node_status, terminal_status }
guard "known_frame" { self.frame_phase.contains_key(frame_id) == true }
guard "frame_running" { self.frame_phase.get_cloned(frame_id) == Some(FrameStatus::Running) }
guard "seal_frame_command" { command == FlowFrameReducerCommandKind::SealFrame }
guard "terminal_frame_status" {
terminal_status == Some(FrameStatus::Completed)
|| terminal_status == Some(FrameStatus::Failed)
|| terminal_status == Some(FrameStatus::Canceled)
}
guard "all_nodes_terminal" {
for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Completed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Failed)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Skipped)
|| self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) == Some(NodeRunStatus::Canceled))
}
guard "terminal_class_matches_nodes" {
(terminal_status == Some(FrameStatus::Failed)
&& for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed)) == false)
|| (terminal_status == Some(FrameStatus::Canceled)
&& for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed))
&& for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Canceled)) == false)
|| (terminal_status == Some(FrameStatus::Completed)
&& for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Failed))
&& for_all(seal_node_id in self.frame_tracked_nodes.get_cloned(frame_id).get("value"),
self.frame_node_status.get_cloned(frame_id).get("value").get_cloned(seal_node_id) != Some(NodeRunStatus::Canceled)))
}
update {
self.frame_phase.insert(frame_id, terminal_status.get("value"));
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandBodyFrameStarted {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "body_frame_started_command" { command == LoopIterationReducerCommandKind::BodyFrameStarted }
guard "blocked_use_CreateFrameSeed_body_side_effect" { false }
guard "no_body_frame_iteration" { body_frame_iteration == None }
guard "body_frame_already_active" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::BodyFrameActive) }
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandBodyFrameCompleted {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "body_frame_active" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::BodyFrameActive) }
guard "body_frame_completed_command" { command == LoopIterationReducerCommandKind::BodyFrameCompleted }
guard "blocked_use_RecordLoopBodyFrameCompleted" { false }
guard "body_frame_iteration_present" { body_frame_iteration != None }
guard "iteration_matches_current" {
self.loop_current_iteration.get_cloned(loop_instance_id) == body_frame_iteration
}
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandBodyFrameFailed {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "body_frame_active" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::BodyFrameActive) }
guard "body_frame_failed_command" { command == LoopIterationReducerCommandKind::BodyFrameFailed }
guard "body_frame_iteration_present" { body_frame_iteration != None }
guard "iteration_matches_current" {
self.loop_current_iteration.get_cloned(loop_instance_id) == body_frame_iteration
}
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Failed);
self.loop_last_completed_iteration.insert(loop_instance_id, body_frame_iteration.get("value"));
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandBodyFrameCanceled {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "body_frame_active" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::BodyFrameActive) }
guard "body_frame_canceled_command" { command == LoopIterationReducerCommandKind::BodyFrameCanceled }
guard "body_frame_iteration_present" { body_frame_iteration != None }
guard "iteration_matches_current" {
self.loop_current_iteration.get_cloned(loop_instance_id) == body_frame_iteration
}
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Canceled);
self.loop_last_completed_iteration.insert(loop_instance_id, body_frame_iteration.get("value"));
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandUntilFeedback {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "awaiting_until_evaluation" { self.loop_stage.get_cloned(loop_instance_id) == Some(LoopIterationStage::AwaitingUntilEvaluation) }
guard "blocked_use_RecordLoopUntilConditionFeedback" { false }
guard "no_body_frame_iteration" { body_frame_iteration == None }
guard "until_feedback_command" {
command == LoopIterationReducerCommandKind::UntilConditionMet
|| command == LoopIterationReducerCommandKind::UntilConditionFailed
}
update {}
to Running
emit EmitRunLifecycleNotice
}
transition AuthorizeLoopIterationReducerCommandCancelLoop {
on input AuthorizeLoopIterationReducerCommand { loop_instance_id, command, body_frame_id, body_frame_iteration }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped || self.lifecycle_phase == Phase::Completed }
guard "known_loop" { self.loop_phase.contains_key(loop_instance_id) == true }
guard "loop_running" { self.loop_phase.get_cloned(loop_instance_id) == Some(LoopStatus::Running) }
guard "cancel_loop_command" { command == LoopIterationReducerCommandKind::CancelLoop }
guard "no_body_frame_iteration" { body_frame_iteration == None }
update {
self.loop_phase.insert(loop_instance_id, LoopStatus::Canceled);
self.loop_active_body_frame.insert(loop_instance_id, None);
}
to Running
emit EmitRunLifecycleNotice
}
transition StartFlowRunning {
on signal StartFlow
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "coordinator_bound" { self.coordinator_bound == true }
update {
self.active_run_count += 1;
}
to Running
emit EmitFlowRunNotice
}
transition CreateRunRunning {
on signal CreateRun
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {
self.active_run_count += 1;
}
to Running
emit EmitRunLifecycleNotice
}
transition StartRunRunning {
on signal StartRun
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
update {
self.active_run_count += 1;
}
to Running
emit EmitRunLifecycleNotice
}
// =====================================================================
// CompleteFlow / FinishRun
// =====================================================================
//
// Two independent flow-terminalization paths drive the authority to
// the same state:
// 1. Natural completion: a run's task finishes and
// `handle_flow_cleanup` fires `CompleteFlow` + `FinishRun`
// (decrementing `active_run_count`, clearing the run-tracker).
// 2. Destroy-driven cancel: `cancel_all_flow_tasks` iterates the
// run-tracker and fires the same signals for any run that has
// not already been cleaned up.
// Because actor-command ordering is unordered between these two
// paths, they race. Whichever lands first drives
// `active_run_count` from 1 → 0; the other arrives with the counter
// already at 0. The *Zero transitions below model "CompleteFlow /
// FinishRun at count 0" as a legitimate terminal convergence
// (no-op update, same target phase) rather than as an error the
// caller must paper over — dogma requires that convergence
// semantics live in the machine authority.
transition CompleteFlowRunning {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Running }
guard "active_runs_present" { self.active_run_count > 0 }
update {
self.active_run_count -= 1;
}
to Running
emit FlowTerminalized
}
transition CompleteFlowRunningZero {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Running }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Running
emit NotifyCoordinator
}
transition FinishRunRunning {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Running }
guard "active_runs_present" { self.active_run_count > 0 }
update {
self.active_run_count -= 1;
}
to Running
emit EmitRunLifecycleNotice
}
transition FinishRunRunningZero {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Running }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Running
emit NotifyCoordinator
}
transition CompleteFlowStopped {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Stopped }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Stopped
emit FlowTerminalized
}
transition CompleteFlowStoppedZero {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Stopped }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Stopped
emit NotifyCoordinator
}
transition CompleteFlowCompleted {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Completed }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Completed
emit FlowTerminalized
}
transition CompleteFlowCompletedZero {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Completed }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Completed
emit NotifyCoordinator
}
transition CompleteFlowDestroyed {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Destroyed }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Destroyed
emit FlowTerminalized
}
transition CompleteFlowDestroyedZero {
on signal CompleteFlow
guard { self.lifecycle_phase == Phase::Destroyed }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Destroyed
emit NotifyCoordinator
}
transition FinishRunStopped {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Stopped }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Stopped
emit EmitRunLifecycleNotice
}
transition FinishRunStoppedZero {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Stopped }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Stopped
emit NotifyCoordinator
}
transition FinishRunCompleted {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Completed }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Completed
emit EmitRunLifecycleNotice
}
transition FinishRunCompletedZero {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Completed }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Completed
emit NotifyCoordinator
}
transition FinishRunDestroyed {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Destroyed }
guard "active_runs_present" { self.active_run_count > 0 }
update { self.active_run_count -= 1; }
to Destroyed
emit EmitRunLifecycleNotice
}
transition FinishRunDestroyedZero {
on signal FinishRun
guard { self.lifecycle_phase == Phase::Destroyed }
guard "no_active_runs" { self.active_run_count == 0 }
update {}
to Destroyed
emit NotifyCoordinator
}
// =====================================================================
// Retire / RetireAll
// =====================================================================
// Public retire requests carry a stable identity, while cancellation
// authority must be scoped to an exact spawn incarnation. Resolve that
// distinction entirely from canonical MobMachine maps before the shell
// performs mechanics. In particular, an identity with no committed
// runtime preserves any pending session for a later incarnation.
transition ClassifyRetirePendingSpawnDispositionCancelCommittedRunning {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "retire_identity_is_committed" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "retire_generation_is_committed" { self.identity_runtime_generations.contains_key(agent_identity) == true }
guard "retire_pending_spawn_is_present" { self.pending_spawn_sessions.contains_key(agent_identity) == true }
update {}
to Running
emit RetirePendingSpawnCancellationAuthorized {
agent_identity: agent_identity,
agent_runtime_id: self.identity_to_runtime.get_cloned(agent_identity).get("value"),
generation: self.identity_runtime_generations.get_copied(agent_identity).get("value"),
pending_spawn_session_id: self.pending_spawn_sessions.get_cloned(agent_identity).get("value")
}
}
transition ClassifyRetirePendingSpawnDispositionCancelCommittedStopped {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "retire_identity_is_committed" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "retire_generation_is_committed" { self.identity_runtime_generations.contains_key(agent_identity) == true }
guard "retire_pending_spawn_is_present" { self.pending_spawn_sessions.contains_key(agent_identity) == true }
update {}
to Stopped
emit RetirePendingSpawnCancellationAuthorized {
agent_identity: agent_identity,
agent_runtime_id: self.identity_to_runtime.get_cloned(agent_identity).get("value"),
generation: self.identity_runtime_generations.get_copied(agent_identity).get("value"),
pending_spawn_session_id: self.pending_spawn_sessions.get_cloned(agent_identity).get("value")
}
}
transition ClassifyRetirePendingSpawnDispositionCommittedWithoutPendingRunning {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "retire_identity_is_committed" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "retire_generation_is_committed" { self.identity_runtime_generations.contains_key(agent_identity) == true }
guard "retire_pending_spawn_is_absent" { self.pending_spawn_sessions.contains_key(agent_identity) == false }
update {}
to Running
emit RetireCommittedIncarnationWithoutPendingSpawnResolved {
agent_identity: agent_identity,
agent_runtime_id: self.identity_to_runtime.get_cloned(agent_identity).get("value"),
generation: self.identity_runtime_generations.get_copied(agent_identity).get("value")
}
}
transition ClassifyRetirePendingSpawnDispositionCommittedWithoutPendingStopped {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "retire_identity_is_committed" { self.identity_to_runtime.contains_key(agent_identity) == true }
guard "retire_generation_is_committed" { self.identity_runtime_generations.contains_key(agent_identity) == true }
guard "retire_pending_spawn_is_absent" { self.pending_spawn_sessions.contains_key(agent_identity) == false }
update {}
to Stopped
emit RetireCommittedIncarnationWithoutPendingSpawnResolved {
agent_identity: agent_identity,
agent_runtime_id: self.identity_to_runtime.get_cloned(agent_identity).get("value"),
generation: self.identity_runtime_generations.get_copied(agent_identity).get("value")
}
}
transition ClassifyRetirePendingSpawnDispositionPreserveAbsentRunning {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "retire_identity_is_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Running
emit RetireAbsentPendingSpawnPreservationResolved { agent_identity: agent_identity }
}
transition ClassifyRetirePendingSpawnDispositionPreserveAbsentStopped {
on input ClassifyRetirePendingSpawnDisposition { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "retire_identity_is_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Stopped
emit RetireAbsentPendingSpawnPreservationResolved { agent_identity: agent_identity }
}
transition RetireRunningReleasing {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_session_bindings.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedReleasing,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: Some(releasing.get("value")), new_session_id: None }
// 0.7.2 L5: member retire opens the kickoff-waiter drain
// obligation; archival is guarded on its closure.
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// Multi-host (§19.L2): retire of a placed member releases it via the
// host-addressed verb. No local runtime retire and no local
// session-ingress detach obligation — the member host owns both; the
// archival observation (typed disposal from the MemberReleased ack)
// closes the retirement.
transition RetireRemoteReleasingRunning {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
// Preserve the exact host session until ReleaseMember has
// durably confirmed pruning and controller custody is
// disposed. The peer endpoint is part of that exact placed
// incarnation authority and remains present for the same
// reason; archive-confirmed terminalization clears both.
self.member_restore_failures.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestMemberRelease {
agent_identity: agent_identity,
generation: generation,
fence_token: self.identity_runtime_fence_tokens.get_copied(agent_identity).get("value"),
host: self.member_placement.get_cloned(agent_identity).get("value")
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireRemoteConfirmedRevokedRunning {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_confirmed_revoked" {
mob_machine_placed_carrier_binding_confirmed_revoked(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.confirmed_host_binding_revocations, agent_identity)
}
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.member_restore_failures.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.topology_epoch += 1;
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireRunningPreservingBinding {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_absent" { releasing == None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireRunningNoBinding {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Running }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "releasing_absent" { releasing == None }
guard "session_absent" { session_id == None }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Running
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPeerOnly,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireStoppedReleasing {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_session_bindings.remove(agent_identity);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.pending_session_ingress_detach_runtime_ids.insert(agent_runtime_id);
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedReleasing,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
emit MemberSessionBindingChanged { epoch: self.topology_epoch, agent_identity: agent_identity, old_session_id: Some(releasing.get("value")), new_session_id: None }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
// MobMachine does not own a mob-id field, so feedback `mob_id` and
// failure `reason` remain protocol payload. The machine-owned check is
// the pending-detach runtime id opened by the Retire transition.
transition RequestPendingSessionIngressDetachForMobDestroyRunning {
on input RequestPendingSessionIngressDetachForMobDestroy { mob_id, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Running }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {}
to Running
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
}
transition RequestPendingSessionIngressDetachForMobDestroyStopped {
on input RequestPendingSessionIngressDetachForMobDestroy { mob_id, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {}
to Stopped
emit RequestSessionIngressDetachForMobDestroy { mob_id: mob_id, agent_runtime_id: agent_runtime_id }
}
transition SessionIngressDetachedForMobDestroyRunning {
on input SessionIngressDetachedForMobDestroy { mob_id, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Running }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {
self.pending_session_ingress_detach_runtime_ids.remove(agent_runtime_id);
}
to Running
}
transition SessionIngressDetachedForMobDestroyStopped {
on input SessionIngressDetachedForMobDestroy { mob_id, agent_runtime_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {
self.pending_session_ingress_detach_runtime_ids.remove(agent_runtime_id);
}
to Stopped
}
transition SessionIngressDetachFailedForMobDestroyRunning {
on input SessionIngressDetachFailedForMobDestroy { mob_id, agent_runtime_id, reason }
guard { self.lifecycle_phase == Phase::Running }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {}
to Running
}
transition SessionIngressDetachFailedForMobDestroyStopped {
on input SessionIngressDetachFailedForMobDestroy { mob_id, agent_runtime_id, reason }
guard { self.lifecycle_phase == Phase::Stopped }
guard "pending_detach_present" { self.pending_session_ingress_detach_runtime_ids.contains(agent_runtime_id) == true }
update {}
to Stopped
}
// Multi-host (§19.L2): the Stopped-phase sibling of
// RetireRemoteReleasingRunning.
transition RetireRemoteReleasingStopped {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_active" {
mob_machine_placed_carrier_binding_active(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.host_binding_generations, agent_identity)
}
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
// Same proof ordering as the Running sibling: host release
// and custody disposal precede session/endpoint removal.
self.member_restore_failures.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestMemberRelease {
agent_identity: agent_identity,
generation: generation,
fence_token: self.identity_runtime_fence_tokens.get_copied(agent_identity).get("value"),
host: self.member_placement.get_cloned(agent_identity).get("value")
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireRemoteConfirmedRevokedStopped {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "placement_present" { self.member_placement.contains_key(agent_identity) == true }
guard "placed_carrier_binding_confirmed_revoked" {
mob_machine_placed_carrier_binding_confirmed_revoked(self.member_placement, self.current_placed_spawn_host_binding_generations, self.host_bind_phase, self.confirmed_host_binding_revocations, agent_identity)
}
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_present" { releasing != None }
guard "releasing_matches_current" { self.member_session_bindings.get_cloned(agent_identity) == Some(releasing.get("value")) }
guard "session_matches_releasing" { session_id == releasing }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.member_restore_failures.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
self.topology_epoch += 1;
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireStoppedPreservingBinding {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "placement_absent" { self.member_placement.contains_key(agent_identity) == false }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "prior_session_binding_present" { self.member_session_bindings.contains_key(agent_identity) == true }
guard "releasing_absent" { releasing == None }
guard "session_binding_matches" { self.member_session_bindings.get_cloned(agent_identity) == session_id }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.insert(agent_runtime_id, session_id.get("value"));
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPreservingBinding,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: session_id
}
emit RequestRuntimeRetire { agent_identity: agent_identity, agent_runtime_id: agent_runtime_id, session_id: session_id.get("value") }
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireStoppedNoBinding {
on input Retire { mob_id, agent_runtime_id, agent_identity, generation, releasing, session_id }
guard { self.lifecycle_phase == Phase::Stopped }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "generation_matches" { self.identity_runtime_generations.get_copied(agent_identity) == Some(generation) }
guard "no_prior_session_binding" { self.member_session_bindings.contains_key(agent_identity) == false }
guard "retirement_session_absent" { self.runtime_retire_pending_sessions.contains_key(agent_runtime_id) == false }
guard "releasing_absent" { releasing == None }
guard "session_absent" { session_id == None }
update {
self.member_state_markers.insert(agent_runtime_id, MobMemberState::Retiring);
self.runtime_retire_pending_sessions.remove(agent_runtime_id);
self.member_restore_failures.remove(agent_identity);
self.member_restore_failure_codes.remove(agent_identity);
self.member_revival_pending.remove(agent_identity);
}
to Stopped
emit AppendLifecycleJournal {
kind: MobLifecycleJournalKind::MemberRetirementStartedPeerOnly,
agent_identity: Some(agent_identity),
agent_runtime_id: Some(agent_runtime_id),
fence_token: None,
generation: Some(generation),
session_id: None
}
emit RequestKickoffQuiesce { member_id: agent_identity }
}
transition RetireAbsentRunning {
on input RetireAbsent { agent_identity }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Running
}
transition RetireAbsentStopped {
on input RetireAbsent { agent_identity }
guard { self.lifecycle_phase == Phase::Stopped }
guard "identity_absent" { self.identity_to_runtime.contains_key(agent_identity) == false }
update {}
to Stopped
}
transition RetireAllRunning {
on input RetireAll
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Running }
update {}
to Running
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retiring }
}
transition RetireAllStopped {
on input RetireAll
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retiring }
}
transition RetireAllCompleted {
on input RetireAll
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Completed
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Retiring }
}
// =====================================================================
// CompleteSpawn
// =====================================================================
transition CompleteSpawnRunning {
on signal CompleteSpawn { agent_identity }
guard { self.lifecycle_phase == Phase::Running || self.lifecycle_phase == Phase::Stopped }
guard "pending_spawns_present" { self.pending_spawn_count > 0 }
guard "pending_identity_present" { self.pending_spawn_sessions.contains_key(agent_identity) == true }
update {
self.pending_spawn_count -= 1;
self.pending_spawn_sessions.remove(agent_identity);
}
to Running
emit EmitMemberLifecycleNotice { kind: MemberLifecycleKind::Spawned }
}
// 0.7.2 L5 D2a (row 14): a spawn completion that arrives after its
// pending slot was already closed (teardown drained it, or a destroy
// retry re-observes a completion) is a legitimate late arrival, not a
// shell error. Accepted as an explicit typed no-op.
transition CompleteSpawnLateArrival {
per_phase [Running, Stopped, Completed]
on signal CompleteSpawn { agent_identity }
guard "pending_identity_absent" { self.pending_spawn_sessions.contains_key(agent_identity) == false }
update {}
to Running
}
transition CompleteSpawnDestroyed {
on signal CompleteSpawn { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// =====================================================================
// CancelPendingSpawn — 0.7.2 L5 (row 14)
//
// Typed teardown closure for an in-flight pending spawn. Fired by the
// shell while discharging `RequestPendingSpawnQuiesceForDestroy` (and
// by member-scoped pending-spawn cancellation), after the provisioning
// waiter task was aborted + awaited and its waiters failed with a
// typed cancellation. Replaces the former laundering of teardown
// cancellation through the `CompleteSpawn` success signal (which
// emitted a `Spawned` lifecycle notice for a spawn that never landed).
// Total: absent identities and the Destroyed phase are accepted
// no-ops so re-drains are idempotent.
// =====================================================================
transition CancelPendingSpawnPresent {
per_phase [Running, Stopped, Completed]
on input CancelPendingSpawn { agent_identity }
guard "pending_spawns_present" { self.pending_spawn_count > 0 }
guard "pending_identity_present" { self.pending_spawn_sessions.contains_key(agent_identity) == true }
update {
self.pending_spawn_count -= 1;
self.pending_spawn_sessions.remove(agent_identity);
}
to Running
}
transition CancelPendingSpawnAbsent {
per_phase [Running, Stopped, Completed]
on input CancelPendingSpawn { agent_identity }
guard "pending_identity_absent" { self.pending_spawn_sessions.contains_key(agent_identity) == false }
update {}
to Running
}
transition CancelPendingSpawnDestroyed {
on input CancelPendingSpawn { agent_identity }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
}
// =====================================================================
// Destroy (input)
// =====================================================================
transition DestroyFromAny {
on input Destroy
guard "adaptive_lifecycle_drained" {
mob_machine_adaptive_lifecycle_drained(
self.adaptive_active_run,
self.adaptive_active_layer,
self.adaptive_active_members,
self.adaptive_layer_phase,
self.adaptive_layer_disposition)
}
guard {
self.lifecycle_phase == Phase::Running
|| self.lifecycle_phase == Phase::Stopped
|| self.lifecycle_phase == Phase::Completed
}
guard "session_ingress_detaches_closed" { self.pending_session_ingress_detach_runtime_ids == EmptySet }
guard "placed_completion_quiesce_started" { self.placed_completion_lifecycle_quiescing == true }
guard "placed_completion_destroy_intent" { self.placed_completion_lifecycle_intent == Some(PlacedCompletionLifecycleIntentKind::Destroy) }
guard "remote_turn_pending_drained" { self.pending_remote_turn_outcomes == EmptySet }
guard "remote_turn_committed_drained" { self.committed_remote_turn_outcomes == EmptySet }
guard "remote_turn_resolved_drained" { self.resolved_remote_turn_outcomes == EmptySet }
guard "placed_completion_pending_drained" { self.pending_placed_completion_outcomes == EmptySet }
guard "placed_completion_cancel_requested_drained" { self.cancel_requested_placed_completion_outcomes == EmptySet }
guard "placed_completion_resolved_drained" { self.resolved_placed_completion_outcomes == EmptySet }
guard "placed_kickoff_pending_drained" { self.pending_placed_kickoff_outcomes == EmptySet }
guard "placed_kickoff_resolved_drained" { self.resolved_placed_kickoff_outcomes == EmptySet }
guard "host_bind_phases_drained" { self.host_bind_phase == EmptyMap }
guard "replacement_host_bind_requests_drained" {
self.replacement_host_bind_endpoints == EmptyMap
&& self.replacement_host_binding_generations == EmptyMap
}
guard "bound_hosts_drained" { self.mob_hosts == EmptySet }
guard "host_authority_epochs_drained" { self.host_authority_epochs == EmptyMap }
guard "host_public_keys_drained" { self.host_public_keys == EmptyMap }
guard "host_endpoints_drained" { self.host_endpoints == EmptyMap }
guard "host_live_endpoints_drained" { self.host_live_endpoints == EmptyMap }
guard "placed_carrier_cleanup_drained" { self.pending_placed_carrier_cleanup == EmptySet }
guard "pending_placed_spawns_drained" { self.pending_placed_spawn_ids == EmptyMap }
guard "committed_placed_spawns_drained" { self.current_placed_spawn_ids == EmptyMap }
// 0.7.2 L5: same teardown-completion gating as `DestroyMob` — no
// in-flight kickoff waiters, pending-spawn obligations closed via
// typed `CancelPendingSpawn` instead of a silent wipe.
guard "kickoff_waiters_quiesced" {
self.member_kickoff_pending == EmptySet
&& self.member_kickoff_starting == EmptySet
&& self.member_kickoff_callback_pending == EmptySet
}
guard "pending_spawns_drained" {
self.pending_spawn_count == 0
&& self.pending_spawn_sessions == EmptyMap
}
update {
self.destroy_admitted = true;
self.live_runtime_ids = EmptySet;
self.externally_addressable_runtime_ids = EmptySet;
self.runtime_fence_tokens = EmptyMap;
self.wiring_edges = EmptySet;
self.pending_respawn_topology = EmptySet;
self.abandoned_respawn_topology = EmptyMap;
self.external_peer_edges = EmptySet;
self.external_peer_edges_by_key = EmptyMap;
self.identity_to_runtime = EmptyMap;
self.identity_runtime_generations = EmptyMap;
self.identity_runtime_fence_tokens = EmptyMap;
self.member_session_bindings = EmptyMap;
self.member_profile_names = EmptyMap;
self.member_runtime_modes = EmptyMap;
self.member_peer_ids = EmptyMap;
self.member_peer_endpoints = EmptyMap;
self.member_prior_peer_endpoints = EmptyMap;
self.runtime_retire_refusal_codes = EmptyMap;
self.runtime_retire_refusal_reasons = EmptyMap;
self.runtime_retire_pending_sessions = EmptyMap;
self.pending_session_ingress_detach_runtime_ids = EmptySet;
self.active_run_count = 0;
self.coordinator_bound = false;
}
to Destroyed
}
// =====================================================================
// Respawn (input, Running self-loop)
// =====================================================================
transition RespawnRunning {
on input Respawn { agent_runtime_id }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "runtime_id_present" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "coordinator_bound" { self.coordinator_bound == true }
update {}
to Running
emit ExposePendingSpawn
}
// =====================================================================
// CancelAllWork
// =====================================================================
transition CancelAllWorkRunning {
on input CancelAllWork { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "active_members_present" { self.live_runtime_ids != EmptySet }
guard "identity_binding_matches" { self.identity_to_runtime.get_cloned(agent_identity) == Some(agent_runtime_id) }
guard "current_binding_matches" { self.live_runtime_ids.contains(agent_runtime_id) }
guard "fence_token_matches" { self.runtime_fence_tokens.get_copied(agent_runtime_id) == Some(fence_token) }
update {
self.active_run_count = 0;
}
to Running
emit FlowTerminalized
}
transition ResolveCancelAllWorkRejectionStopped {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Stopped }
update {}
to Stopped
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveCancelAllWorkRejectionCompleted {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Completed }
update {}
to Completed
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveCancelAllWorkRejectionDestroyed {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Destroyed }
update {}
to Destroyed
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::MobNotRunning,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveCancelAllWorkRejectionMemberNotFound {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_absent" { !self.identity_to_runtime.contains_key(agent_identity) }
update {}
to Running
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::MemberNotFound,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveCancelAllWorkRejectionCurrentRuntimeNotLive {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) }
guard "current_runtime_not_live" { !self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
update {}
to Running
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::MemberNotFound,
expected_fence_token: None,
actual_fence_token: None
}
}
transition ResolveCancelAllWorkRejectionStaleFenceToken {
on input ResolveCancelAllWorkRejection { agent_identity, agent_runtime_id, fence_token }
guard { self.lifecycle_phase == Phase::Running }
guard "identity_present" { self.identity_to_runtime.contains_key(agent_identity) }
guard "current_runtime_live" { self.live_runtime_ids.contains(self.identity_to_runtime.get_cloned(agent_identity).get("value")) }
guard "runtime_or_fence_stale" {
self.identity_to_runtime.get_cloned(agent_identity) != Some(agent_runtime_id)
|| self.runtime_fence_tokens.get_copied(self.identity_to_runtime.get_cloned(agent_identity).get("value")) != Some(fence_token)
}
update {}
to Running
emit CancelAllWorkRejected {
agent_runtime_id: agent_runtime_id,
reason: CancelAllWorkRejectReasonKind::StaleFenceToken,
expected_fence_token: self.runtime_fence_tokens.get_copied(self.identity_to_runtime.get_cloned(agent_identity).get("value")),
actual_fence_token: Some(fence_token)
}
}
// =====================================================================
// Mob coordination board transitions (folded from the former
// standalone MobCoordinationLifecycleAuthorityMachine). MobMachine owns
// the records; every conclusion is recomputed in-DSL from owned maps +
// raw caller facts. No pre-reduced inputs.
// =====================================================================
// Admission: !exists && summary_present && metadata_public &&
// draft_mob_id == authority_mob_id && resources non-empty && owner
// present. Revision is the machine-owned initial revision (1); the
// event sequence is the machine-owned monotonic cursor.
transition RecordCoordinationWorkIntent {
on input RecordCoordinationWorkIntent {
intent_id,
requested_status,
owner_present,
summary_present,
metadata_public,
draft_mob_id,
authority_mob_id,
resource_tokens,
expires_at_ms,
}
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "intent_is_new" { self.work_intent_status.contains_key(intent_id) == false }
guard "summary_present" { summary_present == true }
guard "metadata_public" { metadata_public == true }
guard "owning_mob_ref_matches" { draft_mob_id == authority_mob_id }
guard "resources_non_empty" { resource_tokens.len() > 0 }
guard "owner_present" { owner_present == true }
update {
self.work_intent_status.insert(intent_id, requested_status);
self.work_intent_revision.insert(intent_id, 1);
self.work_intent_resources.insert(intent_id, resource_tokens);
self.work_intent_owner_present.insert(intent_id, owner_present);
self.work_intent_expires_at_ms.insert(intent_id, expires_at_ms);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentRecorded {
intent_id: intent_id,
status: requested_status,
revision: 1,
resource_tokens: resource_tokens,
expires_at_ms: expires_at_ms,
event_kind: MobCoordinationEventKind::WorkIntentRecorded,
sequence: self.coordination_event_next_sequence
}
}
transition RecordCoordinationResourceClaim {
on input RecordCoordinationResourceClaim {
claim_id,
requested_kind,
requested_status,
owner_present,
metadata_public,
draft_mob_id,
authority_mob_id,
resource_tokens,
expires_at_ms,
}
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "claim_is_new" { self.resource_claim_status.contains_key(claim_id) == false }
guard "metadata_public" { metadata_public == true }
guard "owning_mob_ref_matches" { draft_mob_id == authority_mob_id }
guard "resources_non_empty" { resource_tokens.len() > 0 }
guard "owner_present" { owner_present == true }
update {
self.resource_claim_status.insert(claim_id, requested_status);
self.resource_claim_kind.insert(claim_id, requested_kind);
self.resource_claim_revision.insert(claim_id, 1);
self.resource_claim_resources.insert(claim_id, resource_tokens);
self.resource_claim_owner_present.insert(claim_id, owner_present);
self.resource_claim_expires_at_ms.insert(claim_id, expires_at_ms);
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimRecorded {
claim_id: claim_id,
kind: requested_kind,
status: requested_status,
revision: 1,
resource_tokens: resource_tokens,
expires_at_ms: expires_at_ms,
event_kind: MobCoordinationEventKind::ResourceClaimRecorded,
sequence: self.coordination_event_next_sequence
}
}
// Work intent status update: revision CAS against the machine-owned
// stored revision; emit stored+1. Terminal targets (Completed,
// Cancelled) are always legal; live targets (Planned, Active, Blocked)
// require the record not be expired — the expiry conclusion is computed
// in-DSL from the stored expiry + the raw now_ms input.
transition UpdateCoordinationWorkIntentPlanned {
on input UpdateCoordinationWorkIntentStatus { intent_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "intent_present" { self.work_intent_status.contains_key(intent_id) }
guard "revision_cas" {
self.work_intent_revision.get_copied(intent_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_planned" { requested_status == MobCoordinationWorkIntentStatus::Planned }
guard "not_expired" {
mob_coordination_work_intent_unexpired(self.work_intent_expires_at_ms.get_cloned(intent_id).get("value"), now_ms)
}
update {
self.work_intent_status.insert(intent_id, MobCoordinationWorkIntentStatus::Planned);
self.work_intent_revision.insert(intent_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentStatusChanged {
intent_id: intent_id,
status: MobCoordinationWorkIntentStatus::Planned,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::WorkIntentStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationWorkIntentActive {
on input UpdateCoordinationWorkIntentStatus { intent_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "intent_present" { self.work_intent_status.contains_key(intent_id) }
guard "revision_cas" {
self.work_intent_revision.get_copied(intent_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_active" { requested_status == MobCoordinationWorkIntentStatus::Active }
guard "not_expired" {
mob_coordination_work_intent_unexpired(self.work_intent_expires_at_ms.get_cloned(intent_id).get("value"), now_ms)
}
update {
self.work_intent_status.insert(intent_id, MobCoordinationWorkIntentStatus::Active);
self.work_intent_revision.insert(intent_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentStatusChanged {
intent_id: intent_id,
status: MobCoordinationWorkIntentStatus::Active,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::WorkIntentStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationWorkIntentBlocked {
on input UpdateCoordinationWorkIntentStatus { intent_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "intent_present" { self.work_intent_status.contains_key(intent_id) }
guard "revision_cas" {
self.work_intent_revision.get_copied(intent_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_blocked" { requested_status == MobCoordinationWorkIntentStatus::Blocked }
guard "not_expired" {
mob_coordination_work_intent_unexpired(self.work_intent_expires_at_ms.get_cloned(intent_id).get("value"), now_ms)
}
update {
self.work_intent_status.insert(intent_id, MobCoordinationWorkIntentStatus::Blocked);
self.work_intent_revision.insert(intent_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentStatusChanged {
intent_id: intent_id,
status: MobCoordinationWorkIntentStatus::Blocked,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::WorkIntentStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationWorkIntentCompleted {
on input UpdateCoordinationWorkIntentStatus { intent_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "intent_present" { self.work_intent_status.contains_key(intent_id) }
guard "revision_cas" {
self.work_intent_revision.get_copied(intent_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_completed" { requested_status == MobCoordinationWorkIntentStatus::Completed }
update {
self.work_intent_status.insert(intent_id, MobCoordinationWorkIntentStatus::Completed);
self.work_intent_revision.insert(intent_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentStatusChanged {
intent_id: intent_id,
status: MobCoordinationWorkIntentStatus::Completed,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::WorkIntentStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationWorkIntentCancelled {
on input UpdateCoordinationWorkIntentStatus { intent_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "intent_present" { self.work_intent_status.contains_key(intent_id) }
guard "revision_cas" {
self.work_intent_revision.get_copied(intent_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_cancelled" { requested_status == MobCoordinationWorkIntentStatus::Cancelled }
update {
self.work_intent_status.insert(intent_id, MobCoordinationWorkIntentStatus::Cancelled);
self.work_intent_revision.insert(intent_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit WorkIntentStatusChanged {
intent_id: intent_id,
status: MobCoordinationWorkIntentStatus::Cancelled,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::WorkIntentStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
// Resource claim status update: revision CAS; Released/Expired/Cancelled
// are terminal targets (always legal); Active requires not expired.
transition UpdateCoordinationResourceClaimActive {
on input UpdateCoordinationResourceClaimStatus { claim_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "lifecycle_origin_open" { self.placed_completion_lifecycle_quiescing == false }
guard "claim_present" { self.resource_claim_status.contains_key(claim_id) }
guard "revision_cas" {
self.resource_claim_revision.get_copied(claim_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_active" { requested_status == MobCoordinationResourceClaimStatus::Active }
guard "not_expired" {
mob_coordination_resource_claim_unexpired(self.resource_claim_expires_at_ms.get_cloned(claim_id).get("value"), now_ms)
}
update {
self.resource_claim_status.insert(claim_id, MobCoordinationResourceClaimStatus::Active);
self.resource_claim_revision.insert(claim_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimStatusChanged {
claim_id: claim_id,
status: MobCoordinationResourceClaimStatus::Active,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::ResourceClaimStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationResourceClaimReleased {
on input UpdateCoordinationResourceClaimStatus { claim_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "claim_present" { self.resource_claim_status.contains_key(claim_id) }
guard "revision_cas" {
self.resource_claim_revision.get_copied(claim_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_released" { requested_status == MobCoordinationResourceClaimStatus::Released }
update {
self.resource_claim_status.insert(claim_id, MobCoordinationResourceClaimStatus::Released);
self.resource_claim_revision.insert(claim_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimStatusChanged {
claim_id: claim_id,
status: MobCoordinationResourceClaimStatus::Released,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::ResourceClaimStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationResourceClaimExpired {
on input UpdateCoordinationResourceClaimStatus { claim_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "claim_present" { self.resource_claim_status.contains_key(claim_id) }
guard "revision_cas" {
self.resource_claim_revision.get_copied(claim_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_expired" { requested_status == MobCoordinationResourceClaimStatus::Expired }
update {
self.resource_claim_status.insert(claim_id, MobCoordinationResourceClaimStatus::Expired);
self.resource_claim_revision.insert(claim_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimStatusChanged {
claim_id: claim_id,
status: MobCoordinationResourceClaimStatus::Expired,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::ResourceClaimStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
transition UpdateCoordinationResourceClaimCancelled {
on input UpdateCoordinationResourceClaimStatus { claim_id, expected_revision, requested_status, now_ms }
guard { self.lifecycle_phase == Phase::Running }
guard "claim_present" { self.resource_claim_status.contains_key(claim_id) }
guard "revision_cas" {
self.resource_claim_revision.get_copied(claim_id) == Some(expected_revision)
&& expected_revision > 0
}
guard "target_is_cancelled" { requested_status == MobCoordinationResourceClaimStatus::Cancelled }
update {
self.resource_claim_status.insert(claim_id, MobCoordinationResourceClaimStatus::Cancelled);
self.resource_claim_revision.insert(claim_id, expected_revision + 1);
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimStatusChanged {
claim_id: claim_id,
status: MobCoordinationResourceClaimStatus::Cancelled,
revision: expected_revision + 1,
event_kind: MobCoordinationEventKind::ResourceClaimStatusChanged,
sequence: self.coordination_event_next_sequence
}
}
// Overlap observation. The caller proposes `candidate_overlap_ids`;
// MobMachine REVALIDATES it against its own state and rejects any wrong
// set. The proposed set is exactly the active resource claims (other
// than the target) whose affected resources intersect the target's.
// (a) every proposed id is a DIFFERENT, present, active claim whose
// resources intersect the target's;
// (b) no omitted present active claim (other than the target) overlaps
// the target — i.e. every such claim must appear in the proposal.
transition ObserveCoordinationResourceClaimOverlap {
on input ObserveCoordinationResourceClaimOverlap { claim_id, now_ms, candidate_overlap_ids }
guard { self.lifecycle_phase == Phase::Running }
guard "claim_present" { self.resource_claim_status.contains_key(claim_id) }
guard "candidates_are_valid_overlaps" {
for_all(cid in candidate_overlap_ids,
cid != claim_id
&& self.resource_claim_status.contains_key(cid)
&& mob_coordination_resource_claim_active_at(
self.resource_claim_status.get_cloned(cid).get("value"),
self.resource_claim_expires_at_ms.get_cloned(cid).get("value"),
now_ms)
&& exists(r in self.resource_claim_resources.get_cloned(cid).get("value"),
self.resource_claim_resources.get_cloned(claim_id).get("value").contains(r)))
}
guard "no_omitted_overlap" {
for_all(other in self.resource_claim_status.keys(),
other == claim_id
|| mob_coordination_resource_claim_inactive_at(
self.resource_claim_status.get_cloned(other).get("value"),
self.resource_claim_expires_at_ms.get_cloned(other).get("value"),
now_ms)
|| !exists(r in self.resource_claim_resources.get_cloned(other).get("value"),
self.resource_claim_resources.get_cloned(claim_id).get("value").contains(r))
|| candidate_overlap_ids.contains(other))
}
update {
self.coordination_event_next_sequence += 1;
}
to Running
emit ResourceClaimOverlapObserved {
claim_id: claim_id,
overlap_ids: candidate_overlap_ids,
event_kind: MobCoordinationEventKind::ResourceClaimOverlapObserved,
sequence: self.coordination_event_next_sequence
}
}
}
}
impl MobMachineAuthority {
fn mob_machine_remote_turn_custody_admits(
pending: &std::collections::BTreeSet<RemoteTurnObligation>,
committed: &std::collections::BTreeSet<RemoteTurnObligation>,
resolved: &std::collections::BTreeSet<RemoteTurnObligation>,
candidate: &RemoteTurnObligation,
) -> bool {
const PER_MEMBER_HOST_LIMIT: usize = 256;
const GLOBAL_LIMIT: usize = 4096;
let total = pending.len() + committed.len() + resolved.len();
if total >= GLOBAL_LIMIT
|| candidate.dispatch_sequence == 0
|| candidate.input_id.0.is_empty()
|| candidate.run_id.0.is_empty()
|| candidate.step_id.0.is_empty()
|| candidate.host_id.0.is_empty()
|| candidate.member_session_id.0.is_empty()
{
return false;
}
let rows = pending.iter().chain(committed).chain(resolved);
let mut same_member_host = 0usize;
for row in rows {
if row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
{
same_member_host += 1;
}
if row.dispatch_sequence == candidate.dispatch_sequence
|| (row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
&& row.generation == candidate.generation
&& row.fence_token == candidate.fence_token
&& row.input_id == candidate.input_id)
{
return false;
}
}
same_member_host < PER_MEMBER_HOST_LIMIT
}
// Native catalog helpers mirror the generated guard ABI exactly; the
// independently-owned kickoff custody facts cannot be collapsed into
// a shell-side aggregate without hiding authority from codegen/TLA.
#[allow(clippy::too_many_arguments)]
fn mob_machine_finalized_placed_kickoff_recovery_well_formed(
started: &std::collections::BTreeSet<AgentIdentity>,
callback_pending: &std::collections::BTreeSet<AgentIdentity>,
failed: &std::collections::BTreeSet<AgentIdentity>,
cancelled: &std::collections::BTreeSet<AgentIdentity>,
kickoff_errors: &std::collections::BTreeMap<AgentIdentity, String>,
identity: &AgentIdentity,
outcome_kind: &PlacedKickoffOutcomeKind,
outcome_error: &Option<String>,
closure_kind: &PlacedKickoffClosureKind,
) -> bool {
let terminal_count = usize::from(started.contains(identity))
+ usize::from(callback_pending.contains(identity))
+ usize::from(failed.contains(identity))
+ usize::from(cancelled.contains(identity));
if terminal_count != 1 {
return false;
}
let outcome_error_valid = match *outcome_kind {
PlacedKickoffOutcomeKind::Failed => outcome_error.is_some(),
PlacedKickoffOutcomeKind::RejectedNoEffect => {
outcome_error.as_ref().is_some_and(|error| !error.is_empty())
}
PlacedKickoffOutcomeKind::Started
| PlacedKickoffOutcomeKind::CallbackPending
| PlacedKickoffOutcomeKind::Cancelled
| PlacedKickoffOutcomeKind::Disposed => outcome_error.is_none(),
};
if !outcome_error_valid {
return false;
}
let closure_valid = match *closure_kind {
PlacedKickoffClosureKind::Acknowledged => !matches!(
*outcome_kind,
PlacedKickoffOutcomeKind::RejectedNoEffect
| PlacedKickoffOutcomeKind::Disposed
),
PlacedKickoffClosureKind::RejectedNoEffect => {
*outcome_kind == PlacedKickoffOutcomeKind::RejectedNoEffect
}
PlacedKickoffClosureKind::Disposed => {
*outcome_kind != PlacedKickoffOutcomeKind::RejectedNoEffect
}
};
if !closure_valid {
return false;
}
if cancelled.contains(identity) {
return !kickoff_errors.contains_key(identity);
}
if started.contains(identity) {
return *outcome_kind == PlacedKickoffOutcomeKind::Started
&& !kickoff_errors.contains_key(identity);
}
if callback_pending.contains(identity) {
return *outcome_kind == PlacedKickoffOutcomeKind::CallbackPending
&& !kickoff_errors.contains_key(identity);
}
failed.contains(identity)
&& matches!(
*outcome_kind,
PlacedKickoffOutcomeKind::Failed
| PlacedKickoffOutcomeKind::RejectedNoEffect
)
&& kickoff_errors.get(identity) == outcome_error.as_ref()
}
fn mob_machine_placed_kickoff_obligation_well_formed(
candidate: &PlacedKickoffObligation,
) -> bool {
let canonical_uuid = |raw: &str| {
uuid::Uuid::parse_str(raw)
.is_ok_and(|parsed| !parsed.is_nil() && parsed.to_string() == raw)
};
!candidate.agent_identity.0.is_empty()
&& !candidate.host_id.0.is_empty()
&& candidate.host_binding_generation > 0
&& !candidate.member_session_id.0.is_empty()
&& canonical_uuid(&candidate.input_id.0)
&& canonical_uuid(&candidate.objective_id)
}
fn mob_machine_placed_completion_obligation_well_formed(
candidate: &PlacedCompletionObligation,
) -> bool {
let canonical_uuid = |raw: &str| {
uuid::Uuid::parse_str(raw)
.is_ok_and(|parsed| !parsed.is_nil() && parsed.to_string() == raw)
};
!candidate.agent_identity.0.is_empty()
&& !candidate.host_id.0.is_empty()
&& candidate.host_binding_generation > 0
&& !candidate.member_session_id.0.is_empty()
&& candidate.dispatch_sequence > 0
&& canonical_uuid(&candidate.input_id.0)
}
fn mob_machine_adaptive_lifecycle_drained(
active_run: &Option<AdaptiveRunId>,
active_layer: &std::collections::BTreeMap<AdaptiveRunId, AdaptiveLayerId>,
active_members: &std::collections::BTreeMap<AdaptiveRunId, u64>,
layer_phases: &std::collections::BTreeMap<AdaptiveLayerId, AdaptiveLayerPhase>,
layer_dispositions: &std::collections::BTreeMap<AdaptiveLayerId, AdaptiveLayerDispositionKind>,
) -> bool {
active_run.is_none()
&& active_layer.is_empty()
&& active_members.values().all(|count| *count == 0)
&& layer_phases.iter().all(|(layer_id, phase)| {
*phase == AdaptiveLayerPhase::Validating
|| (layer_dispositions.contains_key(layer_id)
&& matches!(
phase,
AdaptiveLayerPhase::Completed
| AdaptiveLayerPhase::SetupFailed
| AdaptiveLayerPhase::RunFailed
| AdaptiveLayerPhase::ResultInvalid
| AdaptiveLayerPhase::Canceled
))
})
}
fn mob_machine_adaptive_run_custody_drained(
adaptive_run_id: &AdaptiveRunId,
active_layer: &std::collections::BTreeMap<AdaptiveRunId, AdaptiveLayerId>,
active_members: &std::collections::BTreeMap<AdaptiveRunId, u64>,
layer_run: &std::collections::BTreeMap<AdaptiveLayerId, AdaptiveRunId>,
layer_phases: &std::collections::BTreeMap<AdaptiveLayerId, AdaptiveLayerPhase>,
layer_dispositions: &std::collections::BTreeMap<AdaptiveLayerId, AdaptiveLayerDispositionKind>,
) -> bool {
!active_layer.contains_key(adaptive_run_id)
&& active_members.get(adaptive_run_id).copied().unwrap_or_default() == 0
&& layer_run.iter().all(|(layer_id, owner_run_id)| {
owner_run_id != adaptive_run_id
|| (layer_dispositions.contains_key(layer_id)
&& layer_phases.get(layer_id).is_some_and(|phase| {
matches!(
phase,
AdaptiveLayerPhase::Completed
| AdaptiveLayerPhase::SetupFailed
| AdaptiveLayerPhase::RunFailed
| AdaptiveLayerPhase::ResultInvalid
| AdaptiveLayerPhase::Canceled
)
}))
})
}
fn mob_machine_placed_completion_custody_admits(
pending: &std::collections::BTreeSet<PlacedCompletionObligation>,
resolved: &std::collections::BTreeSet<PlacedCompletionObligation>,
candidate: &PlacedCompletionObligation,
) -> bool {
const PER_MEMBER_HOST_LIMIT: usize = 256;
const GLOBAL_LIMIT: usize = 4096;
if pending.len() + resolved.len() >= GLOBAL_LIMIT {
return false;
}
let mut same_member_host = 0usize;
for row in pending.iter().chain(resolved) {
if row.dispatch_sequence == candidate.dispatch_sequence
|| (row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
&& row.generation == candidate.generation
&& row.fence_token == candidate.fence_token
&& row.input_id == candidate.input_id)
{
return false;
}
if row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
{
same_member_host += 1;
}
}
same_member_host < PER_MEMBER_HOST_LIMIT
}
#[allow(clippy::too_many_arguments)]
fn mob_machine_placed_kickoff_correlation_available(
pending_kickoffs: &std::collections::BTreeSet<PlacedKickoffObligation>,
resolved_kickoffs: &std::collections::BTreeSet<PlacedKickoffObligation>,
retained_kickoffs: &std::collections::BTreeMap<AgentIdentity, PlacedKickoffObligation>,
pending_remote_turns: &std::collections::BTreeSet<RemoteTurnObligation>,
committed_remote_turns: &std::collections::BTreeSet<RemoteTurnObligation>,
resolved_remote_turns: &std::collections::BTreeSet<RemoteTurnObligation>,
pending_completions: &std::collections::BTreeSet<PlacedCompletionObligation>,
resolved_completions: &std::collections::BTreeSet<PlacedCompletionObligation>,
candidate: &PlacedKickoffObligation,
) -> bool {
if pending_kickoffs
.iter()
.chain(resolved_kickoffs)
.any(|row| {
row.agent_identity == candidate.agent_identity
|| (row.host_id == candidate.host_id
&& row.generation == candidate.generation
&& row.fence_token == candidate.fence_token
&& row.input_id == candidate.input_id)
})
{
return false;
}
if retained_kickoffs
.values()
.any(|row| row.agent_identity == candidate.agent_identity)
{
return false;
}
let remote_available = !pending_remote_turns
.iter()
.chain(committed_remote_turns)
.chain(resolved_remote_turns)
.any(|row| {
row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
&& row.generation == candidate.generation
&& row.fence_token == candidate.fence_token
&& row.input_id == candidate.input_id
});
let completion_available = !pending_completions
.iter()
.chain(resolved_completions)
.any(|row| {
row.agent_identity == candidate.agent_identity
&& row.host_id == candidate.host_id
&& row.generation == candidate.generation
&& row.fence_token == candidate.fence_token
&& row.input_id == candidate.input_id
});
remote_available && completion_available
}
fn mob_machine_placed_kickoff_custody_absent_for_identity(
pending: &std::collections::BTreeSet<PlacedKickoffObligation>,
resolved: &std::collections::BTreeSet<PlacedKickoffObligation>,
agent_identity: &AgentIdentity,
) -> bool {
pending
.iter()
.chain(resolved)
.all(|obligation| obligation.agent_identity != *agent_identity)
}
fn mob_machine_placed_kickoff_custody_absent_for_host(
pending: &std::collections::BTreeSet<PlacedKickoffObligation>,
resolved: &std::collections::BTreeSet<PlacedKickoffObligation>,
host_id: &HostId,
) -> bool {
pending
.iter()
.chain(resolved)
.all(|obligation| obligation.host_id != *host_id)
}
fn mob_machine_remote_turn_input_id_available_to_kickoff(
pending: &std::collections::BTreeSet<PlacedKickoffObligation>,
resolved: &std::collections::BTreeSet<PlacedKickoffObligation>,
retained: &std::collections::BTreeMap<AgentIdentity, PlacedKickoffObligation>,
candidate: &RemoteTurnObligation,
) -> bool {
pending
.iter()
.chain(resolved)
.chain(retained.values())
.all(|obligation| {
obligation.agent_identity != candidate.agent_identity
|| obligation.host_id != candidate.host_id
|| obligation.generation != candidate.generation
|| obligation.fence_token != candidate.fence_token
|| obligation.input_id != candidate.input_id
})
}
fn mob_machine_identity_has_session_binding(
member_session_bindings: &std::collections::BTreeMap<AgentIdentity, SessionId>,
agent_identity: &AgentIdentity,
) -> bool {
member_session_bindings.contains_key(agent_identity)
}
fn mob_machine_session_bound_live_runtime_ids_match(
identity_to_runtime: &std::collections::BTreeMap<AgentIdentity, AgentRuntimeId>,
member_session_bindings: &std::collections::BTreeMap<AgentIdentity, SessionId>,
live_runtime_ids: &std::collections::BTreeSet<AgentRuntimeId>,
expected_runtime_ids: &std::collections::BTreeSet<AgentRuntimeId>,
) -> bool {
let actual_runtime_ids = member_session_bindings
.iter()
.filter_map(|(identity, _)| identity_to_runtime.get(identity))
.filter(|runtime_id| live_runtime_ids.contains(*runtime_id))
.cloned()
.collect::<std::collections::BTreeSet<_>>();
&actual_runtime_ids == expected_runtime_ids
}
fn mob_machine_external_peer_edge_has_matching_key(
edges_by_key: &std::collections::BTreeMap<ExternalPeerKey, ExternalPeerEdge>,
edge: &ExternalPeerEdge,
) -> bool {
let key = ExternalPeerKey::new(edge.local.clone(), edge.endpoint.name.clone());
edges_by_key.get(&key) == Some(edge)
}
fn mob_machine_external_peer_key_matches_edge(
key: &ExternalPeerKey,
edge: &ExternalPeerEdge,
) -> bool {
key.local == edge.local && key.name == edge.endpoint.name
}
fn mob_machine_external_peer_key_matches_local(
key: &ExternalPeerKey,
agent_identity: &AgentIdentity,
) -> bool {
key.local == *agent_identity
}
fn mob_machine_external_peer_identity_absent(
edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> bool {
edges
.iter()
.all(|edge| edge.endpoint.name.0 != agent_identity.0)
}
fn mob_machine_external_peer_edge_peer_id(edge: &ExternalPeerEdge) -> PeerId {
edge.endpoint.peer_id.clone()
}
fn mob_machine_external_peer_edge_local(edge: &ExternalPeerEdge) -> AgentIdentity {
edge.local.clone()
}
fn mob_machine_member_peer_endpoint_peer_id(endpoint: &MemberPeerEndpoint) -> PeerId {
endpoint.peer_id.clone()
}
fn mob_machine_host_id_matches_peer_id(host_id: &HostId, peer_id: &PeerId) -> bool {
host_id.0 == peer_id.0
}
fn mob_machine_member_peer_id_available_for_identity(
current_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
prior_endpoints: &std::collections::BTreeMap<AgentIdentity, std::collections::BTreeSet<MemberPeerEndpoint>>,
agent_identity: &AgentIdentity,
candidate_endpoint: &MemberPeerEndpoint,
) -> bool {
current_endpoints.iter().all(|(other_identity, endpoint)| {
other_identity == agent_identity
|| endpoint.peer_id != candidate_endpoint.peer_id
}) && prior_endpoints.iter().all(|(other_identity, endpoints)| {
other_identity == agent_identity
|| endpoints
.iter()
.all(|endpoint| endpoint.peer_id != candidate_endpoint.peer_id)
})
}
fn mob_machine_member_has_no_external_peer_edges(
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> bool {
external_peer_edges
.iter()
.all(|edge| edge.local != *agent_identity)
}
fn mob_machine_member_prior_peer_endpoints_after_migration(
all_prior_endpoints: &std::collections::BTreeMap<AgentIdentity, std::collections::BTreeSet<MemberPeerEndpoint>>,
agent_identity: &AgentIdentity,
current_endpoint: &MemberPeerEndpoint,
next_endpoint: &MemberPeerEndpoint,
) -> std::collections::BTreeMap<AgentIdentity, std::collections::BTreeSet<MemberPeerEndpoint>> {
let mut all_prior_endpoints = all_prior_endpoints.clone();
{
let prior_endpoints = all_prior_endpoints
.entry(agent_identity.clone())
.or_default();
prior_endpoints.insert(current_endpoint.clone());
// Rotating back to a previously used endpoint makes it
// current again. Trust stores are keyed by PeerId, so remove
// every descriptor for the next PeerId rather than only an
// exactly equal descriptor; cleanup must never remove the live
// trust row through an older metadata shape of the same key.
prior_endpoints.retain(|endpoint| endpoint.peer_id != next_endpoint.peer_id);
}
if all_prior_endpoints
.get(agent_identity)
.is_some_and(std::collections::BTreeSet::is_empty)
{
all_prior_endpoints.remove(agent_identity);
}
all_prior_endpoints
}
fn mob_machine_wiring_edge_a(edge: &WiringEdge) -> AgentIdentity {
edge.a.clone()
}
fn mob_machine_wiring_edge_b(edge: &WiringEdge) -> AgentIdentity {
edge.b.clone()
}
fn mob_machine_wiring_edge_contains_identity(
edge: &WiringEdge,
agent_identity: &AgentIdentity,
) -> bool {
edge.a == *agent_identity || edge.b == *agent_identity
}
fn mob_machine_member_endpoint_migration_cleanup_peer_id(
endpoint_identity: &AgentIdentity,
migrated_identity: &AgentIdentity,
retained_peer_endpoint: &MemberPeerEndpoint,
current_peer_ids: &std::collections::BTreeMap<AgentIdentity, PeerId>,
) -> PeerId {
if endpoint_identity == migrated_identity {
retained_peer_endpoint.peer_id.clone()
} else {
current_peer_ids
.get(endpoint_identity)
.expect("migration cleanup guards require the other member's current peer id")
.clone()
}
}
fn mob_machine_external_peer_endpoint_as_member(
endpoint: &ExternalPeerEndpoint,
) -> MemberPeerEndpoint {
MemberPeerEndpoint {
name: endpoint.name.clone(),
peer_id: endpoint.peer_id.clone(),
address: endpoint.address.clone(),
signing_key: endpoint.signing_key.clone(),
}
}
fn mob_machine_member_peer_overlay_complete(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
agent_identity: &AgentIdentity,
) -> bool {
wiring_edges.iter().all(|edge| {
if edge.a == *agent_identity {
member_peer_endpoints.contains_key(&edge.b)
} else if edge.b == *agent_identity {
member_peer_endpoints.contains_key(&edge.a)
} else {
true
}
})
}
fn mob_machine_member_peer_overlay(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> std::collections::BTreeSet<MemberPeerEndpoint> {
let mut endpoints = std::collections::BTreeSet::new();
for edge in wiring_edges {
let peer_identity = if edge.a == *agent_identity {
Some(&edge.b)
} else if edge.b == *agent_identity {
Some(&edge.a)
} else {
None
};
if let Some(peer_identity) = peer_identity
&& let Some(endpoint) = member_peer_endpoints.get(peer_identity)
{
endpoints.insert(endpoint.clone());
}
}
for edge in external_peer_edges {
if edge.local == *agent_identity {
endpoints.insert(Self::mob_machine_external_peer_endpoint_as_member(
&edge.endpoint,
));
}
}
endpoints
}
fn mob_machine_wiring_contains_pair(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
a_identity: &AgentIdentity,
b_identity: &AgentIdentity,
) -> bool {
wiring_edges.iter().any(|edge| {
(edge.a == *a_identity && edge.b == *b_identity)
|| (edge.a == *b_identity && edge.b == *a_identity)
})
}
fn mob_machine_member_peer_overlay_without_identity_complete(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
agent_identity: &AgentIdentity,
excluded_identity: &AgentIdentity,
) -> bool {
wiring_edges.iter().all(|edge| {
if edge.a == *agent_identity && edge.b != *excluded_identity {
member_peer_endpoints.contains_key(&edge.b)
} else if edge.b == *agent_identity && edge.a != *excluded_identity {
member_peer_endpoints.contains_key(&edge.a)
} else {
true
}
})
}
fn mob_machine_member_peer_overlay_without_identity(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
excluded_identity: &AgentIdentity,
) -> std::collections::BTreeSet<MemberPeerEndpoint> {
let mut endpoints = std::collections::BTreeSet::new();
for edge in wiring_edges {
let peer_identity = if edge.a == *agent_identity && edge.b != *excluded_identity {
Some(&edge.b)
} else if edge.b == *agent_identity && edge.a != *excluded_identity {
Some(&edge.a)
} else {
None
};
if let Some(peer_identity) = peer_identity
&& let Some(endpoint) = member_peer_endpoints.get(peer_identity)
{
endpoints.insert(endpoint.clone());
}
}
for edge in external_peer_edges {
if edge.local == *agent_identity {
endpoints.insert(Self::mob_machine_external_peer_endpoint_as_member(
&edge.endpoint,
));
}
}
endpoints
}
fn mob_machine_member_peer_overlay_without_identity_peer_ids_unique(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
excluded_identity: &AgentIdentity,
) -> bool {
let mut peer_ids = std::collections::BTreeSet::new();
Self::mob_machine_member_peer_overlay_without_identity(
wiring_edges,
member_peer_endpoints,
external_peer_edges,
agent_identity,
excluded_identity,
)
.into_iter()
.all(|endpoint| peer_ids.insert(endpoint.peer_id))
}
fn mob_machine_member_peer_overlay_peer_ids_unique(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
member_peer_endpoints: &std::collections::BTreeMap<AgentIdentity, MemberPeerEndpoint>,
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> bool {
let mut peer_ids = std::collections::BTreeSet::new();
Self::mob_machine_member_peer_overlay(
wiring_edges,
member_peer_endpoints,
external_peer_edges,
agent_identity,
)
.into_iter()
.all(|endpoint| peer_ids.insert(endpoint.peer_id))
}
fn mob_machine_wiring_edge_matches_members(
edge: &WiringEdge,
a_identity: &AgentIdentity,
b_identity: &AgentIdentity,
) -> bool {
edge.a == *a_identity && edge.b == *b_identity
}
/// Retirement is the identity-level topology terminal. Prune every
/// incident edge in the same canonical transition that publishes the
/// final carrier so replay can never recover a wire to an absent
/// member.
fn mob_machine_wiring_edges_without_identity(
wiring_edges: &std::collections::BTreeSet<WiringEdge>,
agent_identity: &AgentIdentity,
) -> std::collections::BTreeSet<WiringEdge> {
wiring_edges
.iter()
.filter(|edge| edge.a != *agent_identity && edge.b != *agent_identity)
.cloned()
.collect()
}
fn mob_machine_external_peer_edges_without_identity(
external_peer_edges: &std::collections::BTreeSet<ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> std::collections::BTreeSet<ExternalPeerEdge> {
external_peer_edges
.iter()
.filter(|edge| edge.local != *agent_identity)
.cloned()
.collect()
}
fn mob_machine_external_peer_edges_by_key_without_identity(
external_peer_edges_by_key: &std::collections::BTreeMap<ExternalPeerKey, ExternalPeerEdge>,
agent_identity: &AgentIdentity,
) -> std::collections::BTreeMap<ExternalPeerKey, ExternalPeerEdge> {
external_peer_edges_by_key
.iter()
.filter(|(key, _)| key.local != *agent_identity)
.map(|(key, edge)| (key.clone(), edge.clone()))
.collect()
}
fn mob_machine_run_step_status_after_set(
all_statuses: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, Option<StepRunStatus>>>,
run_id: &RunId,
step_id: &StepId,
status: &StepRunStatus,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, Option<StepRunStatus>>> {
let mut all_statuses = all_statuses.clone();
all_statuses
.entry(run_id.clone())
.or_default()
.insert(step_id.clone(), Some(*status));
all_statuses
}
fn mob_machine_run_step_bool_after_set(
all_values: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, bool>>,
run_id: &RunId,
step_id: &StepId,
value: &bool,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, bool>> {
let mut all_values = all_values.clone();
all_values
.entry(run_id.clone())
.or_default()
.insert(step_id.clone(), *value);
all_values
}
fn mob_machine_run_step_condition_result_after_set(
all_results: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, Option<bool>>>,
run_id: &RunId,
step_id: &StepId,
result: &bool,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, Option<bool>>> {
let mut all_results = all_results.clone();
all_results
.entry(run_id.clone())
.or_default()
.insert(step_id.clone(), Some(*result));
all_results
}
fn mob_machine_run_step_u64_after_set(
all_counts: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, u64>>,
run_id: &RunId,
step_id: &StepId,
value: &u64,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, u64>> {
let mut all_counts = all_counts.clone();
all_counts
.entry(run_id.clone())
.or_default()
.insert(step_id.clone(), *value);
all_counts
}
fn mob_machine_run_step_u64_after_increment(
all_counts: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, u64>>,
run_id: &RunId,
step_id: &StepId,
delta: &u64,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<StepId, u64>> {
let mut all_counts = all_counts.clone();
let count = all_counts
.entry(run_id.clone())
.or_default()
.entry(step_id.clone())
.or_default();
*count = count.saturating_add(*delta);
all_counts
}
fn mob_machine_run_retry_count_after_increment(
all_counts: &std::collections::BTreeMap<RunId, std::collections::BTreeMap<String, u64>>,
run_id: &RunId,
retry_key: &str,
delta: &u64,
) -> std::collections::BTreeMap<RunId, std::collections::BTreeMap<String, u64>> {
let mut all_counts = all_counts.clone();
let count = all_counts
.entry(run_id.clone())
.or_default()
.entry(retry_key.to_owned())
.or_default();
*count = count.saturating_add(*delta);
all_counts
}
fn mob_machine_frame_node_bool_after_set(
all_values: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, bool>>,
frame_id: &FrameId,
node_id: &FlowNodeId,
value: &bool,
) -> std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, bool>> {
let mut all_values = all_values.clone();
all_values
.entry(frame_id.clone())
.or_default()
.insert(node_id.clone(), *value);
all_values
}
fn mob_machine_frame_node_status_after_admit(
all_statuses: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>>,
frame_branches: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, Option<BranchId>>>,
frame_ordered_nodes: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
frame_id: &FrameId,
node_id: &FlowNodeId,
) -> std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>> {
let mut all_statuses = all_statuses.clone();
let statuses = all_statuses.entry(frame_id.clone()).or_default();
let ordered_nodes = frame_ordered_nodes.get(&frame_id).cloned().unwrap_or_default();
let branches = frame_branches.get(&frame_id).cloned().unwrap_or_default();
let admitted_branch = branches.get(node_id).cloned().unwrap_or(None);
if let Some(branch) = admitted_branch {
for candidate in ordered_nodes {
if &candidate != node_id
&& statuses.get(&candidate) == Some(&NodeRunStatus::Ready)
&& branches.get(&candidate).cloned().unwrap_or(None) == Some(branch.clone())
{
statuses.insert(candidate, NodeRunStatus::Pending);
}
}
}
statuses.insert(node_id.clone(), NodeRunStatus::Running);
all_statuses
}
fn mob_machine_frame_ready_queue_after_admit(
all_ready_queues: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
all_statuses: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>>,
frame_ordered_nodes: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
frame_id: &FrameId,
) -> std::collections::BTreeMap<FrameId, Vec<FlowNodeId>> {
let mut all_ready_queues = all_ready_queues.clone();
let statuses = all_statuses.get(&frame_id).cloned().unwrap_or_default();
let ordered_nodes = frame_ordered_nodes.get(&frame_id).cloned().unwrap_or_default();
let ready = ordered_nodes
.into_iter()
.filter(|node_id| statuses.get(node_id) == Some(&NodeRunStatus::Ready))
.collect();
all_ready_queues.insert(frame_id.clone(), ready);
all_ready_queues
}
fn mob_machine_node_terminal(status: NodeRunStatus) -> bool {
matches!(
status,
NodeRunStatus::Completed
| NodeRunStatus::Failed
| NodeRunStatus::Skipped
| NodeRunStatus::Canceled
)
}
fn mob_machine_step_status_from_frame_node_status(status: &NodeRunStatus) -> StepRunStatus {
match *status {
NodeRunStatus::Completed => StepRunStatus::Completed,
NodeRunStatus::Skipped => StepRunStatus::Skipped,
NodeRunStatus::Failed => StepRunStatus::Failed,
NodeRunStatus::Canceled => StepRunStatus::Canceled,
NodeRunStatus::Pending | NodeRunStatus::Ready | NodeRunStatus::Running => {
StepRunStatus::Dispatched
}
}
}
#[allow(clippy::too_many_arguments)]
fn mob_machine_frame_node_status_after_terminal(
all_statuses: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>>,
frame_branches: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, Option<BranchId>>>,
frame_ordered_nodes: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
frame_node_dependencies: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, Vec<FlowNodeId>>>,
frame_node_dependency_modes: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, DependencyMode>>,
frame_id: &FrameId,
node_id: &FlowNodeId,
terminal_status: &NodeRunStatus,
) -> std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>> {
let mut all_statuses = all_statuses.clone();
let statuses = all_statuses.entry(frame_id.clone()).or_default();
statuses.insert(node_id.clone(), *terminal_status);
let ordered_nodes = frame_ordered_nodes
.get(&frame_id)
.cloned()
.unwrap_or_default();
let branches = frame_branches.get(&frame_id).cloned().unwrap_or_default();
if *terminal_status == NodeRunStatus::Completed {
if let Some(branch) = branches.get(&node_id).cloned().unwrap_or(None) {
for candidate in &ordered_nodes {
if candidate != node_id
&& branches.get(candidate).cloned().unwrap_or(None) == Some(branch.clone())
&& statuses
.get(candidate)
.copied()
.is_some_and(|status| {
!Self::mob_machine_node_terminal(status)
&& status != NodeRunStatus::Running
})
{
statuses.insert(candidate.clone(), NodeRunStatus::Skipped);
}
}
}
}
let dependencies = frame_node_dependencies
.get(&frame_id)
.cloned()
.unwrap_or_default();
let dependency_modes = frame_node_dependency_modes
.get(&frame_id)
.cloned()
.unwrap_or_default();
for candidate in ordered_nodes {
if statuses.get(&candidate) != Some(&NodeRunStatus::Pending) {
continue;
}
let deps = dependencies.get(&candidate).cloned().unwrap_or_default();
let dep_mode = dependency_modes
.get(&candidate)
.copied()
.unwrap_or(DependencyMode::All);
let failed = !deps.is_empty()
&& match dep_mode {
DependencyMode::All => deps.iter().any(|dep| {
statuses.get(dep).copied().is_some_and(|status| {
matches!(
status,
NodeRunStatus::Failed
| NodeRunStatus::Skipped
| NodeRunStatus::Canceled
)
})
}),
DependencyMode::Any => deps.iter().all(|dep| {
statuses.get(dep).copied().is_some_and(|status| {
matches!(
status,
NodeRunStatus::Failed
| NodeRunStatus::Skipped
| NodeRunStatus::Canceled
)
})
}),
};
if failed {
statuses.insert(candidate, NodeRunStatus::Skipped);
continue;
}
let satisfied = deps.is_empty()
|| (dep_mode == DependencyMode::All
&& deps
.iter()
.all(|dep| statuses.get(dep) == Some(&NodeRunStatus::Completed)))
|| (dep_mode == DependencyMode::Any
&& deps
.iter()
.any(|dep| statuses.get(dep) == Some(&NodeRunStatus::Completed)));
if satisfied {
statuses.insert(candidate, NodeRunStatus::Ready);
}
}
all_statuses
}
fn mob_machine_frame_ready_queue_after_terminal(
all_ready_queues: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
all_statuses: &std::collections::BTreeMap<FrameId, std::collections::BTreeMap<FlowNodeId, NodeRunStatus>>,
frame_ordered_nodes: &std::collections::BTreeMap<FrameId, Vec<FlowNodeId>>,
frame_id: &FrameId,
) -> std::collections::BTreeMap<FrameId, Vec<FlowNodeId>> {
let mut all_ready_queues = all_ready_queues.clone();
let statuses = all_statuses.get(&frame_id).cloned().unwrap_or_default();
let ordered_nodes = frame_ordered_nodes.get(&frame_id).cloned().unwrap_or_default();
let ready = ordered_nodes
.into_iter()
.filter(|node_id| statuses.get(node_id) == Some(&NodeRunStatus::Ready))
.collect();
all_ready_queues.insert(frame_id.clone(), ready);
all_ready_queues
}
// -----------------------------------------------------------------
// Mob coordination expiry/active classification (folded). These are
// pure structural functions over RAW machine-owned facts (stored
// expiry timestamp + the caller's raw `now_ms` clock reading). They
// do not accept any pre-reduced `is_expired` input; the expiry
// conclusion is computed here from `Some(e) && e <= now_ms`.
// -----------------------------------------------------------------
fn mob_coordination_expired_at(expires_at_ms: &Option<u64>, now_ms: &u64) -> bool {
matches!(expires_at_ms, Some(expiry) if *expiry <= *now_ms)
}
fn mob_coordination_work_intent_unexpired(expires_at_ms: &Option<u64>, now_ms: &u64) -> bool {
!Self::mob_coordination_expired_at(expires_at_ms, now_ms)
}
fn mob_coordination_resource_claim_unexpired(
expires_at_ms: &Option<u64>,
now_ms: &u64,
) -> bool {
!Self::mob_coordination_expired_at(expires_at_ms, now_ms)
}
// A resource claim is active at `now_ms` iff its status is `Active`
// (the only non-terminal status) and it is not expired. The expired
// classification matches the former board, which treats both the
// `Expired` status and an elapsed `expires_at` as expired; since the
// status arm already requires `Active`, only the timestamp matters.
fn mob_coordination_resource_claim_active_at(
status: &MobCoordinationResourceClaimStatus,
expires_at_ms: &Option<u64>,
now_ms: &u64,
) -> bool {
matches!(status, MobCoordinationResourceClaimStatus::Active)
&& !Self::mob_coordination_expired_at(expires_at_ms, now_ms)
}
fn mob_coordination_resource_claim_inactive_at(
status: &MobCoordinationResourceClaimStatus,
expires_at_ms: &Option<u64>,
now_ms: &u64,
) -> bool {
!Self::mob_coordination_resource_claim_active_at(status, expires_at_ms, now_ms)
}
// -----------------------------------------------------------------
// Wave-G1 catalog fold helpers.
// -----------------------------------------------------------------
// Row #181: compute the generation for an identity's next incarnation.
// Fresh identities start at the domain's generation zero. Retained
// history advances with the same exact-successor arithmetic as
// `crate::ids::Generation::next`.
fn mob_machine_next_respawn_generation(
identity_runtime_generations: &std::collections::BTreeMap<AgentIdentity, Generation>,
agent_identity: &AgentIdentity,
) -> Option<Generation> {
match identity_runtime_generations.get(agent_identity) {
Some(generation) => generation.0.checked_add(1).map(Generation),
None => Some(Generation(0)),
}
}
// Supervisor epochs are durable stale-authority fences. `u64::MAX` is
// the final valid epoch, never a predecessor of zero.
fn mob_machine_u64_is_exact_successor(current: &u64, next: &u64) -> bool {
current.checked_add(1) == Some(*next)
}
fn mob_machine_optional_u64_is_exact_successor(
current: &u64,
next: &Option<u64>,
) -> bool {
current.checked_add(1) == *next
}
// Row #351: members that must be spawned — desired identities that are
// not currently bound to a runtime.
fn mob_machine_members_to_spawn(
identity_to_runtime: &std::collections::BTreeMap<AgentIdentity, AgentRuntimeId>,
desired: &std::collections::BTreeSet<AgentIdentity>,
) -> std::collections::BTreeSet<AgentIdentity> {
desired
.iter()
.filter(|identity| !identity_to_runtime.contains_key(*identity))
.cloned()
.collect()
}
// Row #351: members that must be retired — currently bound identities
// that are no longer desired. Only computed when `retire_stale` is set;
// otherwise no member is retired (the set is empty).
fn mob_machine_members_to_retire(
identity_to_runtime: &std::collections::BTreeMap<AgentIdentity, AgentRuntimeId>,
desired: &std::collections::BTreeSet<AgentIdentity>,
retire_stale: &bool,
) -> std::collections::BTreeSet<AgentIdentity> {
if !*retire_stale {
return std::collections::BTreeSet::new();
}
identity_to_runtime
.keys()
.filter(|identity| !desired.contains(*identity))
.cloned()
.collect()
}
fn mob_machine_placed_cleanup_absent_for_identity(
obligations: &std::collections::BTreeSet<PlacedCarrierCleanupObligation>,
agent_identity: &AgentIdentity,
) -> bool {
obligations
.iter()
.all(|obligation| obligation.agent_identity != *agent_identity)
}
fn mob_machine_placed_carrier_binding_active(
member_placement: &std::collections::BTreeMap<AgentIdentity, HostId>,
current_binding_generations: &std::collections::BTreeMap<AgentIdentity, u64>,
host_bind_phase: &std::collections::BTreeMap<HostId, HostBindPhase>,
host_binding_generations: &std::collections::BTreeMap<HostId, u64>,
agent_identity: &AgentIdentity,
) -> bool {
let Some(host) = member_placement.get(agent_identity) else {
return false;
};
host_bind_phase.get(host) == Some(&HostBindPhase::Bound)
&& current_binding_generations.get(agent_identity).is_some_and(|generation| {
*generation > 0 && host_binding_generations.get(host) == Some(generation)
})
}
fn mob_machine_host_binding_generation_tombstone(
host_id: &HostId,
binding_generation: &u64,
) -> HostBindingGenerationTombstone {
HostBindingGenerationTombstone {
host_id: host_id.clone(),
binding_generation: *binding_generation,
}
}
fn mob_machine_placed_carrier_binding_confirmed_revoked(
member_placement: &std::collections::BTreeMap<AgentIdentity, HostId>,
current_binding_generations: &std::collections::BTreeMap<AgentIdentity, u64>,
host_bind_phase: &std::collections::BTreeMap<HostId, HostBindPhase>,
confirmed_revocations: &std::collections::BTreeSet<HostBindingGenerationTombstone>,
agent_identity: &AgentIdentity,
) -> bool {
let Some(host) = member_placement.get(agent_identity) else {
return false;
};
let Some(generation) = current_binding_generations.get(agent_identity) else {
return false;
};
*generation > 0
&& host_bind_phase.get(host) != Some(&HostBindPhase::Bound)
&& confirmed_revocations.contains(&HostBindingGenerationTombstone {
host_id: host.clone(),
binding_generation: *generation,
})
}
fn mob_machine_placed_cleanup_obligation(
agent_identity: &AgentIdentity,
spawn_id: &PlacedSpawnId,
generation: &Generation,
fence_token: &FenceToken,
provision_operation_id: &str,
operation_owner_session_id: &SessionId,
expected_phase: &PlacedSpawnCarrierExpectedPhase,
) -> PlacedCarrierCleanupObligation {
PlacedCarrierCleanupObligation {
agent_identity: agent_identity.clone(),
spawn_id: spawn_id.clone(),
generation: *generation,
fence_token: *fence_token,
provision_operation_id: provision_operation_id.to_owned(),
operation_owner_session_id: operation_owner_session_id.clone(),
expected_phase: *expected_phase,
}
}
}
};
}
crate::mob_catalog_machine_dsl!("self", "catalog::dsl::mob_machine");
pub type MobToolCallerProvenance = meerkat_core::service::MobToolCallerProvenance;
pub type OpaquePrincipalToken = meerkat_core::service::OpaquePrincipalToken;
// ---------------------------------------------------------------------------
// Mob coordination board bridging newtypes / enums (folded). These mirror the
// product-neutral coordination domain types and let the DSL Set/Map machinery
// treat them as opaque ordered keys/values.
// ---------------------------------------------------------------------------
/// Stable identifier for a product-neutral mob work intent.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct WorkIntentId(pub String);
/// Stable identifier for a mob resource claim.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct ResourceClaimId(pub String);
/// Product-neutral reference to a resource affected by mob coordination.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct CoordinationResourceRef(pub String);
/// Work-intent lifecycle status.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCoordinationWorkIntentStatus {
#[default]
Planned,
Active,
Blocked,
Completed,
Cancelled,
}
/// Resource-claim lifecycle status.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCoordinationResourceClaimStatus {
#[default]
Active,
Released,
Expired,
Cancelled,
}
/// Resource-claim advisory strength.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCoordinationResourceClaimKind {
#[default]
Advisory,
SoftReservation,
Exclusive,
}
/// Coordination event discriminant.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCoordinationEventKind {
#[default]
WorkIntentRecorded,
WorkIntentStatusChanged,
ResourceClaimRecorded,
ResourceClaimStatusChanged,
ResourceClaimOverlapObserved,
}
// ---------------------------------------------------------------------------
// Bridging newtypes
// ---------------------------------------------------------------------------
//
// These types bridge between the DSL's flat representation and the real mob
// domain types in `crate::ids`. The DSL needs Ord+Hash+Clone for Set/Map;
// these newtypes satisfy that while providing From/Into mappings.
/// Stable identifier for one durable placed-spawn carrier row. This is
/// distinct from agent identity, runtime id, and the host provision operation
/// id so retries cannot accidentally acquire authority over another attempt.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PlacedSpawnId(pub String);
impl<T: Into<String>> From<T> for PlacedSpawnId {
fn from(value: T) -> Self {
Self(value.into())
}
}
/// Exact carrier phase expected by a machine-authorized compare-delete.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum PlacedSpawnCarrierExpectedPhase {
#[default]
Pending,
Committed,
}
/// Exact placed-carrier cleanup authority. A cleanup for an older generation,
/// fence, spawn id, or phase cannot authorize deleting its successor.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PlacedCarrierCleanupObligation {
pub agent_identity: AgentIdentity,
pub spawn_id: PlacedSpawnId,
pub generation: Generation,
pub fence_token: FenceToken,
pub provision_operation_id: String,
pub operation_owner_session_id: SessionId,
pub expected_phase: PlacedSpawnCarrierExpectedPhase,
}
/// Exact authenticated host-binding revoke terminal. Historical generations
/// are retained because a logical carrier may remain at G1 across later host
/// bind/revoke cycles until it is revived or explicitly retired.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct HostBindingGenerationTombstone {
pub host_id: HostId,
pub binding_generation: u64,
}
/// Bridging type for agent identity. Maps to `crate::ids::AgentIdentity`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct AgentIdentity(pub String);
impl<T: Into<String>> From<T> for AgentIdentity {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Canonical peer identity for respawn topology-restore feedback. Local
/// member edges use `AgentIdentity`; external peer edges use `PeerId`, not the
/// display-only peer name.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct RespawnTopologyPeerId(pub String);
impl<T: Into<String>> From<T> for RespawnTopologyPeerId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for agent runtime ID. Maps to `crate::ids::AgentRuntimeId`.
///
/// The real `AgentRuntimeId` is a struct `{ identity: AgentIdentity, generation: Generation }`.
/// The DSL uses a single string key `"identity:generation"` for Set/Map operations.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct AgentRuntimeId(pub String);
impl<T: Into<String>> From<T> for AgentRuntimeId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for mob id. Maps to `crate::ids::MobId`.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct MobId(pub String);
impl<T: Into<String>> From<T> for MobId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for fence token. Maps to `crate::ids::FenceToken`.
/// `Default` is required by the `OptionValueExt::get("value")` unwrap path
/// used in the multi-host remote retire/release arms.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct FenceToken(pub u64);
impl From<u64> for FenceToken {
fn from(v: u64) -> Self {
Self(v)
}
}
/// Bridging type for generation counter. Maps to `crate::ids::Generation`.
/// `Default` is required by the `OptionValueExt::get("value")` unwrap path
/// used in the multi-host remote retire/release arms.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct Generation(pub u64);
impl From<u64> for Generation {
fn from(v: u64) -> Self {
Self(v)
}
}
/// Bridging type for work reference. Maps to `crate::ids::WorkRef`.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct WorkId(pub String);
impl<T: Into<String>> From<T> for WorkId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for flow run identity. Maps to `crate::ids::RunId`.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct RunId(pub String);
impl<T: Into<String>> From<T> for RunId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for frame identity. Maps to `crate::ids::FrameId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct FrameId(pub String);
impl<T: Into<String>> From<T> for FrameId {
fn from(s: T) -> Self {
Self(s.into())
}
}
impl FrameId {
pub fn as_str(&self) -> &str {
&self.0
}
}
/// Bridging type for loop instance identity. Maps to `crate::ids::LoopInstanceId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct LoopInstanceId(pub String);
impl<T: Into<String>> From<T> for LoopInstanceId {
fn from(s: T) -> Self {
Self(s.into())
}
}
impl LoopInstanceId {
pub fn as_str(&self) -> &str {
&self.0
}
}
/// Bridging type for loop definition identity. Maps to `crate::ids::LoopId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct LoopId(pub String);
impl<T: Into<String>> From<T> for LoopId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for flow-node identity. Maps to `crate::ids::FlowNodeId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct FlowNodeId(pub String);
impl<T: Into<String>> From<T> for FlowNodeId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for branch identity. Maps to `crate::ids::BranchId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct BranchId(pub String);
impl<T: Into<String>> From<T> for BranchId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for step identity. Maps to `crate::ids::StepId`.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct StepId(pub String);
impl<T: Into<String>> From<T> for StepId {
fn from(s: T) -> Self {
Self(s.into())
}
}
impl StepId {
pub fn as_str(&self) -> &str {
&self.0
}
}
/// Bridging type for bridge session id. Maps to
/// `meerkat_core::session::SessionId` — the bridge session a mob member is
/// attached to for the current runtime generation. The DSL only needs the
/// stringified form for Ord/Hash/Clone/Default; the realtime WS observer
/// materializes it back into the typed core id.
#[derive(
Debug,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
serde::Serialize,
serde::Deserialize,
)]
pub struct SessionId(pub String);
impl<T: Into<String>> From<T> for SessionId {
fn from(s: T) -> Self {
Self(s.into())
}
}
impl SessionId {
/// Project a real `meerkat_core::types::SessionId` into the DSL bridging type.
pub fn from_domain(id: &meerkat_core::types::SessionId) -> Self {
Self(id.to_string())
}
}
/// Bridging type for adaptive run identity.
#[derive(
Debug,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
serde::Serialize,
serde::Deserialize,
)]
pub struct AdaptiveRunId(pub String);
impl<T: Into<String>> From<T> for AdaptiveRunId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Bridging type for adaptive layer identity.
#[derive(
Debug,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
serde::Serialize,
serde::Deserialize,
)]
pub struct AdaptiveLayerId(pub String);
impl<T: Into<String>> From<T> for AdaptiveLayerId {
fn from(s: T) -> Self {
Self(s.into())
}
}
// ---------------------------------------------------------------------------
// Projection helpers: domain types → bridging types
// ---------------------------------------------------------------------------
/// Kickoff lifecycle phase for a member's initial autonomous turn.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum KickoffPhase {
Pending,
Starting,
CallbackPending,
Started,
Failed,
Cancelled,
}
/// Per-identity spawn-execution phase ladder. Absence of an entry in
/// `spawn_exec_phase` == Settled (no spawn-exec in flight for that identity),
/// which makes every late/post-teardown CommitSpawnActivation/AbortSpawnExec
/// input a total no-op. `Opened`: `BeginSpawnExec` committed, membership not yet
/// committed. `MembershipCommitted`: `CommitSpawnMembership` committed the
/// membership facts atomically. `Activated`: terminal rung — reserved for an
/// explicit "activated" marker; the current ladder removes the entry directly at
/// `CommitSpawnActivation` (Settled) rather than parking in `Activated`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SpawnExecPhase {
Opened,
/// Multi-host (§6.1): entered only for remote placements — the
/// materialization request is outstanding on the member host and the
/// remote membership commit (the ack) closes it.
MaterializePending,
MembershipCommitted,
Activated,
}
/// Dependency satisfaction mode for a step or frame node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum DependencyMode {
#[default]
All,
Any,
}
/// Collection policy for a step's fan-out execution.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum CollectionPolicyKind {
#[default]
All,
Any,
Quorum,
}
/// Canonical flow-run lifecycle state once run-local semantics are absorbed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveRunPhase {
#[default]
Active,
CleanupRequired,
EvidenceMissing,
Finished,
Failed,
Canceled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveStopReason {
#[default]
FinishDecision,
DepthLimit,
PlanLimit,
RepairLimit,
FailureLimit,
BudgetExhausted,
DeadlineExceeded,
HostCancel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveDecisionKind {
#[default]
RunLayer,
Finish,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveLayerPhase {
#[default]
Validating,
Admitted,
Provisioning,
Running,
Collecting,
Completed,
SetupFailed,
RunFailed,
ResultInvalid,
Canceled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveLayerAdmissionKind {
#[default]
Denied,
Allowed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveLayerSetupFaultKind {
#[default]
MobCreateFailed,
SpawnFailed,
WiringFailed,
CanceledDuringSetup,
Interrupted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AdaptiveLayerDispositionKind {
#[default]
Destroyed,
Retained,
RetainedAsEvidence,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FlowRunStatus {
#[default]
Absent,
Pending,
Running,
Completed,
Failed,
Canceled,
}
/// Typed public result class for surfaces that expose terminal flow-run
/// completion. MobMachine owns whether a terminal flow status maps to a
/// success envelope or an error envelope.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FlowRunPublicResultClassKind {
#[default]
Failure,
Success,
}
/// Canonical frame lifecycle state once frame-local semantics are absorbed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FrameStatus {
#[default]
Running,
Completed,
Failed,
Canceled,
}
/// Canonical loop lifecycle state once loop-local semantics are absorbed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum LoopStatus {
#[default]
Running,
Completed,
Exhausted,
Failed,
Canceled,
}
/// Canonical step execution status once run-local semantics are absorbed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum StepRunStatus {
#[default]
Dispatched,
Completed,
Failed,
Skipped,
Canceled,
}
/// Root-vs-body frame scope for a frame snapshot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FrameScope {
#[default]
Root,
Body,
}
/// Flow node kind inside a frame DAG.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FlowNodeKind {
#[default]
Step,
Loop,
}
/// Per-node execution status within a frame.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum NodeRunStatus {
Pending,
#[default]
Ready,
Running,
Completed,
Failed,
Skipped,
Canceled,
}
/// Loop-body/evaluate lifecycle stage for an active repeat-until node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum LoopIterationStage {
#[default]
AwaitingBodyFrame,
BodyFrameActive,
AwaitingUntilEvaluation,
}
/// Flow-run projection reducer command authorized by MobMachine.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FlowRunReducerCommandKind {
#[default]
CreateRun,
StartRun,
DispatchStep,
CompleteStep,
RecordStepOutput,
ConditionPassed,
ConditionRejected,
FailStep,
SkipStep,
ProjectFrameStepStatus,
CancelStep,
RegisterTargets,
RecordTargetSuccess,
RecordTargetTerminalFailure,
RecordTargetCanceled,
RecordTargetFailure,
RegisterReadyFrame,
PumpNodeScheduler,
RegisterPendingBodyFrame,
PumpFrameScheduler,
NodeExecutionReleased,
FrameTerminated,
TerminalizeCompleted,
TerminalizeFailed,
TerminalizeCanceled,
}
/// Flow-frame projection reducer command authorized by MobMachine.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum FlowFrameReducerCommandKind {
#[default]
StartRootFrame,
StartBodyFrame,
AdmitNextReadyNode,
CompleteNode,
RecordNodeOutput,
FailNode,
SkipNode,
CancelNode,
SealFrame,
}
/// Loop-iteration projection reducer command authorized by MobMachine.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum LoopIterationReducerCommandKind {
#[default]
StartLoop,
BodyFrameStarted,
BodyFrameCompleted,
BodyFrameFailed,
BodyFrameCanceled,
UntilConditionMet,
UntilConditionFailed,
CancelLoop,
}
/// Per-runtime lifecycle marker tracking whether a member is actively serving
/// work or draining toward retirement. Generated SubmitWork guards consume this
/// marker so work-routing admission stays inside MobMachine authority.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobMemberState {
#[default]
Active,
Retiring,
}
/// Machine-owned shutdown action for one exact autonomous member
/// incarnation. The fail-closed default keeps interruption enabled; skipping
/// is reserved for a machine-proven terminal retirement retry anchor after
/// either Mob-owned archive or host-owned runtime release.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum AutonomousShutdownMemberActionKind {
#[default]
Interrupt,
SkipTerminalRetirementAnchor,
}
/// Typed public wait-admission result for member waits. MobMachine emits this
/// class before wait surfaces decide whether an absent runtime-material
/// snapshot is a hard failure.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MemberWaitClassificationKind {
#[default]
RuntimeMaterialPresent,
MissingRuntimeMaterial,
}
/// Machine-owned execution-health class for one member.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MemberHealthClass {
Healthy,
Degraded,
Wedged,
Unknown,
}
/// Typed description of the last progress observation committed by MobMachine.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MemberProgressEventKind {
ExecutionAdvanced,
BecameIdle,
Unchanged,
}
/// Typed public rejection class for [`MobMachineInput::SubmitWork`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SubmitWorkRejectReasonKind {
#[default]
MobNotRunning,
MemberNotFound,
StaleFenceToken,
NotExternallyAddressable,
}
/// Typed public rejection class for [`MobMachineInput::CancelAllWork`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum CancelAllWorkRejectReasonKind {
#[default]
MobNotRunning,
MemberNotFound,
StaleFenceToken,
}
/// Typed public rejection class for generated agent event subscription
/// authority. The runtime shell may open a stream only when MobMachine emits
/// an authorize effect; rejection effects own the public result class.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum EventSubscriptionRejectReasonKind {
#[default]
MemberNotFound,
NoSessionBinding,
}
/// Typed work-origin classification for
/// [`MobMachineInput::SubmitWork`] / [`MobMachineEffect::RequestRuntimeIngress`].
/// Closed mirror of [`crate::ids::WorkOrigin`] — the DSL uses this enum as
/// guard-visible truth instead of the former `origin == "External"` /
/// `origin == "Internal"` string compares. The `Ingest` variant is only
/// valid on the receiving side of the admission seam
/// (`MeerkatMachine::Ingest` fired by the runtime control plane); mob
/// transitions never produce it.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum WorkOrigin {
#[default]
External,
Internal,
Ingest,
}
/// Typed runtime-mode override carried by generated spawn-policy resolution
/// handoff. The shell may observe an opaque callback result, but MobMachine
/// records this closed enum before unknown-member work may auto-spawn.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SpawnPolicyRuntimeMode {
#[default]
AutonomousHost,
TurnDriven,
}
/// Typed public result class for the respawn topology-restore follow-up.
/// The shell observes concrete peer restoration attempts, but MobMachine owns
/// whether the public respawn envelope is complete or topology-restoration
/// partial failure.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RespawnTopologyRestoreResultKind {
#[default]
Completed,
TopologyRestoreFailed,
}
/// Typed shell observation of a member's live materialization at the dispatch
/// boundary: the member's current bridge session has no live runtime, and the
/// durable session snapshot is either still present (revivable) or gone
/// (terminal). The shell observes; MobMachine owns the verdict.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MemberLiveMaterializationObservationKind {
#[default]
DurableSnapshotPresent,
DurableSnapshotMissing,
}
/// Machine-owned verdict for a member live-materialization observation:
/// authorize exactly one shell revival attempt, or record the terminal Broken
/// classification.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MemberRevivalVerdictKind {
#[default]
ReviveAuthorized,
BrokenRecorded,
}
/// Typed shell observation for a per-row `mob/spawn_many` failure.
/// MobMachine maps this observation to the public failure cause before any
/// surface can serialize the row.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobSpawnManyFailureObservationKind {
#[default]
ProfileNotFound,
MemberNotFound,
MemberAlreadyExists,
NotExternallyAddressable,
InvalidTransition,
WiringError,
SupervisorRotationIncomplete,
BridgeCommandRejected,
MemberRestoreFailed,
KickoffWaitTimedOut,
ReadyWaitTimedOut,
DefinitionError,
FlowNotFound,
FlowFailed,
RunNotFound,
RunCanceled,
FlowTurnTimedOut,
FrameDepthLimitExceeded,
FrameAtomicPersistenceUnavailable,
SpecRevisionConflict,
SchemaValidation,
InsufficientTargets,
TopologyViolation,
BridgeDeliveryRejected,
SupervisorEscalation,
UnsupportedForMode,
MissingMemberCapability,
ResetBarrier,
StorageError,
SessionError,
CommsError,
CallbackPending,
StaleFenceToken,
StaleEventCursor,
WorkNotFound,
Internal,
}
/// Typed public result class for per-row `mob/spawn_many` failures.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobSpawnManyFailureCauseKind {
#[default]
ProfileNotFound,
MemberNotFound,
MemberAlreadyExists,
NotExternallyAddressable,
InvalidTransition,
WiringError,
BridgeCommandRejected,
MemberRestoreFailed,
KickoffWaitTimedOut,
ReadyWaitTimedOut,
DefinitionError,
FlowNotFound,
FlowFailed,
RunNotFound,
RunCanceled,
FlowTurnTimedOut,
FrameDepthLimitExceeded,
FrameAtomicPersistenceUnavailable,
SpecRevisionConflict,
SchemaValidation,
InsufficientTargets,
TopologyViolation,
BridgeDeliveryRejected,
SupervisorEscalation,
UnsupportedForMode,
MissingMemberCapability,
ResetBarrier,
StorageError,
SessionError,
CommsError,
CallbackPending,
StaleFenceToken,
StaleEventCursor,
WorkNotFound,
Internal,
}
/// Pure flow-topology rule-match verdict. The shell extracts this from the
/// declarative `TopologyRules` via `evaluate_topology` and feeds it to
/// MobMachine as an observation; MobMachine — not the shell — derives the
/// admission verdict from it.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobFlowDelegationEdgeRuleVerdictKind {
#[default]
Allow,
Deny,
}
/// Configured topology enforcement mode for a flow delegation edge. Mirrors
/// the shell `PolicyMode`; fed alongside the rule verdict so MobMachine can
/// decide whether a denial blocks (Strict) or merely warns (Advisory).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobFlowDelegationEdgeModeKind {
#[default]
Advisory,
Strict,
}
/// Machine-owned admission verdict for a flow delegation edge. The shell
/// mirrors this: `DeniedStrict` blocks the delegation step
/// (`MobError::TopologyViolation`), `DeniedAdvisory` emits an advisory notice
/// and proceeds, `Admitted` proceeds silently.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobFlowDelegationEdgeAdmissionKind {
#[default]
Admitted,
DeniedStrict,
DeniedAdvisory,
}
/// Pure observation of a remote member's runtime state, extracted by the bridge
/// consumer from the wire `BridgeMemberRuntimeState` projection and fed to
/// MobMachine for terminality classification.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobRemoteMemberRuntimeObservedState {
#[default]
Initializing,
Idle,
Attached,
Running,
Retired,
Stopped,
Destroyed,
}
/// Machine-owned terminality verdict for an observed remote-member runtime
/// state. The bridge shell mirrors this: `Terminal` lets cleanup stop,
/// `NonTerminal` forces a destroy.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobRemoteMemberRuntimeTerminality {
#[default]
NonTerminal,
Terminal,
}
/// Machine-owned composite spawn-member operator admission verdict. The tool
/// shell mirrors this: `Denied` -> `access_denied`, `Allowed` -> proceed.
///
/// Multi-host (§6.1/§15.4/§18.9, A4): ONE merged cause vocabulary for the
/// spawn-exec ladder's placement/portability denial arms. The rich
/// `NonPortableResource { kind }` / `SecretBearingField { field }` /
/// `MissingHostCapability { capability }` wire shapes flatten to unit
/// variants here because the DSL emit grammar has no struct-variant
/// construction (ExprDef::NamedVariant is unit-only) and the TLA metadata
/// models enums as flat string domains; the wire layer reassembles the
/// payload form. `ScheduleTools` is deliberately absent (§18 O6 A3-final
/// supersedes the blanket schedule reject) and `ProviderUnavailableOnHost`
/// arrives with the tier-1 provider probe realization (no phase-1 producer —
/// no dead vocabulary).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobSpawnMemberAdmissionKind {
#[default]
Denied,
Allowed,
NonPortableRustBundles,
NonPortablePerSpawnExternalTools,
NonPortableMobDefaultExternalTools,
NonPortableDefaultLlmClientOverride,
NonPortableHostSurfaceMcpAllowlist,
NonPortableInheritedToolFilter,
NonPortableWorkgraphTools,
SecretBearingShellEnv,
SecretBearingMcpStdioEnv,
SecretBearingMcpHttpHeaders,
MissingHostCapabilityAutonomousMembers,
MissingHostCapabilityDurableSessions,
MissingHostCapabilityTrackedInputCancel,
MissingHostCapabilityProtocolV4,
MissingHostCapabilityMemoryStore,
MissingHostCapabilityMcp,
HostNotBound,
OwnerBridgeSessionAbsent,
LaunchModePlacementMismatch,
ResolvedSpecDigestAbsent,
}
/// Machine-owned per-mob operator admission verdict for current-mob-scoped
/// tools. The tool shell mirrors this: `Denied` -> `access_denied`, `Allowed`
/// -> proceed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCurrentMobAdmissionKind {
#[default]
Denied,
Allowed,
}
/// Machine-owned coarse spawn-tool admission verdict for the spawn-member tool
/// surfaces. The tool shell mirrors this: `Denied` -> `access_denied`,
/// `Allowed` -> proceed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobSpawnToolAdmissionKind {
#[default]
Denied,
Allowed,
}
/// Machine-owned operator create-mob admission verdict for the mob-creation
/// tool. The tool shell mirrors this: `Denied` -> `access_denied`, `Allowed`
/// -> proceed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobCreateMobAdmissionKind {
#[default]
Denied,
Allowed,
}
/// Machine-owned operator profile-mutation admission verdict for realm-profile
/// mutation tools. The tool shell mirrors this: `Denied` -> `access_denied`,
/// `Allowed` -> proceed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobProfileMutationAdmissionKind {
#[default]
Denied,
Allowed,
}
/// Machine-owned eligibility verdict for a within-mob member operation (spawn
/// finalization, peer messaging, respawn finalization) that requires the mob to
/// be live and running. MobMachine — not a handwritten shell phase pre-check —
/// owns the eligibility over its own lifecycle phase plus the `destroy_admitted`
/// projection marker: an operation is `Admitted` iff the machine is `Running`
/// and destruction has not been admitted, and `DeniedNotRunning` otherwise. The
/// owning actor mirrors `DeniedNotRunning` to the same `InvalidTransition`
/// rejection it previously produced.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobMemberOperationEligibilityKind {
#[default]
DeniedNotRunning,
Admitted,
}
/// Pure wire-projection bridge rejection cause, mirroring every variant of the
/// wire `BridgeRejectionCause`. The mob bridge consumer maps the typed wire
/// cause onto this and feeds it to MobMachine for recovery classification.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobBridgeRejectionCause {
#[default]
NotBound,
StaleSupervisor,
SenderMismatch,
AlreadyBound,
InvalidBootstrapToken,
UnsupportedProtocolVersion,
InvalidSupervisorSpec,
InvalidPeerSpec,
AddressMismatch,
Unsupported,
Internal,
}
/// Machine-owned bridge-rejection recovery verdict. The mob shell mirrors this:
/// `RebindRecover` re-runs `BindMember`, `FatalBubbleUp` bubbles the rejection.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobBridgeRejectionRecovery {
#[default]
FatalBubbleUp,
RebindRecover,
}
/// Machine-owned pending-supervisor-acceptance verdict for a re-verified
/// already-accepted remote peer during supervisor rotation. The actor mirrors
/// this: `NotConfirmedReattempt` drops the accepted peer and re-attempts the
/// rotation against it; `StalePendingAuthority` errors with the stale-pending
/// message; `Fatal` bubbles the rejection up.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobPendingSupervisorAcceptanceKind {
#[default]
Fatal,
NotConfirmedReattempt,
StalePendingAuthority,
}
/// Machine-owned frame-seed idempotency disposition. `CreateFrameSeed` emits
/// `Seeded` for a fresh seed and `AlreadySeeded` (a no-op) when re-seeding an
/// already-tracked frame. The flow shell mirrors both as success — replacing
/// the former guard-name string match (`frame_seed_is_new`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobFrameSeedDisposition {
#[default]
Seeded,
AlreadySeeded,
}
/// Fallible reverse mapping: the `Ingest` variant has no counterpart in the
/// shell-side [`crate::ids::WorkOrigin`] (which only classifies mob-submitted
/// work lanes); callers on the mob-domain side assert it away and surface a
/// domain error if the DSL ever produces it back across the seam.
/// Typed member lifecycle notice kind. Replaces the former literal-string
/// `kind` field on [`MobMachineEffect::EmitMemberLifecycleNotice`] — closed
/// set of observed member-lifecycle transitions the orchestrator emits.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MemberLifecycleKind {
#[default]
Spawned,
Retiring,
Retired,
Reset,
Respawned,
Completed,
Destroyed,
}
/// Typed durable mob lifecycle journal request. The runtime may append the
/// matching event only after a generated transition emits this local effect.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MobLifecycleJournalKind {
#[default]
Completed,
Stopped,
Resumed,
Destroying,
DestroyStorageFinalizing,
MemberSpawned,
MemberRetirementStartedReleasing,
MemberRetirementStartedPreservingBinding,
MemberRetirementStartedPeerOnly,
RemoteMemberRuntimeRetired,
RemoteMemberSupervisorRevoked,
MemberRetired,
RespawnTopologyAbandoned,
Reset,
MemberRetirementStarted,
}
impl MemberLifecycleKind {
/// Stable discriminant for logging / wire surfaces.
pub const fn as_str(self) -> &'static str {
match self {
Self::Spawned => "spawned",
Self::Retiring => "retiring",
Self::Retired => "retired",
Self::Reset => "reset",
Self::Respawned => "respawned",
Self::Completed => "completed",
Self::Destroyed => "destroyed",
}
}
}
impl std::fmt::Display for MemberLifecycleKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
/// Typed wiring lifecycle notice kind for
/// [`MobMachineEffect::EmitWiringLifecycleNotice`]. Pair-valued (edge-keyed)
/// counterpart to [`MemberLifecycleKind`] (member-keyed). Emitted alongside
/// [`MobMachineEffect::WiringGraphChanged`] by `WireMembers`/`UnwireMembers`
/// transitions so external observers can reconstruct which identity pair
/// was wired or unwired.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum WiringLifecycleKind {
#[default]
Wired,
Unwired,
}
impl WiringLifecycleKind {
/// Stable discriminant for logging / wire surfaces.
pub const fn as_str(self) -> &'static str {
match self {
Self::Wired => "wired",
Self::Unwired => "unwired",
}
}
}
impl std::fmt::Display for WiringLifecycleKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
/// Typed kickoff-notice intent. Replaces the former literal-string `intent`
/// field on [`MobMachineEffect::EmitKickoffLifecycleNotice`] — closed mirror
/// of [`KickoffPhase`] with an additional `Started` intent variant for the
/// `KickoffResolveStarted` input.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum KickoffIntent {
#[default]
Pending,
Starting,
Started,
CallbackPending,
Failed,
Cancelled,
}
impl KickoffIntent {
/// Stable discriminant for logging / wire surfaces.
pub const fn as_str(self) -> &'static str {
match self {
Self::Pending => "Pending",
Self::Starting => "Starting",
Self::Started => "Started",
Self::CallbackPending => "CallbackPending",
Self::Failed => "Failed",
Self::Cancelled => "Cancelled",
}
}
}
impl std::fmt::Display for KickoffIntent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
// ---------------------------------------------------------------------------
// Wave-G1 catalog fold enums. All are unit-variant closed mirrors carried as
// the typed verdict/disposition/capability fields on the G1 inputs/effects.
// ---------------------------------------------------------------------------
/// Catalog-expansion twins of the public identity reconciliation vocabulary.
/// The production MobMachine expansion imports the exact domain types from
/// `meerkat_mob::identity`; keeping these variants here makes the catalog DSL
/// independently compilable and causes vocabulary drift to fail at compile
/// time.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityAuthorityCondition {
Unavailable,
Missing,
Malformed,
PresentCreateIfAbsent,
PresentRequireExisting,
Absent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityLeaseCondition {
Unavailable,
Missing,
Malformed,
HeldByCurrentIncarnation,
HeldByOtherLiveIncarnation,
HeldByExpiredIncarnation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityResourceCondition {
Unavailable,
Missing,
Matching,
Divergent,
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentitySessionCondition {
Unavailable,
Missing,
Matching,
RecoverableDivergence,
AmbiguousDivergence,
Malformed,
IrrecoverablyCorrupt,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityReceiptCondition {
NotRequired,
Unavailable,
Missing,
Matching,
Conflicting,
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityExternalTrustCondition {
NotRequired,
Unavailable,
Matching,
Absent,
Contradictory,
Indeterminate,
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityExternalCeremonyCondition {
NotRequired,
FreshAvailable,
TemporarilyUnavailable,
AwaitFresh,
SpentOrUnknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityInitialDeliveryCondition {
NotRequired,
Unavailable,
ProvenAbsent,
AcceptedPendingExact,
CommittedExact,
ContentOnlyMatch,
OperationCollision,
Contradictory,
Indeterminate,
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum IdentityReconcileDecision {
Backoff,
RepairBlocked,
AcquireLease,
AwaitLease,
SealRetirementProven,
SealSessionCreationConsumed,
EnsureSessionAuthority,
EnsureRuntimeRegistration,
AwaitExternalBindingCeremony,
EnsureExternalBindingReceipt,
EnsureExternalBinding,
EnsureMemberMaterialization,
EnsureInitialDeliveryReceipt,
EnsureInitialDelivery,
AwaitInitialDelivery,
ReconcileWiring,
RetireMemberMaterialization,
RetireRuntimeRegistration,
ReleaseSessionAuthority,
Converged,
Tombstoned,
Quarantined,
}
/// Row #14: machine-owned duplicate-member admission verdict for
/// [`MobMachineInput::ProbeMemberAdmission`]. The actor mirrors `Admitted ->
/// Ok` / `DuplicateRejected -> MemberAlreadyExists` instead of probing the
/// PendingSpawnLineage side-map.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum MemberAdmissionVerdictKind {
#[default]
Admitted,
DuplicateRejected,
}
/// Row #260: typed step-output fault carried by
/// [`MobMachineInput::ClassifyStepOutputFault`] /
/// [`MobMachineEffect::StepOutputFaultClassified`]. Fault detail strings stay
/// shell-side; this enum is the guard-visible, terminalizable cause.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum StepOutputFaultKind {
#[default]
MalformedJson,
}
/// Row #260: machine-owned step-fault disposition. The flow shell mirrors
/// `Retry` (attempt += 1, continue) / `Terminal` (fail).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum StepFaultDispositionKind {
#[default]
Retry,
Terminal,
}
/// Row #261: typed supervisor-escalation failure cause for
/// [`MobMachineEffect::SupervisorEscalationFailed`]. Fail-closed is a typed
/// terminal, not a free-form `SupervisorEscalation` string.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SupervisorEscalationFailureCause {
#[default]
NoEligibleSupervisor,
TimeoutExceeded,
}
/// Row #293: topology-edge policy decision. Carried by
/// [`MobMachineInput::EvaluateTopologyEdge`] (as `Option<PolicyDecision>` rule
/// match), the declared `topology_default_policy` state field, and the
/// [`MobMachineEffect::TopologyEdgeVerdictResolved`] verdict.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum PolicyDecision {
#[default]
Allow,
Deny,
}
/// Row #314: external-member rebind capability. Minted by the bridge/spawn
/// chokepoints into `external_member_rebind_capability`; read by
/// `project_external_member_observation`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ExternalMemberRebindCapability {
#[default]
Unavailable,
Available,
}
/// Row #320: machine-owned turn-timeout disposition for
/// [`MobMachineEffect::TurnTimeoutDispositionClassified`]. The shell mirrors
/// `Detached` (reconcile detached turn) / `Canceled` (abort) / `Retryable`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum TurnTimeoutDisposition {
#[default]
Detached,
Canceled,
Retryable,
}
/// Undirected wiring edge between two identities. Callers MUST normalize
/// to `(smaller, larger)` before constructing so that edge equality is
/// independent of insertion order.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct WiringEdge {
pub a: AgentIdentity,
pub b: AgentIdentity,
}
impl WiringEdge {
/// Constructs an edge, normalizing so `a <= b`.
pub fn new(lhs: AgentIdentity, rhs: AgentIdentity) -> Self {
if lhs <= rhs {
Self { a: lhs, b: rhs }
} else {
Self { a: rhs, b: lhs }
}
}
}
/// Descriptor-bearing member trust endpoint. MobMachine owns this fact when a
/// member runtime registers its comms identity, so member trust wiring can
/// authorize the exact peer descriptor that will be installed.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct MemberPeerEndpoint {
pub name: PeerName,
pub peer_id: PeerId,
pub address: PeerAddress,
pub signing_key: PeerSigningKey,
}
impl From<&meerkat_core::comms::TrustedPeerDescriptor> for MemberPeerEndpoint {
fn from(spec: &meerkat_core::comms::TrustedPeerDescriptor) -> Self {
Self {
name: PeerName(spec.name.as_str().to_owned()),
peer_id: PeerId(spec.peer_id.to_string()),
address: PeerAddress(spec.address.to_string()),
signing_key: PeerSigningKey(spec.pubkey),
}
}
}
/// Descriptor-bearing external peer trust endpoint. Unlike `WiringEdge`, this
/// preserves the routing id, transport address, and signing key that make an
/// external trust edge authoritative.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct ExternalPeerEndpoint {
pub name: PeerName,
pub peer_id: PeerId,
pub address: PeerAddress,
pub signing_key: PeerSigningKey,
}
impl From<&meerkat_core::comms::TrustedPeerDescriptor> for ExternalPeerEndpoint {
fn from(spec: &meerkat_core::comms::TrustedPeerDescriptor) -> Self {
Self {
name: PeerName(spec.name.as_str().to_owned()),
peer_id: PeerId(spec.peer_id.to_string()),
address: PeerAddress(spec.address.to_string()),
signing_key: PeerSigningKey(spec.pubkey),
}
}
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct ExternalPeerEdge {
pub local: AgentIdentity,
pub endpoint: ExternalPeerEndpoint,
}
impl ExternalPeerEdge {
pub fn new(local: AgentIdentity, endpoint: ExternalPeerEndpoint) -> Self {
Self { local, endpoint }
}
}
impl Default for ExternalPeerEdge {
fn default() -> Self {
Self {
local: AgentIdentity(String::new()),
endpoint: ExternalPeerEndpoint::default(),
}
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PeerName(pub String);
impl<T: Into<String>> From<T> for PeerName {
fn from(s: T) -> Self {
Self(s.into())
}
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct ExternalPeerKey {
pub local: AgentIdentity,
pub name: PeerName,
}
impl ExternalPeerKey {
pub fn new(local: AgentIdentity, name: PeerName) -> Self {
Self { local, name }
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PeerId(pub String);
impl<T: Into<String>> From<T> for PeerId {
fn from(s: T) -> Self {
Self(s.into())
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PeerAddress(pub String);
impl<T: Into<String>> From<T> for PeerAddress {
fn from(s: T) -> Self {
Self(s.into())
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct SupervisorProtocolVersion(pub String);
impl From<String> for SupervisorProtocolVersion {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&str> for SupervisorProtocolVersion {
fn from(s: &str) -> Self {
Self(s.to_owned())
}
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PeerSigningKey(pub [u8; 32]);
impl From<[u8; 32]> for PeerSigningKey {
fn from(key: [u8; 32]) -> Self {
Self(key)
}
}
// ---------------------------------------------------------------------------
// Multi-host mobs (§6.1/§6.2/§6.5/§15/§18) bridging types
// ---------------------------------------------------------------------------
/// Identity-first member-host id: the host's comms `PeerId` string. No second
/// id space; wire-boundary validation (pubkey derivation) is owned by the
/// contracts/shell seam, not this bridging newtype.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct HostId(pub String);
impl<T: Into<String>> From<T> for HostId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Host bind window phase: absence of a `host_bind_phase` entry = unbound.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum HostBindPhase {
#[default]
Requested,
Bound,
}
/// Scheme-qualified `ws|wss` absolute base URL for a host's live channel
/// acceptor (§16 DL5). Shape validation is a wire-boundary concern.
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct LiveWsEndpointUrl(pub String);
impl<T: Into<String>> From<T> for LiveWsEndpointUrl {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Opaque principal identity for control-scope grants (§8).
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PrincipalId(pub String);
impl<T: Into<String>> From<T> for PrincipalId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Remote turn-directive input id (§18 O2 obligation key component).
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct InputId(pub String);
impl<T: Into<String>> From<T> for InputId {
fn from(s: T) -> Self {
Self(s.into())
}
}
/// Principal→mob control-scope vocabulary (A9, ten variants; `Live` gates the
/// §16 live family; `AdminHost` is bind/revoke hosts ONLY; grant
/// administration is `AdminGrants`).
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum ControlScope {
#[default]
List,
ReadHistory,
SubscribeEvents,
SendCommand,
Cancel,
Retire,
WireTopology,
Live,
AdminHost,
AdminGrants,
}
/// Typed member-session disposal carried by the retirement-archived signals
/// (§19.L4). Flat DSL vocabulary; the wire folds `AlreadyArchived` into
/// `Archived` (both mean the durable terminal holds).
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum MemberSessionDisposal {
#[default]
Archived,
RuntimeReleasedOnlyHostOwned,
RuntimeReleasedOnlyNoDurableSessions,
}
/// Machine-owned flow-step dispatch verdict (§18.9).
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum FlowStepDispatchKind {
#[default]
Local,
RemoteTurnDirective,
RejectedOverlayAutonomous,
RejectedHostIncapable,
}
/// Typed member-operator upcall rejection cause (§15 R6).
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum MemberOperatorRejectKind {
#[default]
UnknownIdentity,
SenderKeyMismatch,
StaleGeneration,
StaleFence,
StaleSession,
StaleHost,
StaleHostBindingGeneration,
HostRevoked,
NoPlacement,
}
/// Route-operation discriminant (§6.2). Install may enter the pending ledger;
/// Remove is retained for wire compatibility and synchronous pre-unwire
/// authorization only.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum RouteObligationKind {
#[default]
Install,
Remove,
}
/// Host-scoped route-operation descriptor (§6.2, D4). Only `Install` values
/// may be outstanding in `pending_route_installs`; `Remove` values are
/// ephemeral input/effect authority. Carried whole on the obligation inputs —
/// the DSL cannot construct struct values inside update blocks.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct RouteInstallObligation {
pub edge: WiringEdge,
pub host: HostId,
pub kind: RouteObligationKind,
}
impl Default for RouteInstallObligation {
fn default() -> Self {
Self {
edge: WiringEdge::new(AgentIdentity(String::new()), AgentIdentity(String::new())),
host: HostId::default(),
kind: RouteObligationKind::default(),
}
}
}
/// Outstanding remote turn-directive outcome obligation (§18 O2).
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct RemoteTurnObligation {
pub agent_identity: AgentIdentity,
pub host_id: HostId,
pub host_binding_generation: u64,
pub member_session_id: SessionId,
pub generation: Generation,
pub fence_token: FenceToken,
pub dispatch_sequence: u64,
pub input_id: InputId,
pub run_id: RunId,
pub step_id: StepId,
}
impl Default for RemoteTurnObligation {
fn default() -> Self {
Self {
agent_identity: AgentIdentity(String::new()),
host_id: HostId::default(),
host_binding_generation: 0,
member_session_id: SessionId::default(),
generation: Generation::default(),
fence_token: FenceToken::default(),
dispatch_sequence: 0,
input_id: InputId::default(),
run_id: RunId(String::new()),
step_id: StepId(String::new()),
}
}
}
/// Exact controller cleanup custody for one ordinary placed
/// `SubmitWork(ack_mode = TurnCompleted)` interaction.
///
/// The RPC promise is intentionally not represented. `input_id` is the
/// canonical non-nil interaction id delivered to the member host; the rest
/// is the full residency needed for terminal fold, ACK, cancellation, and
/// release disposal without consulting volatile roster folklore.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct PlacedCompletionObligation {
pub agent_identity: AgentIdentity,
pub host_id: HostId,
pub host_binding_generation: u64,
pub member_session_id: SessionId,
pub generation: Generation,
pub fence_token: FenceToken,
pub dispatch_sequence: u64,
pub input_id: InputId,
}
impl Default for PlacedCompletionObligation {
fn default() -> Self {
Self {
agent_identity: AgentIdentity(String::new()),
host_id: HostId::default(),
host_binding_generation: 0,
member_session_id: SessionId::default(),
generation: Generation::default(),
fence_token: FenceToken::default(),
dispatch_sequence: 0,
input_id: InputId::default(),
}
}
}
/// Exact controlling-side custody key for one placed autonomous kickoff.
///
/// `input_id` is a canonical UUID string shared by the runtime input id,
/// idempotency key, and interaction id. Prompt/content metadata intentionally
/// stays in the private durable intent carrier; the machine owns only the
/// semantic correlation and exact host/member residency needed to authorize
/// send, terminal resolution, ACK, and disposal.
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct PlacedKickoffObligation {
pub agent_identity: AgentIdentity,
pub host_id: HostId,
pub host_binding_generation: u64,
pub member_session_id: SessionId,
pub generation: Generation,
pub fence_token: FenceToken,
pub input_id: InputId,
pub objective_id: String,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum PlacedKickoffOutcomeKind {
Started,
CallbackPending,
Failed,
Cancelled,
RejectedNoEffect,
#[default]
Disposed,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum PlacedKickoffClosureKind {
#[default]
Acknowledged,
Disposed,
RejectedNoEffect,
}
/// Typed durable reason that closes ordinary placed-completion work origin.
///
/// A quiesce marker is retry state for one lifecycle command, not a generic
/// boolean latch: cold recovery and later command retries must be able to
/// distinguish a pending Stop from terminal Complete/Destroy or a temporary
/// RetireAll drain.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum PlacedCompletionLifecycleIntentKind {
Stop,
Reset,
Complete,
RetireAll,
#[default]
Destroy,
}
impl Default for PlacedKickoffObligation {
fn default() -> Self {
Self {
agent_identity: AgentIdentity(String::new()),
host_id: HostId::default(),
host_binding_generation: 0,
member_session_id: SessionId::default(),
generation: Generation::default(),
fence_token: FenceToken::default(),
input_id: InputId::default(),
objective_id: String::new(),
}
}
}