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 tie_break: None,
63 },
64 }],
65 ..BoundaryProposal::default()
66 })
67}
68
69struct UncertaintyPlugin;
70
71impl SimulationPlugin for UncertaintyPlugin {
72 fn name(&self) -> &'static str {
73 "example-uncertainty"
74 }
75
76 fn version(&self) -> &'static str {
77 "1.0.0"
78 }
79
80 fn semantic_hash(&self) -> &'static str {
81 "95f702ca4cf602640094c022286fe741b47c9d7aa8573a719fce21e8df97b561"
82 }
83
84 fn register(&self, registrar: &mut canwu_api::PluginRegistrar<'_>) -> Result<(), CanwuError> {
85 let mut contract = BoundarySystemContract::new(
86 "resolve-random-decision",
87 BoundaryPhase::StrategicAggregation,
88 SystemCadence::Daily,
89 );
90 contract.reads = vec![StateKey::core_decisions()];
91 contract.random_streams = vec![decision_stream()];
92 registrar.register_boundary_system(contract, random_resolution_system)
93 }
94}
95
96fn enqueue_ticket(
97 canwu: &mut Canwu,
98 ticket_id: DecisionTicketId,
99 request_offset: u64,
100 controller: DecisionControllerBinding,
101) -> Result<(), CanwuError> {
102 let now = canwu.time();
103 let controller_id = controller.id.clone();
104 canwu.enqueue_decision(
105 now,
106 0,
107 DecisionIngressRequest::new(
108 DecisionRequestId::new(request_offset),
109 canwu.revision(),
110 DecisionMutation::RegisterController { controller },
111 ),
112 )?;
113 canwu.enqueue_decision(
114 now,
115 0,
116 DecisionIngressRequest::new(
117 DecisionRequestId::new(request_offset + 1),
118 canwu.revision(),
119 DecisionMutation::Open {
120 ticket: DecisionTicketDraft {
121 id: ticket_id,
122 definition: "example.law-passage".to_owned(),
123 decision_maker: EntityRef::Person(Canwu::demo_ids().commander),
124 assigned_controller: controller_id,
125 summary: "Will the proposed law pass?".to_owned(),
126 context: DecisionContext::new(
127 "example.law-passage.v1",
128 json!({
129 "supporting_seats": 72,
130 "opposing_seats": 28,
131 "public_pressure": "high"
132 }),
133 ),
134 options: vec![
135 DecisionOption::new("pass", "Pass the law"),
136 DecisionOption::new("fail", "Reject the law"),
137 ],
138 deadline: None,
139 parent_ticket: None,
140 },
141 },
142 ),
143 )?;
144 canwu.settle_boundary(canwu_api::BoundaryRequest::at(now))?;
145 Ok(())
146}
147
148fn random_branch() -> Result<(), Box<dyn std::error::Error>> {
149 let mut canwu = Canwu::demo(202)?;
150 canwu.register_plugin(&UncertaintyPlugin)?;
151 enqueue_ticket(
152 &mut canwu,
153 RANDOM_TICKET,
154 1,
155 DecisionControllerBinding::new(
156 "law-random-controller",
157 DecisionPolicyIdentity::new(DecisionPolicyKind::Random, "weighted-random", "1"),
158 DecisionAuthority::Actor {
159 actor: Canwu::demo_ids().commander,
160 },
161 ),
162 )?;
163 let selection_at = SimTime::EPOCH + SimDuration::days(1);
164 canwu.schedule_calendar_boundary(selection_at, vec![SystemCadence::Daily])?;
165 canwu.step_canonical()?.expect("random source boundary");
166 canwu
167 .step_canonical()?
168 .expect("generated decision resolution boundary");
169 let trace = canwu
170 .decision_trace(canwu_api::DecisionTraceId::new(1))
171 .expect("random decision trace");
172 println!("random_trace={}", serde_json::to_string(trace)?);
173 Ok(())
174}
175
176fn llm_interface_branch() -> Result<(), Box<dyn std::error::Error>> {
177 let mut canwu = Canwu::demo(202)?;
178 let ticket_id = DecisionTicketId::new(2);
179 enqueue_ticket(
180 &mut canwu,
181 ticket_id,
182 10,
183 DecisionControllerBinding::new(
184 "law-llm-controller",
185 DecisionPolicyIdentity::new(DecisionPolicyKind::Llm, "strict-law-selector", "1"),
186 DecisionAuthority::Actor {
187 actor: Canwu::demo_ids().commander,
188 },
189 ),
190 )?;
191 let mut policy = QueuedLlmPolicy::new(
192 "strict-law-selector",
193 "1",
194 LlmModelIdentity {
195 provider: "not-connected".to_owned(),
196 model: "host-selected-model".to_owned(),
197 prompt_contract: "return one existing option_id and no new action".to_owned(),
198 },
199 );
200 let ticket = canwu.decision_ticket(ticket_id).expect("LLM ticket");
201 let request = policy.external_request(ticket);
202 println!("llm_request={}", serde_json::to_string(&request)?);
203
204 // A real host sends `request` to its model and parses a strict structured
205 // answer. This example supplies the same response object without making a
206 // network call.
207 policy.submit(
208 ticket_id,
209 ExternalDecisionResponse {
210 ticket_version: request.ticket_version,
211 option_id: "pass".to_owned(),
212 provider: "not-connected".to_owned(),
213 request_id: "example-response-1".to_owned(),
214 metadata: BTreeMap::new(),
215 },
216 )?;
217 let evaluation = canwu.drive_decision(
218 canwu.time(),
219 0,
220 DecisionRequestId::new(12),
221 None,
222 ticket_id,
223 &policy,
224 )?;
225 assert!(matches!(evaluation, DecisionEvaluation::Prepared(_)));
226 canwu.step_canonical()?.expect("LLM decision boundary");
227 Ok(())
228}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 parent_ticket: None,
80 },
81 },
82 ),
83 )?;
84 canwu.step_canonical()?.expect("decision intake boundary");
85 Ok(())
86}
87
88fn refresh_aid_options(canwu: &mut Canwu, ids: DemoIds) -> Result<(), Box<dyn std::error::Error>> {
89 canwu.enqueue_decision(
90 canwu.time(),
91 0,
92 DecisionIngressRequest::new(
93 DecisionRequestId::new(3),
94 canwu.revision(),
95 DecisionMutation::ReplaceOptions {
96 ticket_id: DecisionTicketId::new(1),
97 expected_version: 1,
98 context: DecisionContext::new(
99 "beiyang.aid-request.v1",
100 json!({
101 "requester": "warlord-a",
102 "battle": "ongoing-front",
103 "common_enemy": true,
104 "route_confirmed": true
105 }),
106 ),
107 options: vec![
108 DecisionOption {
109 action: DecisionAction::None,
110 utility_inputs: BTreeMap::from([
111 ("home_defense".to_owned(), 80),
112 ("alliance".to_owned(), -40),
113 ]),
114 ..DecisionOption::new("decline", "Decline aid")
115 },
116 DecisionOption {
117 action: DecisionAction::Command {
118 command: serde_json::to_value(Command::OrderMovement {
119 subject: EntityRef::Army(ids.army),
120 destination: ids.eastern_territory,
121 cargo: Vec::new(),
122 })?,
123 },
124 utility_inputs: BTreeMap::from([
125 ("home_defense".to_owned(), -20),
126 ("alliance".to_owned(), 90),
127 ]),
128 ..DecisionOption::new("send-aid", "Send the neighboring army")
129 },
130 ],
131 },
132 ),
133 )?;
134 canwu
135 .step_canonical()?
136 .expect("dynamic option refresh boundary");
137 Ok(())
138}
139
140fn resolve_aid_request(canwu: &mut Canwu) -> Result<(), Box<dyn std::error::Error>> {
141 let policy = WeightedUtilityPolicy::new(
142 "aid-utility",
143 "1",
144 UtilityProfile {
145 weights: BTreeMap::from([("alliance".to_owned(), 3), ("home_defense".to_owned(), 1)]),
146 },
147 );
148 let evaluation = canwu.drive_decision(
149 canwu.time(),
150 0,
151 DecisionRequestId::new(4),
152 Some(CommandRequestId::new(1)),
153 DecisionTicketId::new(1),
154 &policy,
155 )?;
156 assert!(matches!(evaluation, DecisionEvaluation::Prepared(_)));
157 canwu
158 .step_canonical()?
159 .expect("decision resolution boundary");
160 Ok(())
161}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