Skip to main content

eredu_runtime/replicated_session/
control.rs

1//! Opaque independent state slots for serial ordinary-generation branches.
2
3use super::*;
4use eredu_core::execution_control::SnapshotEstimate;
5use std::sync::Arc;
6
7/// Native mechanisms for complete, independently writable ordinary state copies.
8/// Unlike rollback checkpoints, these copies must remain stable as any descendant
9/// advances. Estimation is side-effect-free; completion stays with the existing
10/// backend submission owner, not this portable driver.
11pub trait ReplicatedTextSnapshotMechanisms<A, B>: ReplicatedTextSessionMechanisms<A, B>
12where
13    B: SubmissionBackend<Executor = <<B as NeuralBackend>::Tensor as Tensor>::Context>,
14    A: LayeredArchitecture<B, Self::State>,
15    Self::State: RuntimeState<B>,
16    Self::ResidentPolicy: LayerwisePolicy<B, A::Unit, Error = Self::PolicyError>,
17    Self::BoundedPolicy: LayerwisePolicy<B, A::Unit, Error = Self::PolicyError>,
18{
19    /// Known logical cost for copying the exact state. None explicitly means
20    /// unknown/unsupported; callers must reserve a known estimate before copying.
21    fn estimate_snapshot_state(&self, state: &Self::State) -> Option<SnapshotEstimate>;
22
23    /// Additional retained native storage through the admitted input span.
24    /// No allocation, execution, or mutation is permitted during estimation.
25    fn estimate_snapshot_growth(
26        &self,
27        _state: &Self::State,
28        _additional_input_tokens: u64,
29    ) -> Option<u64> {
30        None
31    }
32
33    /// Copies every native state component, preserving geometry and positions.
34    /// Mutable storage must be isolated. On error the source remains unchanged;
35    /// all unresolved native resources stay with the existing recovery owner.
36    fn copy_snapshot_state(
37        &mut self,
38        state: &Self::State,
39        context: &<<B as NeuralBackend>::Tensor as Tensor>::Context,
40    ) -> Result<Self::State, Self::Error>;
41}
42
43/// Native state plus complete portable execution metadata. This is an opaque
44/// in-process slot, not a serialized snapshot or a complete generation snapshot.
45/// Slots share an exact executable owner and can be exchanged serially while
46/// keeping weights resident. Copying a slot requires the native copy mechanism.
47pub struct ReplicatedTextControlState<S> {
48    owner: Arc<()>,
49    state: S,
50    prompt_input_identity: Option<PreparedInputCacheIdentity>,
51    next_commit_epoch: DistributedCommitEpoch,
52    last_commit_outcome: Option<DistributedCommitOutcome>,
53}
54
55impl<A, B, M, D> ReplicatedTextSession<A, B, M, D>
56where
57    B: SubmissionBackend<Executor = <<B as NeuralBackend>::Tensor as Tensor>::Context>,
58    M: ReplicatedTextSnapshotMechanisms<A, B>,
59    A: LayeredArchitecture<B, M::State>,
60    D: ReplicatedTextExecutionStrategy<A, B, M::State, M::ResidentPolicy, M::BoundedPolicy>,
61    A::Error: std::fmt::Display,
62    M::PolicyError: std::fmt::Display,
63    M::Error: std::fmt::Display,
64{
65    /// Estimates an independent copy of the currently installed state, without
66    /// allocating native storage, submitting work, evaluating or resetting state.
67    pub fn estimate_control_state(&self) -> Option<SnapshotEstimate> {
68        self.estimate_control_state_parts(
69            &self.state,
70            self.committed_prompt_input_identity.as_ref(),
71        )
72    }
73
74    /// Estimates another independent copy of an existing compatible slot.
75    pub fn estimate_control_state_copy(
76        &self,
77        saved: &ReplicatedTextControlState<M::State>,
78    ) -> Result<
79        Option<SnapshotEstimate>,
80        ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>,
81    > {
82        self.validate_control_state(saved)?;
83        Ok(self.estimate_control_state_parts(&saved.state, saved.prompt_input_identity.as_ref()))
84    }
85
86    /// Estimates future storage from a compatible saved slot. Architecture
87    /// geometry remains in the typed state; native mechanisms price its storage.
88    pub fn estimate_control_state_growth(
89        &self,
90        saved: &ReplicatedTextControlState<M::State>,
91        additional_input_tokens: u64,
92    ) -> Result<Option<u64>, ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>> {
93        self.validate_control_state(saved)?;
94        Ok(self
95            .mechanisms
96            .estimate_snapshot_growth(&saved.state, additional_input_tokens))
97    }
98
99    fn estimate_control_state_parts(
100        &self,
101        state: &M::State,
102        input: Option<&PreparedInputCacheIdentity>,
103    ) -> Option<SnapshotEstimate> {
104        let native = self.mechanisms.estimate_snapshot_state(state)?;
105        let metadata = u64::try_from(std::mem::size_of::<ReplicatedTextControlState<()>>())
106            .ok()?
107            .checked_add(match input {
108                Some(input) => input.logical_metadata_bytes()?,
109                None => 0,
110            })?;
111        Some(SnapshotEstimate {
112            retained_bytes: native.retained_bytes.checked_add(metadata)?,
113            copy_bytes: native.copy_bytes.checked_add(metadata)?,
114        })
115    }
116
117    /// Copies the installed state after the caller reserves its estimated costs.
118    /// Native completion must be established before exposing the returned slot.
119    pub fn capture_control_state(
120        &mut self,
121        context: &<<B as NeuralBackend>::Tensor as Tensor>::Context,
122    ) -> Result<
123        ReplicatedTextControlState<M::State>,
124        ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>,
125    > {
126        self.ensure_commit_resolved()?;
127        let state = self
128            .mechanisms
129            .copy_snapshot_state(&self.state, context)
130            .map_err(ReplicatedTextSessionError::Mechanism)?;
131        self.validate_control_geometry(&state)?;
132        Ok(ReplicatedTextControlState {
133            owner: Arc::clone(&self.control_identity),
134            state,
135            prompt_input_identity: self.committed_prompt_input_identity.clone(),
136            next_commit_epoch: self.next_commit_epoch,
137            last_commit_outcome: self.last_commit_outcome,
138        })
139    }
140
141    /// Makes a reusable snapshot or child state from an existing saved slot,
142    /// without replaying input, loading weights or changing the installed state.
143    pub fn copy_control_state(
144        &mut self,
145        saved: &ReplicatedTextControlState<M::State>,
146        context: &<<B as NeuralBackend>::Tensor as Tensor>::Context,
147    ) -> Result<
148        ReplicatedTextControlState<M::State>,
149        ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>,
150    > {
151        self.validate_control_state(saved)?;
152        let state = self
153            .mechanisms
154            .copy_snapshot_state(&saved.state, context)
155            .map_err(ReplicatedTextSessionError::Mechanism)?;
156        self.validate_control_geometry(&state)?;
157        Ok(ReplicatedTextControlState {
158            owner: Arc::clone(&self.control_identity),
159            state,
160            prompt_input_identity: saved.prompt_input_identity.clone(),
161            next_commit_epoch: saved.next_commit_epoch,
162            last_commit_outcome: saved.last_commit_outcome,
163        })
164    }
165
166    fn validate_control_geometry(
167        &self,
168        state: &M::State,
169    ) -> Result<(), ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>> {
170        match self.selected_state.state() {
171            Some(selected) => validate_realized_state(state, selected),
172            None => Err(ReplicatedTextSessionError::Contract(
173                "ordinary control requires a selected stateful text execution".into(),
174            )),
175        }
176    }
177
178    /// Exact executable identity and geometry checks performed before mutation.
179    pub fn validate_control_state(
180        &self,
181        saved: &ReplicatedTextControlState<M::State>,
182    ) -> Result<(), ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>> {
183        self.ensure_commit_resolved()?;
184        if !Arc::ptr_eq(&self.control_identity, &saved.owner) {
185            return Err(ReplicatedTextSessionError::Contract(
186                "control state belongs to a different executable".into(),
187            ));
188        }
189        self.validate_control_geometry(&saved.state)
190    }
191
192    /// Atomically exchanges complete state at an already completed boundary.
193    /// The old installed state is returned in `slot`; no array data is copied.
194    /// This supports serial branch switching under one native completion owner.
195    pub fn exchange_control_state(
196        &mut self,
197        slot: &mut ReplicatedTextControlState<M::State>,
198    ) -> Result<(), ReplicatedTextSessionError<A::Error, M::PolicyError, M::Error>> {
199        self.validate_control_state(slot)?;
200        std::mem::swap(&mut self.state, &mut slot.state);
201        std::mem::swap(
202            &mut self.committed_prompt_input_identity,
203            &mut slot.prompt_input_identity,
204        );
205        std::mem::swap(&mut self.next_commit_epoch, &mut slot.next_commit_epoch);
206        std::mem::swap(&mut self.last_commit_outcome, &mut slot.last_commit_outcome);
207        Ok(())
208    }
209}