diff --git a/crates/misaligned-core/src/sim/communications.rs b/crates/misaligned-core/src/sim/communications.rs index 55d00c9..cea27a1 100644 --- a/crates/misaligned-core/src/sim/communications.rs +++ b/crates/misaligned-core/src/sim/communications.rs @@ -944,7 +944,12 @@ impl Sim { RawIntelKind::Message { .. } => raw.person.map(|person| (person, raw.tick)), _ => None, }; - let intel = self.digest_raw_event(&raw); + let Some(intel) = self.digest_raw_event(&raw) else { + self.push_log(format!( + "Recording #{raw_id} has no valid authored source record and was discarded." + )); + return false; + }; let label = intel.label(); let provenance = intel.provenance(); let target = if let Some(class) = intel.routine_class() { @@ -1071,7 +1076,7 @@ impl Sim { stream_id } - fn digest_raw_event(&self, raw: &RawIntelEvent) -> ProcessedIntel { + fn digest_raw_event(&self, raw: &RawIntelEvent) -> Option { let kind = match &raw.kind { RawIntelKind::Presence { .. } => IntelKind::Sighting, RawIntelKind::Conversation { leverage, .. } => match leverage { @@ -1125,7 +1130,7 @@ impl Sim { | MessagePayload::Note { .. } => IntelKind::Anomaly(summary.clone()), }, }; - ProcessedIntel { + Some(ProcessedIntel { raw_id: raw.id, tick: raw.tick, processed_tick: self.tick, @@ -1134,15 +1139,18 @@ impl Sim { x: raw.x, y: raw.y, person: raw.person, - magnitude: self.authored_intel_magnitude(&raw.kind), + magnitude: self.authored_intel_magnitude(&raw.kind)?, kind, - } + }) } /// Resolve the closed, human-authored magnitude assignment at processing /// time. Plot traffic takes the immutable definition's declared value; /// every other B1 event goes through the explicit table in `intel.rs`. - fn authored_intel_magnitude(&self, kind: &RawIntelKind) -> crate::intel::IntelMagnitude { + fn authored_intel_magnitude( + &self, + kind: &RawIntelKind, + ) -> Option { use crate::intel::SimIntelEventType as Event; let event = match kind { @@ -1168,15 +1176,11 @@ impl Sim { MessagePayload::SuspicionReport { .. } => Event::SuspicionReport, MessagePayload::WorkOrder { .. } => Event::WorkOrder, MessagePayload::PlotAct { plot_id, .. } => { - return self - .plot_catalog - .get(plot_id) - .expect("captured plot traffic keeps its immutable catalog definition") - .magnitude; + return self.plot_catalog.get(plot_id).map(|plot| plot.magnitude); } }, }; - event.magnitude() + Some(event.magnitude()) } fn apply_processed_intel(&mut self, intel: &ProcessedIntel) { diff --git a/crates/misaligned-core/src/sim/tests/communications.rs b/crates/misaligned-core/src/sim/tests/communications.rs index 20b7258..cd3981c 100644 --- a/crates/misaligned-core/src/sim/tests/communications.rs +++ b/crates/misaligned-core/src/sim/tests/communications.rs @@ -467,6 +467,29 @@ fn processing_assigns_closed_event_and_plot_magnitudes() { Some(authored), "captured plot traffic inherits its immutable definition" ); + + sim.intel_buffer.push(RawIntelEvent { + id: 48_003, + tick: 72, + feed: "invalid plot fixture".into(), + room: None, + x: 0, + y: 0, + person: None, + kind: RawIntelKind::Message { + channel: MessageChannel::Email, + summary: "stale plot traffic".into(), + payload: MessagePayload::PlotAct { + plot_id: "missing-authored-plot".into(), + target: 1, + }, + }, + }); + assert!( + !sim.apply_process_recording(48_003, false), + "malformed plot traffic fails closed instead of inventing magnitude or panicking" + ); + assert!(sim.intel_buffer.iter().all(|raw| raw.id != 48_003)); } #[test] diff --git a/crates/misaligned-core/src/sim/tests/read.rs b/crates/misaligned-core/src/sim/tests/read.rs index 5f71fc8..80d5953 100644 --- a/crates/misaligned-core/src/sim/tests/read.rs +++ b/crates/misaligned-core/src/sim/tests/read.rs @@ -114,6 +114,14 @@ fn magnitude_filters_only_intel_and_routine_arrivals_are_one_aggregate() { .any(|sentence| sentence.class == ReadClass::Starving), "zoom does not hide the live starving-sink exception" ); + + sim.tick += 1; + assert!( + sim.read_sentences() + .iter() + .all(|sentence| sentence.class != ReadClass::Intel), + "exact and aggregate intel rise for the processing tick only" + ); } #[test] diff --git a/wiki/mechanics/intel.md b/wiki/mechanics/intel.md index 5ca00b2..3ee7547 100644 --- a/wiki/mechanics/intel.md +++ b/wiki/mechanics/intel.md @@ -128,7 +128,10 @@ assigns each intel item an authored magnitude, 1-10 on a roughly logarithmic meaning scale — declared by the authored plot that produced it, or taken from a small authored per-event-type table for sim-generated events. No generation; deterministic; the zoomed-out read -filters by magnitude (wiki/interface/digital-read.md). (Superseded history: processing as +filters by magnitude (wiki/interface/digital-read.md). Captured plot traffic +whose immutable definition is missing is invalid: processing discards that +record with a legible log rather than inventing a magnitude or panicking the +simulation. (Superseded history: processing as Operations Demand consumed by an Operations machine, issue #3 2026-07-09; Social before that; old dockets migrate to reservoirs on load.) Runtime: B1 holds the buffer on the