From 0b64258943611d50d2e94ecfa0021287a33bebd4 Mon Sep 17 00:00:00 2001 From: Cameron Pfiffer Date: Tue, 28 Jul 2026 06:04:00 -0700 Subject: [PATCH] Make local sight the physical geometry gate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep network control and telemetry legible as knowledge without allowing them to manufacture photographed machine mass in REAL. 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- crates/misaligned-bevy/src/main.rs | 31 ++- crates/misaligned-bevy/src/material_view.rs | 257 +++++++----------- crates/misaligned-bevy/src/rail_ui.rs | 12 +- crates/misaligned-bevy/src/shot_harness.rs | 57 ++-- crates/misaligned-core/src/sim/perception.rs | 7 +- .../src/sim/tests/perception.rs | 54 ++++ .../no-photo-real.png | Bin 0 -> 49211 bytes wiki/interface/bevy.md | 5 +- wiki/interface/computer-visual-language.md | 46 ++-- wiki/interface/flat-materials.md | 12 +- wiki/interface/material-dark-frame.md | 62 +++-- ...026-07-28-local-sight-physical-geometry.md | 71 +++++ wiki/log/DEVLOG.md | 5 + wiki/log/decisions/2026-07-28.md | 17 ++ wiki/mechanics/cursor.md | 22 +- wiki/process/ROADMAP.md | 7 +- 16 files changed, 403 insertions(+), 262 deletions(-) create mode 100644 wiki/images/2026-07-28-local-sight-physical-geometry/no-photo-real.png create mode 100644 wiki/log/2026-07-28-local-sight-physical-geometry.md diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index c23ff2f8..3da08b25 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -44,7 +44,7 @@ use misaligned::operations_ui::{ }; use misaligned::origin::Origin; use misaligned::person::{AssetKnowledge, Knowledge, ScheduleBlock}; -use misaligned::reach::{Device, Party}; +use misaligned::reach::Device; use misaligned::sim::{ Fog, LogEvent, Nudge, OpeningStage, PersonVisualState, Sim, TraceDebtStatus, }; @@ -78,17 +78,16 @@ use material_view::{ BuildBeam, ChassisTier, DataHallInfrastructure3d, DataHallInfrastructureSpec, EvidenceCarrier3d, EyesReveal, FOUNDATION_FLOOR_LIGHTS, Flat2dRoot, FloorFixture, InstitutionFixture3d, InstitutionProp3d, Machine3d, Machines3d, Materials3d, Person3d, - RealCamera, RealGizmos, ServiceCarrier3d, Tile3d, TilePart, WAKE_LEN, WakeState, - apply_material_exposure, apply_render_mode, chassis_visual, data_hall_infrastructure_applies, + RealCamera, RealGizmos, ServiceCarrier3d, Tile3d, WAKE_LEN, WakeState, apply_material_exposure, + apply_render_mode, chassis_visual, data_hall_infrastructure_applies, data_hall_infrastructure_specs, data_hall_infrastructure_visible, evidence_carrier_visible, evidence_has_index, evidence_literal_count, evidence_marker_text, flicker_feeds, floor_fixture_visible, grid_to_world_3d, institution_prop_kind_at, known_tile, - material_feel_route, owned_machine_at, owned_machine_tiles, rectilinear_floor_route, - render_audio_events_3d, render_build_beam, render_evidence_carriers_3d, render_people_3d, - render_real_links, render_service_carriers_3d, restyle_3d, reveal_first_eyes, - service_carrier_visible, setup_3d, sync_data_hall_infrastructure, sync_floor_fixtures, - sync_institution_props, sync_institution_render_layers, sync_machines_3d, update_camera_real, - wake_sequence, + material_feel_route, owned_machine_tiles, rectilinear_floor_route, render_audio_events_3d, + render_build_beam, render_evidence_carriers_3d, render_people_3d, render_real_links, + render_service_carriers_3d, restyle_3d, reveal_first_eyes, service_carrier_visible, setup_3d, + sync_data_hall_infrastructure, sync_floor_fixtures, sync_institution_props, + sync_institution_render_layers, sync_machines_3d, update_camera_real, wake_sequence, }; use opening_ui::{ OpeningInputEcho, OpeningInputReceipts, OpeningModeWord, OpeningOverlay, OpeningReveal, @@ -1573,15 +1572,17 @@ fn main() { frozen: false, }, }; - let has_sight = game.sim.reach.player_sight().next().is_some(); + let core = game.sim.core_position(); + let has_core_sight = matches!(game.sim.fog_at(core.0, core.1), Fog::Seen); let eyes_reveal = EyesReveal { - // Harness eyes shots begin after sight has been staged but retain an - // explicit frozen reveal composition. Ordinary pre-sighted harnesses - // start completed so their settled renderer shots stay canonical. - had_sight: has_sight, + // Harness eyes shots begin after local core sight has been staged but + // retain an explicit frozen reveal composition. Ordinary harnesses + // whose core is already Seen start completed so settled shots stay + // canonical; sight elsewhere cannot resolve the core's body. + had_core_sight: has_core_sight, t: eyes_stage.map(|(t, _)| t), frozen: eyes_stage.is_some_and(|(_, frozen)| frozen), - completed: has_sight && eyes_stage.is_none(), + completed: has_core_sight && eyes_stage.is_none(), }; let shot_mode = harness.is_some(); diff --git a/crates/misaligned-bevy/src/material_view.rs b/crates/misaligned-bevy/src/material_view.rs index 3d3faf33..a0a2534f 100644 --- a/crates/misaligned-bevy/src/material_view.rs +++ b/crates/misaligned-bevy/src/material_view.rs @@ -1,4 +1,5 @@ use super::*; +use misaligned::reach::Party; fn material_fog_range(camera_dist: f32) -> (f32, f32) { let shift = camera_dist - CLOSE_DIST; @@ -171,14 +172,16 @@ pub(super) struct WakeColumn { base: f32, } -/// The first sight feed changes the presence beam into a physical chassis: -/// a white column briefly swallows the amber source, collapses to its instrument, -/// and leaves the server's volume visible. Frontend-only — sight remains a -/// sim fact, this is only its material-render payoff. +/// The first sight feed that actually covers the core changes its presence +/// beam into a physical chassis: a white column briefly swallows the amber +/// source, collapses to its instrument, and leaves the server's volume +/// visible. Frontend-only — local Seen remains a sim fact, this is only its +/// material-render payoff. #[derive(Resource)] pub(super) struct EyesReveal { - /// Sight state last observed from the sim; detects the first Eyes beat. - pub(super) had_sight: bool, + /// Core-tile Seen state last observed from the sim; detects the first + /// body-revealing Eyes beat without borrowing sight from another room. + pub(super) had_core_sight: bool, /// Reveal elapsed time. `None` means either not earned or already over. pub(super) t: Option, /// Harness stages hold a composition for a deterministic PNG. @@ -587,20 +590,8 @@ pub(super) fn floor_fixture_visible(material: bool, fog: Fog) -> bool { material && matches!(fog, Fog::Seen) } -/// Owned compute at this tile answers through telemetry (cursor.md): its -/// chassis may render even when the surrounding room is only Blueprint. -/// Foreign / uncontrolled machine tiles stay absent under blueprint — -/// they are built in the world, but you have no intel that they are there. -pub(super) fn owned_machine_at(sim: &misaligned::sim::Sim, x: i32, y: i32) -> bool { - use misaligned::machine::Provenance; - sim.compute - .machines - .iter() - .any(|m| m.x == x && m.y == y && matches!(m.provenance, Provenance::Owned)) -} - -/// Tile positions of owned machines — built once per restyle so per-entity -/// lookups are O(1) instead of scanning the fleet for every map tile. +/// Tile positions of owned machines for DIGITAL's telemetry read. This set may +/// inform schematic color, but it must never authorize physical REAL geometry. pub(super) fn owned_machine_tiles(sim: &misaligned::sim::Sim) -> HashSet<(i32, i32)> { use misaligned::machine::Provenance; sim.compute @@ -707,12 +698,10 @@ pub(super) fn institution_prop_state( } } -/// Intel tier for a chassis tile (spec criterion 2b): full geometric -/// definition, an undetailed shell, or absent. +/// Local-vision tier for a chassis tile: full geometric definition or absent. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(super) enum ChassisTier { Absent, - Shell { remembered: bool }, Full, } @@ -753,11 +742,6 @@ pub(super) struct Machine3d { #[derive(Resource, Default)] pub(super) struct Machines3d { spawned: HashMap<(i32, i32), (ChassisVisual, Entity)>, - /// Pool undetailed remembered/model shell shapes and materials instead of - /// allocating a hierarchy per one of sixty sites. - rack_shell_mesh: Option>, - switch_shell_mesh: Option>, - shell_materials: HashMap>, } /// Delegated sim mode -> circular instrument. Relays and unassigned machines @@ -897,11 +881,11 @@ mod machine_instrument_tests { /// Decide what one chassis tile shows, from sim facts only. /// -/// Ownership is the chassis albedo: your machines (telemetry — any fog) -/// are white; hardware not under your control is dark. Tier follows -/// intel: owned/networked = fully seen, camera sight = fully seen, -/// location intel or memory = undetailed shell, nothing = absent -/// (blueprint is room topology, never a chassis). +/// Ownership is the chassis albedo once the body has been photographed: your +/// machines are white; hardware not under your control is dark. Tier follows +/// local camera truth: Seen = full, every other fog state = absent. Telemetry, +/// network control, Blueprint, and memory remain readable elsewhere but never +/// manufacture physical mass in REAL. pub(super) fn chassis_visual(game: &Game, x: i32, y: i32, tile: TileType) -> ChassisVisual { // Switches and passive patch relays share the low appliance envelope; // neither should masquerade as a full-height compute rack. @@ -913,36 +897,15 @@ pub(super) fn chassis_visual(game: &Game, x: i32, y: i32, tile: TileType) -> Cha .machines .iter() .find(|m| m.x == x && m.y == y); + // Device custody still determines the albedo of a locally Seen appliance; + // it does not participate in the geometry gate above. let device = game.sim.reach.known_at(x, y); - let networked = device.is_some_and(|d| { - d.controller == Party::Player - || game.sim.reach.feed_to(d.id, Party::Player, true) - || game.sim.reach.feed_to(d.id, Party::Player, false) - }); - let rack_site = game.sim.rack_site_at(x, y); let tier = if matches!(rack_site, Some(RackSite::Commissionable)) { // An allocated pilot bay is floor space, not an empty chassis. ChassisTier::Absent - } else if machine.is_some() { - // Before Eyes the host is a presence beam, not a pictured server. - // Owned compute still answers through telemetry in panels, but its - // physical chassis only exists for the material camera once sight is - // earned (material-dark-frame.md reveal ladder). - if game.sim.reach.player_sight().next().is_some() { - ChassisTier::Full - } else { - ChassisTier::Absent - } - } else if matches!(fog, Fog::Seen) || networked { + } else if matches!(fog, Fog::Seen) { ChassisTier::Full - } else if device.is_some() && !matches!(fog, Fog::Unknown) { - // Known-but-unseen devices: shell only once plan/sight earns the - // tile. Tick-one Unknown stays Absent — feel rails mark the hop - // (feel-floor.md), not a ghost chassis in the dark. - ChassisTier::Shell { remembered: false } - } else if matches!(fog, Fog::Remembered) { - ChassisTier::Shell { remembered: true } } else { ChassisTier::Absent }; @@ -1046,6 +1009,66 @@ pub(super) fn chassis_visual(game: &Game, x: i32, y: i32, tile: TileType) -> Cha } } +#[cfg(test)] +mod chassis_local_sight_tests { + use super::*; + use misaligned::actions::ActionCommand; + + #[test] + fn owned_core_mass_requires_local_seen_even_while_eyes_exists_elsewhere() { + let mut game = Game::new(); + let env = game + .sim + .reach + .device_named("environmental monitor") + .expect("opening sensor") + .id; + let node = Sim::device_sink_node(env); + + game.sim + .pour_thought_into_sinks(node, Sim::EARS_SINK_TOKENS); + game.sim.execute_action(&ActionCommand::TapDevice(env)); + game.sim.pour_thought_into_sinks( + node, + Sim::thought_tokens_for_cost(Sim::DORMANT_CAMERA_TAP_COST), + ); + + let core = game.sim.core_position(); + let tile = game.sim.map().get_tile(core.0, core.1); + assert!(game.sim.reach.player_sight().next().is_some()); + assert!(matches!(game.sim.fog_at(core.0, core.1), Fog::Seen)); + assert_eq!( + chassis_visual(&game, core.0, core.1, tile).tier, + ChassisTier::Full + ); + + // Preserve the real active Eyes subscription while taking only this + // tile out of its local coverage. The remembered snapshot must not + // keep the chassis in REAL. + game.sim.seen.remove(&core); + assert!(matches!(game.sim.fog_at(core.0, core.1), Fog::Remembered)); + assert_eq!( + chassis_visual(&game, core.0, core.1, tile).tier, + ChassisTier::Absent + ); + + game.sim.remembered.remove(&core); + game.sim.blueprint.insert(core); + assert!(matches!(game.sim.fog_at(core.0, core.1), Fog::Blueprint)); + assert_eq!( + chassis_visual(&game, core.0, core.1, tile).tier, + ChassisTier::Absent + ); + + game.sim.blueprint.remove(&core); + assert!(matches!(game.sim.fog_at(core.0, core.1), Fog::Unknown)); + assert_eq!( + chassis_visual(&game, core.0, core.1, tile).tier, + ChassisTier::Absent + ); + } +} + /// Keep one 3D chassis hierarchy per machine tile in sync with the sim. /// Runs before restyle_3d so both react to the same change tick; the /// chassis replaces those tiles' prop billboards entirely. @@ -1064,25 +1087,6 @@ pub(super) fn sync_machines_3d( return; }; - let rack_shell_mesh = reg - .rack_shell_mesh - .get_or_insert_with(|| meshes.add(Cuboid::new(0.40, 1.32, 0.26))) - .clone(); - let switch_shell_mesh = reg - .switch_shell_mesh - .get_or_insert_with(|| meshes.add(Cuboid::new(0.50, 0.42, 0.22))) - .clone(); - for remembered in [false, true] { - reg.shell_materials.entry(remembered).or_insert_with(|| { - materials.add(StandardMaterial { - base_color: scaled(GUNMETAL, if remembered { 0.40 } else { 0.55 }), - unlit: true, - ..default() - }) - }); - } - let shell_materials = reg.shell_materials.clone(); - let mut desired: HashMap<(i32, i32), ChassisVisual> = HashMap::new(); for y in 0..game.sim.map().height { for x in 0..game.sim.map().width { @@ -1108,25 +1112,12 @@ pub(super) fn sync_machines_3d( commands.entity(e).despawn(); } } - let shell_assets = ChassisShellAssets { - rack_mesh: &rack_shell_mesh, - switch_mesh: &switch_shell_mesh, - materials: &shell_materials, - }; for (&(x, y), &v) in desired.iter() { if reg.spawned.contains_key(&(x, y)) { continue; } let pos = grid_to_world_3d(x, y, 0.0); - let e = spawn_chassis( - &mut commands, - &mut meshes, - &mut materials, - v, - pos, - root, - &shell_assets, - ); + let e = spawn_chassis(&mut commands, &mut meshes, &mut materials, v, pos, root); commands.entity(e).insert(Machine3d { x, y, @@ -1139,14 +1130,7 @@ pub(super) fn sync_machines_3d( } } -struct ChassisShellAssets<'a> { - rack_mesh: &'a Handle, - switch_mesh: &'a Handle, - materials: &'a HashMap>, -} - -/// Spawn the mesh for one chassis visual: the monolith rack or switch -/// box at full definition, or the undetailed intel shell. +/// Spawn the full mesh for one locally Seen chassis visual. fn spawn_chassis( commands: &mut Commands, meshes: &mut Assets, @@ -1154,29 +1138,7 @@ fn spawn_chassis( v: ChassisVisual, pos: Vec3, root: Entity, - shells: &ChassisShellAssets<'_>, ) -> Entity { - if let ChassisTier::Shell { remembered } = v.tier { - let (mesh, h) = if v.switch { - (shells.switch_mesh.clone(), 0.42) - } else { - (shells.rack_mesh.clone(), 1.32) - }; - let mat = shells - .materials - .get(&remembered) - .expect("all chassis shell epistemic materials are pooled") - .clone(); - return commands - .spawn(( - Mesh3d(mesh), - MeshMaterial3d(mat), - Transform::from_translation(pos + Vec3::Y * (h * 0.5)), - ChildOf(root), - )) - .id(); - } - let (e, ring_inv) = if v.switch { ( spawn_switch_chassis( @@ -2277,18 +2239,16 @@ pub(super) fn restyle_3d( return; } mode.dirty = false; - let owned = owned_machine_tiles(&game.sim); for (t, mut mesh, mut mat, mut tf, mut vis) in q.iter_mut() { let fog = game.sim.fog_at(t.x, t.y); let tile = known_tile(&game, t.x, t.y); // Light is the only revealer (material-dark-frame.md): the material // render is a camera, and a camera photographs light, not floor - // plans. Only camera-seen surfaces draw as physical matter; owned - // machines legitimized by telemetry keep rendering (they are their - // own light). Blueprint/remembered mass is plan knowledge — it reads - // in the flat sensorium (F3) and overlays, never as matter the camera - // did not see. Audio is channel evidence and never creates matter. - let owned_prop = machine_tile(tile) && owned.contains(&(t.x, t.y)); + // plans. Only camera-Seen surfaces draw as physical matter. Owned + // telemetry remains readable without sight, but its amber presence + // language is separate from geometry. Blueprint/Remembered mass reads + // in DIGITAL and overlays, never as matter the camera did not see. + // Audio is channel evidence and never creates matter. let show = match (t.part, fog) { (_, Fog::Unknown) => false, (TilePart::Floor, Fog::Seen) => true, @@ -2306,9 +2266,6 @@ pub(super) fn restyle_3d( // Chassis tiles render as real 3D machine meshes // (sync_machines_3d) — never as billboards. (TilePart::Prop, _) if chassis_3d_tile(tile) => false, - // Owned machines are their own light: telemetry keeps their - // prop drawing even without room sight. - (TilePart::Prop, _) if owned_prop => true, (TilePart::Prop, Fog::Seen) => prop_tile(tile), (TilePart::Prop, _) => false, }; @@ -2336,17 +2293,10 @@ pub(super) fn restyle_3d( tf.translation.y = height + 0.002; } } - // Live-feed emissive state (flat-materials.md criterion 3): a seen + // Live-feed emissive state (flat-materials.md criterion 3): a Seen // device actively feeding the player scans in the cold signal color. - // Owned machines under blueprint still use Seen materials — telemetry - // legitimizes the chassis without granting room sight. - // An owned machine prop reads as telemetry-lit regardless of room - // sight — the only non-Seen mass the material render draws. - let mat_fog = if t.part == TilePart::Prop && !matches!(fog, Fog::Seen) && owned_prop { - Fog::Seen - } else { - fog - }; + // Telemetry without local Seen remains non-geometric in REAL. + let mat_fog = fog; let live = t.part == TilePart::Prop && matches!(mat_fog, Fog::Seen) && game.sim.reach.known_at(t.x, t.y).is_some_and(|d| { @@ -2495,10 +2445,11 @@ pub(super) fn wake_sequence( } } -/// Give the first camera feed a body-level payoff: when Eyes arrives, the -/// amber presence source bleaches to white, then contracts to expose the -/// server's silhouette, edges, and chassis. At the same moment, camera -/// exposure neutrally lights Seen geometry; Unknown remains dark. +/// Give the first camera feed covering the core a body-level payoff: when that +/// local Eyes image arrives, the amber presence source bleaches to white, then +/// contracts to expose the server's silhouette, edges, and chassis. Camera +/// exposure may begin from sight elsewhere, but it cannot reveal or dismiss +/// the core's light-only presence until the core tile itself is Seen. pub(super) fn reveal_first_eyes( time: Res