telltale_vm/vm/vm_config_and_observability.rs
1/// VM configuration.
2#[derive(Debug, Clone, Serialize, Deserialize)]
3pub struct VMConfig {
4 /// Migration-safe config schema version.
5 #[serde(default = "default_config_schema_version")]
6 pub config_schema_version: u32,
7 /// Scheduling policy.
8 pub sched_policy: SchedPolicy,
9 /// Default buffer configuration for new sessions.
10 pub buffer_config: BufferConfig,
11 /// Maximum number of concurrent sessions.
12 pub max_sessions: usize,
13 /// Maximum number of concurrent coroutines.
14 pub max_coroutines: usize,
15 /// Number of registers per coroutine.
16 pub num_registers: u16,
17 /// Simulated time per scheduler round.
18 pub tick_duration: Duration,
19 /// Guard layers configured for the VM.
20 pub guard_layers: Vec<GuardLayerConfig>,
21 /// Whether speculative execution is enabled.
22 pub speculation_enabled: bool,
23 /// Determinism profile for replay/equivalence behavior.
24 pub determinism_mode: DeterminismMode,
25 /// Effect determinism tier used by admission and envelope artifacts.
26 #[serde(default)]
27 pub effect_determinism_tier: EffectDeterminismTier,
28 /// Output-condition policy for commit eligibility of observable outputs.
29 pub output_condition_policy: OutputConditionPolicy,
30 /// Monitor mode for pre-dispatch type checks.
31 #[serde(default)]
32 pub monitor_mode: MonitorMode,
33 /// Flow policy for epistemic knowledge checks.
34 #[serde(default)]
35 pub flow_policy: FlowPolicy,
36 /// Deterministic cost charged for each instruction dispatch.
37 #[serde(default = "default_instruction_cost")]
38 pub instruction_cost: usize,
39 /// Initial cost budget assigned to each coroutine.
40 #[serde(default = "default_initial_cost_budget")]
41 pub initial_cost_budget: usize,
42 /// Whether threaded scheduler may admit same-session picks when footprint-disjoint.
43 #[serde(default)]
44 pub footprint_guided_wave_widening: bool,
45 /// Runtime tuning profile used by instrumentation/benchmark harnesses.
46 #[serde(default)]
47 pub runtime_tuning_profile: RuntimeTuningProfile,
48 /// Round semantics mode used by threaded scheduler.
49 #[serde(default)]
50 pub threaded_round_semantics: ThreadedRoundSemantics,
51 /// Effect-trace capture mode for integration/perf tuning.
52 #[serde(default)]
53 pub effect_trace_capture_mode: EffectTraceCaptureMode,
54 /// Runtime payload hardening mode for inbound/outbound messages.
55 #[serde(default)]
56 pub payload_validation_mode: PayloadValidationMode,
57 /// Upper bound for VM payload values in estimated wire bytes.
58 #[serde(default = "default_max_payload_bytes")]
59 pub max_payload_bytes: usize,
60 /// Enable runtime host-contract assertions with deterministic diagnostics.
61 #[serde(default)]
62 pub host_contract_assertions: bool,
63}
64
65impl Default for VMConfig {
66 fn default() -> Self {
67 Self {
68 config_schema_version: default_config_schema_version(),
69 sched_policy: SchedPolicy::Cooperative,
70 buffer_config: BufferConfig::default(),
71 max_sessions: 256,
72 max_coroutines: 1024,
73 num_registers: 16,
74 tick_duration: Duration::from_millis(1),
75 guard_layers: Vec::new(),
76 speculation_enabled: false,
77 determinism_mode: DeterminismMode::Full,
78 effect_determinism_tier: EffectDeterminismTier::StrictDeterministic,
79 output_condition_policy: OutputConditionPolicy::AllowAll,
80 monitor_mode: MonitorMode::SessionTypePrecheck,
81 flow_policy: FlowPolicy::AllowAll,
82 instruction_cost: 1,
83 initial_cost_budget: usize::MAX,
84 footprint_guided_wave_widening: false,
85 runtime_tuning_profile: RuntimeTuningProfile::Standard,
86 threaded_round_semantics: ThreadedRoundSemantics::CanonicalOneStep,
87 effect_trace_capture_mode: EffectTraceCaptureMode::Full,
88 payload_validation_mode: PayloadValidationMode::Structural,
89 max_payload_bytes: default_max_payload_bytes(),
90 host_contract_assertions: false,
91 }
92 }
93}
94
95impl VMConfig {
96 /// Assert VM configuration invariants required for safe state initialization.
97 ///
98 /// # Panics
99 ///
100 /// Panics when a required invariant is violated.
101 pub fn assert_invariants(&self) {
102 assert!(
103 self.config_schema_version >= 1,
104 "config_schema_version must be >= 1"
105 );
106 assert!(self.max_sessions > 0, "max_sessions must be > 0");
107 assert!(self.max_coroutines > 0, "max_coroutines must be > 0");
108 assert!(self.num_registers > 0, "num_registers must be > 0");
109 assert!(self.instruction_cost > 0, "instruction_cost must be > 0");
110 assert!(self.max_payload_bytes > 0, "max_payload_bytes must be > 0");
111 }
112}
113
114/// Observable event emitted by the VM.
115#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
116pub struct TickedObsEvent {
117 /// Scheduler tick when the wrapped event occurred.
118 pub tick: u64,
119 /// Underlying observable event payload.
120 pub event: ObsEvent,
121}
122
123/// Observable event emitted by the VM.
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125pub enum ObsEvent {
126 /// Value sent on an edge.
127 Sent {
128 /// Scheduler tick when the event occurred.
129 tick: u64,
130 /// Session-scoped edge for this send.
131 edge: Edge,
132 /// Session ID.
133 session: SessionId,
134 /// Sender role.
135 from: String,
136 /// Receiver role.
137 to: String,
138 /// Message label.
139 label: String,
140 },
141 /// Value received on an edge.
142 Received {
143 /// Scheduler tick when the event occurred.
144 tick: u64,
145 /// Session-scoped edge for this receive.
146 edge: Edge,
147 /// Session ID.
148 session: SessionId,
149 /// Sender role.
150 from: String,
151 /// Receiver role.
152 to: String,
153 /// Message label.
154 label: String,
155 },
156 /// Label offered on an edge.
157 Offered {
158 /// Scheduler tick when the event occurred.
159 tick: u64,
160 /// Session-scoped edge for this offer.
161 edge: Edge,
162 /// Label offered.
163 label: String,
164 },
165 /// Label chosen on an edge.
166 Chose {
167 /// Scheduler tick when the event occurred.
168 tick: u64,
169 /// Session-scoped edge for this choice.
170 edge: Edge,
171 /// Label chosen.
172 label: String,
173 },
174 /// Session opened.
175 Opened {
176 /// Scheduler tick when the event occurred.
177 tick: u64,
178 /// Session ID.
179 session: SessionId,
180 /// Participating roles.
181 roles: Vec<String>,
182 },
183 /// Session closed.
184 Closed {
185 /// Scheduler tick when the event occurred.
186 tick: u64,
187 /// Session ID.
188 session: SessionId,
189 },
190 /// Session epoch advanced.
191 EpochAdvanced {
192 /// Scheduler tick when the event occurred.
193 tick: u64,
194 /// Session ID.
195 sid: SessionId,
196 /// New epoch number.
197 epoch: usize,
198 },
199 /// Coroutine halted.
200 Halted {
201 /// Scheduler tick when the event occurred.
202 tick: u64,
203 /// Coroutine ID.
204 coro_id: usize,
205 },
206 /// Effect handler invoked.
207 Invoked {
208 /// Scheduler tick when the event occurred.
209 tick: u64,
210 /// Coroutine ID.
211 coro_id: usize,
212 /// Role name.
213 role: String,
214 },
215 /// Guard layer acquired.
216 Acquired {
217 /// Scheduler tick when the event occurred.
218 tick: u64,
219 /// Session ID.
220 session: SessionId,
221 /// Role name.
222 role: String,
223 /// Guard layer identifier.
224 layer: String,
225 },
226 /// Guard layer released.
227 Released {
228 /// Scheduler tick when the event occurred.
229 tick: u64,
230 /// Session ID.
231 session: SessionId,
232 /// Role name.
233 role: String,
234 /// Guard layer identifier.
235 layer: String,
236 },
237 /// Endpoint transferred between coroutines.
238 Transferred {
239 /// Scheduler tick when the event occurred.
240 tick: u64,
241 /// Session ID.
242 session: SessionId,
243 /// Role name.
244 role: String,
245 /// Source coroutine.
246 from: usize,
247 /// Target coroutine.
248 to: usize,
249 },
250 /// Speculation forked for a ghost session.
251 Forked {
252 /// Scheduler tick when the event occurred.
253 tick: u64,
254 /// Session ID.
255 session: SessionId,
256 /// Ghost session id.
257 ghost: usize,
258 },
259 /// Speculation joined.
260 Joined {
261 /// Scheduler tick when the event occurred.
262 tick: u64,
263 /// Session ID.
264 session: SessionId,
265 },
266 /// Speculation aborted.
267 Aborted {
268 /// Scheduler tick when the event occurred.
269 tick: u64,
270 /// Session ID.
271 session: SessionId,
272 },
273 /// Knowledge fact tagged.
274 Tagged {
275 /// Scheduler tick when the event occurred.
276 tick: u64,
277 /// Session ID.
278 session: SessionId,
279 /// Role name.
280 role: String,
281 /// Fact payload.
282 fact: String,
283 },
284 /// Knowledge fact checked.
285 Checked {
286 /// Scheduler tick when the event occurred.
287 tick: u64,
288 /// Session ID.
289 session: SessionId,
290 /// Role name.
291 role: String,
292 /// Target role.
293 target: String,
294 /// Whether the flow policy permitted the fact.
295 permitted: bool,
296 },
297 /// Coroutine faulted.
298 Faulted {
299 /// Scheduler tick when the event occurred.
300 tick: u64,
301 /// Coroutine ID.
302 coro_id: usize,
303 /// The fault.
304 fault: Fault,
305 },
306 /// Output-condition verification was evaluated at commit time.
307 OutputConditionChecked {
308 /// Scheduler tick when the event occurred.
309 tick: u64,
310 /// Predicate reference that was checked.
311 predicate_ref: String,
312 /// Optional witness reference used by the check.
313 witness_ref: Option<String>,
314 /// Opaque output digest checked by the verifier.
315 output_digest: String,
316 /// Verification outcome.
317 passed: bool,
318 },
319}
320
321/// The VM execution result for a single step.
322#[derive(Debug)]
323pub enum StepResult {
324 /// A coroutine executed an instruction and may continue.
325 Continue,
326 /// No coroutines are ready (all blocked or done).
327 Stuck,
328 /// All coroutines have completed.
329 AllDone,
330}
331
332/// Terminal status returned by bounded VM run APIs.
333#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
334pub enum RunStatus {
335 /// All coroutines reached terminal states.
336 AllDone,
337 /// No runnable coroutines remain (blocked/stuck).
338 Stuck,
339 /// `max_rounds`/`max_steps` budget was exhausted before termination.
340 MaxRoundsExceeded,
341}
342
343/// Debug metadata for the most recent scheduler-dispatched step.
344#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
345pub enum SchedExecStatus {
346 /// Instruction continued execution.
347 Continue,
348 /// Instruction yielded cooperative control.
349 Yielded,
350 /// Instruction blocked.
351 Blocked,
352 /// Coroutine halted normally.
353 Halted,
354 /// Coroutine faulted.
355 Faulted,
356}
357
358/// Debug metadata for the most recent scheduler-dispatched step.
359#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
360pub struct SchedStepDebug {
361 /// Selected coroutine id.
362 pub selected_coro: usize,
363 /// Instruction-step execution status.
364 pub exec_status: SchedExecStatus,
365}