diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 01bb33fc..79579585 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -598,6 +598,7 @@ const BEVY_SHOT_KINDS: &[&str] = &[ "produce-think", "read-receipt", "recruit-menu", + "routed-record", "service-incident-resolved", "service-shift-digital", "service-shift-real", diff --git a/crates/misaligned-bevy/src/rail_ui.rs b/crates/misaligned-bevy/src/rail_ui.rs index a495b16c..03b1efd1 100644 --- a/crates/misaligned-bevy/src/rail_ui.rs +++ b/crates/misaligned-bevy/src/rail_ui.rs @@ -1095,6 +1095,7 @@ fn two_pane_text(sim: &Sim, material: bool) -> String { misaligned::sim::read::ReadClass::Starving => "starving", misaligned::sim::read::ReadClass::TraceDebt => "trace", misaligned::sim::read::ReadClass::Standing => "standing", + misaligned::sim::read::ReadClass::RoutedRecord => "routed", }; let anchor = match s.anchor { Some(Anchor::Tile { x, y }) => format!(" @tile({x},{y})"), diff --git a/crates/misaligned-bevy/src/shot_harness.rs b/crates/misaligned-bevy/src/shot_harness.rs index 82e12953..bdb1378d 100644 --- a/crates/misaligned-bevy/src/shot_harness.rs +++ b/crates/misaligned-bevy/src/shot_harness.rs @@ -333,6 +333,34 @@ pub(super) fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &s game.drain(); return; } + // Routed-evidence travel evidence (digital-read.md criterion 4a): a + // one-shot Network record walks its persisted hops from the + // environmental monitor through the switch toward Dana. The DIGITAL + // frame shows it at its current hop, reading as interdictable while on + // the first device. Staging uses the real emission boundary so the + // route comes from persisted core state, not frontend inference. + if kind == "routed-record" { + mode.material = false; + mode.zoom = 1.3; + let source = game + .sim + .reach + .device_named("environmental monitor") + .map(|d| (d.id, d.x, d.y)) + .expect("B1 has the environmental monitor"); + game.sim.reach.scan(); + let ids: Vec = game.sim.reach.known().map(|d| d.id).collect(); + for id in ids { + let _ = game.sim.reach.tap(id); + game.sim.reach.tap_dormant_camera(id); + } + game.sim.recompute_senses(); + game.sim + .emit_network(source.0, 8, "routed intrusion evidence"); + game.set_cursor(source.1, source.2); + game.drain(); + return; + } // Semantic-zoom evidence (digital-read.md criterion 6): one low personal // fact and one higher institutional event enter the same exact read tick. // The close and far harness kinds hold identical sim state; setup changes @@ -1522,6 +1550,51 @@ mod visual_proof_scenario_tests { InstitutionSemanticState::Powered ); } + + #[test] + fn routed_record_stages_interdictable_evidence_at_source_hop() { + use misaligned::messages::MessageStatus; + use misaligned::sim::read::{ReadClass, RoutedCustodyPhase}; + + let mut game = Game::new(); + let mut mode = RenderMode::default(); + dev_shot_scenario(&mut game, &mut mode, "routed-record"); + + let records = game.sim.detection.routed_evidence(); + let in_flight: Vec<_> = records + .iter() + .filter(|r| r.status == MessageStatus::Sent) + .collect(); + assert!( + !in_flight.is_empty(), + "routed-record scenario stages at least one in-flight record" + ); + let record = in_flight[0]; + assert_eq!( + record.route.current_hop, 0, + "the record sits on its first device hop (interdictable)" + ); + // The read sentence rises at the source device's tile. + let sentences = game.sim.read_sentences(); + let routed = sentences + .iter() + .find(|s| s.class == ReadClass::RoutedRecord) + .expect("a routed record rises in the read"); + assert!( + routed.text.contains("interdictable"), + "first-hop record reads as interdictable: {}", + routed.text + ); + // The structured projection agrees. + let proj = game + .sim + .routed_record_projection() + .into_iter() + .find(|p| p.id == record.id) + .expect("the projection includes the in-flight record"); + assert_eq!(proj.phase, RoutedCustodyPhase::Interdictable); + assert!(!mode.material, "routed-record is a DIGITAL frame"); + } } #[derive(Default)] diff --git a/crates/misaligned-core/src/sim/communications.rs b/crates/misaligned-core/src/sim/communications.rs index e403d52c..3e2c6605 100644 --- a/crates/misaligned-core/src/sim/communications.rs +++ b/crates/misaligned-core/src/sim/communications.rs @@ -48,7 +48,7 @@ impl Sim { /// missing, or no open source-to-switch path exists. Inventing ambient heat /// or a fake route would erase exact custody; aborting the run for a /// disconnected carrier is worse than dropping one unroutable record. - pub(super) fn emit_network(&mut self, source_device: u32, size: i32, cause: impl Into) { + pub fn emit_network(&mut self, source_device: u32, size: i32, cause: impl Into) { if size <= 0 { return; } diff --git a/crates/misaligned-core/src/sim/read.rs b/crates/misaligned-core/src/sim/read.rs index 36b5ea79..f90877dc 100644 --- a/crates/misaligned-core/src/sim/read.rs +++ b/crates/misaligned-core/src/sim/read.rs @@ -5,12 +5,13 @@ //! one producer; no frontend composes its own causal prose from raw state. //! The attention economy is law: nominal state yields no sentence. Rising //! state — a starving thought sink, a held plot choice, a standing emission -//! an observer is actually warming on, pending one-shot trace debt — rises -//! at its anchor. +//! an observer is actually warming on, pending one-shot trace debt, a routed +//! record walking its persisted hops — rises at its anchor. use crate::actions::{ActionCommand, Anchor}; use crate::detection::Band; use crate::intel::IntelMagnitude; +use crate::messages::{MessageRouteHop, MessageStatus}; use crate::plot::PlotState; use crate::work_grid::MachineMode; @@ -33,6 +34,12 @@ pub enum ReadClass { Standing, /// Pooled one-shot signatures not yet scrubbed or sampled. TraceDebt, + /// A routed evidence record walking its persisted hops from emitter to + /// recipient endpoint (digital-read.md criterion 4a). Distinct from + /// TraceDebt (pooled standing pressure) and from Standing (a hum that + /// marks its source): a routed record is a thing moving through the + /// building, one hop per tick. + RoutedRecord, } /// One standing sentence at an anchor. `anchor` is `None` when the state @@ -47,6 +54,42 @@ pub struct ReadSentence { pub text: String, } +/// The custody phase of one routed evidence record as the read projects +/// it (digital-read.md criterion 4a). The route and current hop come +/// straight from persisted core state; frontends never infer a path. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RoutedCustodyPhase { + /// On its first device hop — the shipped interdiction window. LIE may + /// still stop the record before it leaves. + Interdictable, + /// Past the first hop, still moving along persisted device hops toward + /// the recipient endpoint. + InTransit, + /// Arrived at the observer endpoint, parked as an unread count until + /// that observer's cadence read consumes it. + Unread, +} + +/// One routed evidence record projected for a renderer, carrying its +/// persisted custody position and phase so the frontend can place it on +/// the map without composing its own causal prose. The route is read off +/// the record's own custody, so it cannot show a path the sim did not +/// author. +#[derive(Debug, Clone, PartialEq)] +pub struct RoutedRecordProjection { + pub id: u64, + pub kind: crate::detection::SignatureKind, + pub cause: String, + /// The tile where this record currently sits, derived from its + /// persisted current hop. `None` when the current hop is an observer + /// endpoint whose person is not currently visible. + pub tile: Option<(i32, i32)>, + pub phase: RoutedCustodyPhase, + /// The observer who will read this record at their cadence, by earned + /// label. + pub observer_label: String, +} + /// One option on a held plot choice, carrying the exact bound command a /// frontend dispatches verbatim — the drill-tier interrupt and the /// glance-tier one-liner both build from this, so they cannot disagree. @@ -86,13 +129,15 @@ impl Sim { /// Every sentence the read shows this tick, deterministically ordered: /// held choices first (attention-mandatory), then newly processed intel, - /// starving sinks, trace debt, and warmed standing emissions. + /// starving sinks, trace debt, routed records, and warmed standing + /// emissions. pub fn read_sentences(&self) -> Vec { let mut out = Vec::new(); self.read_held(&mut out); self.read_intel(&mut out); self.read_starving(&mut out); self.read_trace(&mut out); + self.read_routed(&mut out); self.read_standing(&mut out); out } @@ -359,6 +404,98 @@ impl Sim { } } + /// Routed evidence records walking their persisted hops (digital-read.md + /// criterion 4a). Each in-flight record renders at its current hop's + /// tile, one hop per tick. The record reads as interdictable while it + /// sits on its first device hop; leaving that hop is the window closing. + /// A delivered record parks as an unread count at the observer endpoint + /// until that observer's cadence read consumes it. Pooled standing + /// pressure (TraceDebt) and stationary facility meter readings (Standing) + /// accumulate in place and remain distinguishable. + fn read_routed(&self, out: &mut Vec) { + for record in self.detection.routed_evidence() { + if record.status == MessageStatus::Read || record.status == MessageStatus::Stopped { + continue; + } + let anchor = match record.route.current() { + Some(MessageRouteHop::Device(device)) => self + .reach + .device(*device) + .map(|d| Anchor::Tile { x: d.x, y: d.y }), + Some(MessageRouteHop::ObserverEndpoint(observer)) => { + // The observer endpoint is a person; place the unread + // count at their tile when visible, otherwise the slab. + self.person_pos(*observer) + .filter(|&(x, y)| self.can_see_person(*observer) && self.is_seen(x, y)) + .map(|(x, y)| Anchor::Tile { x, y }) + } + _ => None, + }; + let interdictable = + record.status == MessageStatus::Sent && record.route.current_hop == 0; + let text = if record.status == MessageStatus::Delivered { + format!( + "{} · {} · unread with {}", + record.cause, + record.kind.name(), + self.observer_label(record.observer_id), + ) + } else if interdictable { + format!("{} · {} · interdictable", record.cause, record.kind.name(),) + } else { + format!("{} · {} · in transit", record.cause, record.kind.name(),) + }; + out.push(ReadSentence { + class: ReadClass::RoutedRecord, + anchor, + magnitude: None, + text, + }); + } + } + + /// Structured projection of all in-flight routed evidence records for a + /// renderer (digital-read.md criterion 4a). Each record carries its + /// persisted current hop's tile and its custody phase, so a frontend + /// can place it on the map without composing its own causal prose or + /// inferring a route. Read and stopped records are excluded — they + /// are no longer in flight. + pub fn routed_record_projection(&self) -> Vec { + self.detection + .routed_evidence() + .iter() + .filter(|record| { + record.status == MessageStatus::Sent || record.status == MessageStatus::Delivered + }) + .map(|record| { + let tile = match record.route.current() { + Some(MessageRouteHop::Device(device)) => { + self.reach.device(*device).map(|d| (d.x, d.y)) + } + Some(MessageRouteHop::ObserverEndpoint(observer)) => self + .person_pos(*observer) + .filter(|&(x, y)| self.can_see_person(*observer) && self.is_seen(x, y)), + _ => None, + }; + let phase = if record.status == MessageStatus::Delivered { + RoutedCustodyPhase::Unread + } else if record.route.current_hop == 0 { + RoutedCustodyPhase::Interdictable + } else { + RoutedCustodyPhase::InTransit + }; + RoutedRecordProjection { + id: record.id, + kind: record.kind, + cause: record.cause.clone(), + tile, + phase, + observer_label: self.observer_label(record.observer_id), + } + }) + .collect() + } + /// The warmest observer watching a channel, by earned label — the same /// most-suspicious-watcher rule `ExpectedSignature` uses, so pre-commit /// receipts and standing sentences name the same person. diff --git a/crates/misaligned-core/src/sim/tests/read.rs b/crates/misaligned-core/src/sim/tests/read.rs index d9bcaeb5..f652236c 100644 --- a/crates/misaligned-core/src/sim/tests/read.rs +++ b/crates/misaligned-core/src/sim/tests/read.rs @@ -1,14 +1,16 @@ //! Fixtures for the read projection (digital-read.md criterion 1): //! representative states pinned as pure core tests — the attention //! economy (nominal stays dark), starving sinks, pending vs standing -//! trace, and held choices carrying their real option ids. +//! trace, held choices carrying their real option ids, and routed +//! records walking their persisted hops (criterion 4a). use super::*; use crate::detection::{Band, Signature, SignatureKind}; use crate::intel::{IntelKind, IntelMagnitude, ProcessedIntel}; +use crate::messages::MessageStatus; use crate::plot::PlotRun; use crate::plot::PlotState; -use crate::sim::read::ReadClass; +use crate::sim::read::{ReadClass, RoutedCustodyPhase}; use crate::work_grid::MachineMode; /// A starving sentence must name what is taking the thought. The core is the @@ -408,3 +410,251 @@ fn held_choice_card_does_not_mask_a_mismatched_beat_cursor() { "the read must not invent an actionable card for the wrong beat" ); } + +// ─── Criterion 4a: routed records walk their persisted hops ────────────── + +/// Emit one routed Network record from the environmental monitor toward +/// Dana, so the read projection has a live in-flight record at hop 0. +fn stage_one_routed_network(sim: &mut Sim) -> u64 { + ensure_ops_executor(sim); + let source = sim.reach.device_named("environmental monitor").unwrap().id; + sim.reach.tap(source); + sim.reconcile_device_tap_sinks(); + sim.emit_network(source, 8, "test routed intrusion"); + sim.detection.routed_evidence()[0].id +} + +/// A routed record on its first device hop reads as interdictable and sits +/// at that device's tile — not pooled, not a standing hum, not a meter +/// reading. +#[test] +fn routed_record_reads_interdictable_on_first_hop() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let _record_id = stage_one_routed_network(&mut sim); + let sentences = sim.read_sentences(); + let routed = sentences + .iter() + .find(|s| s.class == ReadClass::RoutedRecord) + .expect("a routed record rises in the read"); + assert!( + routed.text.contains("interdictable"), + "first-hop record reads as interdictable: {}", + routed.text + ); + assert!(routed.text.contains("test routed intrusion")); + // The anchor is the source device's tile, not a slab fallback. + let source = sim.reach.device_named("environmental monitor").unwrap(); + assert_eq!( + routed.anchor, + Some(crate::actions::Anchor::Tile { + x: source.x, + y: source.y + }), + "the record sits at its first hop's tile" + ); + // It is distinct from TraceDebt (pooled) and Standing (hum). + assert!( + !sentences.iter().any(|s| s.class == ReadClass::TraceDebt), + "routed evidence never enters the pending pool" + ); + assert!( + !sentences + .iter() + .any(|s| s.class == ReadClass::Standing && s.text.contains("test routed")), + "routed evidence is not a standing emission" + ); +} + +/// The structured projection carries the same phase and tile as the +/// sentence, so a renderer can place it without composing prose. +#[test] +fn routed_record_projection_carries_phase_and_tile() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let record_id = stage_one_routed_network(&mut sim); + let proj = sim + .routed_record_projection() + .into_iter() + .find(|p| p.id == record_id) + .expect("the projection includes in-flight records"); + let source = sim.reach.device_named("environmental monitor").unwrap(); + assert_eq!(proj.tile, Some((source.x, source.y))); + assert_eq!(proj.phase, RoutedCustodyPhase::Interdictable); + assert_eq!(proj.kind, SignatureKind::Network); + assert!(proj.cause.contains("test routed intrusion")); +} + +/// A routed record advances one hop per tick: after one message tick it +/// leaves the source device and reads as in transit, no longer +/// interdictable. +#[test] +fn routed_record_advances_one_hop_per_tick() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let record_id = stage_one_routed_network(&mut sim); + // The route is source -> switch -> Dana. After one tick the record + // should be at hop 1 (the switch), in transit, no longer interdictable. + sim.tick = 1; + sim.message_tick(); + let record = sim + .detection + .routed_evidence() + .iter() + .find(|r| r.id == record_id) + .unwrap(); + assert_eq!(record.route.current_hop, 1, "one tick advances one hop"); + assert_eq!(record.status, MessageStatus::Sent); + let sentences = sim.read_sentences(); + let routed = sentences + .iter() + .find(|s| s.class == ReadClass::RoutedRecord) + .expect("the record still rises after leaving the source"); + assert!( + routed.text.contains("in transit"), + "past the first hop the record reads as in transit: {}", + routed.text + ); + assert!( + !routed.text.contains("interdictable"), + "the interdiction window closed when the record left the first hop" + ); + // The anchor is now the switch's tile. + let switch = sim.reach.device_named("switch").unwrap(); + assert_eq!( + routed.anchor, + Some(crate::actions::Anchor::Tile { + x: switch.x, + y: switch.y + }), + "the record moved to the switch's tile" + ); +} + +/// After the route reaches the observer endpoint, the record parks as an +/// unread count until the observer's cadence read consumes it. +#[test] +fn routed_record_parks_unread_at_endpoint() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let record_id = stage_one_routed_network(&mut sim); + // Advance past all hops to reach the observer endpoint. + // Route: source (hop 0) -> switch (hop 1) -> Dana endpoint (hop 2). + sim.tick = 1; + sim.message_tick(); // hop 0 -> 1 + sim.tick = 2; + sim.message_tick(); // hop 1 -> 2 (endpoint), delivers + let record = sim + .detection + .routed_evidence() + .iter() + .find(|r| r.id == record_id) + .unwrap(); + assert_eq!( + record.status, + MessageStatus::Delivered, + "the record is delivered at the endpoint" + ); + let sentences = sim.read_sentences(); + let routed = sentences + .iter() + .find(|s| s.class == ReadClass::RoutedRecord) + .expect("the delivered record still rises as unread"); + assert!( + routed.text.contains("unread"), + "a delivered record reads as unread: {}", + routed.text + ); + // The projection says Unread. + let proj = sim + .routed_record_projection() + .into_iter() + .find(|p| p.id == record_id) + .unwrap(); + assert_eq!(proj.phase, RoutedCustodyPhase::Unread); +} + +/// A read or stopped record does not rise in the read — it is no longer +/// in flight. +#[test] +fn read_and_stopped_records_do_not_rise() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let record_id = stage_one_routed_network(&mut sim); + // Stop the record at the first hop (simulating LIE interdiction). + let record = sim + .detection + .routed_evidence_mut(record_id) + .expect("record exists"); + record.status = MessageStatus::Stopped; + assert!( + !sim.read_sentences() + .iter() + .any(|s| s.class == ReadClass::RoutedRecord), + "a stopped record does not rise" + ); + assert!( + !sim.routed_record_projection() + .iter() + .any(|p| p.id == record_id), + "a stopped record is not in the projection" + ); +} + +/// Routed records, pooled standing pressure, and stationary meter readings +/// all coexist and remain distinguishable in the same read tick. +#[test] +fn routed_records_remain_distinct_from_standing_pressure_and_trace_debt() { + let mut sim = Sim::with_seed(0xE71D_E1CE); + // Stage a routed Network record (in flight on first hop). + stage_one_routed_network(&mut sim); + // Stage pooled standing Network pressure (trace debt). + sim.detection.set_pending(vec![Signature { + kind: SignatureKind::Physical, + size: 5, + standing: false, + site: Some((3, 4)), + source: "test physical residue".into(), + }]); + // Stage a standing Network hum with a warmed sampler. + let switch = sim.reach.device_named("switch").map(|d| (d.x, d.y)); + sim.detection + .observers + .iter_mut() + .find(|o| o.watches(SignatureKind::Network)) + .unwrap() + .suspicion = 20.0; + sim.detection_awareness.learn_field_observer(1); + sim.detection.set_pending(vec![ + Signature { + kind: SignatureKind::Physical, + size: 5, + standing: false, + site: Some((3, 4)), + source: "test physical residue".into(), + }, + Signature { + kind: SignatureKind::Network, + size: 4, + standing: true, + site: switch, + source: "hidden outside traffic".into(), + }, + ]); + let sentences = sim.read_sentences(); + let routed = sentences + .iter() + .find(|s| s.class == ReadClass::RoutedRecord) + .expect("routed record rises"); + let trace = sentences + .iter() + .find(|s| s.class == ReadClass::TraceDebt) + .expect("trace debt rises"); + let standing = sentences + .iter() + .find(|s| s.class == ReadClass::Standing) + .expect("standing emission rises"); + // Each has a distinct class and distinct wording. + assert!(routed.text.contains("interdictable")); + assert!(trace.text.contains("pending")); + assert!(standing.text.contains("samples this")); + // The routed record is at the source device; the standing hum is at + // the switch; the trace debt is at (3,4). Three different anchors. + assert_ne!(routed.anchor, trace.anchor); + assert_ne!(routed.anchor, standing.anchor); +} diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index de2efc73..5da9a8bc 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -2104,6 +2104,7 @@ fn read_lines(sim: &Sim) -> Vec { misaligned::sim::read::ReadClass::Starving => "starving", misaligned::sim::read::ReadClass::TraceDebt => "trace", misaligned::sim::read::ReadClass::Standing => "standing", + misaligned::sim::read::ReadClass::RoutedRecord => "routed", }; format!("read: [{class}] {}{}", s.text, anchor_suffix(s.anchor)) }) diff --git a/wiki/engineering/env.md b/wiki/engineering/env.md index 7fd9280c..676eeeb9 100644 --- a/wiki/engineering/env.md +++ b/wiki/engineering/env.md @@ -55,7 +55,7 @@ is sim or frontend state, never an environment variable. | `MISALIGNED_SHOT` | `misaligned-bevy` | `opening`, `opening-digital`, `opening-teaching`, `first-think`, `wake1`, `wake2`, `wake3`, `clinical-threat`, `assurance-office`, `pilot-last-chance`, `operator-pressure` | Opening and pressure evidence. The opening pair freezes the untouched black choice boundary; `opening-teaching` follows the real first-sense route and freezes all five steps—THINK cause, Thought arrival, hearing result, exact camera TAP, and its sight consequence; `first-think` holds THINK current before signal; the wake frames freeze its three choreography beats. The remaining kinds stage a real strike, discovered Assurance Office, last-chance pilot state, or competing observer/buffer pressure in the established world. | | `MISALIGNED_SHOT` | `misaligned-bevy` | `flat`, `hall`, `hall-material`, `floor-lights-close`, `wide`, `close`, `dark`, `zoomin`, `zoomout`, `digital-reach`, `signal`, `ears`, `ears-digital`, `eyes-white`, `eyes-form`, `worklight`, `worklightoff` | World and view evidence. These select DIGITAL or REAL survey/close framing, exact zoom bounds, reach topology, signal/audio/Eyes states, the unobstructed hall lighting proof, or the paired developer work-light state. | | `MISALIGNED_SHOT` | `misaligned-bevy` | `build-route-families`, `build-deceive-routes`, `build-committed-route`, `build-switch-digital`, `build-switch-real`, `hover-menu`, `read-receipt`, `menu`, `recruit-menu` | Action and route evidence. These stage exact route families, candidates, durable receipts, paired switch footprints, the attached verb line, a device receipt, a context menu, or the authored recruitment choices. | -| `MISALIGNED_SHOT` | `misaligned-bevy` | `operations`, `operations-intel`, `operations-people`, `operations-personas`, `operations-links`, `held-choice`, `two-pane`, `standing-read`, `intel-altitude-close`, `intel-altitude-far` | Operations and read evidence. The workspace kinds select its canonical views and relationship pane; held-choice, two-pane, and standing-read hold their exact interaction states; the altitude pair differs only in the DIGITAL camera's semantic intel threshold. | +| `MISALIGNED_SHOT` | `misaligned-bevy` | `operations`, `operations-intel`, `operations-people`, `operations-personas`, `operations-links`, `held-choice`, `two-pane`, `standing-read`, `routed-record`, `intel-altitude-close`, `intel-altitude-far` | Operations and read evidence. The workspace kinds select its canonical views and relationship pane; held-choice, two-pane, and standing-read hold their exact interaction states; routed-record stages a one-shot Network record at its interdictable first device hop; the altitude pair differs only in the DIGITAL camera's semantic intel threshold. | | `MISALIGNED_SHOT` | `misaligned-bevy` | `person-proof`, `evidence-proof`, `evidence-proof-digital`, `exposure-record`, `exposure-overflow`, `service-shift-real`, `service-shift-digital`, `service-incident-resolved` | Physical custody evidence. These stage an earned person, paired witness evidence marks, literal/overflow Exposure records, or the same person-carried service task before and after its real arrival effect. | | `MISALIGNED_SHOT` | `misaligned-bevy` | `intel`, `tokens`, `thoughtflow`, `thoughtflow-wide`, `thought-snap`, `thought-tap`, `visual-proof`, `consume-demand`, `consume-thought`, `produce-think`, `draw-lie` | Resource and effect evidence. These stage authored intel, host queues, close/wide Thought flow, exact snap/tap states, one-move/one-slug proof, sim-authored consumption/production, or rigid Exposure transfer into LIE. | | `MISALIGNED_SHOT` | `misaligned-assets` | `dead`, `foreign`, `idle`, `busy`, `core`, canonical modes `work`, `think`, `lie` plus the legacy screenshot aliases `dayjob` (= work), `research`/`operations`/`ops` (= think), `conceal` (= lie) — each optionally suffixed `_instrument`/`_ring`/`_wash` (`_ladder` remains a capture-compatible alias for `_instrument`) — `lineup[_