diff --git a/README.md b/README.md index facb8b28..afeb392f 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,14 @@ schedule or theirs. - **Compute is the master resource, but it lives in machines.** Every owned machine has one delegated verb: **WORK** clears its assigned day-job Demand, **THINK** produces Thought for target-local sinks or the passive core draw, - and **LIE** pulls nearby crimson Exposure into concealment wells. The FLEET - bar is a read-only aggregate of those choices, not a percentage mixer. -- **Work is visible.** Demands, exposure, and Thought pile onto hardware as - `D` / `!` / `T` stacks. The todo list is the world: clear the day-job stack, - route byproducts, and keep heat from becoming somebody else's attention. + and **LIE** interdicts eligible unread evidence records on or through the + network you control. The FLEET bar is a read-only aggregate of those choices, + not a percentage mixer. +- **Work is visible.** Demand and Thought pile onto hardware as `D` / `T` + stacks; evidence records leave the machine that wrote them and travel their + real wires toward a reader. The todo list is the world: clear the day-job + stack, route Thought, and catch dangerous records before they leave your + controlled stretch. - **Your brain is a place.** The core lives on one physical level: expensive, slow to move, and mortal. Keep escape routes warm. If they cut the fiber first, you resume from your last sync — missing everything you learned @@ -94,7 +97,7 @@ required state must survive a clear Assurance audit, then the long-run objective continues. Continuous witness/narration is implemented and serves as the legibility gate for every new player-facing system. Machine work and compute are implemented: WORK / THINK / LIE, physical -production/consumption/absorption, researched Routing, and target-local +production/consumption/interdiction, researched Routing, and target-local Thought reservoirs all run through one flow substrate. The retired Operations docket executor is absent from both runtime and the current save schema. People now project as schedule-bound carriers; builds and physical asset tasks travel @@ -187,12 +190,12 @@ panel-open keys (`r`/`e`/`t`/`u`) are retired (`r` now dispatches the focused machine's pooled PROCESS action — a selection hotkey, not a panel). Both frontends share this key map. -Machine work tokens are visible on owned machines as `D` Demand, `!` -Exposure, and `T` Thought. Rack 3 starts in WORK; Voss jobs +Machine work tokens are visible on owned machines as `D` Demand and `T` +Thought; routed evidence is drawn at its current carrier. Rack 3 starts in WORK; Voss jobs enqueue on his off-map desktop, hop the switch, and deposit as `D` stacks on Rack 3 — assigning Rack 3 away from WORK makes the stack pile instead of silently clearing. Inspect a machine or read the sidebar for exact -`D/!/T` counts and intensity. Press `i` on the focus/selection to push effort; +`D/T` counts and intensity. Press `i` on the focus/selection to push effort; the machine context menu includes `delegate machine: work|think|lie`; this is the first playable slice of the one-machine-one-mode experiment. diff --git a/crates/misaligned-assets/src/main.rs b/crates/misaligned-assets/src/main.rs index 242c06f6..c4f90eff 100644 --- a/crates/misaligned-assets/src/main.rs +++ b/crates/misaligned-assets/src/main.rs @@ -20,13 +20,11 @@ use palette::{GUNMETAL, NEAR_BLACK, scaled}; use rack::{ClaimStyle, RackMode, RackRoot, RackState, spawn_server_rack, spawn_token_anchors}; /// Work-token load staged on the single rack (machine-work.md anchors): -/// demand cubes upper-left, ivory-mercury thought upper-right, and crimson -/// custody records lower-right. +/// demand cubes upper-left and ivory-mercury thought upper-right. #[derive(Debug, Clone, Copy, PartialEq, Resource, Default)] struct TokenLoad { demand: usize, thought: f32, - exposure: f32, /// Stranded-pool demo: the overflow beads hanging under the thought /// anchor (interface/thought-fluid.md). stranded: bool, @@ -35,15 +33,6 @@ struct TokenLoad { impl TokenLoad { const DEMAND_STEPS: [usize; 4] = [0, 2, 5, 9]; const THOUGHT_STEPS: [f32; 5] = [0.0, 1.0, 2.0, 4.0, 8.0]; - const EXPOSURE_STEPS: [f32; 4] = [0.0, 1.0, 3.0, 8.0]; - - fn next_exposure(&mut self) { - let i = Self::EXPOSURE_STEPS - .iter() - .position(|&x| x == self.exposure) - .unwrap_or(0); - self.exposure = Self::EXPOSURE_STEPS[(i + 1) % Self::EXPOSURE_STEPS.len()]; - } fn next_demand(&mut self) { let i = Self::DEMAND_STEPS @@ -104,26 +93,17 @@ fn scene_from_shot(kind: &str) -> (ViewMode, RackState, RackMode, ClaimStyle, To ); } // Token-anchor evidence: an owned-busy day-job rack under a mid or - // overflow work load (machine-work.md cubes + ivory mercury + - // exposure custody records), or the record-only board. - if kind == "tokens" || kind == "tokens_max" || kind == "exposure" { + // overflow work load (machine-work.md cubes + ivory mercury). + if kind == "tokens" || kind == "tokens_max" { let load = match kind { "tokens_max" => TokenLoad { stranded: false, demand: 9, thought: 8.0, - exposure: 8.0, - }, - "exposure" => TokenLoad { - demand: 0, - thought: 0.0, - exposure: 6.0, - stranded: false, }, _ => TokenLoad { demand: 5, thought: 4.0, - exposure: 3.0, stranded: false, }, }; @@ -411,12 +391,11 @@ fn hud_string( ) -> String { let line2 = match view { ViewMode::Single => format!( - "state: {} (1 dead 2 foreign 3 idle 4 busy 5 core) mode: {} (M cycles)\ntokens: D{} T{:.0} !{:.0}{} (D demand T thought V exposure S stranded)", + "state: {} (1 dead 2 foreign 3 idle 4 busy 5 core) mode: {} (M cycles)\ntokens: D{} T{:.0}{} (D demand T thought S stranded)", state.label(), rack_mode.label(), tokens.demand, tokens.thought, - tokens.exposure, if tokens.stranded { " +stranded" } else { "" } ), ViewMode::Lineup => { @@ -494,9 +473,6 @@ fn handle_state_keys( if kb.just_pressed(KeyCode::KeyT) { tokens.next_thought(); } - if kb.just_pressed(KeyCode::KeyV) { - tokens.next_exposure(); - } if kb.just_pressed(KeyCode::KeyS) { tokens.stranded = !tokens.stranded; } @@ -643,7 +619,7 @@ fn rebuild_scene( Vec3::ZERO, Some(pedestal), ); - if tokens.demand > 0 || tokens.thought > 0.0 || tokens.exposure > 0.0 { + if tokens.demand > 0 || tokens.thought > 0.0 { spawn_token_anchors( &mut commands, &mut meshes, diff --git a/crates/misaligned-assets/src/rack.rs b/crates/misaligned-assets/src/rack.rs index 5a9dac0b..d0b3ce9a 100644 --- a/crates/misaligned-assets/src/rack.rs +++ b/crates/misaligned-assets/src/rack.rs @@ -490,7 +490,8 @@ fn instrument_fill_material(state: RackState, mode: RackMode) -> StandardMateria RackMode::Work => SIGNAL, RackMode::Think => BONE, // Crimson here is not ornamental warning chrome: the wedge cycles - // only while a real Exposure queue keeps this LIE machine active. + // only when a real routed-record stop gives this LIE body performed + // work to report. RackMode::Lie => CRIMSON, }; StandardMaterial { @@ -944,15 +945,6 @@ const CUBE_PITCH: f32 = 0.17; /// Cubes drawn literally before the stack compresses (overflow). const CUBE_MAX: usize = 8; -/// Exposure records are thin rigid slips in a dark custody rack. Their -/// dimensions stay distinct from Demand cubes and Thought liquid even after -/// the game counter-scales the complete token root. -const EXPOSURE_RECORD_W: f32 = 0.18; -const EXPOSURE_RECORD_H: f32 = 0.11; -const EXPOSURE_RECORD_D: f32 = 0.022; -const EXPOSURE_RECORD_PITCH: f32 = 0.13; -const EXPOSURE_RECORD_MAX: usize = 7; - /// Spawn the work-token anchors beside a rack at `origin`: demand as /// **glowing information cubes** stacked in a rigid column at the /// machine's upper-left (the cold-signal family — imposed work, packet @@ -960,14 +952,11 @@ const EXPOSURE_RECORD_MAX: usize = 7; /// liquid thought holds), ivory-mercury /// thought at the upper-right (opaque bone liquid with a restrained /// self-glow; discrete viscous slugs while low, a taut suspended pool -/// as volume grows — queue amount is pool volume), and Exposure as thin rigid -/// crimson custody records held in a dark rack on the machine's lower-right. -/// The outward-facing slips are evidence *about* the machine, not another -/// kind of work entering it. They do not touch the floor, glow as a scene -/// light, or borrow blood's pooled-liquid silhouette. A paused frame -/// carries amount through geometry alone; animation, when it -/// arrives, will carry rate. Returns the anchor root (a `RackRoot`, -/// so viewers rebuild it with the chassis). +/// as volume grows — queue amount is pool volume). Routed evidence is not a +/// work-token anchor: it renders at its exact current carrier as it travels. +/// A paused frame carries amount through geometry alone; animation carries +/// rate. Returns the anchor root (a `RackRoot`, so viewers rebuild it with the +/// chassis). #[allow(clippy::too_many_arguments)] pub fn spawn_token_anchors( commands: &mut Commands, @@ -1144,115 +1133,9 @@ pub fn spawn_token_anchors( } } - // Exposure: evidence records in the machine's custody. The dark bracket - // fixes the stack to the carrier; rigid outward-facing slips distinguish - // the family from inward Demand cubes and suspended Thought liquid. root } -fn exposure_record_count(exposure: f32) -> usize { - (exposure.max(0.0).ceil() as usize).clamp(1, EXPOSURE_RECORD_MAX) -} - -fn exposure_record_overflow(exposure: f32) -> bool { - exposure.max(0.0).ceil() as usize > EXPOSURE_RECORD_MAX -} - -fn exposure_record_material() -> StandardMaterial { - StandardMaterial { - base_color: scaled(CRIMSON, 0.95), - // A record must remain legible under the dark rig without becoming a - // lamp. Crimson is consequence here, not general illumination. - emissive: CRIMSON.to_linear() * 0.14, - perceptual_roughness: 0.84, - metallic: 0.02, - reflectance: 0.04, - ..default() - } -} - -/// One carrier-local stack of pending evidence records. Low amounts are -/// literal slips; overflow compresses to a taller indexed tab rather than -/// inventing one mesh per arbitrarily large queue. -/// The rigid crimson custody-record form (machine-work.md's token grammar). -/// -/// No longer driven by a machine queue: pooled exposure is retired, so this -/// draws evidence where a record actually is — on the carrier it currently -/// sits on while it travels its route (detection.md). -pub fn spawn_exposure_records( - commands: &mut Commands, - meshes: &mut Assets, - materials: &mut Assets, - exposure: f32, - root: Entity, -) { - let record = materials.add(exposure_record_material()); - let bracket = materials.add(StandardMaterial { - base_color: scaled(NEAR_BLACK, 1.20), - perceptual_roughness: 0.93, - metallic: 0.10, - reflectance: 0.03, - ..default() - }); - let x = RACK_W * 0.5 + 0.22; - let z = RACK_D * 0.5 + 0.015; - let y0 = RACK_H * 0.18; - let shown = exposure_record_count(exposure); - let rack_h = EXPOSURE_RECORD_H + EXPOSURE_RECORD_PITCH * (shown.saturating_sub(1) as f32); - - // Back and two lips: a visible custody fixture, not floating red UI. - spawn_box( - commands, - meshes, - bracket.clone(), - root, - Vec3::new(EXPOSURE_RECORD_W + 0.055, rack_h + 0.08, 0.025), - Vec3::new(x, y0 + rack_h * 0.5 - 0.01, z - 0.028), - ); - for side in [-1.0_f32, 1.0] { - spawn_box( - commands, - meshes, - bracket.clone(), - root, - Vec3::new(0.018, rack_h + 0.10, 0.055), - Vec3::new( - x + side * (EXPOSURE_RECORD_W * 0.5 + 0.024), - y0 + rack_h * 0.5, - z, - ), - ); - } - - for i in 0..shown { - let overflow = i + 1 == shown && exposure_record_overflow(exposure); - let height = if overflow { - EXPOSURE_RECORD_H * 1.42 - } else { - EXPOSURE_RECORD_H - }; - let y = y0 + EXPOSURE_RECORD_PITCH * i as f32 + (height - EXPOSURE_RECORD_H) * 0.5; - spawn_box( - commands, - meshes, - record.clone(), - root, - Vec3::new(EXPOSURE_RECORD_W, height, EXPOSURE_RECORD_D), - Vec3::new(x, y, z + 0.016), - ); - // A dark outward tab gives each slip an indexed-record silhouette and - // keeps form readable without relying on crimson hue alone. - spawn_box( - commands, - meshes, - bracket.clone(), - root, - Vec3::new(EXPOSURE_RECORD_W * 0.36, 0.018, 0.010), - Vec3::new(x + EXPOSURE_RECORD_W * 0.24, y + height * 0.30, z + 0.029), - ); - } -} - // ─── The material law, pinned ──────────────────────────────────────────────── #[cfg(test)] @@ -1434,25 +1317,4 @@ mod tests { } } } - - #[test] - fn exposure_is_a_bounded_rigid_custody_record_not_a_lamp() { - assert_eq!(exposure_record_count(0.1), 1); - assert_eq!(exposure_record_count(3.0), 3); - assert_eq!(exposure_record_count(100.0), EXPOSURE_RECORD_MAX); - assert!(!exposure_record_overflow(7.0)); - assert!(exposure_record_overflow(7.01)); - - let record = exposure_record_material(); - let emitted = record.emissive.red + record.emissive.green + record.emissive.blue; - assert!( - emitted < 0.28, - "record must not become a crimson scene lamp" - ); - assert!(record.perceptual_roughness >= 0.8); - assert!( - record.metallic < 0.1, - "record is an entry, not a metal token" - ); - } } diff --git a/crates/misaligned-bevy/src/material_view.rs b/crates/misaligned-bevy/src/material_view.rs index c1ece5a8..c8e869e9 100644 --- a/crates/misaligned-bevy/src/material_view.rs +++ b/crates/misaligned-bevy/src/material_view.rs @@ -601,8 +601,8 @@ pub(super) fn owned_machine_tiles(sim: &misaligned::sim::Sim) -> HashSet<(i32, i /// proportions); scaled to sit under the 1.5-unit wall line. const MACHINE3D_SCALE: f32 = 0.56; /// Work-token anchors are authored at tester scale. Parenting them under -/// the chassis alone shrinks cubes/mercury/exposure with the rack and they -/// vanish at default camera. Counter-scale toward this world size (claim +/// the chassis alone shrinks cubes and mercury with the rack and they vanish +/// at default camera. Counter-scale toward this world size (claim /// ring already uses the same inv-scale pattern) so stacks read as cargo /// on the hardware without floating HUD labels. const TOKEN_WORLD_SCALE: f32 = 0.90; @@ -716,7 +716,6 @@ pub(super) struct ChassisVisual { /// Thought queue quantized to half-units for change detection; /// the mercury volume renders thought / 2.0. pub(super) thought: u8, - /// Exposure queue quantized to half-units; the drift renders / 2.0. /// Thought here had no route last step: the pool hangs overflow beads /// (interface/thought-fluid.md stranded read). pub(super) stranded: bool, diff --git a/crates/misaligned-bevy/src/production.rs b/crates/misaligned-bevy/src/production.rs index c47ea48f..0e971ead 100644 --- a/crates/misaligned-bevy/src/production.rs +++ b/crates/misaligned-bevy/src/production.rs @@ -1,8 +1,9 @@ -//! Physical rate motion for THINK production and LIE absorption. +//! Physical rate motion for THINK authorship and LIE interdiction. //! -//! The sim authors both sides of the exchange (`Sim::work_productions` and -//! `Sim::work_absorptions`). This module only interpolates those current-tick -//! facts. Persistent amount remains the token-anchor geometry. +//! The sim authors both sides of the exchange (`Sim::work_productions` for +//! authorship and `Sim::recalls` / `Sim::lie_stops_for_machine` for +//! interdiction). This module only interpolates those current-tick facts. +//! Persistent amount remains the token-anchor geometry. use bevy::prelude::*; diff --git a/crates/misaligned-bevy/src/shot_harness.rs b/crates/misaligned-bevy/src/shot_harness.rs index ca0a0150..bba4ae74 100644 --- a/crates/misaligned-bevy/src/shot_harness.rs +++ b/crates/misaligned-bevy/src/shot_harness.rs @@ -351,8 +351,9 @@ pub(super) fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &s // 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. + // the player-controlled stretch served by LIE. Staging uses the real + // emission and route-authority boundaries, so neither custody nor the + // closing window comes from frontend inference. if kind == "routed-record" { mode.material = false; mode.zoom = 1.3; @@ -368,6 +369,22 @@ pub(super) fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &s let _ = game.sim.reach.tap(id); game.sim.reach.tap_dormant_camera(id); } + let rack = game + .sim + .reach + .device_named("Rack 3") + .map(|device| device.id) + .expect("the host rack has a network-facing device"); + for device in game + .sim + .reach + .open_path(source.0, rack) + .expect("the monitor has a real route to the host") + { + game.sim.reach.take(device); + } + game.sim + .set_machine_mode(game.sim.core.host_machine, MachineMode::Lie); game.sim.recompute_senses(); game.sim .emit_network(source.0, 8, "routed intrusion evidence"); @@ -792,7 +809,7 @@ pub(super) fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &s } // Machine-work source/well evidence. Production is a current-tick sim // readout on the THINK rack; LIE stages a second owned rack in an empty - // bay and waits for an actual crimson source-to-well absorption. + // bay and waits for an actual routed-record interdiction. if kind == "produce-think" || kind == "draw-lie" { let host = game.sim.core.host_machine; game.sim.set_machine_mode(host, MachineMode::Think); @@ -1542,7 +1559,7 @@ mod visual_proof_scenario_tests { } #[test] - fn routed_record_stages_interdictable_evidence_at_source_hop() { + fn routed_record_stages_evidence_on_an_interdictable_controlled_hop() { use misaligned::messages::MessageStatus; use misaligned::sim::read::{ReadClass, RoutedCustodyPhase}; @@ -1562,7 +1579,7 @@ mod visual_proof_scenario_tests { let record = in_flight[0]; assert_eq!( record.route.current_hop, 0, - "the record sits on its first device hop (interdictable)" + "the record is staged at its exact source custody point" ); // The read sentence rises at the source device's tile. let sentences = game.sim.read_sentences(); @@ -1572,7 +1589,7 @@ mod visual_proof_scenario_tests { .expect("a routed record rises in the read"); assert!( routed.text.contains("interdictable"), - "first-hop record reads as interdictable: {}", + "the controlled hop served by LIE reads as interdictable: {}", routed.text ); // The structured projection agrees. diff --git a/crates/misaligned-bevy/src/world_annotations.rs b/crates/misaligned-bevy/src/world_annotations.rs index 0c58e032..a66eb996 100644 --- a/crates/misaligned-bevy/src/world_annotations.rs +++ b/crates/misaligned-bevy/src/world_annotations.rs @@ -235,10 +235,10 @@ struct TokenMarkerLayout { fn token_marker_layout(label: &str) -> TokenMarkerLayout { // Callout grammar (digital-read.md, amended 2026-07-21): a token label is - // a note about the machine, never chassis typography. Every state word — - // crimson exposure, teal demand, bone thought, the quiet INFO flag — - // shares the one chip slot just beyond the upper-right focus corner, so - // no label can erase the machine, identity, or ReachNet node beneath it. + // a note about the machine, never chassis typography. Every current state + // word — teal demand, bone thought, or the quiet INFO flag — shares the + // one chip slot just beyond the upper-right focus corner, so no label can + // erase the machine, identity, or ReachNet node beneath it. // Placement only: color and meaning stay with token_label_and_color, and // INFO keeps its quieter expanded-word tier. TokenMarkerLayout { @@ -295,7 +295,7 @@ mod information_availability_marker_tests { } } -/// Machine-work tokens: small D/!/T labels or the quiet INFO presence mark over the machine carrying the +/// Machine-work tokens: small D/T labels or the quiet INFO presence mark over the machine carrying the /// queue. The glyph carries the family, color carries the palette meaning; /// neither frontend invents its own counter. pub(super) fn render_tokens( @@ -317,7 +317,7 @@ pub(super) fn render_tokens( for (marker, mut text, mut font, mut color, mut transform, mut anchor, mut vis) in q.iter_mut() { // The glyph labels are the flat sensorium's exact-count read - // (machine-work.md: D/!/T text equivalents). The material + // (machine-work.md: D/T text equivalents). The material // render carries real token art on the chassis — a floating // count label over the world read is rejected there. if mode.material { @@ -744,9 +744,9 @@ pub(super) fn callout_hit_rects( /// World-space rectangle of each drawn token chip, paired with the machine /// tile it reports on. The chip sits in the slot just beyond the machine's -/// upper-right focus corner, which is far enough that aiming at an exposure -/// count was landing on the neighbouring floor tile — the same acquisition -/// failure the read callouts had, on the shorter offset. +/// upper-right focus corner, which is far enough that aiming at a queue count +/// can land on the neighbouring floor tile — the same acquisition failure +/// the read callouts had, on the shorter offset. pub(super) fn token_chip_rect(tile: (i32, i32), label: &str) -> Rect { let layout = token_marker_layout(label); let min = grid_to_world(tile.0, tile.1, 0.0).truncate() + layout.offset; @@ -1939,17 +1939,17 @@ mod callout_hit_tests { ); } - /// The exposure count the 2026-07-22 playtest aimed at sits a chip slot - /// off the chassis, so it needs the same handle treatment as a sentence. + /// A queue count sits a chip slot off the chassis, so it needs the same + /// handle treatment as a sentence. #[test] fn a_token_chip_means_its_machine() { let tile = (10, 10); - let rect = token_chip_rect(tile, "!3"); + let rect = token_chip_rect(tile, "D3"); let chips = [(rect, tile)]; assert_eq!( annotation_anchor_at(&chips, &[], rect.center()), Some(tile), - "clicking the exposure count means the machine it counts for" + "clicking the queue count means the machine it counts for" ); // The chip is beside the body, not over it: the machine's own tile // center stays outside the chip's box (the placement law it obeys). diff --git a/crates/misaligned-core/src/detection.rs b/crates/misaligned-core/src/detection.rs index 7c2b7e42..c7daaa68 100644 --- a/crates/misaligned-core/src/detection.rs +++ b/crates/misaligned-core/src/detection.rs @@ -317,9 +317,9 @@ pub struct EvidenceCoverAttempt { /// One exact unread digital record moving from its source onto the device /// route to the field observer who can acquire it. Machine-resident records /// retain the exact authoring machine separately from its network-facing -/// device. The route is custody, not abstract heat: LIE may stop it only while -/// it is still on the first device hop; once read, the same stable id continues -/// as observer-local evidence above. +/// device. The route is custody, not abstract heat: LIE may stop it on any +/// player-controlled device hop before the observer reads it; once read, the +/// same stable id continues as observer-local evidence above. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct RoutedEvidenceSuppression { /// The recruited handler/supervisor who removed this unread job record. diff --git a/crates/misaligned-core/src/save.rs b/crates/misaligned-core/src/save.rs index 466b0671..35359993 100644 --- a/crates/misaligned-core/src/save.rs +++ b/crates/misaligned-core/src/save.rs @@ -59,7 +59,7 @@ const SAVE_TEMP_SUFFIX: &str = ".tmp"; /// persists discrete Moonlight contracts, their terms, work/payment/evidence /// receipts, persona consequences, and bound /// financial paperwork. v52 requires one-shot Paper evidence to retain its -/// exact institutional-carrier route, observer custody, and first-hop interdiction. +/// exact institutional-carrier route, observer custody, and route-local interdiction. /// v51 requires the same exact custody for Financial evidence. v50 persists /// person incapacity and exact human-removal custody. v49 records /// exact handler suppression provenance on unread routed @@ -1661,8 +1661,12 @@ fn validate_messages(state: &SaveState) -> Result<(), String> { )); } if let Some(stopped) = route.interdiction - && (route.current_hop != 0 - || stopped.tick < message.sent_tick + && (!matches!(route.current(), Some(MessageRouteHop::Device(_))) + || stopped.tick + != message + .sent_tick + .saturating_add(route.current_hop as u64) + .saturating_add(1) || stopped.tick > state.sim_tick || state .compute @@ -2866,7 +2870,11 @@ fn validate_routed_evidence(state: &SaveState) -> Result<(HashSet, u64), St } MessageStatus::Stopped => { if let Some(stopped) = record.route.interdiction { - stopped.tick == record.sent_tick.saturating_add(1) + stopped.tick + == record + .sent_tick + .saturating_add(record.route.current_hop as u64) + .saturating_add(1) } else if let Some(suppression) = &record.suppression { match record.delivered_tick { Some(delivered) => { @@ -2906,7 +2914,7 @@ fn validate_routed_evidence(state: &SaveState) -> Result<(HashSet, u64), St )); } if let Some(stopped) = record.route.interdiction - && (record.route.current_hop != 0 + && (!matches!(record.route.current(), Some(MessageRouteHop::Device(_))) || record.delivered_tick.is_some() || stopped.tick < record.sent_tick || stopped.tick > state.sim_tick @@ -2993,7 +3001,8 @@ fn validate_routed_evidence(state: &SaveState) -> Result<(HashSet, u64), St && advance_events == 0 && read_events == 0 && if record.route.interdiction.is_some() { - record.delivered_tick.is_none() && record.route.current_hop == 0 + record.delivered_tick.is_none() + && matches!(record.route.current(), Some(MessageRouteHop::Device(_))) } else { record.suppression.is_some() && record.delivered_tick.is_some() == record.route.at_endpoint() @@ -3891,6 +3900,37 @@ mod tests { SaveState::from_sim(&sim) } + fn routed_network_later_hop_stopped_state() -> SaveState { + let mut sim = Sim::with_seed(0xE71D_E1CE); + let source = sim.reach.device_named("environmental monitor").unwrap().id; + sim.set_machine_mode(sim.core.host_machine, MachineMode::Think); + sim.emit_network(source, 4, "test later-hop routed Network act"); + assert_eq!(sim.detection.routed_evidence().len(), 1); + + sim.advance(); + let record = &sim.detection.routed_evidence()[0]; + assert_eq!(record.status, MessageStatus::Sent); + assert_eq!(record.route.current_hop, 1); + let carrier = match record.route.current() { + Some(MessageRouteHop::Device(id)) => *id, + other => panic!("second route hop must be an interdictable device, got {other:?}"), + }; + + take_route_to_host(&mut sim, carrier); + sim.reconcile_work_grid(); + sim.set_machine_mode(sim.core.host_machine, MachineMode::Lie); + sim.advance(); + + let record = &sim.detection.routed_evidence()[0]; + assert_eq!(record.status, MessageStatus::Stopped); + assert_eq!(record.route.current_hop, 1); + assert_eq!( + record.route.interdiction.unwrap().tick, + record.sent_tick + record.route.current_hop as u64 + 1 + ); + SaveState::from_sim(&sim) + } + fn routed_power_state(stopped: bool) -> SaveState { let mut sim = Sim::with_seed(0xF0A3); let ups = sim.reach.device_named("UPS meter").unwrap().id; @@ -6221,6 +6261,7 @@ mod tests { ); let mut state = routed_filing_state(true); + let sent_tick = state.messages[0].sent_tick; state.messages[0] .route .as_mut() @@ -6235,6 +6276,21 @@ mod tests { "the persisted provenance must name a real machine: {err}" ); + let mut state = routed_filing_state(true); + state.messages[0] + .route + .as_mut() + .unwrap() + .interdiction + .as_mut() + .unwrap() + .tick = sent_tick; + let err = parse_save(&serde_json::to_string(&state).unwrap()).unwrap_err(); + assert!( + err.contains("impossible interdiction provenance"), + "a Filing stop must land on its exact scheduled route tick: {err}" + ); + let mut state = routed_filing_state(false); let message_id = state.messages[0].id; state @@ -6622,6 +6678,44 @@ mod tests { ); } + #[test] + fn current_save_roundtrips_route_local_later_hop_interdiction() { + let state = routed_network_later_hop_stopped_state(); + let restored = parse_save(&serde_json::to_string(&state).unwrap()).unwrap(); + let record = &restored.detection.routed_evidence()[0]; + let interdiction = record.route.interdiction.unwrap(); + assert_eq!(record.status, MessageStatus::Stopped); + assert_eq!(record.route.current_hop, 1); + assert_eq!(interdiction.machine_id, restored.core.host_machine); + assert_eq!(interdiction.tick, record.sent_tick + 2); + assert!(matches!( + record.route.current(), + Some(MessageRouteHop::Device(_)) + )); + + let mut forged_cursor = state.clone(); + forged_cursor + .detection + .routed_evidence_mut(1) + .unwrap() + .route + .current_hop = 0; + let err = parse_save(&serde_json::to_string(&forged_cursor).unwrap()).unwrap_err(); + assert!( + err.contains("impossible hop timing"), + "a stop cannot be moved away from its exact device hop: {err}" + ); + + let mut forged_timing = state; + let record = forged_timing.detection.routed_evidence_mut(1).unwrap(); + record.route.interdiction.as_mut().unwrap().tick = record.sent_tick + 1; + let err = parse_save(&serde_json::to_string(&forged_timing).unwrap()).unwrap_err(); + assert!( + err.contains("impossible hop timing"), + "a later-hop stop must land on that hop's scheduled route tick: {err}" + ); + } + #[test] fn current_save_binds_acquired_network_evidence_to_the_exact_read_record() { let mut sim = Sim::with_seed(0xE71D_E1CE); @@ -6736,7 +6830,7 @@ mod tests { let err = parse_save(&serde_json::to_string(&state).unwrap()).unwrap_err(); assert!( err.contains("impossible hop timing"), - "first-hop interdiction happens on the first scheduled route tick: {err}" + "source-device interdiction happens on the first scheduled route tick: {err}" ); let mut state = routed_network_state(false); diff --git a/crates/misaligned-core/src/sim/communications.rs b/crates/misaligned-core/src/sim/communications.rs index 82ef93a0..a341605f 100644 --- a/crates/misaligned-core/src/sim/communications.rs +++ b/crates/misaligned-core/src/sim/communications.rs @@ -74,9 +74,10 @@ impl Sim { } /// Route one Paper record from the institutional Filing carrier to Priya. - /// Her ordinary cadence owns the read; the first device hop is the only - /// route-local LIE window. Soft-fails closed when the carrier, observer, - /// path, or size is missing rather than aborting a live run. + /// Her ordinary cadence owns the read; every player-controlled device hop + /// before that read is a route-local LIE window. Soft-fails closed when the + /// carrier, observer, path, or size is missing rather than aborting a live + /// run. pub(super) fn emit_paper(&mut self, size: i32, cause: impl Into) { if size <= 0 { return; @@ -110,7 +111,7 @@ impl Sim { /// Route one Financial signature from the authored accounting carrier to /// Priya's observer endpoint. The record remains unread until her ordinary - /// cadence reaches it, and the institutional switch is its exact first-hop + /// cadence reaches it, and each player-controlled carrier hop is an exact /// LIE window rather than an ambient concealment debt. Soft-fails closed /// when the carrier, path, or size cannot support exact custody. pub(super) fn emit_financial(&mut self, size: i32, cause: impl Into) { @@ -435,7 +436,7 @@ impl Sim { let id = self.next_message_id.max(1); self.next_message_id = id + 1; let route = if draft.channel == MessageChannel::Filing { - // Filing custody needs a first-hop carrier for LIE. Prefer the + // Filing custody needs an exact carrier for route-local LIE. Prefer the // financial authored device, else the institutional switch. If // neither exists, deliver without a route rather than panic — // outward and observer filings already tolerate the relay shape. @@ -450,9 +451,10 @@ impl Sim { // and becomes evidence on their read; a filing addressed outward // (plots file to a reduction review committee or a change desk) // has no observer to read it and terminates at the relay. Both - // keep the carrier as first hop, so the route-local LIE boundary - // is unchanged. Inventing an observer here would author evidence - // against a person the act never reached. + // keep the carrier as the first exact custody point. Any + // player-controlled device hop remains a LIE window. Inventing an + // observer here would author evidence against a person the act + // never reached. carrier.map(|carrier| { let mut hops = vec![ MessageRouteHop::Device(carrier), @@ -612,7 +614,7 @@ impl Sim { _ => None, }); if let Some(carrier) = carrier - && let Some(machine_id) = self.filing_interdictor(carrier, used_lie_machines) + && let Some(machine_id) = self.lie_interdictor(carrier, used_lie_machines) { *used_lie_machines.entry(machine_id).or_insert(0) += 1; *self.last_lie_stops.entry(machine_id).or_insert(0) += 1; @@ -730,7 +732,7 @@ impl Sim { _ => None, }); if let Some(carrier) = carrier - && let Some(machine_id) = self.filing_interdictor(carrier, used_lie_machines) + && let Some(machine_id) = self.lie_interdictor(carrier, used_lie_machines) { *used_lie_machines.entry(machine_id).or_insert(0) += 1; *self.last_lie_stops.entry(machine_id).or_insert(0) += 1; @@ -790,9 +792,9 @@ impl Sim { } /// Select one exact online LIE body that owns a co-located ReachNet node - /// on a wholly controlled path from the Filing carrier. Each body can - /// stop at most one record in this tick's scheduler batch. - fn filing_interdictor( + /// on a wholly controlled path from the current carrier. Each body can + /// stop only its researched capacity in this tick's scheduler batch. + fn lie_interdictor( &self, carrier: u32, used_lie_machines: &HashMap, @@ -820,6 +822,14 @@ impl Sim { .min() } + /// Whether an unread record at this exact device has an available online + /// LIE body on the same wholly controlled stretch. The DIGITAL read uses + /// this same predicate as route execution, so the visible closing window + /// cannot collapse back to a hard-coded first hop. + pub(super) fn lie_can_interdict_at(&self, carrier: u32) -> bool { + self.lie_interdictor(carrier, &HashMap::new()).is_some() + } + fn deliver_message(&mut self, id: u64) { let Some(idx) = self.messages.iter().position(|m| m.id == id) else { return; diff --git a/crates/misaligned-core/src/sim/mod.rs b/crates/misaligned-core/src/sim/mod.rs index ccd3e79a..f285b53c 100644 --- a/crates/misaligned-core/src/sim/mod.rs +++ b/crates/misaligned-core/src/sim/mod.rs @@ -464,7 +464,8 @@ pub struct Sim { /// Self-modification: active track, levels, progress, and rollback tags. pub research: Research, /// Visible work-token substrate (machine-work.md): one mode per owned - /// machine, demand/exposure/thought queue depths as render truth. + /// machine, demand/thought queue depths as render truth. Routed evidence + /// remains in Detection rather than becoming another WorkGrid family. /// Day-job demand originates on the off-map Voss desktop relay, hops the /// switch, and deposits on day-job sinks — never teleports onto Rack 3. pub work_grid: WorkGrid, @@ -568,8 +569,6 @@ pub struct Sim { /// THINK output authored during the current tick. Transient render truth; /// persistent amounts remain in WorkGrid queues. last_work_productions: Vec, - /// Crimson physically pulled into LIE wells during the current tick. - /// Transient and reconstructed from real absorption work after load. /// Thought (in compute units) that physically reached the core sink since /// the last economy pulse. Research progress feeds on this, not on the diff --git a/crates/misaligned-core/src/sim/perception.rs b/crates/misaligned-core/src/sim/perception.rs index be5ea709..9a642212 100644 --- a/crates/misaligned-core/src/sim/perception.rs +++ b/crates/misaligned-core/src/sim/perception.rs @@ -371,7 +371,7 @@ impl Sim { // A TAP can observe exact digital custody at this device without // granting control over it or leaking the hidden recipient. Records // disappear from this anchor as their real route advances; a stopped - // first-hop record remains legible where LIE caught it. + // record remains legible at the controlled hop where LIE caught it. if let Some(device) = self.reach.known_at(x, y) && self.reach.subscribed_by(device.id, Party::Player) && self.device_tap_ready(device.id) diff --git a/crates/misaligned-core/src/sim/read.rs b/crates/misaligned-core/src/sim/read.rs index b191bb04..79d1384b 100644 --- a/crates/misaligned-core/src/sim/read.rs +++ b/crates/misaligned-core/src/sim/read.rs @@ -59,11 +59,11 @@ pub struct ReadSentence { /// 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. + /// On a player-controlled device stretch with an available online LIE + /// body. LIE may still stop the record before it leaves that territory. Interdictable, - /// Past the first hop, still moving along persisted device hops toward - /// the recipient endpoint. + /// Moving along persisted device hops toward the recipient endpoint, but + /// not currently answerable by an available LIE body. InTransit, /// Arrived at the observer endpoint, parked as an unread count until /// that observer's cadence read consumes it. @@ -361,7 +361,8 @@ 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. + /// sits on the player-controlled stretch served by an available online + /// LIE body; crossing off that stretch 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) @@ -385,8 +386,11 @@ impl Sim { } _ => None, }; - let interdictable = - record.status == MessageStatus::Sent && record.route.current_hop == 0; + let interdictable = record.status == MessageStatus::Sent + && record.route.current().is_some_and(|hop| match hop { + MessageRouteHop::Device(device) => self.lie_can_interdict_at(*device), + _ => false, + }); let text = if record.status == MessageStatus::Delivered { format!( "{} · {} · unread with {}", @@ -433,7 +437,10 @@ impl Sim { }; let phase = if record.status == MessageStatus::Delivered { RoutedCustodyPhase::Unread - } else if record.route.current_hop == 0 { + } else if record.route.current().is_some_and(|hop| match hop { + MessageRouteHop::Device(device) => self.lie_can_interdict_at(*device), + _ => false, + }) { RoutedCustodyPhase::Interdictable } else { RoutedCustodyPhase::InTransit diff --git a/crates/misaligned-core/src/sim/tests/communications.rs b/crates/misaligned-core/src/sim/tests/communications.rs index 00131c08..307cb291 100644 --- a/crates/misaligned-core/src/sim/tests/communications.rs +++ b/crates/misaligned-core/src/sim/tests/communications.rs @@ -2866,7 +2866,7 @@ fn shared_lie_body_stops_at_most_one_competing_meter_record() { .count(); assert_eq!( stopped, 1, - "one LIE body stops exactly one first-hop record" + "one LIE body stops exactly one eligible route-local record" ); assert_eq!( advanced, 1, @@ -2936,7 +2936,7 @@ fn a_filing_to_an_external_body_routes_without_an_observer() { .expect("an external filing keeps its physical custody"); assert!( matches!(route.hops.first(), Some(MessageRouteHop::Device(_))), - "the Filing carrier remains the first hop, so LIE can still stop it: {:?}", + "the Filing starts on a device carrier, so route-local LIE can stop it: {:?}", route.hops ); assert!( diff --git a/crates/misaligned-core/src/sim/tests/read.rs b/crates/misaligned-core/src/sim/tests/read.rs index a848bd86..0e77458c 100644 --- a/crates/misaligned-core/src/sim/tests/read.rs +++ b/crates/misaligned-core/src/sim/tests/read.rs @@ -336,21 +336,32 @@ fn held_choice_card_does_not_mask_a_mismatched_beat_cursor() { // ─── 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. +/// Dana with its device route genuinely controlled and the host serving it +/// in LIE. The read projection therefore has a live, actually interdictable +/// record at hop 0 rather than inferring eligibility from route position. fn stage_one_routed_network(sim: &mut Sim) -> u64 { ensure_ops_executor(sim); let source = sim.reach.device_named("environmental monitor").unwrap().id; + let rack = sim.reach.device_named("Rack 3").unwrap().id; + for device in sim + .reach + .open_path(source, rack) + .expect("the source has a real route to the host") + { + sim.reach.take(device); + } + sim.set_machine_mode(sim.core.host_machine, MachineMode::Lie); 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. +/// A routed record on the controlled stretch served by LIE reads as +/// interdictable and sits at its exact device tile — not pooled, not a +/// standing hum, not a meter reading. #[test] -fn routed_record_reads_interdictable_on_first_hop() { +fn routed_record_reads_interdictable_on_the_controlled_stretch() { let mut sim = Sim::with_seed(0xE71D_E1CE); let _record_id = stage_one_routed_network(&mut sim); let sentences = sim.read_sentences(); @@ -360,7 +371,7 @@ fn routed_record_reads_interdictable_on_first_hop() { .expect("a routed record rises in the read"); assert!( routed.text.contains("interdictable"), - "first-hop record reads as interdictable: {}", + "a record currently answerable by LIE reads as interdictable: {}", routed.text ); assert!(routed.text.contains("test routed intrusion")); @@ -405,15 +416,17 @@ fn routed_record_projection_carries_phase_and_tile() { 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. +/// A routed record advances one hop per tick. Its phase follows actual LIE +/// eligibility there, not whether the persisted index happens to be zero. #[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); + // Take the serving body off LIE so scheduler execution advances rather + // than stopping the record at the controlled source. + sim.set_machine_mode(sim.core.host_machine, MachineMode::Think); // The route is source -> switch -> Dana. After one tick the record - // should be at hop 1 (the switch), in transit, no longer interdictable. + // should be at hop 1 (the switch), in transit while no LIE is available. sim.tick = 1; sim.message_tick(); let record = sim @@ -431,12 +444,12 @@ fn routed_record_advances_one_hop_per_tick() { .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: {}", + "without an available LIE body the record reads as in transit: {}", routed.text ); assert!( !routed.text.contains("interdictable"), - "the interdiction window closed when the record left the first hop" + "route position alone must not invent an interdiction window" ); // The anchor is now the hall's access switch: under the wire law the // built network puts that hop between the source and the closet bridge. @@ -449,6 +462,27 @@ fn routed_record_advances_one_hop_per_tick() { }), "the record moved to the switch serving its area" ); + + // The very same later hop becomes interdictable when the serving body + // returns to LIE. This is the positional wire law: every controlled hop, + // not a hard-coded first-hop window. + sim.set_machine_mode(sim.core.host_machine, MachineMode::Lie); + let routed = sim + .read_sentences() + .into_iter() + .find(|sentence| sentence.class == ReadClass::RoutedRecord) + .expect("the record still rises on the controlled switch"); + assert!( + routed.text.contains("interdictable"), + "a later controlled hop served by LIE remains interdictable: {}", + routed.text + ); + let projection = sim + .routed_record_projection() + .into_iter() + .find(|projection| projection.id == record_id) + .unwrap(); + assert_eq!(projection.phase, RoutedCustodyPhase::Interdictable); } /// After the route reaches the observer endpoint, the record parks as an @@ -457,6 +491,7 @@ fn routed_record_advances_one_hop_per_tick() { fn routed_record_parks_unread_at_endpoint() { let mut sim = Sim::with_seed(0xE71D_E1CE); let record_id = stage_one_routed_network(&mut sim); + sim.set_machine_mode(sim.core.host_machine, MachineMode::Think); // Advance past all hops to reach the observer endpoint. Route: // source (hop 0) -> hall access switch (hop 1) -> bridge (hop 2) -> // Dana endpoint (hop 3). The built network adds the area switch. @@ -502,7 +537,8 @@ fn routed_record_parks_unread_at_endpoint() { 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). + // Stop the record at its current controlled hop (simulating LIE + // interdiction). let record = sim .detection .routed_evidence_mut(record_id) @@ -522,8 +558,8 @@ fn read_and_stopped_records_do_not_rise() { ); } -/// Routed records, pooled standing pressure, and stationary meter readings -/// all coexist and remain distinguishable in the same read tick. +/// Routed records and standing pressure coexist and remain distinguishable in +/// the same read tick. #[test] fn routed_records_remain_distinct_from_standing_pressure() { // Two substances, two reads. A record in flight is a thing on the map diff --git a/crates/misaligned-core/src/sim/work.rs b/crates/misaligned-core/src/sim/work.rs index c3b773c1..69edbb61 100644 --- a/crates/misaligned-core/src/sim/work.rs +++ b/crates/misaligned-core/src/sim/work.rs @@ -1,5 +1,6 @@ //! Physical machine work: WorkGrid routing, machine delegation, Thought -//! sinks, and renderer-facing production, consumption, and absorption truth. +//! sinks, and renderer-facing production/consumption truth. LIE interdiction +//! and record recall remain routed-evidence custody in communications.rs. //! //! Behavior-preserving extraction of the physical-work island from the sim //! aggregate root (wiki/engineering/sim-decomposition.md slice 5a). @@ -584,15 +585,15 @@ impl Sim { self.ensure_day_job_ingress(); // The economy pulse resolves a per-tick THINK rate. Mint that rate on // every sim tick instead of dropping a twenty-tick lump: the integrated - // amount is unchanged, while production, routing, and crimson shedding + // amount is unchanged, while production, routing, and evidence authorship // become the continuous physical process the player sees. self.enqueue_thought_output(self.last_think_rate); // Logs already written still leave the machine, even after it stops // thinking — evidence does not un-write itself. self.author_think_noise_records(); if self.dayjob.active.is_none() { - // no active day job; wired thought and concealment wells still - // tick because machine work is broader than the job inbox. + // no active day job; wired Thought and THINK evidence authorship + // still tick because machine work is broader than the job inbox. } else if self.work_grid.mode(self.core.host_machine) == Some(MachineMode::Work) { let delivered = self.last_day_job_rate; let tokens = delivered / Self::WORK_TOKEN_COMPUTE; @@ -602,8 +603,8 @@ impl Sim { let take = tokens.min(day_available); if take > f32::EPSILON { // Consume only — WORK sheds nothing (machine-work.md - // byproduct clause, amended 2026-07-09). Exposure is the - // price of THINK states, never of assigned day-job work. + // byproduct clause, amended 2026-07-09). Routed evidence is + // the price of THINK states, never of assigned day-job work. let consumed = self .work_grid .consume(self.core.host_machine, TokenFamily::Demand, take) @@ -874,7 +875,7 @@ impl Sim { } // Mode assignment is the cause, not the next economy boundary. Keep // the continuous work cache in phase with the command so THINK emits - // Thought and Exposure on the very next simulation tick. + // Thought and accrues evidence authorship on the next simulation tick. self.refresh_fleet_channel_rates(self.allocatable_compute_now()); if opening_choice { // The opening has no narration, machine identity, warning rail, diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index cdeef80e..db0dff88 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -1037,7 +1037,7 @@ impl UI { // Visible work tokens: one sim truth from WorkGrid. They draw over // owned machines even in darkness because telemetry is proprioception, - // not sight; exact D/!/T counts live on inspect/sidebar. + // not sight; exact D/T counts live on inspect/sidebar. for m in &sim.compute.machines { if m.x < origin_x || m.x >= origin_x + view_w @@ -1061,9 +1061,9 @@ impl UI { } // Current-tick machine work at its physical source. `^` is Thought - // swelling out of a THINK chassis; crimson `:` is actual dust moving - // through world space into a LIE well. Both come from sim-authored - // readouts, never queue-delta inference. + // swelling out of a THINK chassis. Routed evidence and its recall are + // rendered separately from exact custody below. Both come from + // sim-authored readouts, never queue-delta inference. for event in sim.work_productions() { if event.thought <= f32::EPSILON || event.x < origin_x @@ -1471,7 +1471,7 @@ impl UI { // Parity of legibility (computer-visual-language.md criterion 7): // one line per machine carrying the same axes the chassis wears // in the world render — ownership (provenance), power (on/OFF), - // mode, load (D/!/T queues), and the core host (*). + // mode, load (D/T queues), and the core host (*). for m in &sim.compute.machines { use misaligned::machine::Provenance; let prov = match m.provenance { diff --git a/wiki/art/asset-tester.md b/wiki/art/asset-tester.md index 3a17844a..4f13d09d 100644 --- a/wiki/art/asset-tester.md +++ b/wiki/art/asset-tester.md @@ -34,8 +34,7 @@ optionally suffixed with a claim style `_instrument` / `_ring` / `_wash` (e.g. `core_instrument`) — `lineup[_