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}