Skip to main content

arkhe_kernel/state/
config.rs

1//! `InstanceConfig` — caller-supplied per-instance configuration.
2//!
3//! `EffectiveConfig` (parent-derived bounds, A10 — every quota = min(parent,
4//! requested)) is composed at `Kernel::create_instance` time when parent ↔
5//! child relationships are wired.
6
7use serde::{Deserialize, Serialize};
8
9use crate::abi::{CapabilityMask, InstanceId};
10use crate::state::quota::QuotaReductionPolicy;
11
12/// Per-instance configuration supplied at `Kernel::create_instance`.
13/// All fields are pub — `InstanceConfig { field: ..., ..Default::default() }`
14/// is the idiomatic construction pattern.
15#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
16pub struct InstanceConfig {
17    /// The instance's capability grant — the upper bound on the authority
18    /// any action running against this instance can hold. `effective_caps`
19    /// resolves a `System` action to exactly this, and an `External` action
20    /// to this intersected with the submission/scheduling ceiling, so no
21    /// action can exceed what the instance config permits (there is no
22    /// `Principal::System` blanket bypass).
23    pub default_caps: CapabilityMask,
24    /// Hard upper bound on entities (0 = unlimited).
25    pub max_entities: u32,
26    /// Hard upper bound on scheduled actions (0 = unlimited).
27    pub max_scheduled: u32,
28    /// Per-route inbound-signal queue depth (0 = unlimited). A `SendSignal`
29    /// whose target route inbox is at this depth is dropped with
30    /// `KernelEvent::SignalDropped { reason: QueueFull }` and credits no
31    /// in-flight refcount.
32    pub max_inbox_per_route: u32,
33    /// Component byte ceiling enforced per-Op in `step()`.
34    /// `0` = unlimited (default). When `> 0`, an Op whose projected
35    /// post-commit total exceeds this is denied per-Op (`EffectFailed`)
36    /// without rolling back sibling Ops.
37    pub memory_budget_bytes: u64,
38    /// Parent `InstanceId` for hierarchical quota enforcement
39    /// (`apply_quota_reduction`); `None` for root instances.
40    pub parent: Option<InstanceId>,
41    /// Policy applied when a parent's quota would drop below current
42    /// child aggregate usage. See [`QuotaReductionPolicy`].
43    pub quota_reduction: QuotaReductionPolicy,
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn config_default_is_zero_quota_reject_policy() {
52        let c = InstanceConfig::default();
53        assert_eq!(c.max_entities, 0);
54        assert_eq!(c.max_scheduled, 0);
55        assert_eq!(c.max_inbox_per_route, 0);
56        assert_eq!(c.memory_budget_bytes, 0);
57        assert!(c.parent.is_none());
58        assert_eq!(c.quota_reduction, QuotaReductionPolicy::Reject);
59        assert!(c.default_caps.is_empty());
60    }
61
62    #[test]
63    fn config_clone_eq() {
64        let c1 = InstanceConfig {
65            default_caps: CapabilityMask::SYSTEM,
66            max_entities: 10,
67            max_scheduled: 100,
68            max_inbox_per_route: 16,
69            memory_budget_bytes: 1024,
70            parent: InstanceId::new(7),
71            quota_reduction: QuotaReductionPolicy::ThrottleProportional,
72        };
73        let c2 = c1.clone();
74        assert_eq!(c1, c2);
75    }
76
77    #[test]
78    fn config_field_assignment() {
79        let c = InstanceConfig {
80            max_entities: 42,
81            parent: InstanceId::new(3),
82            quota_reduction: QuotaReductionPolicy::GrandfatherExisting,
83            ..Default::default()
84        };
85        assert_eq!(c.max_entities, 42);
86        assert_eq!(c.parent, InstanceId::new(3));
87        assert_eq!(c.quota_reduction, QuotaReductionPolicy::GrandfatherExisting);
88    }
89}