Skip to main content

chio_kernel/operator_report/
budget_report.rs

1use super::*;
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
4#[serde(rename_all = "camelCase")]
5pub struct BudgetUtilizationSummary {
6    pub matching_grants: u64,
7    pub returned_grants: u64,
8    pub distinct_capabilities: u64,
9    pub distinct_subjects: u64,
10    pub total_invocations: u64,
11    pub total_cost_charged: u64,
12    pub near_limit_count: u64,
13    pub exhausted_count: u64,
14    pub rows_missing_scope: u64,
15    pub rows_missing_lineage: u64,
16    pub truncated: bool,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20#[serde(rename_all = "camelCase")]
21pub struct BudgetDimensionUsage {
22    pub used: u64,
23    pub limit: u64,
24    pub remaining: u64,
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub utilization_rate: Option<f64>,
27    pub near_limit: bool,
28    pub exhausted: bool,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
32#[serde(rename_all = "camelCase")]
33pub struct BudgetDimensionProfile {
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub invocations: Option<BudgetDimensionUsage>,
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub money: Option<BudgetDimensionUsage>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
41#[serde(rename_all = "camelCase")]
42pub struct BudgetUtilizationRow {
43    pub capability_id: String,
44    pub grant_index: u32,
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub subject_key: Option<String>,
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub tool_server: Option<String>,
49    #[serde(default, skip_serializing_if = "Option::is_none")]
50    pub tool_name: Option<String>,
51    pub invocation_count: u32,
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub max_invocations: Option<u32>,
54    pub total_cost_charged: u64,
55    #[serde(default, skip_serializing_if = "Option::is_none")]
56    pub currency: Option<String>,
57    #[serde(default, skip_serializing_if = "Option::is_none")]
58    pub max_total_cost_units: Option<u64>,
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub remaining_cost_units: Option<u64>,
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub invocation_utilization_rate: Option<f64>,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub cost_utilization_rate: Option<f64>,
65    pub near_limit: bool,
66    pub exhausted: bool,
67    pub updated_at: i64,
68    pub scope_resolved: bool,
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub scope_resolution_error: Option<String>,
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub dimensions: Option<BudgetDimensionProfile>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76#[serde(rename_all = "camelCase")]
77pub struct BudgetUtilizationReport {
78    pub summary: BudgetUtilizationSummary,
79    pub rows: Vec<BudgetUtilizationRow>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
83#[serde(rename_all = "camelCase")]
84pub struct ComplianceReport {
85    pub matching_receipts: u64,
86    pub evidence_ready_receipts: u64,
87    pub uncheckpointed_receipts: u64,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub checkpoint_coverage_rate: Option<f64>,
90    pub lineage_covered_receipts: u64,
91    pub lineage_gap_receipts: u64,
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub lineage_coverage_rate: Option<f64>,
94    pub pending_settlement_receipts: u64,
95    pub failed_settlement_receipts: u64,
96    pub direct_evidence_export_supported: bool,
97    pub child_receipt_scope: EvidenceChildReceiptScope,
98    pub proofs_complete: bool,
99    pub export_query: EvidenceExportQuery,
100    #[serde(default, skip_serializing_if = "Option::is_none")]
101    pub export_scope_note: Option<String>,
102}
103
104impl ComplianceReport {
105    /// Compute a weighted compliance score on top of this report.
106    ///
107    /// Thin convenience wrapper over
108    /// [`crate::compliance_score::compliance_score`]. See that module for
109    /// the scoring model and weights.
110    #[must_use]
111    pub fn compliance_score(
112        &self,
113        inputs: &crate::compliance_score::ComplianceScoreInputs,
114        config: &crate::compliance_score::ComplianceScoreConfig,
115        agent_id: &str,
116        now: u64,
117    ) -> crate::compliance_score::ComplianceScore {
118        crate::compliance_score::compliance_score(self, inputs, config, agent_id, now)
119    }
120}