Skip to main content

printobserver_types/
policy.rs

1//! What an actor is allowed to ask for, and the decision taken on one request.
2
3use std::collections::BTreeMap;
4
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use crate::action::{ActionKind, ActorClass};
9use crate::adjustable::Adjustable;
10use crate::printer::PrinterState;
11use crate::reported::Range;
12
13/// Server configuration: what any actor may ask for at all.
14///
15/// This is the operator's safety envelope. It is a different contract from the
16/// plausibility ranges [`Reported`](crate::Reported) fields carry, is narrower
17/// by orders of magnitude, and the two are never intersected, compared or
18/// substituted for one another.
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
20#[serde(deny_unknown_fields)]
21pub struct SafetyEnvelope {
22    /// The range each adjustable may be set to, inclusive.
23    pub allowed: BTreeMap<Adjustable, Range>,
24    /// The actions each actor class may request at all.
25    pub actions: BTreeMap<ActorClass, Vec<ActionKind>>,
26    /// The minimum interval between agent actions, in whole seconds.
27    pub agent_min_interval_s: i64,
28}
29
30/// The envelope intersected with the print's manifest.
31///
32/// This is what context reports, so that the agent can see its own limits
33/// before it asks. Computing one is the supervision core's; this crate declares
34/// the shape and nothing that produces it.
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
36#[serde(deny_unknown_fields)]
37pub struct EffectiveBounds {
38    /// The range each adjustable may be set to, inclusive.
39    pub allowed: BTreeMap<Adjustable, Range>,
40}
41
42/// Why a request was refused.
43///
44/// Each rejection is a distinct variant, so a consumer distinguishes them by
45/// matching rather than by reading a message.
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
47#[serde(rename_all = "snake_case", deny_unknown_fields)]
48pub enum RejectionReason {
49    /// The value asked for is outside the range allowed for that adjustable.
50    OutOfBounds {
51        /// The adjustable that was asked for.
52        adjustable: Adjustable,
53        /// The value that was asked for.
54        requested: f64,
55        /// The range that was allowed.
56        allowed: Range,
57    },
58    /// This actor class may not request this action at all.
59    ActorMayNotRequest {
60        /// The class of the actor that asked.
61        actor_class: ActorClass,
62        /// The action they asked for.
63        action: ActionKind,
64    },
65    /// There is no active print to act on.
66    NoActivePrint,
67    /// The printer is not in a state this action is valid from.
68    InvalidFromState {
69        /// The state the printer is in.
70        state: PrinterState,
71    },
72    /// The agent's minimum interval has not elapsed.
73    MinIntervalNotElapsed {
74        /// The minimum interval, in whole seconds.
75        interval_s: i64,
76        /// How long it has been since the last agent action, in whole seconds.
77        since_last_s: i64,
78    },
79    /// The adjustable is not one this printer has.
80    UnsupportedAdjustable {
81        /// The adjustable this printer cannot express.
82        adjustable: Adjustable,
83    },
84}
85
86/// The decision policy took on one request.
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
88#[serde(rename_all = "snake_case", deny_unknown_fields)]
89pub enum PolicyDecision {
90    /// The request may proceed.
91    Accepted,
92    /// The request may not, for this reason.
93    Rejected(RejectionReason),
94}