//! Intel: recordings, processing, and standing watches (wiki/mechanics/intel.md). //! //! Subscribed feeds record raw, timestamped events. The raw buffer is opaque //! until the process spends social-ops bandwidth to digest it into intel with //! provenance. Processed intel is durable; overflowing the buffer only drops //! unprocessed recordings. use crate::messages::{MessageChannel, MessagePayload}; use crate::person::Leverage; /// A raw event captured by a subscribed feed. Raw recordings are intentionally /// coarse: they know where/when/source, but do not grant knowledge until /// processed by the intel pipeline. #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct RawIntelEvent { pub id: u64, pub tick: u64, pub feed: String, pub room: Option, pub x: i32, pub y: i32, pub person: Option, pub kind: RawIntelKind, } impl RawIntelEvent { pub fn opaque_label(&self) -> &'static str { match self.kind { RawIntelKind::Presence { .. } => "presence segment", RawIntelKind::Conversation { .. } => "audio segment", RawIntelKind::Message { .. } => "message traffic", RawIntelKind::Machinery { .. } => "machine telemetry", RawIntelKind::Document { .. } => "document scan", RawIntelKind::FinancialFlow { .. } => "financial record", } } pub fn matches_person(&self, person: u8) -> bool { self.person == Some(person) } } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum RawIntelKind { /// A person entered or left covered space. Presence { entered: bool }, /// A covered microphone caught speech. `leverage` marks authored payloads /// like Marcus's creditor call; most conversations are only sightings. Conversation { note: String, leverage: Option, }, /// Intercepted social-graph traffic. The payload is typed so processing /// can stage schedule/leverage/account/filing intel without parsing the /// human-readable summary. Message { channel: MessageChannel, summary: String, payload: MessagePayload, }, /// Machine state changed while the process had telemetry/coverage. Machinery { machine: u32, online: bool }, /// A physical record or other document was captured into the same buffer. Document { note: String, leverage: Option, }, /// Accounting snapshot captured from a finance carrier. Processing this /// turns hidden account ids and flow ids into known ledger entries. FinancialFlow { label: String, accounts: Vec, flows: Vec, }, } /// Durable, processed intel. This is what knowledge panels may cite; it never /// evaporates when the raw buffer overflows. #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct ProcessedIntel { pub raw_id: u64, pub tick: u64, pub processed_tick: u64, pub feed: String, pub room: Option, pub x: i32, pub y: i32, pub person: Option, pub kind: IntelKind, } impl ProcessedIntel { pub fn provenance(&self) -> String { format!("{} @ tick {}", self.feed, self.tick) } pub fn label(&self) -> String { match &self.kind { IntelKind::Sighting => "sighting".into(), IntelKind::Schedule => "schedule".into(), IntelKind::Leverage(l) => format!("leverage: {}", l.label()), IntelKind::Anomaly(note) => format!("anomaly: {note}"), IntelKind::Financial { label, .. } => format!("financial: {label}"), } } } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum IntelKind { Sighting, Schedule, Leverage(Leverage), Anomaly(String), Financial { label: String, accounts: Vec, flows: Vec, }, } /// B1 standing watch: a per-person filter. Later acts can add room/kind /// filters without changing the concept. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct IntelWatch { pub person: u8, pub enabled: bool, } impl IntelWatch { pub fn new(person: u8) -> Self { Self { person, enabled: true, } } }