Skip to main content

bb_runtime/errors/
bootstrap.rs

1//! `BootstrapError`
2//!
3//! Returned by [`crate::node::Node::run_bootstrap`] when input
4//! staging or target selection violates the contract per
5//! `docs/internal/superpowers/specs/2026-06-25-host-driven-bootstrap.md`
6//! §3.2.
7//!
8//! Each variant carries every datum a host needs to recover (the
9//! offending name plus the declared set, the unknown slot id plus
10//! the available ids, …) so callers can surface human-readable
11//! prompts without re-introspecting the engine.
12
13/// Errors surfaced by host-facing bootstrap staging methods on
14/// `Node`. Returned by [`crate::node::Node::run_bootstrap`].
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum BootstrapError {
17    /// `run_bootstrap(&[BootstrapInput])` named a target the engine
18    /// has no bootstrap registration for. Carries the queue snapshot
19    /// so callers can present the legal set.
20    UnknownTarget {
21        /// Target name the caller supplied.
22        target_name: String,
23        /// Target names currently registered as Module bootstrap
24        /// targets, in install order.
25        available: Vec<String>,
26    },
27
28    /// `run_bootstrap(&[BootstrapInput])` named an input the target
29    /// does not declare as a formal. Carries the declared set so
30    /// callers can correct the request.
31    UnknownInput {
32        /// Target name the request targeted.
33        target_name: String,
34        /// Input name the caller supplied.
35        input_name: String,
36        /// Input names declared as formals on the target.
37        declared: Vec<String>,
38    },
39
40    /// `run_bootstrap(&[BootstrapInput])` is missing a required
41    /// formal input. Validation fails atomically — no inputs stage
42    /// when this fires.
43    MissingInput {
44        /// Target name the request targeted.
45        target_name: String,
46        /// Input name declared as a formal but not supplied.
47        input_name: String,
48    },
49
50    /// Bootstrap input staging hit the engine's `ingress_byte_budget`
51    /// cap or the `try_reserve_exact` seam returned `TryReserveError`.
52    /// Carries the offending input's byte count + the remaining
53    /// budget at the point of rejection so the host can decide
54    /// whether to back off, shrink the payload, or raise the cap.
55    /// Any per-input charges that landed earlier in the same
56    /// request are released before the engine surfaces this error —
57    /// the bootstrap state stays untouched.
58    AllocationFailed {
59        /// Target name the request targeted.
60        target_name: String,
61        /// Bytes the staging step tried to admit when the cap or
62        /// allocator rejected the request.
63        byte_count: usize,
64        /// Bytes still available under `ingress_byte_budget` at the
65        /// point of the rejection.
66        budget_remaining: usize,
67    },
68}
69
70impl std::fmt::Display for BootstrapError {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        match self {
73            Self::UnknownTarget {
74                target_name,
75                available,
76            } => write!(
77                f,
78                "unknown bootstrap target '{target_name}'; available: {available:?}",
79            ),
80            Self::UnknownInput {
81                target_name,
82                input_name,
83                declared,
84            } => write!(
85                f,
86                "target '{target_name}' has no input '{input_name}'; declared: {declared:?}",
87            ),
88            Self::MissingInput {
89                target_name,
90                input_name,
91            } => write!(
92                f,
93                "target '{target_name}' missing required input '{input_name}'",
94            ),
95            Self::AllocationFailed {
96                target_name,
97                byte_count,
98                budget_remaining,
99            } => write!(
100                f,
101                "target '{target_name}' input staging refused {byte_count}B (budget remaining {budget_remaining}B)",
102            ),
103        }
104    }
105}
106
107impl std::error::Error for BootstrapError {}
108