pub struct DecisionTicketId(pub u64);Expand description
Stable numeric identifier for DecisionTicketId.
Tuple Fields§
§0: u64Implementations§
Source§impl DecisionTicketId
impl DecisionTicketId
Sourcepub const fn new(value: u64) -> DecisionTicketId
pub const fn new(value: u64) -> DecisionTicketId
Creates an identifier from its wire value.
Examples found in repository?
examples/uncertainty_resolution.rs (line 16)
16const RANDOM_TICKET: DecisionTicketId = DecisionTicketId::new(1);
17
18fn decision_stream() -> RandomStreamKey {
19 RandomStreamKey::new("example-uncertainty", "decision-selection", 1)
20}
21
22fn random_resolution_system(
23 view: &SimulationView<'_>,
24 context: &BoundaryContext,
25) -> Result<BoundaryProposal, CanwuError> {
26 let ticket = view
27 .decision_ticket(RANDOM_TICKET)?
28 .expect("the example opens the ticket before the daily boundary");
29 let calendar_ingress = context
30 .admitted_ingress
31 .first()
32 .copied()
33 .expect("the example runs this system from calendar ingress");
34 let option_weights = vec![
35 DecisionOptionWeight::new("fail", 25),
36 DecisionOptionWeight::new("pass", 75),
37 ];
38 let sample = view.random_sample_for_operation(
39 &decision_stream(),
40 EvidenceRef::Ingress(calendar_ingress),
41 "decision_selection",
42 "law-proposal-42",
43 RandomOperationTarget::DecisionTicket {
44 ticket_id: ticket.id,
45 ticket_version: ticket.version,
46 },
47 0,
48 100,
49 "select whether the law passes from configured weights",
50 )?;
51 Ok(BoundaryProposal {
52 directives: vec![BoundaryDirective::ResolveDecisionRandomly {
53 resolution: RandomDecisionResolution {
54 priority: 0,
55 decision_request_id: DecisionRequestId::new(3),
56 command_request_id: None,
57 ticket_id: ticket.id,
58 expected_version: ticket.version,
59 controller_id: ticket.assigned_controller.clone(),
60 sample,
61 option_weights,
62 },
63 }],
64 ..BoundaryProposal::default()
65 })
66}
67
68struct UncertaintyPlugin;
69
70impl SimulationPlugin for UncertaintyPlugin {
71 fn name(&self) -> &'static str {
72 "example-uncertainty"
73 }
74
75 fn version(&self) -> &'static str {
76 "1.0.0"
77 }
78
79 fn semantic_hash(&self) -> &'static str {
80 "95f702ca4cf602640094c022286fe741b47c9d7aa8573a719fce21e8df97b561"
81 }
82
83 fn register(&self, registrar: &mut canwu_api::PluginRegistrar<'_>) -> Result<(), CanwuError> {
84 let mut contract = BoundarySystemContract::new(
85 "resolve-random-decision",
86 BoundaryPhase::StrategicAggregation,
87 SystemCadence::Daily,
88 );
89 contract.reads = vec![StateKey::core_decisions()];
90 contract.random_streams = vec![decision_stream()];
91 registrar.register_boundary_system(contract, random_resolution_system)
92 }
93}
94
95fn enqueue_ticket(
96 canwu: &mut Canwu,
97 ticket_id: DecisionTicketId,
98 request_offset: u64,
99 controller: DecisionControllerBinding,
100) -> Result<(), CanwuError> {
101 let now = canwu.time();
102 let controller_id = controller.id.clone();
103 canwu.enqueue_decision(
104 now,
105 0,
106 DecisionIngressRequest::new(
107 DecisionRequestId::new(request_offset),
108 canwu.revision(),
109 DecisionMutation::RegisterController { controller },
110 ),
111 )?;
112 canwu.enqueue_decision(
113 now,
114 0,
115 DecisionIngressRequest::new(
116 DecisionRequestId::new(request_offset + 1),
117 canwu.revision(),
118 DecisionMutation::Open {
119 ticket: DecisionTicketDraft {
120 id: ticket_id,
121 definition: "example.law-passage".to_owned(),
122 decision_maker: EntityRef::Person(Canwu::demo_ids().commander),
123 assigned_controller: controller_id,
124 summary: "Will the proposed law pass?".to_owned(),
125 context: DecisionContext::new(
126 "example.law-passage.v1",
127 json!({
128 "supporting_seats": 72,
129 "opposing_seats": 28,
130 "public_pressure": "high"
131 }),
132 ),
133 options: vec![
134 DecisionOption::new("pass", "Pass the law"),
135 DecisionOption::new("fail", "Reject the law"),
136 ],
137 deadline: None,
138 },
139 },
140 ),
141 )?;
142 canwu.settle_boundary(canwu_api::BoundaryRequest::at(now))?;
143 Ok(())
144}
145
146fn random_branch() -> Result<(), Box<dyn std::error::Error>> {
147 let mut canwu = Canwu::demo(202)?;
148 canwu.register_plugin(&UncertaintyPlugin)?;
149 enqueue_ticket(
150 &mut canwu,
151 RANDOM_TICKET,
152 1,
153 DecisionControllerBinding::new(
154 "law-random-controller",
155 DecisionPolicyIdentity::new(DecisionPolicyKind::Random, "weighted-random", "1"),
156 DecisionAuthority::Actor {
157 actor: Canwu::demo_ids().commander,
158 },
159 ),
160 )?;
161 let selection_at = SimTime::EPOCH + SimDuration::days(1);
162 canwu.schedule_calendar_boundary(selection_at, vec![SystemCadence::Daily])?;
163 canwu.step_canonical()?.expect("random source boundary");
164 canwu
165 .step_canonical()?
166 .expect("generated decision resolution boundary");
167 let trace = canwu
168 .decision_trace(canwu_api::DecisionTraceId::new(1))
169 .expect("random decision trace");
170 println!("random_trace={}", serde_json::to_string(trace)?);
171 Ok(())
172}
173
174fn llm_interface_branch() -> Result<(), Box<dyn std::error::Error>> {
175 let mut canwu = Canwu::demo(202)?;
176 let ticket_id = DecisionTicketId::new(2);
177 enqueue_ticket(
178 &mut canwu,
179 ticket_id,
180 10,
181 DecisionControllerBinding::new(
182 "law-llm-controller",
183 DecisionPolicyIdentity::new(DecisionPolicyKind::Llm, "strict-law-selector", "1"),
184 DecisionAuthority::Actor {
185 actor: Canwu::demo_ids().commander,
186 },
187 ),
188 )?;
189 let mut policy = QueuedLlmPolicy::new(
190 "strict-law-selector",
191 "1",
192 LlmModelIdentity {
193 provider: "not-connected".to_owned(),
194 model: "host-selected-model".to_owned(),
195 prompt_contract: "return one existing option_id and no new action".to_owned(),
196 },
197 );
198 let ticket = canwu.decision_ticket(ticket_id).expect("LLM ticket");
199 let request = policy.external_request(ticket);
200 println!("llm_request={}", serde_json::to_string(&request)?);
201
202 // A real host sends `request` to its model and parses a strict structured
203 // answer. This example supplies the same response object without making a
204 // network call.
205 policy.submit(
206 ticket_id,
207 ExternalDecisionResponse {
208 ticket_version: request.ticket_version,
209 option_id: "pass".to_owned(),
210 provider: "not-connected".to_owned(),
211 request_id: "example-response-1".to_owned(),
212 metadata: BTreeMap::new(),
213 },
214 )?;
215 let evaluation = canwu.drive_decision(
216 canwu.time(),
217 0,
218 DecisionRequestId::new(12),
219 None,
220 ticket_id,
221 &policy,
222 )?;
223 assert!(matches!(evaluation, DecisionEvaluation::Prepared(_)));
224 canwu.step_canonical()?.expect("LLM decision boundary");
225 Ok(())
226}More examples
examples/decision_ticket.rs (line 57)
29fn open_aid_request(canwu: &mut Canwu, ids: DemoIds) -> Result<(), Box<dyn std::error::Error>> {
30 let now = canwu.time();
31 let controller = DecisionControllerBinding::new(
32 "warlord-b-ai",
33 DecisionPolicyIdentity::new(DecisionPolicyKind::Utility, "aid-utility", "1"),
34 DecisionAuthority::Actor {
35 actor: ids.commander,
36 },
37 )
38 .with_command_subject(EntityRef::Army(ids.army));
39
40 canwu.enqueue_decision(
41 now,
42 0,
43 DecisionIngressRequest::new(
44 DecisionRequestId::new(1),
45 canwu.revision(),
46 DecisionMutation::RegisterController { controller },
47 ),
48 )?;
49 canwu.enqueue_decision(
50 now,
51 0,
52 DecisionIngressRequest::new(
53 DecisionRequestId::new(2),
54 canwu.revision(),
55 DecisionMutation::Open {
56 ticket: DecisionTicketDraft {
57 id: DecisionTicketId::new(1),
58 definition: "beiyang.request-military-aid".to_owned(),
59 decision_maker: EntityRef::Person(ids.commander),
60 assigned_controller: "warlord-b-ai".to_owned(),
61 summary: "Neighboring warlord requests immediate military aid".to_owned(),
62 context: DecisionContext::new(
63 "beiyang.aid-request.v1",
64 json!({
65 "requester": "warlord-a",
66 "battle": "ongoing-front",
67 "common_enemy": true
68 }),
69 ),
70 options: vec![DecisionOption {
71 action: DecisionAction::None,
72 utility_inputs: BTreeMap::from([
73 ("home_defense".to_owned(), 80),
74 ("alliance".to_owned(), -40),
75 ]),
76 ..DecisionOption::new("decline", "Decline aid")
77 }],
78 deadline: Some(now + SimDuration::days(2)),
79 },
80 },
81 ),
82 )?;
83 canwu.step_canonical()?.expect("decision intake boundary");
84 Ok(())
85}
86
87fn refresh_aid_options(canwu: &mut Canwu, ids: DemoIds) -> Result<(), Box<dyn std::error::Error>> {
88 canwu.enqueue_decision(
89 canwu.time(),
90 0,
91 DecisionIngressRequest::new(
92 DecisionRequestId::new(3),
93 canwu.revision(),
94 DecisionMutation::ReplaceOptions {
95 ticket_id: DecisionTicketId::new(1),
96 expected_version: 1,
97 context: DecisionContext::new(
98 "beiyang.aid-request.v1",
99 json!({
100 "requester": "warlord-a",
101 "battle": "ongoing-front",
102 "common_enemy": true,
103 "route_confirmed": true
104 }),
105 ),
106 options: vec![
107 DecisionOption {
108 action: DecisionAction::None,
109 utility_inputs: BTreeMap::from([
110 ("home_defense".to_owned(), 80),
111 ("alliance".to_owned(), -40),
112 ]),
113 ..DecisionOption::new("decline", "Decline aid")
114 },
115 DecisionOption {
116 action: DecisionAction::Command {
117 command: serde_json::to_value(Command::OrderMovement {
118 subject: EntityRef::Army(ids.army),
119 destination: ids.eastern_territory,
120 cargo: Vec::new(),
121 })?,
122 },
123 utility_inputs: BTreeMap::from([
124 ("home_defense".to_owned(), -20),
125 ("alliance".to_owned(), 90),
126 ]),
127 ..DecisionOption::new("send-aid", "Send the neighboring army")
128 },
129 ],
130 },
131 ),
132 )?;
133 canwu
134 .step_canonical()?
135 .expect("dynamic option refresh boundary");
136 Ok(())
137}
138
139fn resolve_aid_request(canwu: &mut Canwu) -> Result<(), Box<dyn std::error::Error>> {
140 let policy = WeightedUtilityPolicy::new(
141 "aid-utility",
142 "1",
143 UtilityProfile {
144 weights: BTreeMap::from([("alliance".to_owned(), 3), ("home_defense".to_owned(), 1)]),
145 },
146 );
147 let evaluation = canwu.drive_decision(
148 canwu.time(),
149 0,
150 DecisionRequestId::new(4),
151 Some(CommandRequestId::new(1)),
152 DecisionTicketId::new(1),
153 &policy,
154 )?;
155 assert!(matches!(evaluation, DecisionEvaluation::Prepared(_)));
156 canwu
157 .step_canonical()?
158 .expect("decision resolution boundary");
159 Ok(())
160}Trait Implementations§
Source§impl Clone for DecisionTicketId
impl Clone for DecisionTicketId
Source§fn clone(&self) -> DecisionTicketId
fn clone(&self) -> DecisionTicketId
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Copy for DecisionTicketId
Source§impl Debug for DecisionTicketId
impl Debug for DecisionTicketId
Source§impl Default for DecisionTicketId
impl Default for DecisionTicketId
Source§fn default() -> DecisionTicketId
fn default() -> DecisionTicketId
Returns the “default value” for a type. Read more
Source§impl<'de> Deserialize<'de> for DecisionTicketId
impl<'de> Deserialize<'de> for DecisionTicketId
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<DecisionTicketId, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<DecisionTicketId, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Source§impl Display for DecisionTicketId
impl Display for DecisionTicketId
impl Eq for DecisionTicketId
Source§impl Hash for DecisionTicketId
impl Hash for DecisionTicketId
Source§impl Ord for DecisionTicketId
impl Ord for DecisionTicketId
Source§fn cmp(&self, other: &DecisionTicketId) -> Ordering
fn cmp(&self, other: &DecisionTicketId) -> Ordering
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the minimum of two values. Read more
Source§impl PartialEq for DecisionTicketId
impl PartialEq for DecisionTicketId
Source§impl PartialOrd for DecisionTicketId
impl PartialOrd for DecisionTicketId
Source§impl Serialize for DecisionTicketId
impl Serialize for DecisionTicketId
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
Serialize this value into the given Serde serializer. Read more
impl StructuralPartialEq for DecisionTicketId
Auto Trait Implementations§
impl Freeze for DecisionTicketId
impl RefUnwindSafe for DecisionTicketId
impl Send for DecisionTicketId
impl Sync for DecisionTicketId
impl Unpin for DecisionTicketId
impl UnsafeUnpin for DecisionTicketId
impl UnwindSafe for DecisionTicketId
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more