Skip to main content

canic_host/observatory/view/
mod.rs

1//! Read-only observed facts and the smaller public presentation contract.
2
3use serde::{Deserialize, Serialize};
4
5/// Stable failure classes never carry private tool output or free-form runtime errors.
6#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
7#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
8pub enum ObservationFailure {
9    AuthorityUnavailable,
10    BindingUnavailable,
11    BudgetExceeded,
12    InvalidResponse,
13    ProfileMismatch,
14    Rejected { code: u32 },
15    TimedOut,
16    TransportUnavailable,
17    Stale,
18    Unsupported,
19}
20
21/// Evidence source explicitly distinguishes retained authority and live replies.
22#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
23#[serde(rename_all = "snake_case")]
24pub enum ObservationSource {
25    LocalOperationJournal,
26    PublicRoleOverview,
27    ProtectedRoleStatus,
28    RetainedTerminalReview,
29}
30
31/// Each field has its own observation time and failure; another role cannot fill it in.
32#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
33#[serde(tag = "state", rename_all = "snake_case", deny_unknown_fields)]
34pub enum Observation<T> {
35    Observed {
36        observed_at_unix_ms: u64,
37        source: ObservationSource,
38        value: T,
39    },
40    Unavailable {
41        observed_at_unix_ms: u64,
42        failure: ObservationFailure,
43    },
44}
45
46/// Actual responsiveness and bootstrap readiness from the declared role's public contract.
47#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
48#[serde(deny_unknown_fields)]
49pub struct RoleOverviewView {
50    pub bootstrap_ready: bool,
51    pub canic_version: String,
52    pub canister_version: u64,
53}
54
55/// Protected operating-funding facts, not a public balance or a conservation receipt.
56#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
57#[serde(deny_unknown_fields)]
58pub struct RoleFundingView {
59    pub native_cycles: String,
60    pub automatic_funding_enabled: bool,
61    pub policy_generation: u64,
62    pub pending_operations: u64,
63}
64
65/// Root-owned physical estate totals; no individual asset identities are projected.
66#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
67#[serde(deny_unknown_fields)]
68pub struct RootEstateView {
69    pub tracked: u32,
70    pub stores: u32,
71    pub workloads: u32,
72    pub ready: u32,
73    pub failed: u32,
74    pub resetting: u32,
75    pub pending_operations: u32,
76}
77
78/// Current Store occupancy and inventory, independent of historical metric counters.
79#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
80#[serde(deny_unknown_fields)]
81pub struct StoreInventoryView {
82    pub occupied_bytes: u64,
83    pub maximum_bytes: u64,
84    pub remaining_bytes: u64,
85    pub retained_templates: u32,
86    pub retained_releases: u32,
87    pub approved_catalog_entries: u64,
88    pub expected_template_chunks: u64,
89    pub stored_template_chunks: u64,
90    pub fixture_sources: u64,
91    pub expected_fixture_chunks: u64,
92    pub stored_fixture_chunks: u64,
93    pub gc_state: String,
94}
95
96/// Exact private source and independent observations for one retained role instance.
97#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
98#[serde(deny_unknown_fields)]
99pub struct ObservatoryRoleView {
100    pub role: String,
101    pub canister_id: String,
102    #[serde(deserialize_with = "Option::deserialize")]
103    pub parent_canister_id: Option<String>,
104    #[serde(deserialize_with = "Option::deserialize")]
105    pub subnet_id: Option<String>,
106    #[serde(deserialize_with = "Option::deserialize")]
107    pub release_identity: Option<String>,
108    #[serde(deserialize_with = "Option::deserialize")]
109    pub expected_module_sha256: Option<String>,
110    pub overview: Observation<RoleOverviewView>,
111    pub funding: Observation<RoleFundingView>,
112    pub estate: Observation<RootEstateView>,
113    pub store: Observation<StoreInventoryView>,
114}
115
116/// Private terminal provenance without controller lists, admission users or mutation proofs.
117#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
118#[serde(deny_unknown_fields)]
119pub struct ObservatoryAuthorityView {
120    pub app: String,
121    pub canonical_network_id: String,
122    pub plan_sha256: String,
123    pub registry_revision: u64,
124    pub admission_principals: usize,
125}
126
127/// Local durable progress is evidence of intents and receipts, not a live runtime assertion.
128#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
129#[serde(deny_unknown_fields)]
130pub struct LocalOperationView {
131    pub operation_id: String,
132    pub plan_sha256: String,
133    pub completion: LocalOperationCompletion,
134    pub applied_effects: usize,
135    pub pending_effects: usize,
136    pub funding_review_required: bool,
137    pub stalled_observations: u32,
138}
139
140/// Closed local completion classes; the report grants no permission to resume an operation.
141#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
142#[serde(rename_all = "snake_case")]
143pub enum LocalOperationCompletion {
144    Converged,
145    Prepared,
146    InProgress,
147    ReplanRequired,
148}
149
150/// One bounded collection, including unavailable authority instead of invented role success.
151#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
152#[serde(deny_unknown_fields)]
153pub struct ObservatorySnapshotView {
154    pub schema_version: u16,
155    pub environment: String,
156    pub fleet: String,
157    pub collected_at_unix_ms: u64,
158    pub freshness_secs: u32,
159    pub collection_elapsed_ms: u64,
160    pub remote_call_attempts: u64,
161    pub authority: Observation<ObservatoryAuthorityView>,
162    pub operation: Observation<LocalOperationView>,
163    pub roles: Vec<ObservatoryRoleView>,
164}
165
166/// Public role projection deliberately omits Principals, hashes, placement and exact funding.
167#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
168#[serde(deny_unknown_fields)]
169pub struct PublicObservatoryRoleView {
170    pub key: usize,
171    pub label: String,
172    pub role: String,
173    pub overview: Observation<RoleOverviewView>,
174    pub store: Observation<StoreInventoryView>,
175}
176
177/// Publishable JSON/HTML input; profiles cannot reintroduce private fields.
178#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
179#[serde(deny_unknown_fields)]
180pub struct PublicObservatoryView {
181    pub schema_version: u16,
182    pub title: String,
183    pub collected_at_unix_ms: u64,
184    pub freshness_secs: u32,
185    pub authority_available: bool,
186    pub roles: Vec<PublicObservatoryRoleView>,
187}
188
189/// Framework-neutral HTTP adapter output; the downstream application owns routing and serving.
190pub struct ObservatoryHttpView {
191    pub status: u16,
192    pub content_type: &'static str,
193    pub cache_control: &'static str,
194    pub content_security_policy: &'static str,
195    pub body: Vec<u8>,
196}