From 55e5297dabb1370b0eecfceaa630f2a5232c13d7 Mon Sep 17 00:00:00 2001 From: Cameron Pfiffer Date: Wed, 29 Jul 2026 23:11:06 -0700 Subject: [PATCH] Put evidence on the wire. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Machine evidence now travels through exact routed custody, and LIE can interdict it at every controlled device hop while save validation and player reads preserve the same topology. The obsolete machine-local Exposure rack and its current-facing vocabulary are retired. ๐Ÿ‘พ Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- README.md | 21 +- crates/misaligned-assets/src/main.rs | 34 +--- crates/misaligned-assets/src/rack.rs | 152 +------------- crates/misaligned-bevy/src/material_view.rs | 5 +- crates/misaligned-bevy/src/production.rs | 9 +- crates/misaligned-bevy/src/shot_harness.rs | 29 ++- .../misaligned-bevy/src/world_annotations.rs | 26 +-- crates/misaligned-core/src/detection.rs | 6 +- crates/misaligned-core/src/save.rs | 108 +++++++++- .../misaligned-core/src/sim/communications.rs | 36 ++-- crates/misaligned-core/src/sim/mod.rs | 5 +- crates/misaligned-core/src/sim/perception.rs | 2 +- crates/misaligned-core/src/sim/read.rs | 23 ++- .../src/sim/tests/communications.rs | 4 +- crates/misaligned-core/src/sim/tests/read.rs | 66 ++++-- crates/misaligned-core/src/sim/work.rs | 15 +- crates/misaligned-terminal/src/ui.rs | 10 +- wiki/art/asset-tester.md | 11 +- wiki/art/effects-lab.md | 4 +- wiki/art/visual-identity.md | 12 +- wiki/engineering/current-build.md | 2 +- wiki/engineering/env.md | 6 +- wiki/engineering/flow-substrate.md | 8 +- wiki/engineering/sim-decomposition.md | 2 +- wiki/interface/action-vocabulary.md | 4 +- wiki/interface/bevy.md | 9 +- wiki/interface/clinical-frame.md | 17 +- wiki/interface/computer-visual-language.md | 7 +- wiki/interface/digital-read.md | 50 ++--- wiki/interface/fleet-command.md | 4 +- wiki/interface/terminal.md | 9 +- .../2026-07-30-wire-law-current-mirrors.md | 51 +++++ wiki/log/DEVLOG.md | 5 + wiki/mechanics/detection.md | 81 ++++---- wiki/mechanics/machine-work.md | 188 +++++++++--------- wiki/mechanics/messages.md | 42 ++-- wiki/mechanics/people-tokens.md | 46 +++-- wiki/mechanics/reach.md | 19 +- wiki/mechanics/sim-mechanics.md | 46 +++-- wiki/mechanics/system-laws.md | 2 +- wiki/process/ROADMAP.md | 58 +++--- wiki/vision/simulation-laws.md | 16 +- wiki/world/characters/priya.md | 7 +- 43 files changed, 675 insertions(+), 582 deletions(-) create mode 100644 wiki/log/2026-07-30-wire-law-current-mirrors.md 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[_