metrale_circuit/state_kinds.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-10-02: What a declared state is ([`StateKind`]) and how long a unit of it lives
4//! ([`Lifetime`]), split from `state.rs`.
5//!
6//! Owner: metrale-circuit.
7//! Invariants:
8//! - Every kind has one spelling ([`StateKind::parse`] of [`StateKind::name`] is the kind) and
9//! one lifetime ([`Lifetime::of_kind`]); a spelling outside the list is refused by the loader.
10
11#[cfg(doc)]
12use super::{Holding, StatePlan};
13
14/// 2026-09-30: What a state is.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum StateKind {
17 /// 2026-09-30: A recurrent state, one unit per sequence slot (GatedDeltaNet and Mamba2
18 /// `h`, their conv windows).
19 Recurrent,
20 /// 2026-09-30: One side of a paged KV cache, one unit per token.
21 PagedKv,
22 /// 2026-10-02: A prefix-cache (Marconi) snapshot of a recurrent state (`of`), or of the
23 /// last-token hidden row, one unit per snapshot slot.
24 PrefixSnapshot,
25 /// 2026-10-02: The decode-rollback ring's copy of a recurrent state (`of`), one unit per ring
26 /// slot per sequence slot.
27 RingSnapshot,
28 /// 2026-10-02: The carried-state verify's per-slot stash of a recurrent layer, one unit per
29 /// verify slot (the dummy included).
30 CarryStash,
31 /// 2026-10-02: The carried-state verify's per-layer pointer and flag tables, one unit per
32 /// carry-table row.
33 CarryTable,
34 /// 2026-10-02: A verify's per-layer WY pointer tables, one unit per verify-table row.
35 VerifyTable,
36 /// 2026-10-02: The hidden rows of accepted drafts a verify stashes for the next propose, one
37 /// unit per verify-table row.
38 AcceptStash,
39 /// 2026-10-02: Hidden rows captured for the draft head (the prompt's, for the drafter
40 /// prefill; DFlash's per-step capture), one unit per captured row.
41 HiddenCapture,
42 /// 2026-10-02: Host: a sequence's prompt-lookup n-gram index, one entry per history token
43 /// (sized by the hash table law in `memory::caches`).
44 PromptLookupIndex,
45 /// 2026-10-02: A token tree's attention mask, one unit per (tree node, tree node) pair of a
46 /// verify slot.
47 TokenTreeMask,
48 /// 2026-10-02: A speculative step's drafted tokens and their scores, one unit per draft
49 /// position of a verify slot (tree nodes under a token tree).
50 DraftTokens,
51}
52
53/// 2026-10-02: Every kind and its spelling in the circuit TOML.
54const KINDS: [(StateKind, &str); 12] = [
55 (StateKind::Recurrent, "recurrent"),
56 (StateKind::PagedKv, "paged_kv"),
57 (StateKind::PrefixSnapshot, "prefix_snapshot"),
58 (StateKind::RingSnapshot, "ring_snapshot"),
59 (StateKind::CarryStash, "carry_stash"),
60 (StateKind::CarryTable, "carry_table"),
61 (StateKind::VerifyTable, "verify_table"),
62 (StateKind::AcceptStash, "accept_stash"),
63 (StateKind::HiddenCapture, "hidden_capture"),
64 (StateKind::PromptLookupIndex, "prompt_lookup_index"),
65 (StateKind::TokenTreeMask, "token_tree_mask"),
66 (StateKind::DraftTokens, "draft_tokens"),
67];
68
69impl StateKind {
70 /// 2026-09-30: The spelling in the circuit TOML.
71 pub fn parse(s: &str) -> Option<Self> {
72 KINDS.iter().find(|(_, n)| *n == s).map(|(k, _)| *k)
73 }
74
75 /// 2026-10-02: The spelling.
76 pub fn name(self) -> &'static str {
77 KINDS
78 .iter()
79 .find(|(k, _)| *k == self)
80 .map(|(_, n)| *n)
81 .unwrap_or("?")
82 }
83
84 /// 2026-10-02: Every spelling, for refusals.
85 pub fn spellings() -> Vec<&'static str> {
86 KINDS.iter().map(|(_, n)| *n).collect()
87 }
88
89 /// 2026-10-02: A cache: a kind no layer node touches, sized by `memory::caches` from the
90 /// cache inputs, never by [`StatePlan`]. It may copy another state of its block (`of`).
91 pub fn is_cache(self) -> bool {
92 !matches!(self, Self::Recurrent | Self::PagedKv)
93 }
94
95 /// 2026-10-02: The kinds whose unit copies a declared state (`of`).
96 pub fn copies_a_state(self) -> bool {
97 matches!(self, Self::PrefixSnapshot | Self::RingSnapshot)
98 }
99
100 /// 2026-10-02: Held in host memory rather than device memory (on a unified-memory device it
101 /// still competes for the same pool, outside the util budget).
102 pub fn is_host(self) -> bool {
103 matches!(self, Self::PromptLookupIndex)
104 }
105}
106
107/// 2026-09-30: How long a unit of state lives (LIFECYCLE-DESIGN.md section 3.3).
108#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
109pub enum Lifetime {
110 /// 2026-09-30: Allocated once with the model (a KV pool; its blocks are per sequence).
111 Model,
112 /// 2026-09-30: Claimed with a sequence's slot and released with it.
113 Sequence,
114 /// 2026-09-30: Valid from a verify's snapshot to its commit or rollback.
115 Verify,
116 /// 2026-10-02: Owned by the prefix cache or the scheduler's ring, in slots of their own.
117 Snapshot,
118}
119
120impl Lifetime {
121 /// 2026-09-30: The spelling in the circuit TOML.
122 pub fn parse(s: &str) -> Option<Self> {
123 match s {
124 "model" => Some(Self::Model),
125 "sequence" => Some(Self::Sequence),
126 "verify" => Some(Self::Verify),
127 "snapshot" => Some(Self::Snapshot),
128 _ => None,
129 }
130 }
131
132 /// 2026-09-30: The spelling.
133 pub fn name(self) -> &'static str {
134 match self {
135 Self::Model => "model",
136 Self::Sequence => "sequence",
137 Self::Verify => "verify",
138 Self::Snapshot => "snapshot",
139 }
140 }
141
142 /// 2026-09-30: The one lifetime a state of `kind` may declare: a recurrent state lives with
143 /// its sequence, a KV side with the model's pool. For a recurrent state `Verify` belongs to
144 /// the verify holdings ([`Holding::lifetime`]), never to its declaration. 2026-10-02: The
145 /// caches: snapshots live in their owner's slots, the verify caches across one verify, the
146 /// verify tables with the model, a prompt-lookup index and a hidden capture with their
147 /// sequence.
148 pub fn of_kind(kind: StateKind) -> Self {
149 match kind {
150 StateKind::Recurrent | StateKind::PromptLookupIndex | StateKind::HiddenCapture => {
151 Self::Sequence
152 }
153 StateKind::PagedKv | StateKind::CarryTable | StateKind::VerifyTable => Self::Model,
154 StateKind::PrefixSnapshot | StateKind::RingSnapshot => Self::Snapshot,
155 StateKind::CarryStash
156 | StateKind::AcceptStash
157 | StateKind::TokenTreeMask
158 | StateKind::DraftTokens => Self::Verify,
159 }
160 }
161}