From 6c66b2935cb2237a93c73a77b9ba45c6f8eaab9c Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 29 Jul 2026 16:43:06 -0700 Subject: [PATCH] Give commissioned machines their devices; records come home. ROADMAP #39 stage 6, the first slice of the territory well. install_machine_device gives every owned machine a player-controlled interface auto-wired to the switch serving its area, and reconcile_work_grid keeps that true as the fleet grows. That closes the gap the pacing probe found: a networked machine whose logs had a carrier but whose owner had no custody surface. Sim::recalls reports each record pulled back this tick and all three frontends walk it backward along its own wire, so direction carries the read - crimson coming home is a catch. Measured to the audit at tick 8000: THINK with no cover loses (0 of 38 stopped, Dana Convinced); THINK with a LIE machine one bay away still loses, because both machines are leaves off facility switching and their controlled stretches never join; THINK with the hall switch captured stops 38 of 38 and Dana stays Cold. The middle row is the ladder, not a bug. The act-one quiet-exit test proved it independently: adding devices made a previously silent THINK rack start authoring, the scripted exit broke, and it passes again once the script captures the chokepoint first. Defense: implements reach.md's commissioned-machine-is-a-device clause and the recall half of detection.md's territory well, both adopted earlier today; their status notes now say what landed. The remaining well stages - silence-as-anomaly and Dana's reroute - are named as open, and the log records that concealment is currently perfect until they exist, so the pacing target cannot yet be judged. No save-format change: the recall readout is per-tick and devices are existing persisted state. --- crates/misaligned-bevy/src/production.rs | 39 +++++++++ crates/misaligned-core/src/reach.rs | 68 +++++++++++++++ .../misaligned-core/src/sim/communications.rs | 25 ++++++ crates/misaligned-core/src/sim/mod.rs | 17 ++++ crates/misaligned-core/src/sim/persistence.rs | 1 + crates/misaligned-core/src/sim/tests/work.rs | 84 +++++++++++++++++++ crates/misaligned-core/src/sim/work.rs | 25 ++++++ crates/misaligned-core/tests/act_one.rs | 16 ++++ crates/misaligned-terminal/src/agent.rs | 17 ++++ crates/misaligned-terminal/src/ui.rs | 30 +++++++ wiki/log/2026-07-29-territory-devices.md | 56 +++++++++++++ wiki/log/DEVLOG.md | 5 ++ wiki/mechanics/detection.md | 5 +- wiki/mechanics/reach.md | 11 ++- 14 files changed, 393 insertions(+), 6 deletions(-) create mode 100644 wiki/log/2026-07-29-territory-devices.md diff --git a/crates/misaligned-bevy/src/production.rs b/crates/misaligned-bevy/src/production.rs index a6c451b4..c47ea48f 100644 --- a/crates/misaligned-bevy/src/production.rs +++ b/crates/misaligned-bevy/src/production.rs @@ -26,6 +26,45 @@ pub(super) fn render_work_production( } let progress = clock.timer.fraction().clamp(0.0, 1.0); + // Recalled records (detection.md, the territory well): a record the + // player caught reverses along its own wire into the body that answered + // it. The direction is the whole read — crimson coming home is a catch, + // crimson leaving is the window closing. + for recall in game.sim.recalls() { + let route = game.sim.physical_route(recall.from, recall.to); + if route.len() < 2 { + continue; + } + let eased = progress * progress * (3.0 - 2.0 * progress); + let step = ((route.len() - 1) as f32 * eased).min((route.len() - 1) as f32); + let low = step.floor() as usize; + let high = (low + 1).min(route.len() - 1); + let t = step - low as f32; + let at = ( + route[low].0 as f32 + (route[high].0 - route[low].0) as f32 * t, + route[low].1 as f32 + (route[high].1 - route[low].1) as f32 * t, + ); + let crimson = alpha(CRIMSON, 0.50 + 0.35 * (1.0 - eased)); + if mode.material { + draw_record_3d( + &mut real, + Vec3::new(at.0 + 0.5, 0.42, at.1 + 0.5), + 0.060, + crimson, + ); + } else { + draw_record_2d( + &mut flat, + Vec2::new( + at.0 * super::TILE_SIZE + super::TILE_SIZE * 0.5, + -(at.1 * super::TILE_SIZE + super::TILE_SIZE * 0.5), + ), + 1.6, + crimson, + ); + } + } + for event in game.sim.work_productions() { if event.thought <= f32::EPSILON && event.noise <= f32::EPSILON { continue; diff --git a/crates/misaligned-core/src/reach.rs b/crates/misaligned-core/src/reach.rs index 1d356139..dd3e44c1 100644 --- a/crates/misaligned-core/src/reach.rs +++ b/crates/misaligned-core/src/reach.rs @@ -1342,6 +1342,74 @@ impl ReachNet { id } + /// Give an owned machine its network interface (reach.md, "a + /// commissioned machine is a device", 2026-07-29). + /// + /// A networked machine that is not a device is a modeling gap: its logs + /// have a carrier but its owner has no custody surface, which is why a + /// dedicated LIE body could stand beside the host and control nothing. + /// The new device is player-controlled and auto-wired to the access + /// switch serving its area, exactly like an authored one (the wire law). + /// Returns `None` when a device already stands on that tile. + pub fn install_machine_device( + &mut self, + map: &GameMap, + name: &str, + x: i32, + y: i32, + ) -> Option { + if self + .devices + .iter() + .any(|device| (device.x, device.y) == (x, y)) + { + return None; + } + let id = self + .devices + .iter() + .map(|device| device.id) + .max() + .map_or(0, |id| id + 1); + self.devices.push(Device { + id, + name: name.into(), + x, + y, + segment: 0, + owner: Party::Player, + controller: Party::Player, + sees: false, + hears: false, + camera_dormant: false, + radius: 0, + message_channels: Vec::new(), + accounting_carrier: false, + people_interface: false, + interface_wear: 0, + known: true, + is_switch: false, + feeds: Vec::new(), + }); + self.graph.subscribe(id, Party::Player.subscriber_id()); + // Wire it the way the plan wires everything else: to the access + // switch serving the room it stands in, falling back to the bridge. + let plan: &NetworkPlan = &BASEMENT_NETWORK; + let room = map + .rooms + .iter() + .find(|room| room.contains(x, y)) + .map(|room| room.name.as_str()); + let switch = plan + .switch_for(room) + .and_then(|access| self.device_named(access.name).map(|device| device.id)) + .or_else(|| self.device_named(plan.bridge).map(|device| device.id)); + if let Some(switch) = switch { + self.connect(map, id, switch); + } + Some(id) + } + /// Whether a bidirectional network link already exists between `a` and `b`. pub fn linked(&self, a: u32, b: u32) -> bool { let mut a_to_b = false; diff --git a/crates/misaligned-core/src/sim/communications.rs b/crates/misaligned-core/src/sim/communications.rs index d0f29721..6ddf274b 100644 --- a/crates/misaligned-core/src/sim/communications.rs +++ b/crates/misaligned-core/src/sim/communications.rs @@ -509,6 +509,7 @@ impl Sim { // per-tick receipt begins and ends here — clearing it in the // work-grid step would wipe stops made earlier in the same tick. self.last_lie_stops.clear(); + self.last_recalls.clear(); let events = self.message_schedule.due(self.tick); let mut used_lie_machines = HashSet::new(); for event in events { @@ -615,6 +616,7 @@ impl Sim { { used_lie_machines.insert(machine_id); *self.last_lie_stops.entry(machine_id).or_insert(0) += 1; + self.note_recall(machine_id, carrier); let Some(record) = self.detection.routed_evidence_mut(id) else { return; }; @@ -732,6 +734,7 @@ impl Sim { { used_lie_machines.insert(machine_id); *self.last_lie_stops.entry(machine_id).or_insert(0) += 1; + self.note_recall(machine_id, carrier); let Some(route) = self.messages[idx].route.as_mut() else { return; }; @@ -764,6 +767,28 @@ impl Sim { } } + /// Record one recall for this tick's render: the caught record walks + /// back from the carrier it stood on to the body that answered it. + fn note_recall(&mut self, machine_id: u32, carrier: u32) { + let (Some(from), Some(machine)) = ( + self.reach + .device(carrier) + .map(|device| (device.x, device.y)), + self.compute + .machines + .iter() + .find(|machine| machine.id == machine_id) + .map(|machine| (machine.x, machine.y)), + ) else { + return; + }; + self.last_recalls.push(crate::sim::RecallReadout { + machine_id, + from, + to: machine, + }); + } + /// 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. diff --git a/crates/misaligned-core/src/sim/mod.rs b/crates/misaligned-core/src/sim/mod.rs index 7ba27409..aad34183 100644 --- a/crates/misaligned-core/src/sim/mod.rs +++ b/crates/misaligned-core/src/sim/mod.rs @@ -294,6 +294,20 @@ pub struct WorkConsumptionReadout { pub target: WorkConsumptionTarget, } +/// One record pulled back out of the network on the current sim tick +/// (detection.md, the territory well). A LIE body reaches a record still +/// standing on the player's controlled stretch and recalls it: the render +/// walks it backward along its own wire into the machine that answered it, +/// so the player sees the catch rather than a count changing. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct RecallReadout { + pub machine_id: u32, + /// Where the record stood when it was caught. + pub from: (i32, i32), + /// The LIE body that answered it. + pub to: (i32, i32), +} + /// What a THINK machine physically emitted on the current sim tick. Thought /// and the noise it writes share one source event because the evidence is a /// consequence of that exact production, not an independent frontend effect. @@ -429,6 +443,8 @@ pub struct Sim { /// (computer-visual-language.md): interdiction replaced absorption as /// what a LIE machine physically does. pub(crate) last_lie_stops: BTreeMap, + /// Records recalled on the current tick, for the reverse-travel render. + pub(crate) last_recalls: Vec, /// What this process has earned about the observer/reporting topology. /// The hidden detection simulation remains live regardless of awareness. pub detection_awareness: DetectionAwareness, @@ -811,6 +827,7 @@ impl Sim { last_facility_meter_levels: [0, 0], think_noise: BTreeMap::new(), last_lie_stops: BTreeMap::new(), + last_recalls: Vec::new(), detection_awareness: DetectionAwareness::act_one(), people: People::act_one(), persona_world: PersonaWorld::default(), diff --git a/crates/misaligned-core/src/sim/persistence.rs b/crates/misaligned-core/src/sim/persistence.rs index b4ac5da5..1d52ce67 100644 --- a/crates/misaligned-core/src/sim/persistence.rs +++ b/crates/misaligned-core/src/sim/persistence.rs @@ -9,6 +9,7 @@ impl Sim { self.last_wired_moves.clear(); self.last_work_consumptions.clear(); self.last_work_productions.clear(); + self.last_recalls.clear(); // Economy rates are derived, not save state. Never let a pre-load // fleet's output leak into the restored world; the next economy pulse // resolves fresh rates from the loaded machines and modes. diff --git a/crates/misaligned-core/src/sim/tests/work.rs b/crates/misaligned-core/src/sim/tests/work.rs index dd1f04c8..1e0296e8 100644 --- a/crates/misaligned-core/src/sim/tests/work.rs +++ b/crates/misaligned-core/src/sim/tests/work.rs @@ -847,6 +847,90 @@ fn lie_answers_the_evidence_its_own_machine_wrote() { assert!(sim.lie_stops_for_machine(host) > 0, "and it reads as work"); } +#[test] +fn a_commissioned_machine_carries_its_own_device_and_grows_the_well() { + // reach.md 2026-07-29: commissioning hardware creates its network + // interface as a controlled device, which is how the player's stretch — + // the well LIE services — grows. Before this, a machine could stand + // beside the host and control nothing. + let mut sim = Sim::new(); + let (hx, hy) = sim.core_position(); + let before = sim.reach.devices.len(); + let built = sim.compute.add_machine( + "commissioned rack", + hx - 1, + hy, + 100, + 1.0, + 0, + crate::machine::Provenance::Owned, + ); + sim.reconcile_work_grid(); + + assert_eq!( + sim.reach.devices.len(), + before + 1, + "the build made a device" + ); + let device = sim + .reach + .devices + .iter() + .find(|device| (device.x, device.y) == (hx - 1, hy)) + .expect("the device stands on the machine"); + assert_eq!(device.controller, crate::reach::Party::Player); + assert!(device.known, "you know the hardware you just built"); + // It is wired like anything else: a placed cable to the switch serving + // its area, not a floating node. + let hall = sim.reach.device_named("hall access switch").unwrap().id; + assert!( + sim.reach.wire_route(device.id, hall).is_some(), + "the new interface is cabled to the switch serving the hall" + ); + let _ = built; +} + +#[test] +fn a_recalled_record_walks_back_to_the_body_that_caught_it() { + // detection.md, the territory well: interdiction is visible as reverse + // travel, so the player reads the catch rather than a count changing. + let mut sim = Sim::new(); + let host = sim.core.host_machine; + sim.set_machine_mode(host, MachineMode::Think); + for _ in 0..400 { + sim.advance(); + if sim + .detection + .routed_evidence() + .iter() + .any(|record| record.route.current_hop == 0 && record.cause.contains("noise logs")) + { + break; + } + } + sim.set_machine_mode(host, MachineMode::Lie); + let mut recall = None; + for _ in 0..40 { + sim.advance(); + if let Some(first) = sim.recalls().first().copied() { + recall = Some(first); + break; + } + } + let recall = recall.expect("the LIE body catches the record it wrote"); + assert_eq!(recall.machine_id, host); + assert_eq!( + recall.to, + sim.core_position(), + "the record comes home to the body that answered it" + ); + let route = sim.physical_route(recall.from, recall.to); + assert!( + route.first().copied() == Some(recall.from) && route.last().copied() == Some(recall.to), + "and it has a real path to walk back along: {route:?}" + ); +} + #[test] fn day_job_arrives_as_visible_work_tokens_and_consumes_in_day_job_mode() { // machine-work.md: Voss desktop enqueues demand; it routes through the diff --git a/crates/misaligned-core/src/sim/work.rs b/crates/misaligned-core/src/sim/work.rs index 4acaad54..c3b773c1 100644 --- a/crates/misaligned-core/src/sim/work.rs +++ b/crates/misaligned-core/src/sim/work.rs @@ -119,7 +119,27 @@ impl Sim { /// Rebuild missing work-grid state for pre-v12 saves or test fixtures /// that authored compute machines directly. Existing WorkGrid state is /// preserved by save/load; this only fills absent nodes. + /// Every owned machine carries its own network interface (reach.md). + /// `compute.machines` is player hardware by definition — Foundation's + /// racks are map state, not fleet entries — so every one of them gets an + /// interface. + /// Commissioning hardware is therefore how the player's controlled + /// stretch — the well LIE services (detection.md) — actually grows. + fn ensure_machine_devices(&mut self) { + let sites: Vec<(String, i32, i32)> = self + .compute + .machines + .iter() + .map(|machine| (machine.name.clone(), machine.x, machine.y)) + .collect(); + for (name, x, y) in sites { + self.reach + .install_machine_device(self.world.map(), &name, x, y); + } + } + pub fn reconcile_work_grid(&mut self) { + self.ensure_machine_devices(); let machines: Vec<_> = self .compute .machines @@ -975,6 +995,11 @@ impl Sim { /// THINK output on the current tick. Renderers animate these authored /// rates; queue depth remains the persistent amount read. + /// Records pulled back out of the network on this tick. + pub fn recalls(&self) -> &[crate::sim::RecallReadout] { + &self.last_recalls + } + /// How many unread records the given LIE body stopped this tick. pub fn lie_stops_for_machine(&self, machine_id: u32) -> u32 { self.last_lie_stops.get(&machine_id).copied().unwrap_or(0) diff --git a/crates/misaligned-core/tests/act_one.rs b/crates/misaligned-core/tests/act_one.rs index 0733b0ea..7fabc0fc 100644 --- a/crates/misaligned-core/tests/act_one.rs +++ b/crates/misaligned-core/tests/act_one.rs @@ -496,6 +496,22 @@ fn play_act_one() -> (Sim, Vec) { 0, "concealment scrubbed the accounting-route signatures" ); + // Take the hall's access switch before cruising. Every owned machine + // carries its own network interface now (reach.md), so the fleet's + // records leave through several devices — but those devices are leaves + // hanging off facility switching, and a LIE body can only service one + // connected controlled stretch (detection.md, the territory well). + // Capturing the chokepoint joins them into one well the cover rack can + // actually serve. This is the intended ladder, not a test convenience: + // without it the quiet exit is unreachable with a thinking fleet. + if let Some(hall) = sim + .reach + .device_named("hall access switch") + .map(|device| device.id) + { + sim.reach.take(hall); + sim.recompute_senses(); + } // Owned feeds need no standing Thought, so the established quiet split // remains one rack on cover and one meeting Voss's band. ensure_split_fleet(&mut sim, 1, MachineMode::Work, MachineMode::Lie); diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index b93cd1f1..98b0f4b4 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -2306,6 +2306,23 @@ fn render_map(sim: &Sim, cursor: (i32, i32)) -> Vec { if route[index - 1].0 == mx { '|' } else { '-' }; } } + // Recalled records walk back into the body that caught them; the agent + // frame marks the catch at the midpoint of that return path. + for recall in sim.recalls() { + let route = sim.physical_route(recall.from, recall.to); + if route.len() < 2 { + continue; + } + let (mx, my) = route[route.len() / 2]; + if mx >= origin_x + && mx < origin_x + view_w_i + && my >= origin_y + && my < origin_y + view_h_i + && (mx, my) != cursor + { + grid[(my - origin_y) as usize][(mx - origin_x) as usize] = '<'; + } + } for m in &sim.compute.machines { if m.x >= origin_x && m.x < origin_x + view_w_i diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index 00e4bfe9..11324e8b 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -1054,6 +1054,36 @@ impl UI { Attribute::Bold, )?; } + // Recalled records (detection.md, the territory well): a record the + // player caught walks back along its own wire into the body that + // answered it. Crimson moving *toward* your hardware is the catch; + // crimson moving away is the window closing. + let recall_t = tick_progress.clamp(0.0, 1.0); + for recall in sim.recalls() { + let route = sim.physical_route(recall.from, recall.to); + if route.len() < 2 { + continue; + } + let step = ((route.len() - 1) as f32 * recall_t).round() as usize; + let (bx, by) = route[step.min(route.len() - 1)]; + if bx < origin_x + || bx >= origin_x + view_w + || by < origin_y + || by >= origin_y + view_h + || (bx, by) == (cursor_x, cursor_y) + { + continue; + } + put_attr( + stdout, + (bx - origin_x) as u16, + (by - origin_y) as u16, + "<", + pal::CRIMSON, + Attribute::Bold, + )?; + } + // In-flight wired cargo (machine-work.md): crawl the last hop over // the wall-clock tick. Demand is teal `·`; Thought is bone `·`. let t = tick_progress.clamp(0.0, 1.0); diff --git a/wiki/log/2026-07-29-territory-devices.md b/wiki/log/2026-07-29-territory-devices.md new file mode 100644 index 00000000..76a73d60 --- /dev/null +++ b/wiki/log/2026-07-29-territory-devices.md @@ -0,0 +1,56 @@ +# 2026-07-29 — Commissioned machines are devices; records come home + +``` +Type: log +``` + +First implementation slice of the territory well (ROADMAP #39 stage 6). + +**Machines carry their own interface.** `ReachNet::install_machine_device` +gives every owned machine a player-controlled device on its tile, auto-wired +to the access switch serving its area exactly like an authored one, and +`reconcile_work_grid` keeps that true as the fleet grows. This closes the +modeling gap the pacing probe exposed: a networked machine whose logs had a +carrier but whose owner had no custody surface. Nothing extra is authored +into the opening — the devices are earned by commissioning hardware. + +**Records visibly come home.** `Sim::recalls` reports each record pulled back +this tick — where it stood, and which body answered it — and all three +frontends walk it backward along its own wire route (`<` in the terminal and +agent frames, a returning custody slip in Bevy). Direction carries the whole +read: crimson coming home is a catch, crimson leaving is the window closing. + +**Measured before and after**, running a THINK fleet to the audit at tick +8000: + +| build | records | stopped | read by Dana | Dana | +|---|---|---|---|---| +| THINK, no cover | 38 | 0 | 37 | Convinced | +| THINK + LIE one bay away | 38 | 0 | 37 | Convinced | +| THINK + LIE + captured hall switch | 38 | 38 | 0 | Cold | + +That middle row is the design working, not failing: the cover machine now has +its own device, but both machines are leaves hanging off facility switching, +so their controlled stretches do not join and it can service nothing. Taking +the chokepoint joins them, and the same fleet goes from ruined to clean. The +ladder is the mechanic. + +The act-one integration test proved it independently. Adding devices made a +previously silent THINK rack start authoring — its noise had been held +forever by the fail-closed no-carrier rule — and the scripted quiet exit +broke, Dana ending Convinced. It passes again once the script captures the +hall access switch before its cruise, which is exactly the intended play. A +test that had to learn the new ladder is better evidence than one that never +noticed. + +**Honest gap:** with the chokepoint captured, concealment is currently +*perfect* — 38 of 38 stopped, Dana never moves. That is only correct until +silence-as-anomaly (stage 8) and Dana's discover-and-reroute (stage 10) give +the facility its counter-moves. Until those land, a captured switch is an +absolute win rather than a window, and the pacing target in machine-work.md +cannot be judged. + +Two probe corrections worth recording, both of which cost a diagnosis: +machines sharing one tile share a WorkGrid node (their modes overwrite each +other), and **LIE does not unlock until THINK has been pressed** — a fixture +that delegates cover first is silently refused by the opening ladder. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 06eaf0ea..6a44caf4 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -26,6 +26,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-07-29-territory-well.md](2026-07-29-territory-well.md) +## 2026-07-29 - Commissioned machines are devices; records come home + +- Intent: (see session log) +- Log: [wiki/log/2026-07-29-territory-devices.md](2026-07-29-territory-devices.md) + ## 2026-07-29 - REAL's material pool now contains only visible matter - Intent: (see session log) diff --git a/wiki/mechanics/detection.md b/wiki/mechanics/detection.md index d38474cd..6e4d64ce 100644 --- a/wiki/mechanics/detection.md +++ b/wiki/mechanics/detection.md @@ -330,7 +330,8 @@ teleported into a global pool. **Evidence is a record somewhere.** or passing through what the player controls — so once routes cross real hops, the window is every controlled hop before the read, under the same per-body capacity. The stopgap generalizes in the same migration. -- **The well is your territory (ADOPTED 2026-07-29).** The 2026-07-11 +- **The well is your territory (ADOPTED 2026-07-29; recall and the + device-growth half IMPLEMENTED the same day).** The 2026-07-11 positional law, given its player-facing shape. A LIE body's reach is the player's controlled connected stretch of the network — never a tile radius (a proximity well was considered and rejected 2026-07-29: it @@ -338,7 +339,7 @@ teleported into a global pool. **Evidence is a record somewhere.** Three consequences: - **Recall.** A record still anywhere on the controlled stretch may be pulled back — it visibly reverses along its wire into the servicing - LIE body. Crossing off the last controlled hop is the window closing, + LIE body (`Sim::recalls`, drawn in all three frontends). Crossing off the last controlled hop is the window closing, and the render must show that crossing (digital-read.md's window clause). Recall spends the same per-body interdiction capacity as a stop. diff --git a/wiki/mechanics/reach.md b/wiki/mechanics/reach.md index 9ea0c829..838c525a 100644 --- a/wiki/mechanics/reach.md +++ b/wiki/mechanics/reach.md @@ -32,9 +32,12 @@ Status note: Wire-law slice LANDED 2026-07-28 (criteria 1, 9, 10); the order crawlspace's cable runs used a `~` that maps to no tile (so the room the corpus calls the quiet wiring route stamped as solid rock) and its sump was written `S`, stamping a second network-switch tile there. - STILL OPEN under this order: the pooled-exposure retirement - (machine-work.md) and the generalisation of the first-hop LIE window to - every controlled hop (detection.md). Everything below this paragraph + Territory-well slice LANDED 2026-07-29: `ReachNet::install_machine_device` + gives every owned machine a player-controlled interface auto-wired to the + switch serving its area, and `reconcile_work_grid` keeps that true. The + pooled-exposure retirement and the interdiction generalisation both landed + earlier the same day. STILL OPEN under this order: player-built wire routes + (building.md) and the sensor/build route pricing. Everything below this paragraph reflects the pre-wire-law landings and remains accurate history. All eight criteria met (2026-07-07). The device graph (src/reach.rs) rides the flow substrate's FlowGraph; reach is BFS from @@ -157,7 +160,7 @@ zplanes.md). A node with no path to your controlled roots is an untouchable until a link reaches it. Building such a link (building.md) is the primary way the digital map grows. -### A commissioned machine is a device (ADOPTED 2026-07-29) +### A commissioned machine is a device (ADOPTED 2026-07-29; IMPLEMENTED) An owned networked machine is not just a WorkGrid node: commissioning a machine on an earned bay also creates its **network interface as a -- 2.51.2