1use std::collections::{HashMap, HashSet};
4
5use superfluid_abi::array::read_array;
6use superfluid_abi::{
7 cert_domain, cert_mode, exactness, strategy_cap, ArenaBounds, CapabilityReq, ExactnessCert,
8 op_state, space_kind, tier, MatchCandidate, MatchResult, OpStatus, RingRef,
9 SamplingParams, SpaceMatch, StateSpaceDesc, StrategyGrant,
10 StrategyRegistration, TickEvents, TickPlan, TokenRange, RecordArena,
11 Status,
12};
13use superfluid_engine::engine::{Engine, OpHandle, SeqHandle};
14use superfluid_engine::Rings;
15
16use crate::cache::{CacheEntry, PrefixCache, HOST_EXPORT_CLASS, RESIDENT_PREFIX_CLASS, SHARED_PREFIX_CLASS};
17use crate::grammar::{Grammars, LaneGrammar};
18use crate::primitives::{PrimError, RuntimeDescriptor, RuntimePrimitives, Seq};
19
20pub const KV_SPACE: u32 = 1;
21
22const HOST_SHORT_TICKS: u64 = 64;
25
26#[derive(Debug, Clone)]
27pub struct ExecutorConfig {
28 pub seed_ttl_ticks: u64,
29}
30
31impl Default for ExecutorConfig {
32 fn default() -> Self {
33 ExecutorConfig { seed_ttl_ticks: 64 }
34 }
35}
36
37static FATAL_EXITS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
38
39pub fn exit_on_fatal(on: bool) {
40 FATAL_EXITS.store(on, std::sync::atomic::Ordering::Relaxed);
41}
42
43pub(crate) fn fatal_exits() -> bool {
44 FATAL_EXITS.load(std::sync::atomic::Ordering::Relaxed)
45}
46
47pub(crate) struct Lane {
48 pub seq: Seq,
49 pub sampling: u32,
50 pub params: SamplingParams,
51 pub rng_base: u64,
52 pub rng_counter: u64,
53 pub prompt: Vec<u32>,
54 pub prefilled: u64,
55 pub prefill_end: u64,
56 pub committed: Vec<u32>,
57 pub pending_input: Option<u32>,
58 pub pending_logits: Option<RingRef>,
59 pub finished: bool,
60 pub bias: Option<Vec<(u32, f32)>>,
61 pub logprobs_top: Option<usize>,
62 pub grammar: Option<LaneGrammar>,
63 pub spec: Option<crate::speculate::LaneSpec>,
65}
66
67pub(crate) struct Strategy {
69 pub slot: u32,
70 pub cert_id: u32,
71 pub cfg: crate::speculate::SpecConfig,
72}
73
74pub(crate) struct SeedLease {
75 pub prefix: Vec<u32>,
76 pub entry_seq: Seq,
77 pub determinism: u8,
78 pub expires_at_tick: u64,
79 pub adopted: Option<Seq>,
80}
81
82pub(crate) struct PendingExport {
83 pub len: u64,
84 pub encoding: u8,
85 pub gen: u64,
86 pub sealed: Vec<u8>,
87}
88
89pub(crate) struct OpRecord {
90 pub state: u8,
91 pub error: u32,
92 pub bytes_moved: u64,
93 pub output: Option<Vec<u8>>,
94}
95
96pub(crate) struct AbiStore<T> {
97 #[allow(dead_code)]
98 pub arena: RecordArena,
99 pub value: Box<T>,
100}
101
102pub struct Executor<P: RuntimePrimitives> {
103 pub(crate) prim: P,
104 pub(crate) desc: RuntimeDescriptor,
105 pub(crate) cfg: ExecutorConfig,
106 pub(crate) descs: Vec<StateSpaceDesc>,
107
108 pub(crate) lanes: HashMap<u64, Lane>,
109 pub(crate) strategy: Option<Strategy>,
110 pub(crate) spec_gate: crate::speculate::ThroughputGate,
111 pub(crate) prefill_secs_per_token: Option<f64>,
113 grant_store: Option<AbiStore<StrategyGrant>>,
114 pub(crate) bare: HashSet<Seq>,
115 pub(crate) forks: HashSet<Seq>,
118 pub(crate) adopt_leased: HashSet<Seq>,
119 pub(crate) bare_tokens: HashMap<Seq, Vec<u32>>,
120 pub(crate) seq_taint: HashMap<Seq, u32>,
121 pub(crate) seeds: HashMap<u64, SeedLease>,
122 pub(crate) cache: PrefixCache,
123 pub(crate) biases: HashMap<u32, Vec<(u32, f32)>>,
124 pub(crate) grammars: Grammars,
125 pub(crate) capabilities: std::sync::OnceLock<String>,
126
127 pub(crate) seq_gen: HashMap<Seq, u64>,
128 pub(crate) pending_export: HashMap<Seq, Vec<PendingExport>>,
129 pub(crate) ops: HashMap<OpHandle, OpRecord>,
130 pub(crate) completions_pending: Vec<superfluid_abi::OpComplete>,
131
132 pub(crate) next_seed: u64,
133 pub(crate) next_bias: u32,
134 pub(crate) next_op: OpHandle,
135 pub(crate) tick_count: u64,
136 pub(crate) last_plan_seq: Option<u64>,
137
138 pub(crate) inject_fault: HashMap<u64, u32>,
139 pub(crate) faulted: HashSet<u64>,
140 pub(crate) penalty_exempt: Option<HashSet<u32>>,
141 pub(crate) last_logprobs: Vec<superfluid_abi::LaneLogprob>,
142
143 pub(crate) match_store: Option<AbiStore<MatchResult>>,
144 pub(crate) events_store: Option<AbiStore<TickEvents>>,
145 pub(crate) exports_after_tick: u64,
147}
148
149fn build_descs(d: &RuntimeDescriptor) -> Vec<StateSpaceDesc> {
150 let mut name = [0u8; 32];
151 name[..7].copy_from_slice(b"kv.full");
152 vec![StateSpaceDesc {
153 space_id: KV_SPACE,
154 kind: space_kind::PAGED_TOKEN_KV,
155 version_tag: 1,
156 bytes_per_token: d.kv_bytes_per_token,
157 blob_bytes: 0,
158 page_size_tokens: d.page_size_tokens.max(1),
159 fork_cost_class: 0,
160 fork_cost_bytes: 0,
161 snapshot_cadence: 0,
162 snapshot_interval_tokens: 0,
163 placement: 0,
164 flags: 0,
165 name,
166 }]
167}
168
169pub(crate) fn prim_status(e: PrimError) -> Status {
170 match e {
171 PrimError::Unsupported => Status::Unsupported,
172 PrimError::UnknownSeq => Status::UnknownHandle,
173 PrimError::OutOfBoundary => Status::OutOfBoundary,
174 PrimError::Capacity => Status::NeedsReplan,
175 PrimError::Fault(_) | PrimError::Fatal => Status::Fatal,
176 }
177}
178
179impl<P: RuntimePrimitives> Executor<P> {
180 pub fn new(prim: P, cfg: ExecutorConfig) -> Executor<P> {
181 let desc = prim.describe();
182 let descs = build_descs(&desc);
183 Executor {
184 prim,
185 desc,
186 cfg,
187 descs,
188 lanes: HashMap::new(),
189 strategy: None,
190 spec_gate: Default::default(),
191 prefill_secs_per_token: None,
192 grant_store: None,
193 bare: HashSet::new(),
194 forks: HashSet::new(),
195 adopt_leased: HashSet::new(),
196 bare_tokens: HashMap::new(),
197 seq_taint: HashMap::new(),
198 seeds: HashMap::new(),
199 cache: PrefixCache::default(),
200 biases: HashMap::new(),
201 grammars: Grammars::default(),
202 capabilities: std::sync::OnceLock::new(),
203 seq_gen: HashMap::new(),
204 pending_export: HashMap::new(),
205 ops: HashMap::new(),
206 completions_pending: Vec::new(),
207 next_seed: 1,
208 next_bias: 1,
209 next_op: 1,
210 tick_count: 0,
211 last_plan_seq: None,
212 inject_fault: HashMap::new(),
213 faulted: HashSet::new(),
214 penalty_exempt: None,
215 last_logprobs: Vec::new(),
216 match_store: None,
217 events_store: None,
218 exports_after_tick: 0,
219 }
220 }
221
222 pub fn primitives(&self) -> &P {
223 &self.prim
224 }
225
226 pub fn primitives_mut(&mut self) -> &mut P {
227 &mut self.prim
228 }
229
230 pub fn descriptor(&self) -> &RuntimeDescriptor {
231 &self.desc
232 }
233
234 pub fn lane_committed(&self, lane_tag: u64) -> Option<&[u32]> {
235 self.lanes.get(&lane_tag).map(|l| l.committed.as_slice())
236 }
237
238 pub fn inject_fault(&mut self, lane_tag: u64, code: u32) {
239 self.inject_fault.insert(lane_tag, code);
240 }
241
242 pub fn cache_bytes(&self) -> u64 {
244 self.cache.resident_bytes()
245 }
246
247 pub fn cache_exported_tokens(&self) -> u64 {
249 self.cache.exported_tokens()
250 }
251
252 pub fn match_lengths(&self, span: &[u32]) -> Vec<u64> {
253 self.cache.candidates(span, self.page(), self.exact_only()).into_iter().map(|(l, _)| l).collect()
254 }
255
256 pub fn live_sequences(&self) -> u64 {
259 let in_pool = self.cache.entries.iter().filter(|e| e.exported.is_none()).count();
260 (self.lanes.len() + self.bare.len() + in_pool) as u64
261 }
262
263 pub fn last_logprobs(&self) -> Vec<superfluid_abi::LaneLogprob> {
264 self.last_logprobs.clone()
265 }
266
267 pub(crate) fn page(&self) -> u64 {
268 self.desc.page_size_tokens.max(1) as u64
269 }
270
271 pub(crate) fn exact_only(&self) -> bool {
272 !self.desc.truncate_partial
273 }
274
275 pub(crate) fn entry_bytes(&self, tokens: u64) -> u64 {
276 tokens * self.desc.kv_bytes_per_token.max(1)
277 }
278
279 fn free_evicted(&mut self, gone: Vec<(Seq, bool)>) {
280 for (s, in_pool) in gone {
281 self.forget_seq(s);
282 if in_pool {
283 self.prim.seq_free(s);
284 }
285 }
286 }
287
288 pub fn compat_identity(&self) -> [u8; 32] {
289 crate::envelope::compat_identity(
290 space_kind::PAGED_TOKEN_KV,
291 1,
292 &self.desc.runtime_id,
293 &self.desc.runtime_version,
294 &self.desc.weights_identity,
295 )
296 }
297
298 pub(crate) fn pin(&mut self, seq: Seq) {
299 if let Some(e) = self.cache.entries.iter_mut().find(|e| e.seq == seq) {
300 e.pins += 1;
301 }
302 }
303
304 pub(crate) fn unpin(&mut self, seq: Seq) {
305 if let Some(e) = self.cache.entries.iter_mut().find(|e| e.seq == seq) {
306 e.pins = e.pins.saturating_sub(1);
307 }
308 }
309
310 pub(crate) fn gen_of(&self, seq: Seq) -> u64 {
311 self.seq_gen.get(&seq).copied().unwrap_or(1)
312 }
313
314 pub(crate) fn bump(&mut self, seq: Seq) {
315 *self.seq_gen.entry(seq).or_insert(1) += 1;
316 self.pending_export.remove(&seq);
317 }
318
319 pub(crate) fn forget_seq(&mut self, seq: Seq) {
320 self.seq_gen.remove(&seq);
321 self.pending_export.remove(&seq);
322 self.seq_taint.remove(&seq);
323 self.bare_tokens.remove(&seq);
324 self.adopt_leased.remove(&seq);
325 self.forks.remove(&seq);
326 }
327
328 pub(crate) fn inherit_taint(&mut self, src: Seq, dst: Seq) {
329 if let Some(t) = self.seq_taint.get(&src).copied().filter(|t| *t != 0) {
330 self.seq_taint.insert(dst, t);
331 }
332 }
333
334 pub(crate) fn seq_is_cached(&self, seq: Seq) -> bool {
335 self.cache.entries.iter().any(|e| e.seq == seq)
336 }
337
338 pub(crate) fn tokens_of(&self, seq: Seq) -> Option<&[u32]> {
339 self.lanes
340 .values()
341 .find(|l| l.seq == seq)
342 .map(|l| l.committed.as_slice())
343 .or_else(|| self.cache.entries.iter().find(|e| e.seq == seq).map(|e| e.tokens.as_slice()))
344 .or_else(|| self.bare_tokens.get(&seq).map(|t| t.as_slice()))
345 }
346
347 pub(crate) fn seq_known(&self, seq: Seq) -> bool {
348 self.bare.contains(&seq)
349 || self.lanes.values().any(|l| l.seq == seq)
350 || self.cache.entries.iter().any(|e| e.seq == seq && e.exported.is_none())
351 }
352
353 pub(crate) fn seq_is_lane(&self, seq: Seq) -> bool {
354 self.lanes.values().any(|l| l.seq == seq)
355 }
356
357 pub(crate) fn provenance_of(&self, seq: Seq, len: u64) -> [u8; 32] {
358 match self.tokens_of(seq) {
359 Some(t) if t.len() as u64 >= len => superfluid_fingerprint::content_digest(&t[..len as usize]),
360 _ => [0u8; 32],
361 }
362 }
363
364 pub(crate) fn compat(&self) -> [u8; 32] {
365 self.compat_identity()
366 }
367
368 pub(crate) fn complete_op(&mut self, result: Result<Vec<u8>, Status>, bytes: u64) -> OpHandle {
369 let h = self.next_op;
370 self.next_op += 1;
371 let rec = match result {
372 Ok(out) => OpRecord { state: op_state::DONE, error: 0, bytes_moved: bytes, output: Some(out) },
373 Err(e) => OpRecord { state: op_state::FAILED, error: e.raw() as u32, bytes_moved: 0, output: None },
374 };
375 self.completions_pending.push(superfluid_abi::OpComplete {
376 op: h,
377 state: rec.state,
378 _pad0: [0; 3],
379 error: rec.error,
380 bytes_moved: rec.bytes_moved,
381 });
382 self.ops.insert(h, rec);
383 h
384 }
385
386 fn size_export(&mut self, seq: Seq, len: u64, encoding: u8) -> Result<(u64, u64), Status> {
387 if !self.desc.export_encodings.contains(&encoding) {
388 return Err(Status::Unsupported);
389 }
390 if len == 0 || len > self.prim.seq_len(seq) {
391 return Err(Status::RejectBounds);
392 }
393 let gen = self.gen_of(seq);
394 if let Some(pe) = self
395 .pending_export
396 .get(&seq)
397 .and_then(|v| v.iter().find(|pe| pe.len == len && pe.encoding == encoding && pe.gen == gen))
398 {
399 return Ok((pe.sealed.len() as u64, gen));
400 }
401 let payload = self.prim.seq_export(seq, len, encoding).map_err(prim_status)?;
402 let taint_bits = self.seq_taint.get(&seq).copied().unwrap_or(0)
403 | if encoding == superfluid_abi::encoding::LOSSLESS { 0 } else { superfluid_abi::taint::QUANTIZED_DEMOTION };
404 let sealed = crate::envelope::seal(crate::envelope::SealArgs {
405 kind: space_kind::PAGED_TOKEN_KV,
406 version_tag: 1,
407 compat: self.compat(),
408 provenance: self.provenance_of(seq, len),
409 taint_bits,
410 range: TokenRange { start: 0, end: len },
411 encoding,
412 payload: &payload,
413 });
414 let bytes = sealed.len() as u64;
415 let list = self.pending_export.entry(seq).or_default();
416 list.retain(|pe| pe.gen == gen);
417 list.push(PendingExport { len, encoding, gen, sealed });
418 Ok((bytes, gen))
419 }
420
421 fn take_export(&mut self, seq: Seq, len: u64, encoding: u8, dst_len: u64, sizing_gen: u64) -> Result<OpHandle, Status> {
422 if sizing_gen != self.gen_of(seq) {
423 return Err(Status::StaleSizing);
424 }
425 let list = self.pending_export.get_mut(&seq).ok_or(Status::StaleSizing)?;
426 let pos = list
427 .iter()
428 .position(|pe| pe.len == len && pe.encoding == encoding && pe.gen == sizing_gen)
429 .ok_or(Status::StaleSizing)?;
430 let sealed_len = list[pos].sealed.len() as u64;
431 if dst_len < sealed_len {
432 return Err(Status::BufferTooSmall);
433 }
434 let pe = list.remove(pos);
435 Ok(self.complete_op(Ok(pe.sealed), sealed_len))
436 }
437
438 pub(crate) fn sweep_expired_seeds(&mut self) {
439 let now = self.tick_count;
440 let expired: Vec<u64> = self
441 .seeds
442 .iter()
443 .filter(|(_, l)| l.expires_at_tick < now)
444 .map(|(h, _)| *h)
445 .collect();
446 for h in expired {
447 if let Some(lease) = self.seeds.remove(&h) {
448 match lease.adopted {
449 Some(seq) => {
450 self.adopt_leased.remove(&seq);
451 }
452 None => self.unpin(lease.entry_seq),
453 }
454 }
455 }
456 }
457
458 fn seq_create_making_room(&mut self) -> Result<Seq, PrimError> {
462 match self.prim.seq_create() {
463 Err(PrimError::Capacity) if self.desc.max_seqs > 0 => {
464 let (_, left, _) = self.evict_bytes(1, u64::MAX);
465 if left == 0 {
466 return Err(PrimError::Capacity);
467 }
468 self.prim.seq_create()
469 }
470 other => other,
471 }
472 }
473
474 pub(crate) fn evict_bytes(&mut self, bytes: u64, cap: u64) -> (u64, usize, Vec<(u64, u64)>) {
477 self.evict_classes(bytes, cap, true)
478 }
479
480 fn evict_classes(&mut self, bytes: u64, cap: u64, shared_too: bool) -> (u64, usize, Vec<(u64, u64)>) {
481 let (freed, picked) = self.cache.plan_evict(bytes, cap, shared_too);
482 let seqs: Vec<Seq> = picked.iter().map(|&i| self.cache.entries[i].seq).collect();
483 let mut lost = Vec::new();
484 for &seq in &seqs {
485 self.leave_pool(seq, &mut lost);
486 }
487 (freed, seqs.len(), lost)
488 }
489
490 fn drop_exports(&mut self) {
493 self.exports_after_tick = self.tick_count + HOST_SHORT_TICKS;
494 let gone: Vec<Seq> = self.cache.entries.iter().filter(|e| e.exported.is_some() && e.pins == 0).map(|e| e.seq).collect();
495 for seq in gone {
496 self.cache.remove(seq);
497 self.forget_seq(seq);
498 }
499 }
500
501 fn covered(&self, seq: Seq) -> bool {
504 let Some(e) = self.cache.get(seq) else { return false };
505 if self.exact_only() || (e.tokens.len() as u64) < self.desc.seed_min_tokens {
506 return false;
507 }
508 let taint = |s: Seq| self.seq_taint.get(&s).copied().unwrap_or(0);
509 self.cache.entries.iter().any(|o| o.seq != seq && e.covered_by(o) && taint(o.seq) & !taint(seq) == 0)
510 }
511
512 fn export_entry(&mut self, seq: Seq, lost: &mut Vec<(u64, u64)>) -> bool {
515 const LOSSLESS: u8 = superfluid_abi::encoding::LOSSLESS;
516 let Some(e) = self.cache.get(seq) else { return false };
517 let (len, worth) = (e.tokens.len() as u64, (e.holds_shared_prefix(), e.last_used));
518 let budget = self.desc.cache_exported_cells;
519 let host_short = self.tick_count < self.exports_after_tick;
520 if host_short || len > budget || !self.desc.export_encodings.contains(&LOSSLESS) || self.prim.seq_len(seq) != len {
521 return false;
522 }
523 let mut over = (self.cache.exported_tokens() + len).saturating_sub(budget);
524 let mut lesser: Vec<&CacheEntry> = self
525 .cache
526 .entries
527 .iter()
528 .filter(|o| o.exported.is_some() && o.pins == 0 && (o.holds_shared_prefix(), o.last_used) <= worth)
529 .collect();
530 lesser.sort_by_key(|o| (o.holds_shared_prefix(), o.last_used));
531 let mut out: Vec<Seq> = Vec::new();
532 for o in lesser {
533 if over == 0 {
534 break;
535 }
536 over = over.saturating_sub(o.tokens.len() as u64);
537 out.push(o.seq);
538 }
539 if over > 0 {
540 return false;
541 }
542 let Ok(payload) = self.prim.seq_export(seq, len, LOSSLESS) else { return false };
543 for o in out {
544 if let Some(gone) = self.cache.remove(o) {
545 self.forget_seq(o);
546 lost.push((0, gone.tokens.len() as u64));
547 }
548 }
549 self.prim.seq_free(seq);
550 self.seq_gen.remove(&seq);
553 self.pending_export.remove(&seq);
554 if let Some(e) = self.cache.entries.iter_mut().find(|e| e.seq == seq) {
555 e.exported = Some(payload);
556 }
557 true
558 }
559
560 pub(crate) fn leave_pool(&mut self, seq: Seq, lost: &mut Vec<(u64, u64)>) {
563 if !self.covered(seq) && self.export_entry(seq, lost) {
564 return;
565 }
566 if let Some(e) = self.cache.remove(seq) {
567 self.forget_seq(seq);
568 self.prim.seq_free(seq);
569 lost.push((e.bytes, e.tokens.len() as u64));
570 }
571 }
572
573 pub(crate) fn settle_cache(&mut self, lost: &mut Vec<(u64, u64)>) {
581 let limit = self.desc.cache_resident_cells;
582 while limit > 0 && self.prim.cells_released(&self.cache.resident()) > limit {
583 let mut idle: Vec<&CacheEntry> = self.cache.entries.iter().filter(|e| e.exported.is_none() && e.pins == 0).collect();
584 idle.sort_by_key(|e| (e.holds_shared_prefix(), e.last_used));
585 let gives = |e: &&CacheEntry| self.covered(e.seq) || self.prim.cells_released(&[e.seq]) > 0;
586 let Some(seq) = idle.iter().copied().find(gives).or(idle.first().copied()).map(|e| e.seq) else { break };
587 self.leave_pool(seq, lost);
588 }
589 if !std::mem::take(&mut self.cache.changed) {
590 return;
591 }
592 let covered: Vec<Seq> =
593 self.cache.entries.iter().filter(|e| e.exported.is_some() && e.pins == 0 && self.covered(e.seq)).map(|e| e.seq).collect();
594 for seq in covered {
595 if let Some(e) = self.cache.remove(seq) {
596 self.forget_seq(seq);
597 lost.push((0, e.tokens.len() as u64));
598 }
599 }
600 }
601
602 fn store_match(&mut self, candidates: Vec<MatchCandidate>) -> &MatchResult {
603 let mut arena_out = RecordArena::new();
604 let spaces = vec![SpaceMatch {
605 space_id: KV_SPACE,
606 _pad0: 0,
607 candidates: arena_out.push_records(&candidates),
608 }];
609 let result = MatchResult {
610 struct_size: std::mem::size_of::<MatchResult>() as u64,
611 spaces: arena_out.push_records(&spaces),
612 };
613 self.match_store = Some(AbiStore { arena: arena_out, value: Box::new(result) });
614 &self.match_store.as_ref().expect("just stored").value
615 }
616}
617
618impl<P: RuntimePrimitives> Engine for Executor<P> {
619 fn tick<'a>(
620 &'a mut self,
621 plan: &TickPlan,
622 arena: &RecordArena,
623 rings: &mut dyn Rings,
624 ) -> Result<&'a TickEvents, Status> {
625 self.run_tick(plan, arena, rings)?;
626 Ok(&self.events_store.as_ref().expect("stored by run_tick").value)
627 }
628
629 fn pump(&mut self) {
630 }
631
632 fn state_spaces(&self) -> &[StateSpaceDesc] {
633 &self.descs
634 }
635
636 fn strategy_register(
637 &mut self,
638 reg: &StrategyRegistration,
639 ) -> Result<&StrategyGrant, Status> {
640 if !self.desc.verify_rows || !self.desc.truncate_partial || reg.strategy_id.is_null() {
643 return Err(Status::RegistrationRefused);
644 }
645 let id = unsafe { std::ffi::CStr::from_ptr(reg.strategy_id) }.to_string_lossy().into_owned();
647 if id != crate::speculate::STRATEGY_ID || reg.kernel_caps_required != 0 {
648 return Err(Status::RegistrationRefused);
649 }
650 let bounds = ArenaBounds { base: 0, len: usize::MAX };
651 let caps: Vec<CapabilityReq> =
654 unsafe { read_array(®.capabilities, &bounds) }.map_err(|e| e.status())?.collect();
655 let archs: Vec<u64> = unsafe { read_array(®.target_archs, &bounds) }.map_err(|e| e.status())?.collect();
657 if !archs.is_empty() || caps.iter().any(|c| c.kind_id != strategy_cap::PROPOSAL_LINEAR) {
658 return Err(Status::RegistrationRefused);
659 }
660 let mut params = String::new();
661 for c in &caps {
662 let bytes: Vec<u8> = unsafe { read_array(&c.params, &bounds) }.map_err(|e| e.status())?.collect();
664 params.push_str(&String::from_utf8_lossy(&bytes));
665 }
666 let cfg = crate::speculate::SpecConfig::parse(¶ms);
667 let (slot, cert_id) = (1, 1);
668 self.strategy = Some(Strategy { slot, cert_id, cfg });
669 self.spec_gate = Default::default();
670 let mut arena = RecordArena::new();
671 let certificates = arena.push_records(&[ExactnessCert {
674 cert_id,
675 exactness: exactness::DISTRIBUTION_EXACT,
676 sampling_modes: cert_mode::GREEDY | cert_mode::GUMBEL,
677 grammar_allowed: 0,
678 logit_bias_allowed: 0,
679 param_domain: cert_domain::ANY,
680 verification_shape_class: 1,
681 admissible_host_identities: superfluid_abi::Array::EMPTY,
682 }]);
683 let grant = StrategyGrant {
684 struct_size: std::mem::size_of::<StrategyGrant>() as u64,
685 strategy_slot: slot,
686 _pad0: 0,
687 certificates,
688 state_spaces: superfluid_abi::Array::EMPTY,
689 reserved_bytes: 0,
690 };
691 self.grant_store = Some(AbiStore { arena, value: Box::new(grant) });
692 Ok(&self.grant_store.as_ref().expect("just stored").value)
693 }
694
695 fn space_match(
696 &mut self,
697 space_id: u32,
698 span_tokens: &[u32],
699 _media_deps: &[[u8; 32]],
700 ) -> Result<&MatchResult, Status> {
701 if space_id != KV_SPACE && space_id != superfluid_abi::ALL_SPACES {
702 return Err(Status::UnknownHandle);
703 }
704 let page = self.page();
705 let exact = self.exact_only();
706 let candidates: Vec<MatchCandidate> = self
707 .cache
708 .candidates(span_tokens, page, exact)
709 .into_iter()
710 .map(|(len, seq)| MatchCandidate {
711 prefix_len: len,
712 provenance_digest: superfluid_fingerprint::content_digest(&span_tokens[..len as usize]),
713 taint_bits: self.seq_taint.get(&seq).copied().unwrap_or(0),
714 resident_tier: if self.cache.get(seq).is_some_and(|e| e.exported.is_some()) { tier::HOST } else { tier::GPU },
716 _pad0: [0; 3],
717 })
718 .collect();
719 Ok(self.store_match(candidates))
720 }
721
722 fn seed_acquire(
723 &mut self,
724 span_tokens: &[u32],
725 prefix_len: u64,
726 determinism_class: u8,
727 ) -> Result<u64, Status> {
728 let page = self.page();
729 let exact = self.exact_only();
730 if prefix_len == 0 || !prefix_len.is_multiple_of(page) || prefix_len > span_tokens.len() as u64 {
731 return Err(Status::SeedUnservable);
732 }
733 if exact && prefix_len == span_tokens.len() as u64 {
734 return Err(Status::SeedUnservable);
735 }
736 let want = &span_tokens[..prefix_len as usize];
737 let entry_seq = self
738 .cache
739 .entries
740 .iter()
741 .filter(|e| {
742 let covers = e.tokens.len() as u64 >= prefix_len && e.tokens[..prefix_len as usize] == *want;
743 let whole = e.tokens.len() as u64 == prefix_len;
744 covers && (!exact || whole) && (whole || prefix_len >= self.desc.seed_min_tokens) && e.serves(prefix_len)
745 })
746 .min_by_key(|e| e.exported.is_some())
749 .map(|e| e.seq)
750 .ok_or(Status::SeedUnservable)?;
751 self.pin(entry_seq);
752 let handle = self.next_seed;
753 self.next_seed += 1;
754 self.seeds.insert(
755 handle,
756 SeedLease {
757 prefix: want.to_vec(),
758 entry_seq,
759 determinism: determinism_class,
760 expires_at_tick: self.tick_count + self.cfg.seed_ttl_ticks,
761 adopted: None,
762 },
763 );
764 Ok(handle)
765 }
766
767 fn seed_lease_ticks(&self) -> Option<u64> {
768 Some(self.cfg.seed_ttl_ticks)
769 }
770
771 fn seed_release(&mut self, seed_handle: u64) -> Result<(), Status> {
772 let lease = self.seeds.remove(&seed_handle).ok_or(Status::UnknownHandle)?;
773 match lease.adopted {
774 Some(seq) => {
775 self.adopt_leased.remove(&seq);
776 }
777 None => self.unpin(lease.entry_seq),
778 }
779 Ok(())
780 }
781
782 fn seed_adopt(&mut self, seq: SeqHandle, span_tokens: &[u32]) -> Result<u64, Status> {
783 if !self.bare.contains(&seq) {
784 return Err(Status::UnknownHandle);
785 }
786 if self.adopt_leased.contains(&seq) {
787 return Err(Status::Busy);
788 }
789 if span_tokens.len() as u64 != self.prim.seq_len(seq) || span_tokens.is_empty() {
790 return Err(Status::OutOfBoundary);
791 }
792 self.adopt_leased.insert(seq);
793 self.bare_tokens.insert(seq, span_tokens.to_vec());
794 let handle = self.next_seed;
795 self.next_seed += 1;
796 self.seeds.insert(
797 handle,
798 SeedLease {
799 prefix: span_tokens.to_vec(),
800 entry_seq: 0,
801 determinism: superfluid_abi::determinism::BEST_EFFORT,
802 expires_at_tick: self.tick_count + self.cfg.seed_ttl_ticks,
803 adopted: Some(seq),
804 },
805 );
806 Ok(handle)
807 }
808
809 fn seq_fork(&mut self, parent: SeqHandle, flags: u32) -> Result<SeqHandle, Status> {
810 if !self.seq_known(parent) {
811 return Err(Status::UnknownHandle);
812 }
813 let len = self.prim.seq_len(parent);
814 let child = self.seq_create_making_room().map_err(prim_status)?;
815 if let Err(e) = self.prim.seq_copy(parent, child, len) {
816 self.prim.seq_free(child);
817 return Err(prim_status(e));
818 }
819 self.bare.insert(child);
820 if flags & superfluid_abi::fork_flags::PRIVATE == 0 {
821 self.forks.insert(child);
822 }
823 self.seq_gen.insert(child, 1);
824 if let Some(tokens) = self.tokens_of(parent).map(|t| t[..t.len().min(len as usize)].to_vec()) {
825 self.bare_tokens.insert(child, tokens);
826 }
827 self.inherit_taint(parent, child);
828 Ok(child)
829 }
830
831 fn lane_sequence(&self, lane_tag: u64) -> Option<SeqHandle> {
832 self.lanes.get(&lane_tag).map(|l| l.seq)
833 }
834
835 fn create_sequence(&mut self) -> Result<SeqHandle, Status> {
836 let seq = self.seq_create_making_room().map_err(prim_status)?;
837 self.bare.insert(seq);
838 Ok(seq)
839 }
840
841 fn free_sequence(&mut self, seq: SeqHandle) -> Result<(), Status> {
842 if !self.bare.contains(&seq) {
843 return Err(Status::UnknownHandle);
844 }
845 if self.adopt_leased.contains(&seq) {
846 return Err(Status::Busy);
847 }
848 self.bare.remove(&seq);
849 self.forget_seq(seq);
850 self.prim.seq_free(seq);
851 Ok(())
852 }
853
854 fn publish_sequence(&mut self, seq: SeqHandle, tokens: &[u32]) -> Result<(), Status> {
855 if !self.bare.contains(&seq) {
856 return Err(Status::UnknownHandle);
857 }
858 if self.adopt_leased.contains(&seq) {
859 return Err(Status::Busy);
860 }
861 if tokens.len() as u64 > self.prim.seq_len(seq) {
862 return Err(Status::OutOfBoundary);
863 }
864 let page = self.page();
865 let len = self.prim.seq_len(seq);
866 let key_len = if self.exact_only() { tokens.len() as u64 } else { tokens.len() as u64 / page * page };
867 if self.exact_only() && key_len != len {
868 return Err(Status::OutOfBoundary);
869 }
870 self.bare.remove(&seq);
871 self.pending_export.remove(&seq);
872 if key_len == 0 {
873 self.forget_seq(seq);
874 self.prim.seq_free(seq);
875 return Ok(());
876 }
877 let held = if key_len < len && self.prim.seq_truncate(seq, key_len).is_ok() { key_len } else { len };
878 let bytes = self.entry_bytes(held);
879 let now = self.tick_count;
880 let shared = self.forks.remove(&seq);
881 self.cache.insert(seq, tokens[..key_len as usize].to_vec(), 0, bytes, now);
882 if let Some(e) = self.cache.entries.last_mut() {
883 e.shared = shared;
884 }
885 self.settle_cache(&mut Vec::new());
886 Ok(())
887 }
888
889 fn space_export_size(
890 &mut self,
891 seq: SeqHandle,
892 space_id: u32,
893 range: TokenRange,
894 encoding: u8,
895 ) -> Result<(u64, u64), Status> {
896 if space_id != KV_SPACE {
897 return Err(Status::UnknownHandle);
898 }
899 if !self.seq_known(seq) {
900 return Err(Status::UnknownHandle);
901 }
902 if range.start != 0 || range.end < range.start {
903 return Err(Status::Unsupported);
904 }
905 self.size_export(seq, range.end, encoding)
906 }
907
908 fn space_snapshot(
909 &mut self,
910 seq: SeqHandle,
911 space_id: u32,
912 boundary_pos: u64,
913 dst_len: u64,
914 sizing_gen: u64,
915 ) -> Result<OpHandle, Status> {
916 if space_id != KV_SPACE || !self.seq_known(seq) {
917 return Err(Status::UnknownHandle);
918 }
919 if boundary_pos == 0 {
920 return Err(Status::RejectBounds);
921 }
922 if self.prim.seq_boundary(seq, boundary_pos) != boundary_pos {
923 return Err(Status::OutOfBoundary);
924 }
925 self.take_export(seq, boundary_pos, superfluid_abi::encoding::LOSSLESS, dst_len, sizing_gen)
926 }
927
928 fn space_snapshot_boundary(&mut self, seq: SeqHandle, space_id: u32, cap: u64) -> Result<u64, Status> {
929 if space_id != KV_SPACE || !self.seq_known(seq) {
930 return Err(Status::UnknownHandle);
931 }
932 let b = self.prim.seq_boundary(seq, cap);
933 Ok(if self.desc.truncate_partial { b / self.page() * self.page() } else { b })
934 }
935
936 fn space_restore(&mut self, seq: SeqHandle, space_id: u32, src: &[u8]) -> Result<OpHandle, Status> {
937 if space_id != KV_SPACE || !self.bare.contains(&seq) {
938 return Err(Status::UnknownHandle);
939 }
940 if self.prim.seq_len(seq) != 0 || self.adopt_leased.contains(&seq) {
941 return Err(Status::Busy);
942 }
943 let compat = self.compat();
944 let (env, payload) = crate::envelope::open(src, space_kind::PAGED_TOKEN_KV, 1, &compat)?;
945 if env.range.start != 0 || env.range.end == 0 || env.range.end > self.desc.max_seq_len {
946 return Ok(self.complete_op(Err(Status::RejectBounds), 0));
947 }
948 let result = self.prim.seq_import(seq, payload).map_err(prim_status);
949 let bytes = payload.len() as u64;
950 let failed = match result {
951 Ok(len) if len == env.range.end => None,
952 Ok(_) => Some(Status::EnvelopeMismatch),
953 Err(e) => Some(e),
954 };
955 if let Some(err) = failed {
956 let rolled_back = self.prim.seq_truncate(seq, 0).is_ok() && self.prim.seq_len(seq) == 0;
957 let err = if rolled_back { err } else { Status::Fatal };
958 return Ok(self.complete_op(Err(err), 0));
959 }
960 self.bump(seq);
961 self.bare_tokens.remove(&seq);
962 self.seq_taint.remove(&seq);
963 if env.taint_bits != 0 {
964 self.seq_taint.insert(seq, env.taint_bits);
965 }
966 Ok(self.complete_op(Ok(Vec::new()), bytes))
967 }
968
969 fn space_trim(&mut self, seq: SeqHandle, space_id: u32, new_len: u64) -> Result<(), Status> {
970 if space_id != KV_SPACE || !self.seq_known(seq) {
971 return Err(Status::UnknownHandle);
972 }
973 if self.seq_is_lane(seq) || self.seq_is_cached(seq) || self.adopt_leased.contains(&seq) {
974 return Err(Status::Busy);
975 }
976 if new_len > self.prim.seq_len(seq) {
977 return Err(Status::RejectBounds);
978 }
979 self.prim.seq_truncate(seq, new_len).map_err(prim_status)?;
980 self.bump(seq);
981 Ok(())
982 }
983
984 fn space_demote(
985 &mut self,
986 seq: SeqHandle,
987 space_id: u32,
988 range: TokenRange,
989 encoding: u8,
990 dst_len: u64,
991 sizing_gen: u64,
992 ) -> Result<OpHandle, Status> {
993 if space_id != KV_SPACE || !self.seq_known(seq) {
994 return Err(Status::UnknownHandle);
995 }
996 if range.start != 0 {
997 return Err(Status::Unsupported);
998 }
999 self.take_export(seq, range.end, encoding, dst_len, sizing_gen)
1000 }
1001
1002 fn space_promote(
1003 &mut self,
1004 _seq: SeqHandle,
1005 _space_id: u32,
1006 _range: TokenRange,
1007 _src: &[u8],
1008 ) -> Result<OpHandle, Status> {
1009 Err(Status::Unsupported)
1010 }
1011
1012 fn op_poll(&mut self, op: OpHandle) -> Result<OpStatus, Status> {
1013 let o = self.ops.get(&op).ok_or(Status::UnknownHandle)?;
1014 Ok(OpStatus {
1015 struct_size: std::mem::size_of::<OpStatus>() as u64,
1016 state: o.state,
1017 _pad0: [0; 3],
1018 error: o.error,
1019 bytes_moved: o.bytes_moved,
1020 })
1021 }
1022
1023 fn take_op_output(&mut self, op: OpHandle) -> Option<Vec<u8>> {
1024 let o = self.ops.get_mut(&op)?;
1025 if o.state != op_state::DONE {
1026 return None;
1027 }
1028 o.output.take()
1029 }
1030
1031 fn op_cancel(&mut self, op: OpHandle) -> Result<(), Status> {
1032 self.ops.get(&op).map(|_| ()).ok_or(Status::UnknownHandle)
1033 }
1034
1035 fn cache_evict(
1036 &mut self,
1037 evictable_cache_classes: u64,
1038 protected_quota_bytes: u64,
1039 max_evict_bytes: u64,
1040 bytes_target: u64,
1041 ) -> Result<u64, Status> {
1042 if evictable_cache_classes & HOST_EXPORT_CLASS != 0 {
1043 self.drop_exports();
1044 }
1045 if evictable_cache_classes & RESIDENT_PREFIX_CLASS == 0 {
1046 return Ok(0);
1047 }
1048 let cap = max_evict_bytes.min(self.cache.resident_bytes().saturating_sub(protected_quota_bytes));
1049 let want = bytes_target.min(cap);
1050 if want == 0 {
1051 return Ok(0);
1052 }
1053 let (freed, _, _) = self.evict_classes(want, cap, evictable_cache_classes & SHARED_PREFIX_CLASS != 0);
1054 Ok(freed)
1055 }
1056
1057 fn cache_evict_entries(&mut self, keys: &[([u8; 32], [u8; 32])]) -> Result<(), Status> {
1058 let chain = self.compat_identity();
1059 if keys.iter().any(|(c, _)| *c != chain) {
1060 return Err(Status::IdentityMismatch);
1061 }
1062 let digests: Vec<[u8; 32]> = keys.iter().map(|k| k.1).collect();
1063 let gone = self.cache.evict_digests(&digests);
1064 self.free_evicted(gone);
1065 Ok(())
1066 }
1067
1068 fn unpublish(&mut self, tokens: &[u32]) -> Result<(), Status> {
1069 let gone = self.cache.evict_exact(tokens);
1070 self.free_evicted(gone);
1071 Ok(())
1072 }
1073
1074 fn logit_bias_create(&mut self, tokens: &[i32], values: &[f32]) -> Result<u32, Status> {
1075 let bias: Vec<(u32, f32)> = tokens
1076 .iter()
1077 .zip(values.iter())
1078 .filter(|(t, _)| **t >= 0 && (**t as u32) < self.desc.vocab_size)
1079 .map(|(t, v)| (*t as u32, *v))
1080 .collect();
1081 let h = self.next_bias;
1082 self.next_bias += 1;
1083 self.biases.insert(h, bias);
1084 Ok(h)
1085 }
1086
1087 fn logit_bias_free(&mut self, handle: u32) -> Result<(), Status> {
1088 self.biases.remove(&handle).map(|_| ()).ok_or(Status::UnknownHandle)
1089 }
1090
1091 fn grammar_create(&mut self, json_schema: &str) -> Result<u32, Status> {
1092 let prim = &self.prim;
1093 self.grammars.create_schema(|| prim.vocabulary(), json_schema)
1094 }
1095
1096 fn grammar_create_structural(&mut self, tag_json: &str) -> Result<u32, Status> {
1097 let prim = &self.prim;
1098 self.grammars.create_structural(|| prim.vocabulary(), tag_json)
1099 }
1100
1101 fn grammar_free(&mut self, handle: u32) -> Result<(), Status> {
1102 self.grammars.free(handle)
1103 }
1104
1105 fn capability_descriptor(&self) -> Option<String> {
1106 let d = self
1107 .capabilities
1108 .get_or_init(|| crate::capabilities::descriptor(&self.desc, self.prim.vocabulary().is_some()));
1109 Some(d.clone())
1110 }
1111}
1112
1113impl<P: RuntimePrimitives> superfluid_engine::testing::EngineInspect for Executor<P> {
1114 fn lane_committed(&self, lane_tag: u64) -> Option<&[u32]> {
1115 Executor::lane_committed(self, lane_tag)
1116 }
1117 fn inject_fault(&mut self, lane_tag: u64, code: u32) {
1118 Executor::inject_fault(self, lane_tag, code)
1119 }
1120}