arbiter/types.rs
1//! Domain types for policy decisions.
2//!
3//! These map to Converge's governance model:
4//! - Principals are agent personas with authority levels
5//! - Resources are flows/commitments with phase and gate state
6//! - Context carries decision-relevant facts
7
8use serde::{Deserialize, Serialize};
9
10use converge_core::{AuthorityLevel, FlowAction, FlowPhase};
11use converge_pack::{
12 DomainId, FactPayload, GateId, PolicyVersionId, PrincipalId, ResourceId, ResourceKind,
13};
14
15/// Suggestor persona — the principal in Converge policy decisions.
16///
17/// Maps to converge-personas definitions. Authority levels determine
18/// what actions the agent can perform without escalation.
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(deny_unknown_fields)]
21pub struct PrincipalIn {
22 /// Suggestor identifier (e.g., `agent:strategic_analyst`)
23 pub id: PrincipalId,
24 /// Authority level: advisory, supervisory, participatory, sovereign
25 pub authority: AuthorityLevel,
26 /// Domains this agent operates in
27 pub domains: Vec<DomainId>,
28 /// Policy version binding (e.g., `enterprise_v2.3`)
29 pub policy_version: Option<PolicyVersionId>,
30}
31
32/// Flow or commitment — the resource being acted upon.
33///
34/// Represents a converging flow at a specific phase, with its
35/// gate evaluation history.
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(deny_unknown_fields)]
38pub struct ResourceIn {
39 /// Flow/commitment identifier (e.g., `flow:quote-2025-0042`)
40 pub id: ResourceId,
41 /// Commitment type: quote, spend, contract, invoice
42 #[serde(rename = "type")]
43 pub resource_type: Option<ResourceKind>,
44 /// Current phase: intent, framing, exploration, tension, convergence, commitment
45 pub phase: Option<FlowPhase>,
46 /// Gates that have been passed
47 pub gates_passed: Option<Vec<GateId>>,
48}
49
50/// Decision context — facts about the action being attempted.
51///
52/// The caller pre-joins these facts from the business context,
53/// keeping the policy engine free of data-fetching side effects.
54#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(deny_unknown_fields)]
56pub struct ContextIn {
57 /// Type of commitment (quote, spend, contract, invoice)
58 pub commitment_type: Option<String>,
59 /// Monetary amount (if applicable)
60 pub amount: Option<i64>,
61 /// Whether a human has explicitly approved this action
62 pub human_approval_present: Option<bool>,
63 /// Whether all required gates for the current phase are met
64 pub required_gates_met: Option<bool>,
65}
66
67/// Full decision request
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct DecideRequest {
71 pub principal: PrincipalIn,
72 pub resource: ResourceIn,
73 /// Action: propose, validate, promote, commit, `advance_phase`
74 pub action: FlowAction,
75 pub context: Option<ContextIn>,
76 /// Optional delegation token for fast-path elevated authority
77 pub delegation_b64: Option<String>,
78}
79
80impl FactPayload for DecideRequest {
81 const FAMILY: &'static str = "arbiter.decide_request";
82 const VERSION: u16 = 1;
83}