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}