Skip to main content

opsis_core/
schema.rs

1//! Schema definitions — metadata describing known event schemas.
2
3use serde::{Deserialize, Serialize};
4
5use crate::feed::SchemaKey;
6use crate::state::StateDomain;
7
8/// What kind of entity produces events under this schema.
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum SchemaProducer {
11    Feed,
12    Agent,
13    Gaia,
14    System,
15}
16
17/// Hint for the expected OpsisEventKind variants under this schema.
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub enum OpsisEventKindHint {
20    WorldObservation,
21    AgentObservation,
22    AgentAlert,
23    GaiaCorrelation,
24    GaiaAnomaly,
25    Custom,
26}
27
28/// Metadata describing a known event schema.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct SchemaDefinition {
31    pub key: SchemaKey,
32    pub version: u32,
33    pub description: String,
34    pub producer: SchemaProducer,
35    pub event_kind_hint: OpsisEventKindHint,
36    pub domain_hint: Option<StateDomain>,
37}
38
39/// Built-in schemas shipped with Opsis.
40pub fn builtin_schemas() -> Vec<SchemaDefinition> {
41    vec![
42        SchemaDefinition {
43            key: SchemaKey::new("usgs.geojson.v1"),
44            version: 1,
45            description: "USGS earthquake GeoJSON feed".into(),
46            producer: SchemaProducer::Feed,
47            event_kind_hint: OpsisEventKindHint::WorldObservation,
48            domain_hint: Some(StateDomain::Emergency),
49        },
50        SchemaDefinition {
51            key: SchemaKey::new("openmeteo.current.v1"),
52            version: 1,
53            description: "Open-Meteo current weather conditions".into(),
54            producer: SchemaProducer::Feed,
55            event_kind_hint: OpsisEventKindHint::WorldObservation,
56            domain_hint: Some(StateDomain::Weather),
57        },
58        SchemaDefinition {
59            key: SchemaKey::new("gaia.v1"),
60            version: 1,
61            description: "Gaia cross-domain correlations and anomalies".into(),
62            producer: SchemaProducer::Gaia,
63            event_kind_hint: OpsisEventKindHint::GaiaCorrelation,
64            domain_hint: None,
65        },
66        SchemaDefinition {
67            key: SchemaKey::new("arcan.agent.v1"),
68            version: 1,
69            description: "Arcan agent consciousness stream events".into(),
70            producer: SchemaProducer::Agent,
71            event_kind_hint: OpsisEventKindHint::AgentObservation,
72            domain_hint: None,
73        },
74    ]
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn builtin_schemas_have_unique_keys() {
83        let schemas = builtin_schemas();
84        let keys: Vec<_> = schemas.iter().map(|s| &s.key).collect();
85        for (i, k) in keys.iter().enumerate() {
86            assert!(!keys[i + 1..].contains(k), "duplicate key: {k}");
87        }
88    }
89
90    #[test]
91    fn schema_definition_json_roundtrip() {
92        let def = &builtin_schemas()[0];
93        let json = serde_json::to_string(def).unwrap();
94        let restored: SchemaDefinition = serde_json::from_str(&json).unwrap();
95        assert_eq!(restored.key, def.key);
96        assert_eq!(restored.version, def.version);
97    }
98
99    #[test]
100    fn arcan_agent_schema_exists() {
101        let schemas = builtin_schemas();
102        assert!(
103            schemas
104                .iter()
105                .any(|s| s.key == SchemaKey::new("arcan.agent.v1"))
106        );
107    }
108
109    #[test]
110    fn four_builtin_schemas() {
111        assert_eq!(builtin_schemas().len(), 4);
112    }
113}