Skip to main content

pi/
hostcall_superinstructions.rs

1//! Superinstruction compiler for hot typed-hostcall opcode traces.
2
3use serde::{Deserialize, Serialize};
4use std::collections::{BTreeMap, HashMap};
5
6/// Versioned schema for serialized superinstruction plans.
7pub const HOSTCALL_SUPERINSTRUCTION_SCHEMA_VERSION: &str = "pi.ext.hostcall_superinstruction.v1";
8/// Plan payload version.
9pub const HOSTCALL_SUPERINSTRUCTION_PLAN_VERSION: u16 = 1;
10
11const DEFAULT_MIN_SUPPORT: u32 = 3;
12const DEFAULT_MAX_WINDOW: usize = 4;
13const BASE_OPCODE_COST_UNITS: i64 = 10;
14const FUSED_OPCODE_FIXED_COST_UNITS: i64 = 6;
15const FUSED_OPCODE_STEP_COST_UNITS: i64 = 2;
16
17/// A fused superinstruction plan derived from repeated hostcall opcode windows.
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct HostcallSuperinstructionPlan {
20    pub schema: String,
21    pub version: u16,
22    pub plan_id: String,
23    pub trace_signature: String,
24    pub opcode_window: Vec<String>,
25    pub support_count: u32,
26    pub estimated_cost_baseline: i64,
27    pub estimated_cost_fused: i64,
28    pub expected_cost_delta: i64,
29}
30
31impl HostcallSuperinstructionPlan {
32    #[must_use]
33    pub fn width(&self) -> usize {
34        self.opcode_window.len()
35    }
36
37    #[must_use]
38    pub fn matches_trace_prefix(&self, trace: &[String]) -> bool {
39        trace.len() >= self.opcode_window.len()
40            && trace
41                .iter()
42                .zip(self.opcode_window.iter())
43                .all(|(left, right)| left == right)
44    }
45}
46
47/// Deterministic compiler for recurring opcode motifs.
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct HostcallSuperinstructionCompiler {
50    enabled: bool,
51    min_support: u32,
52    max_window: usize,
53}
54
55impl Default for HostcallSuperinstructionCompiler {
56    fn default() -> Self {
57        Self::from_env()
58    }
59}
60
61impl HostcallSuperinstructionCompiler {
62    #[must_use]
63    pub const fn new(enabled: bool, min_support: u32, max_window: usize) -> Self {
64        Self {
65            enabled,
66            min_support,
67            max_window,
68        }
69    }
70
71    #[must_use]
72    pub fn from_env() -> Self {
73        let enabled = bool_from_env("PI_HOSTCALL_SUPERINSTRUCTIONS", true);
74        let min_support = std::env::var("PI_HOSTCALL_SUPERINSTRUCTION_MIN_SUPPORT")
75            .ok()
76            .and_then(|raw| raw.trim().parse::<u32>().ok())
77            .map_or(DEFAULT_MIN_SUPPORT, |value| value.max(2));
78        let max_window = std::env::var("PI_HOSTCALL_SUPERINSTRUCTION_MAX_WINDOW")
79            .ok()
80            .and_then(|raw| raw.trim().parse::<usize>().ok())
81            .map_or(DEFAULT_MAX_WINDOW, |value| value.max(2));
82        Self::new(enabled, min_support, max_window)
83    }
84
85    #[must_use]
86    pub const fn enabled(&self) -> bool {
87        self.enabled
88    }
89
90    #[must_use]
91    pub const fn min_support(&self) -> u32 {
92        self.min_support
93    }
94
95    #[must_use]
96    pub const fn max_window(&self) -> usize {
97        self.max_window
98    }
99
100    /// Compile frequent opcode windows into deterministic fused plans.
101    #[must_use]
102    pub fn compile_plans(&self, traces: &[Vec<String>]) -> Vec<HostcallSuperinstructionPlan> {
103        if !self.enabled {
104            return Vec::new();
105        }
106        let mut windows: BTreeMap<Vec<String>, u32> = BTreeMap::new();
107        for trace in traces {
108            let trace_len = trace.len();
109            if trace_len < 2 {
110                continue;
111            }
112            let max_width = self.max_window.min(trace_len);
113            for width in 2..=max_width {
114                let mut next_valid: HashMap<&[String], usize> = HashMap::new();
115                for start in 0..=trace_len - width {
116                    let window_slice = &trace[start..start + width];
117                    if window_slice.iter().any(|opcode| opcode.trim().is_empty()) {
118                        continue;
119                    }
120
121                    let min_start = *next_valid.get(window_slice).unwrap_or(&0);
122                    if start >= min_start {
123                        let entry = windows.entry(window_slice.to_vec()).or_insert(0);
124                        *entry = entry.saturating_add(1);
125                        next_valid.insert(window_slice, start + width);
126                    }
127                }
128            }
129        }
130
131        let mut plans = windows
132            .into_iter()
133            .filter_map(|(opcode_window, support_count)| {
134                if support_count < self.min_support {
135                    return None;
136                }
137                let estimated_cost_baseline = estimated_baseline_cost(opcode_window.len());
138                let estimated_cost_fused = estimated_fused_cost(opcode_window.len());
139                let expected_cost_delta =
140                    estimated_cost_baseline.saturating_sub(estimated_cost_fused);
141                if expected_cost_delta <= 0 {
142                    return None;
143                }
144
145                let trace_signature = opcode_window_signature(&opcode_window);
146                let plan_id = format!("fuse_{trace_signature}");
147                Some(HostcallSuperinstructionPlan {
148                    schema: HOSTCALL_SUPERINSTRUCTION_SCHEMA_VERSION.to_string(),
149                    version: HOSTCALL_SUPERINSTRUCTION_PLAN_VERSION,
150                    plan_id,
151                    trace_signature,
152                    opcode_window,
153                    support_count,
154                    estimated_cost_baseline,
155                    estimated_cost_fused,
156                    expected_cost_delta,
157                })
158            })
159            .collect::<Vec<_>>();
160
161        plans.sort_by(|left, right| {
162            right
163                .expected_cost_delta
164                .cmp(&left.expected_cost_delta)
165                .then_with(|| right.support_count.cmp(&left.support_count))
166                .then_with(|| right.width().cmp(&left.width()))
167                .then_with(|| left.opcode_window.cmp(&right.opcode_window))
168                .then_with(|| left.plan_id.cmp(&right.plan_id))
169        });
170        plans
171    }
172}
173
174/// Plan lookup/deoptimization result for a concrete trace.
175#[derive(Debug, Clone, PartialEq, Eq)]
176pub struct HostcallSuperinstructionSelection {
177    pub trace_signature: String,
178    pub selected_plan_id: Option<String>,
179    pub selected_window: Option<Vec<String>>,
180    pub expected_cost_delta: i64,
181    pub deopt_reason: Option<&'static str>,
182}
183
184impl HostcallSuperinstructionSelection {
185    #[must_use]
186    pub const fn hit(&self) -> bool {
187        self.selected_plan_id.is_some()
188    }
189}
190
191/// Canonical + fused execution representation with safe fallback details.
192#[derive(Debug, Clone, PartialEq, Eq)]
193pub struct HostcallSuperinstructionExecution {
194    pub canonical_trace: Vec<String>,
195    pub fused_trace: Vec<String>,
196    pub selection: HostcallSuperinstructionSelection,
197}
198
199/// Select the best matching superinstruction plan for a trace prefix.
200#[must_use]
201pub fn select_plan_for_trace(
202    trace: &[String],
203    plans: &[HostcallSuperinstructionPlan],
204) -> HostcallSuperinstructionSelection {
205    let trace_signature = opcode_window_signature(trace);
206    if trace.is_empty() {
207        return HostcallSuperinstructionSelection {
208            trace_signature,
209            selected_plan_id: None,
210            selected_window: None,
211            expected_cost_delta: 0,
212            deopt_reason: Some("empty_trace"),
213        };
214    }
215
216    let mut matching = plans
217        .iter()
218        .filter(|plan| plan.matches_trace_prefix(trace))
219        .collect::<Vec<_>>();
220    if matching.is_empty() {
221        return HostcallSuperinstructionSelection {
222            trace_signature,
223            selected_plan_id: None,
224            selected_window: None,
225            expected_cost_delta: 0,
226            deopt_reason: Some("no_matching_plan"),
227        };
228    }
229
230    matching.sort_by(|left, right| {
231        right
232            .expected_cost_delta
233            .cmp(&left.expected_cost_delta)
234            .then_with(|| right.support_count.cmp(&left.support_count))
235            .then_with(|| right.width().cmp(&left.width()))
236            .then_with(|| left.plan_id.cmp(&right.plan_id))
237    });
238
239    let best = matching[0];
240    if matching.iter().skip(1).any(|candidate| {
241        candidate.expected_cost_delta == best.expected_cost_delta
242            && candidate.support_count == best.support_count
243            && candidate.width() == best.width()
244    }) {
245        return HostcallSuperinstructionSelection {
246            trace_signature,
247            selected_plan_id: None,
248            selected_window: None,
249            expected_cost_delta: 0,
250            deopt_reason: Some("ambiguous_top_plan"),
251        };
252    }
253
254    HostcallSuperinstructionSelection {
255        trace_signature,
256        selected_plan_id: Some(best.plan_id.clone()),
257        selected_window: Some(best.opcode_window.clone()),
258        expected_cost_delta: best.expected_cost_delta,
259        deopt_reason: None,
260    }
261}
262
263/// Execute a trace under superinstruction selection with immediate safe fallback.
264///
265/// Semantic output always remains canonical opcode ordering.
266#[must_use]
267pub fn execute_with_superinstruction(
268    trace: &[String],
269    plans: &[HostcallSuperinstructionPlan],
270) -> HostcallSuperinstructionExecution {
271    let canonical_trace = trace.to_vec();
272    let selection = select_plan_for_trace(trace, plans);
273    if !selection.hit() {
274        return HostcallSuperinstructionExecution {
275            canonical_trace: canonical_trace.clone(),
276            fused_trace: canonical_trace,
277            selection,
278        };
279    }
280
281    let mut fused_trace = Vec::new();
282    if let Some(plan_id) = selection.selected_plan_id.as_ref() {
283        fused_trace.push(format!("@{plan_id}"));
284    }
285    let consumed = selection
286        .selected_window
287        .as_ref()
288        .map_or(0, std::vec::Vec::len)
289        .min(trace.len());
290    fused_trace.extend_from_slice(&trace[consumed..]);
291
292    HostcallSuperinstructionExecution {
293        canonical_trace,
294        fused_trace,
295        selection,
296    }
297}
298
299fn estimated_baseline_cost(width: usize) -> i64 {
300    let width_units = i64::try_from(width).unwrap_or(i64::MAX);
301    width_units.saturating_mul(BASE_OPCODE_COST_UNITS)
302}
303
304fn estimated_fused_cost(width: usize) -> i64 {
305    let width_units = i64::try_from(width).unwrap_or(i64::MAX);
306    FUSED_OPCODE_FIXED_COST_UNITS
307        .saturating_add(width_units.saturating_mul(FUSED_OPCODE_STEP_COST_UNITS))
308}
309
310fn opcode_window_signature(window: &[String]) -> String {
311    let mut hash = 0xcbf2_9ce4_8422_2325_u64;
312    for opcode in window {
313        for byte in opcode.as_bytes() {
314            hash ^= u64::from(*byte);
315            hash = hash.wrapping_mul(0x0100_0000_01b3_u64);
316        }
317        hash ^= u64::from(b'|');
318        hash = hash.wrapping_mul(0x0100_0000_01b3_u64);
319    }
320    format!("{hash:016x}")
321}
322
323fn bool_from_env(var: &str, default: bool) -> bool {
324    std::env::var(var).ok().as_deref().map_or(default, |value| {
325        match value.trim().to_ascii_lowercase().as_str() {
326            "1" | "true" | "on" | "enabled" | "yes" => true,
327            "0" | "false" | "off" | "disabled" | "no" => false,
328            _ => default,
329        }
330    })
331}
332
333#[cfg(test)]
334mod tests {
335    use super::*;
336
337    fn opcode_trace(values: &[&str]) -> Vec<String> {
338        values.iter().map(ToString::to_string).collect()
339    }
340
341    fn plan(
342        plan_id: &str,
343        window: &[&str],
344        support_count: u32,
345        expected_cost_delta: i64,
346    ) -> HostcallSuperinstructionPlan {
347        HostcallSuperinstructionPlan {
348            schema: HOSTCALL_SUPERINSTRUCTION_SCHEMA_VERSION.to_string(),
349            version: HOSTCALL_SUPERINSTRUCTION_PLAN_VERSION,
350            plan_id: plan_id.to_string(),
351            trace_signature: opcode_window_signature(&opcode_trace(window)),
352            opcode_window: opcode_trace(window),
353            support_count,
354            estimated_cost_baseline: 0,
355            estimated_cost_fused: 0,
356            expected_cost_delta,
357        }
358    }
359
360    #[test]
361    fn compiler_extracts_hot_windows_deterministically() {
362        let compiler = HostcallSuperinstructionCompiler::new(true, 2, 4);
363        let traces = vec![
364            opcode_trace(&[
365                "session.get_state",
366                "session.get_messages",
367                "session.get_entries",
368                "events.list_flags",
369            ]),
370            opcode_trace(&[
371                "session.get_state",
372                "session.get_messages",
373                "session.get_entries",
374                "events.emit",
375            ]),
376            opcode_trace(&[
377                "session.get_state",
378                "session.get_messages",
379                "session.get_entries",
380                "events.get_model",
381            ]),
382        ];
383
384        let plans = compiler.compile_plans(&traces);
385        assert!(!plans.is_empty());
386        assert!(plans.iter().any(|entry| {
387            entry.opcode_window
388                == opcode_trace(&[
389                    "session.get_state",
390                    "session.get_messages",
391                    "session.get_entries",
392                ])
393        }));
394
395        let reversed = traces.iter().rev().cloned().collect::<Vec<_>>();
396        let plans_reversed = compiler.compile_plans(&reversed);
397        assert_eq!(plans, plans_reversed);
398    }
399
400    #[test]
401    fn selection_prefers_higher_delta_then_support_then_width() {
402        let trace = opcode_trace(&["tool.read", "events.list", "events.get_model"]);
403        let plans = vec![
404            plan("p_low_delta", &["tool.read", "events.list"], 8, 10),
405            plan(
406                "p_best",
407                &["tool.read", "events.list", "events.get_model"],
408                7,
409                14,
410            ),
411            plan(
412                "p_low_support",
413                &["tool.read", "events.list", "events.get_model"],
414                4,
415                14,
416            ),
417        ];
418
419        let selected = select_plan_for_trace(&trace, &plans);
420        assert_eq!(selected.selected_plan_id.as_deref(), Some("p_best"));
421        assert!(selected.deopt_reason.is_none());
422        assert!(selected.hit());
423    }
424
425    #[test]
426    fn selection_deopts_on_ambiguous_top_plan() {
427        let trace = opcode_trace(&["session.get_state", "session.get_entries"]);
428        let plans = vec![
429            plan("p_a", &["session.get_state", "session.get_entries"], 5, 11),
430            plan("p_b", &["session.get_state", "session.get_entries"], 5, 11),
431        ];
432
433        let selected = select_plan_for_trace(&trace, &plans);
434        assert!(!selected.hit());
435        assert_eq!(selected.deopt_reason, Some("ambiguous_top_plan"));
436    }
437
438    #[test]
439    fn execution_preserves_canonical_semantics_with_fused_projection() {
440        let trace = opcode_trace(&[
441            "session.get_state",
442            "session.get_messages",
443            "session.get_entries",
444            "events.list",
445        ]);
446        let plans = vec![plan(
447            "p_fuse",
448            &[
449                "session.get_state",
450                "session.get_messages",
451                "session.get_entries",
452            ],
453            6,
454            18,
455        )];
456
457        let execution = execute_with_superinstruction(&trace, &plans);
458        assert_eq!(execution.canonical_trace, trace);
459        assert_eq!(execution.fused_trace.len(), 2);
460        assert_eq!(execution.fused_trace[0], "@p_fuse");
461        assert_eq!(execution.fused_trace[1], "events.list");
462        assert!(execution.selection.hit());
463    }
464
465    #[test]
466    fn execution_deopts_immediately_on_guard_mismatch() {
467        let trace = opcode_trace(&["events.get_model", "events.set_model"]);
468        let plans = vec![plan("p_tool", &["tool.read", "tool.write"], 9, 12)];
469
470        let execution = execute_with_superinstruction(&trace, &plans);
471        assert_eq!(execution.canonical_trace, trace);
472        assert_eq!(execution.fused_trace, execution.canonical_trace);
473        assert!(!execution.selection.hit());
474        assert_eq!(execution.selection.deopt_reason, Some("no_matching_plan"));
475    }
476
477    // ── Cost estimation ──
478
479    #[test]
480    fn estimated_baseline_cost_is_linear_in_width() {
481        assert_eq!(estimated_baseline_cost(1), BASE_OPCODE_COST_UNITS);
482        assert_eq!(estimated_baseline_cost(2), 2 * BASE_OPCODE_COST_UNITS);
483        assert_eq!(estimated_baseline_cost(4), 4 * BASE_OPCODE_COST_UNITS);
484        assert_eq!(estimated_baseline_cost(0), 0);
485    }
486
487    #[test]
488    fn estimated_fused_cost_is_fixed_plus_step() {
489        assert_eq!(
490            estimated_fused_cost(2),
491            FUSED_OPCODE_FIXED_COST_UNITS + 2 * FUSED_OPCODE_STEP_COST_UNITS
492        );
493        assert_eq!(
494            estimated_fused_cost(4),
495            FUSED_OPCODE_FIXED_COST_UNITS + 4 * FUSED_OPCODE_STEP_COST_UNITS
496        );
497        assert_eq!(estimated_fused_cost(0), FUSED_OPCODE_FIXED_COST_UNITS);
498    }
499
500    #[test]
501    fn fused_cost_always_less_than_baseline_for_width_ge_2() {
502        for width in 2..=32 {
503            let baseline = estimated_baseline_cost(width);
504            let fused = estimated_fused_cost(width);
505            assert!(
506                fused < baseline,
507                "fused ({fused}) should be less than baseline ({baseline}) at width {width}"
508            );
509        }
510    }
511
512    // ── Compiler disabled ──
513
514    #[test]
515    fn compiler_disabled_returns_empty_plans() {
516        let compiler = HostcallSuperinstructionCompiler::new(false, 2, 4);
517        let traces = vec![
518            opcode_trace(&["a", "b", "c"]),
519            opcode_trace(&["a", "b", "c"]),
520            opcode_trace(&["a", "b", "c"]),
521        ];
522        let plans = compiler.compile_plans(&traces);
523        assert!(plans.is_empty());
524    }
525
526    // ── Compiler edge cases ──
527
528    #[test]
529    fn compiler_ignores_single_opcode_traces() {
530        let compiler = HostcallSuperinstructionCompiler::new(true, 1, 4);
531        let traces = vec![
532            opcode_trace(&["single"]),
533            opcode_trace(&["single"]),
534            opcode_trace(&["single"]),
535        ];
536        let plans = compiler.compile_plans(&traces);
537        assert!(plans.is_empty());
538    }
539
540    #[test]
541    fn compiler_ignores_empty_traces() {
542        let compiler = HostcallSuperinstructionCompiler::new(true, 1, 4);
543        let plans = compiler.compile_plans(&[Vec::new(), Vec::new()]);
544        assert!(plans.is_empty());
545    }
546
547    #[test]
548    fn compiler_skips_windows_with_empty_opcodes() {
549        let compiler = HostcallSuperinstructionCompiler::new(true, 1, 4);
550        let traces = vec![opcode_trace(&["a", "", "c"]), opcode_trace(&["a", "", "c"])];
551        let plans = compiler.compile_plans(&traces);
552        // Windows containing "" are skipped
553        assert!(
554            plans
555                .iter()
556                .all(|p| p.opcode_window.iter().all(|op| !op.trim().is_empty())),
557            "no plan should contain empty opcodes"
558        );
559    }
560
561    #[test]
562    fn compiler_respects_min_support_threshold() {
563        let compiler = HostcallSuperinstructionCompiler::new(true, 5, 4);
564        // Only 3 traces — below min_support of 5
565        let traces = vec![
566            opcode_trace(&["a", "b"]),
567            opcode_trace(&["a", "b"]),
568            opcode_trace(&["a", "b"]),
569        ];
570        let plans = compiler.compile_plans(&traces);
571        assert!(plans.is_empty(), "support 3 < min_support 5");
572    }
573
574    #[test]
575    fn compiler_respects_max_window_size() {
576        let compiler = HostcallSuperinstructionCompiler::new(true, 2, 2);
577        let traces = vec![
578            opcode_trace(&["a", "b", "c", "d"]),
579            opcode_trace(&["a", "b", "c", "d"]),
580            opcode_trace(&["a", "b", "c", "d"]),
581        ];
582        let plans = compiler.compile_plans(&traces);
583        assert!(
584            plans.iter().all(|p| p.width() <= 2),
585            "max_window=2 should cap window width"
586        );
587    }
588
589    #[test]
590    fn compiler_plans_sorted_by_cost_delta_descending() {
591        let compiler = HostcallSuperinstructionCompiler::new(true, 2, 4);
592        let traces = vec![
593            opcode_trace(&["a", "b", "c", "d"]),
594            opcode_trace(&["a", "b", "c", "d"]),
595            opcode_trace(&["a", "b", "c", "d"]),
596        ];
597        let plans = compiler.compile_plans(&traces);
598        for pair in plans.windows(2) {
599            assert!(
600                pair[0].expected_cost_delta >= pair[1].expected_cost_delta,
601                "plans should be sorted by cost delta descending"
602            );
603        }
604    }
605
606    // ── Plan schema + serde ──
607
608    #[test]
609    fn plan_serde_roundtrip() {
610        let compiler = HostcallSuperinstructionCompiler::new(true, 2, 4);
611        let traces = vec![
612            opcode_trace(&["x", "y", "z"]),
613            opcode_trace(&["x", "y", "z"]),
614            opcode_trace(&["x", "y", "z"]),
615        ];
616        let plans = compiler.compile_plans(&traces);
617        assert!(!plans.is_empty());
618        for p in &plans {
619            let json = serde_json::to_string(p).expect("serialize");
620            let roundtrip: HostcallSuperinstructionPlan =
621                serde_json::from_str(&json).expect("deserialize");
622            assert_eq!(*p, roundtrip);
623            assert_eq!(p.schema, HOSTCALL_SUPERINSTRUCTION_SCHEMA_VERSION);
624            assert_eq!(p.version, HOSTCALL_SUPERINSTRUCTION_PLAN_VERSION);
625        }
626    }
627
628    // ── Plan.matches_trace_prefix ──
629
630    #[test]
631    fn matches_trace_prefix_exact() {
632        let p = plan("test", &["a", "b"], 3, 10);
633        assert!(p.matches_trace_prefix(&opcode_trace(&["a", "b"])));
634        assert!(p.matches_trace_prefix(&opcode_trace(&["a", "b", "c"])));
635        assert!(!p.matches_trace_prefix(&opcode_trace(&["a"])));
636        assert!(!p.matches_trace_prefix(&opcode_trace(&["b", "a"])));
637        assert!(!p.matches_trace_prefix(&[]));
638    }
639
640    // ── Selection edge cases ──
641
642    #[test]
643    fn selection_on_empty_trace_returns_empty_trace_deopt() {
644        let plans = vec![plan("p", &["a", "b"], 3, 10)];
645        let selected = select_plan_for_trace(&[], &plans);
646        assert!(!selected.hit());
647        assert_eq!(selected.deopt_reason, Some("empty_trace"));
648    }
649
650    #[test]
651    fn selection_on_empty_plans_returns_no_matching_plan() {
652        let trace = opcode_trace(&["a", "b"]);
653        let selected = select_plan_for_trace(&trace, &[]);
654        assert!(!selected.hit());
655        assert_eq!(selected.deopt_reason, Some("no_matching_plan"));
656    }
657
658    // ── Opcode window signature ──
659
660    #[test]
661    fn opcode_window_signature_is_deterministic() {
662        let window = opcode_trace(&["session.get_state", "session.get_messages"]);
663        let sig1 = opcode_window_signature(&window);
664        let sig2 = opcode_window_signature(&window);
665        assert_eq!(sig1, sig2);
666        assert_eq!(sig1.len(), 16, "signature should be 16 hex chars");
667    }
668
669    #[test]
670    fn opcode_window_signature_differs_for_different_windows() {
671        let sig_ab = opcode_window_signature(&opcode_trace(&["a", "b"]));
672        let sig_ba = opcode_window_signature(&opcode_trace(&["b", "a"]));
673        let sig_abc = opcode_window_signature(&opcode_trace(&["a", "b", "c"]));
674        assert_ne!(sig_ab, sig_ba, "order matters");
675        assert_ne!(sig_ab, sig_abc, "different length windows differ");
676    }
677
678    // ── Execution with entire trace consumed ──
679
680    #[test]
681    fn execution_fuses_entire_trace() {
682        let trace = opcode_trace(&["a", "b"]);
683        let plans = vec![plan("p_full", &["a", "b"], 5, 14)];
684        let execution = execute_with_superinstruction(&trace, &plans);
685        assert!(execution.selection.hit());
686        assert_eq!(execution.fused_trace, vec!["@p_full"]);
687        assert!(execution.fused_trace.len() < execution.canonical_trace.len());
688    }
689
690    // ── Compiler constructor + accessors ──
691
692    #[test]
693    fn compiler_accessors_match_constructor() {
694        let compiler = HostcallSuperinstructionCompiler::new(true, 7, 5);
695        assert!(compiler.enabled());
696        assert_eq!(compiler.min_support(), 7);
697        assert_eq!(compiler.max_window(), 5);
698
699        let disabled = HostcallSuperinstructionCompiler::new(false, 2, 3);
700        assert!(!disabled.enabled());
701    }
702
703    // ── Property tests ──
704
705    mod proptest_superinstructions {
706        use super::*;
707        use proptest::prelude::*;
708
709        fn arb_opcode() -> impl Strategy<Value = String> {
710            prop::sample::select(vec![
711                "session.get_state".to_string(),
712                "session.get_messages".to_string(),
713                "events.list".to_string(),
714                "events.emit".to_string(),
715                "tool.read".to_string(),
716                "tool.write".to_string(),
717                "events.get_model".to_string(),
718                "session.set_label".to_string(),
719            ])
720        }
721
722        fn arb_trace() -> impl Strategy<Value = Vec<String>> {
723            prop::collection::vec(arb_opcode(), 0..6)
724        }
725
726        fn arb_compiler() -> impl Strategy<Value = HostcallSuperinstructionCompiler> {
727            (2..8u32, 2..6usize).prop_map(|(min_support, max_window)| {
728                HostcallSuperinstructionCompiler::new(true, min_support, max_window)
729            })
730        }
731
732        proptest! {
733            #[test]
734            fn compile_plans_is_deterministic(
735                compiler in arb_compiler(),
736                traces in prop::collection::vec(arb_trace(), 0..8),
737            ) {
738                let plans1 = compiler.compile_plans(&traces);
739                let plans2 = compiler.compile_plans(&traces);
740                assert!(plans1 == plans2, "compile_plans must be deterministic");
741            }
742
743            #[test]
744            fn all_plans_have_positive_cost_delta(
745                compiler in arb_compiler(),
746                traces in prop::collection::vec(arb_trace(), 1..8),
747            ) {
748                let plans = compiler.compile_plans(&traces);
749                for plan in &plans {
750                    assert!(
751                        plan.expected_cost_delta > 0,
752                        "plan {} has non-positive delta {}",
753                        plan.plan_id,
754                        plan.expected_cost_delta,
755                    );
756                }
757            }
758
759            #[test]
760            fn plans_sorted_by_cost_delta_descending(
761                compiler in arb_compiler(),
762                traces in prop::collection::vec(arb_trace(), 1..8),
763            ) {
764                let plans = compiler.compile_plans(&traces);
765                for pair in plans.windows(2) {
766                    assert!(
767                        pair[0].expected_cost_delta >= pair[1].expected_cost_delta,
768                        "plans must be sorted by cost delta descending: {} vs {}",
769                        pair[0].expected_cost_delta,
770                        pair[1].expected_cost_delta,
771                    );
772                }
773            }
774
775            #[test]
776            fn cost_delta_equals_baseline_minus_fused(
777                width in 2..64usize,
778            ) {
779                let baseline = estimated_baseline_cost(width);
780                let fused = estimated_fused_cost(width);
781                let delta = baseline.saturating_sub(fused);
782                assert!(
783                    delta > 0,
784                    "fused cost must be less than baseline for width {width}"
785                );
786                assert!(
787                    delta == baseline - fused,
788                    "delta must equal baseline - fused"
789                );
790            }
791
792            #[test]
793            fn fused_cost_strictly_less_than_baseline_for_width_ge_2(
794                width in 2..1000usize,
795            ) {
796                let baseline = estimated_baseline_cost(width);
797                let fused = estimated_fused_cost(width);
798                assert!(
799                    fused < baseline,
800                    "fused ({fused}) must be < baseline ({baseline}) at width {width}"
801                );
802            }
803
804            #[test]
805            fn opcode_window_signature_is_deterministic(
806                window in prop::collection::vec(arb_opcode(), 1..6),
807            ) {
808                let sig1 = opcode_window_signature(&window);
809                let sig2 = opcode_window_signature(&window);
810                assert!(sig1 == sig2, "signature must be deterministic");
811                assert!(sig1.len() == 16, "signature must be 16 hex chars");
812            }
813
814            #[test]
815            fn disabled_compiler_always_returns_empty(
816                min_support in 1..10u32,
817                max_window in 2..8usize,
818                traces in prop::collection::vec(arb_trace(), 0..8),
819            ) {
820                let compiler = HostcallSuperinstructionCompiler::new(false, min_support, max_window);
821                let plans = compiler.compile_plans(&traces);
822                assert!(plans.is_empty(), "disabled compiler must return no plans");
823            }
824
825            #[test]
826            fn plan_width_never_exceeds_max_window(
827                compiler in arb_compiler(),
828                traces in prop::collection::vec(arb_trace(), 1..8),
829            ) {
830                let plans = compiler.compile_plans(&traces);
831                for plan in &plans {
832                    assert!(
833                        plan.width() <= compiler.max_window(),
834                        "plan width {} exceeds max_window {}",
835                        plan.width(),
836                        compiler.max_window(),
837                    );
838                }
839            }
840
841            #[test]
842            fn plan_support_count_meets_min_support(
843                compiler in arb_compiler(),
844                traces in prop::collection::vec(arb_trace(), 1..10),
845            ) {
846                let plans = compiler.compile_plans(&traces);
847                for plan in &plans {
848                    assert!(
849                        plan.support_count >= compiler.min_support(),
850                        "plan {} has support {} < min_support {}",
851                        plan.plan_id,
852                        plan.support_count,
853                        compiler.min_support(),
854                    );
855                }
856            }
857        }
858    }
859}