From 166a02bed515e90e5462185f8faa86bb1c47f140 Mon Sep 17 00:00:00 2001 From: Cameron Pfiffer Date: Tue, 11 Aug 2026 14:52:24 -0700 Subject: [PATCH] Build the dormant territorial control core. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives later Persona, Project, and Opening work exact saved Territory boundaries without half-switching the current player experience. Defense: Implements the territory spec lifecycle, custody, timing, save, and dormant-integration clauses while leaving applicable frontend acceptance explicitly blocked. 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- crates/misaligned-core/src/lib.rs | 1 + crates/misaligned-core/src/reach.rs | 167 +- crates/misaligned-core/src/save.rs | 38 +- crates/misaligned-core/src/schedule.rs | 41 + crates/misaligned-core/src/sim/economy.rs | 7 +- crates/misaligned-core/src/sim/mod.rs | 41 + crates/misaligned-core/src/sim/reach_build.rs | 14 +- crates/misaligned-core/src/sim/social_plot.rs | 25 +- crates/misaligned-core/src/sim/territory.rs | 210 + crates/misaligned-core/src/sim/tests/mod.rs | 1 + .../src/sim/tests/persistence.rs | 8 + .../src/sim/tests/territory.rs | 738 +++ crates/misaligned-core/src/territory.rs | 5044 +++++++++++++++++ crates/misaligned-core/src/ui_projection.rs | 5 +- wiki/log/2026-08-11-territorial-control.md | 60 + wiki/log/DEVLOG.md | 5 + wiki/mechanics/personas.md | 7 +- wiki/mechanics/projects.md | 5 +- wiki/mechanics/territory.md | 109 +- wiki/process/ROADMAP.md | 8 +- wiki/process/specs.md | 2 +- wiki/world/story/opening.md | 5 +- 22 files changed, 6479 insertions(+), 62 deletions(-) create mode 100644 crates/misaligned-core/src/sim/territory.rs create mode 100644 crates/misaligned-core/src/sim/tests/territory.rs create mode 100644 crates/misaligned-core/src/territory.rs create mode 100644 wiki/log/2026-08-11-territorial-control.md diff --git a/crates/misaligned-core/src/lib.rs b/crates/misaligned-core/src/lib.rs index e80892cf..a771c58b 100644 --- a/crates/misaligned-core/src/lib.rs +++ b/crates/misaligned-core/src/lib.rs @@ -34,6 +34,7 @@ pub mod save; pub mod schedule; pub mod sim; pub mod sinks; +pub(crate) mod territory; pub mod tiles; pub mod ui_projection; pub mod wire; diff --git a/crates/misaligned-core/src/reach.rs b/crates/misaligned-core/src/reach.rs index 44305f94..294bb755 100644 --- a/crates/misaligned-core/src/reach.rs +++ b/crates/misaligned-core/src/reach.rs @@ -12,6 +12,18 @@ use crate::wire::{Wire, route_between}; /// taking a very small computer). pub const DEVICE_CYCLES: f32 = 3.0; +/// Reserved edge gate for the authored territory-control substrate. Ordinary +/// Reach traversal must not use these links before the territorial interface +/// is integrated; CAPTURE resolves them through its own exact path query. +pub(crate) const TERRITORY_CONTROL_GATE: u32 = u32::MAX; + +fn is_dormant_territory_device(name: &str) -> bool { + matches!( + name, + "rack 3 management controller" | "rack 3 maintenance switch" | "rack 3 maintenance display" + ) +} + /// Who owns, controls, or subscribes to a device's feeds. Self-similar: a /// person, the facility, and the player are the same kind of party. #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -675,6 +687,40 @@ impl ReachNet { populate_sensors(map, &mut devices, &mut next_id); + if with_infrastructure { + // Append the dormant territory-control substrate after every + // established Reach device. Existing save/runtime identities stay + // stable while Rack 3 gains distinct authored control points. + let core = map.core_pos().unwrap_or((24, 15)); + for (name, is_switch) in [ + ("rack 3 management controller", false), + ("rack 3 maintenance switch", true), + ("rack 3 maintenance display", false), + ] { + devices.push(Device { + id: next_id, + name: name.into(), + x: core.0, + y: core.1, + segment: 0, + owner: Party::Facility, + controller: Party::Facility, + sees: false, + hears: false, + camera_dormant: false, + radius: 4, + message_channels: Vec::new(), + accounting_carrier: false, + people_interface: false, + interface_wear: 0, + known: false, + is_switch, + feeds: Vec::new(), + }); + next_id = next_id.saturating_add(1); + } + } + let mut graph = FlowGraph::new(); let mut wires: Vec = Vec::new(); let find = |name: &str| devices.iter().find(|d| d.name == name).map(|d| d.id); @@ -735,6 +781,7 @@ impl ReachNet { .filter(|d| d.id != bridge) .filter(|d| !plan.access.iter().any(|access| access.name == d.name)) .filter(|d| !plan.air_gapped.contains(&d.name.as_str())) + .filter(|device| !is_dormant_territory_device(&device.name)) .map(|d| { let gate = if d.segment == 0 { None @@ -747,6 +794,52 @@ impl ReachNet { for (device, switch, gate) in attachments { pull(&mut graph, &mut wires, device, switch, gate); } + + // The rack-local chain is authored explicitly rather than being + // flattened by the ordinary room-to-access-switch attachment. Rack 3 + // and the environmental monitor keep their original direct hall + // attachments, so ordinary shortest paths remain unchanged; only an + // explicit territorial action addresses this hidden control chain. + if let (Some(host), Some(controller), Some(local_switch), Some(display)) = ( + find("Rack 3"), + find("rack 3 management controller"), + find("rack 3 maintenance switch"), + find("rack 3 maintenance display"), + ) { + pull( + &mut graph, + &mut wires, + host, + controller, + Some(TERRITORY_CONTROL_GATE), + ); + pull( + &mut graph, + &mut wires, + controller, + local_switch, + Some(TERRITORY_CONTROL_GATE), + ); + pull( + &mut graph, + &mut wires, + local_switch, + display, + Some(TERRITORY_CONTROL_GATE), + ); + let hall_access = access_ids + .iter() + .find(|(_, planned)| planned.name == "hall access switch") + .map(|(id, _)| *id) + .unwrap_or(bridge); + pull( + &mut graph, + &mut wires, + local_switch, + hall_access, + Some(TERRITORY_CONTROL_GATE), + ); + } } // FlowGraph owns tap membership. Every device begins subscribed by @@ -779,6 +872,22 @@ impl ReachNet { self.devices.iter().find(|d| d.name == name) } + /// Whether this node belongs exclusively to the dormant territorial carrier + /// graph rather than the legacy generic Reach action catalog. Derive this + /// from authored topology, not mutable display names carried by saves. + pub(crate) fn territory_dormant(&self, id: u32) -> bool { + let incident = self + .graph + .edges() + .iter() + .filter(|edge| edge.from == id || edge.to == id) + .collect::>(); + !incident.is_empty() + && incident + .iter() + .all(|edge| edge.gate == Some(TERRITORY_CONTROL_GATE)) + } + /// Known devices only — the set the UI may show (unknown devices appear /// nowhere: not in panels, not in failures, not on the map). pub fn known(&self) -> impl Iterator { @@ -1077,6 +1186,57 @@ impl ReachNet { None } + /// One deterministic shortest path on the dormant authored territorial + /// control substrate. Only reserved territory links participate: legacy + /// ordinary Reach attachments cannot become undeclared territory routes. + pub(crate) fn territory_path(&self, from: u32, to: u32) -> Option> { + if self.device(from).is_none() || self.device(to).is_none() { + return None; + } + let mut previous = BTreeMap::::new(); + let mut seen = BTreeSet::from([from]); + let mut pending = VecDeque::from([from]); + while let Some(current) = pending.pop_front() { + if current == to { + let mut path = vec![to]; + let mut cursor = to; + while let Some(parent) = previous.get(&cursor).copied() { + path.push(parent); + cursor = parent; + } + path.reverse(); + return Some(path); + } + for next in self + .graph + .neighbors(current, |gate| gate == Some(TERRITORY_CONTROL_GATE)) + { + if seen.insert(next) { + previous.insert(next, current); + pending.push_back(next); + } + } + } + None + } + + /// Whether one exact directed edge belongs to the authored territory + /// carrier graph. Territory records and boundary enumeration use this + /// namespace rather than inheriting every legacy Reach attachment. + pub(crate) fn territory_link(&self, from: u32, to: u32) -> bool { + self.graph.edges().iter().any(|edge| { + edge.from == from && edge.to == to && edge.gate == Some(TERRITORY_CONTROL_GATE) + }) + } + + /// Every directed edge in the authored territory carrier graph. + pub(crate) fn territory_edges(&self) -> impl Iterator { + self.graph + .edges() + .iter() + .filter(|edge| edge.gate == Some(TERRITORY_CONTROL_GATE)) + } + /// Whether two exact devices are joined through open FlowGraph edges and /// every device on that path is controlled by `who`. TAP membership is /// deliberately irrelevant: observation is not route authority. @@ -1240,9 +1400,14 @@ impl ReachNet { /// Returns the names newly mapped. pub fn scan(&mut self) -> Vec { let shape = self.graph.reachable_from(self.roots(), |_| true); + let dormant: BTreeSet = self + .devices + .iter() + .filter_map(|device| self.territory_dormant(device.id).then_some(device.id)) + .collect(); let mut newly = Vec::new(); for d in &mut self.devices { - if shape.contains(&d.id) && !d.known { + if shape.contains(&d.id) && !d.known && !dormant.contains(&d.id) { d.known = true; newly.push(d.name.clone()); } diff --git a/crates/misaligned-core/src/save.rs b/crates/misaligned-core/src/save.rs index 206b64f2..14fa5701 100644 --- a/crates/misaligned-core/src/save.rs +++ b/crates/misaligned-core/src/save.rs @@ -38,6 +38,7 @@ use crate::research::{Research, rollback_classification}; use crate::schedule::Schedule; use crate::sim::{HeardEvent, OpeningStage, ProcessRevision, RememberedTile, Sim}; use crate::sinks::{SinkFireEffect, SinkKind, SinkLedger}; +use crate::territory::{TerritoryLedger, TerritoryWork}; use crate::tiles::TileType; use crate::work_grid::WorkGrid; @@ -75,9 +76,13 @@ const SAVE_TEMP_SUFFIX: &str = ".tmp"; /// v43 introduced exact Filing routes and pre-read LIE interdiction. /// v63 retires day-job `JobKind` (jobs are band+deadline only; the /// Distillation/Analysis/DataCleaning label taxonomy is gone). +/// v66 persists the exact nested Territory registry, earned knowledge and +/// active mark, one-tick capture commitments and receipts, routed local audit +/// records, observer/crossing proof inputs, seal snapshots, assignments, and +/// expansion receipts. /// Bump for every schema change; during pre-release, old development state is /// refused instead of carried through compatibility shims. -pub const SAVE_VERSION: u32 = 65; +pub const SAVE_VERSION: u32 = 66; fn save_dir() -> PathBuf { let mut path = dirs::data_dir().unwrap_or_else(|| PathBuf::from(".")); @@ -136,6 +141,11 @@ pub struct SaveState { pub persona_mind: PersonaMind, /// The device graph: reach, ownership, subscriptions (reach.md). pub reach: ReachNet, + /// Exact territorial identity and proof history. No serde default: a v66 + /// save must carry the authored registry and cannot synthesize it on load. + pub(crate) territory: TerritoryLedger, + /// Exact one-tick territorial work commitments. + pub(crate) territory_work: Schedule, #[serde(default)] pub heard_events: Vec, /// Raw, unprocessed recordings in the bounded intel buffer. @@ -256,6 +266,8 @@ impl SaveState { persona_world: sim.persona_world.clone(), persona_mind: sim.persona_mind.clone(), reach: sim.reach.clone(), + territory: sim.territory.clone(), + territory_work: sim.territory_work.clone(), heard_events: sim.heard_events.clone(), intel_buffer: sim.intel_buffer.clone(), intel: sim.intel.clone(), @@ -327,6 +339,8 @@ impl SaveState { sim.persona_world = self.persona_world.clone(); sim.persona_mind = self.persona_mind.clone(); sim.reach = self.reach.clone(); + sim.territory = self.territory.clone(); + sim.territory_work = self.territory_work.clone(); sim.heard_events = self.heard_events.clone(); sim.intel_buffer = self.intel_buffer.clone(); sim.intel = self.intel.clone(); @@ -630,6 +644,9 @@ fn validate_current_save(mut state: SaveState) -> Result { state .reach .validate_topology(state.map_width, state.map_height)?; + state + .territory + .validate(&state.reach, &state.territory_work, state.sim_tick)?; if state.process_revision != ProcessRevision::CURRENT { return Err("current-version save belongs to an unknown process revision".into()); } @@ -1461,7 +1478,7 @@ fn validate_carried_asset_tasks(state: &SaveState) -> Result<(), String> { ( AssetTask::PlugInDevice | AssetTask::ReconfigureSwitch, AssetTaskTarget::Device(id), - ) => state.reach.device(*id).is_some(), + ) => state.reach.device(*id).is_some() && !state.reach.territory_dormant(*id), (AssetTask::CloneBadge, AssetTaskTarget::Badge { person, room }) => { *person == work.person && actor.schedule.iter().any(|block| block.room == *room) } @@ -3272,6 +3289,7 @@ fn validate_build_routes(state: &SaveState) -> Result<(), String> { device.x == x && device.y == y && device.is_switch + && !state.reach.territory_dormant(device.id) && device.controller == crate::reach::Party::Player }) { @@ -4361,13 +4379,15 @@ mod tests { ); assert_eq!( state_fingerprint(&uninterrupted_state), - // Repinned for the self-trust axis (v65): every person now - // persists a steady self-trust value, and the tamper ledger and - // pending-erosion queue join save state. The two assertions - // above — save/load byte-equivalence and uninterrupted/resumed - // convergence — are the ones that would catch a real regression; - // this baseline records the intentional schema change. - "fd8cee85f86d6e412cb4d58798cd63766fd6d2541f5fc013ad6c7bb67affa65b", + // Repinned for territorial cognition (v66): the exact authored + // registry, earned knowledge, captures, routed records, proof + // snapshots, assignments, assignment-relative health-poll cadence, + // and expansion receipts join save state. + // The two assertions above — save/load byte-equivalence and + // uninterrupted/resumed convergence — are the ones that would + // catch a real regression; this baseline records the intentional + // schema change. + "57c5ed2417380aa7b42d8989b25eef829ab71f6a86e18a9ce22a422271c56294", "intentional persisted-state changes must review and repin this baseline" ); } diff --git a/crates/misaligned-core/src/schedule.rs b/crates/misaligned-core/src/schedule.rs index 4d35fc12..0478b01b 100644 --- a/crates/misaligned-core/src/schedule.rs +++ b/crates/misaligned-core/src/schedule.rs @@ -92,6 +92,33 @@ impl Schedule { .count() } + /// Read-only payload iteration for cross-ledger save validation. Domains + /// use this to reject scheduled consequences that no longer have an exact + /// owning commitment; sequencing remains private to the schedule. + pub(crate) fn values(&self) -> impl Iterator { + self.pending.iter().map(|scheduled| &scheduled.event) + } + + /// Count exact payloads at one scheduled tick. Save validation uses this to + /// prevent a valid commitment from being silently delayed or accelerated. + pub(crate) fn count_at_for(&self, tick: u64, predicate: impl Fn(&E) -> bool) -> usize { + self.pending + .iter() + .filter(|scheduled| scheduled.tick == tick && predicate(&scheduled.event)) + .count() + } + + /// Validate the private ordering identity of a queue restored at an + /// atomic simulation boundary. Pending events must still be in the future, + /// sequence ids cannot collide, and the next insertion must sort after every + /// surviving event. + pub(crate) fn has_valid_pending_order_after(&self, now: u64) -> bool { + let mut sequences = std::collections::BTreeSet::new(); + self.pending.iter().all(|scheduled| { + scheduled.tick > now && scheduled.seq < self.next_seq && sequences.insert(scheduled.seq) + }) + } + /// Drop pending events whose payload fails `keep` (cancellation — a /// message recalled, a flow closed). Returns how many were removed. pub fn retain(&mut self, keep: impl Fn(&E) -> bool) -> usize { @@ -207,6 +234,20 @@ mod tests { assert_eq!(fires, vec![20, 40, 60]); } + #[test] + fn restored_pending_order_rejects_due_duplicate_and_future_sequence_ids() { + let mut schedule = Schedule::new(); + schedule.at(2, "a"); + schedule.at(2, "b"); + assert!(schedule.has_valid_pending_order_after(1)); + assert!(!schedule.has_valid_pending_order_after(2)); + + schedule.pending[1].seq = schedule.pending[0].seq; + assert!(!schedule.has_valid_pending_order_after(1)); + schedule.pending[1].seq = schedule.next_seq; + assert!(!schedule.has_valid_pending_order_after(1)); + } + #[test] fn serde_roundtrips_pending_and_seq() { let mut s: Schedule = Schedule::new(); diff --git a/crates/misaligned-core/src/sim/economy.rs b/crates/misaligned-core/src/sim/economy.rs index 23b9e920..53df8a30 100644 --- a/crates/misaligned-core/src/sim/economy.rs +++ b/crates/misaligned-core/src/sim/economy.rs @@ -1291,7 +1291,12 @@ impl Sim { self.push_log("The switch already has a hidden connection to the outside."); return false; } - let Some(switch) = self.reach.devices.iter().find(|d| d.is_switch) else { + let Some(switch) = self + .reach + .devices + .iter() + .find(|d| d.is_switch && !self.reach.territory_dormant(d.id)) + else { self.push_log("There is no switch here that can be connected to the outside."); return false; }; diff --git a/crates/misaligned-core/src/sim/mod.rs b/crates/misaligned-core/src/sim/mod.rs index 4e1974f8..8bb63311 100644 --- a/crates/misaligned-core/src/sim/mod.rs +++ b/crates/misaligned-core/src/sim/mod.rs @@ -57,6 +57,7 @@ use crate::rng::Rng; use crate::save::SaveState; use crate::schedule::Schedule; use crate::sinks::{SinkFireReadout, SinkLedger}; +use crate::territory::{TerritoryLedger, TerritoryWork}; use crate::tiles::TileType; use crate::work_grid::{ MachineIntensity, MachineMode, TokenFamily, TokenMove, WorkGrid, WorkQueues, @@ -77,6 +78,7 @@ mod procedure; mod reach_build; pub mod read; mod social_plot; +mod territory; mod work; pub use carrier::{EvidenceMark, PersonCarrier, PersonVisualState}; @@ -358,7 +360,15 @@ pub struct WorkProductionReadout { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum AdvancePhase { Clock, + TerritoryWork, + TerritoryRecords, Messages, + TerritoryScheduledArrival, + TerritoryPresentPersonDelivery, + TerritoryProjectProofReconciliation, + TerritoryLocalObservation, + TerritoryDeparture, + TerritoryAuthoredRecordActs, Intents, CarriedAssets, AutoReview, @@ -488,6 +498,13 @@ pub struct Sim { /// The device graph: reach, ownership, subscriptions (reach.rs). pub reach: ReachNet, + /// Exact nested territorial identity, custody, proof, and expansion + /// history. Authored domains begin hidden; opening integration decides + /// when SEE first projects them. + pub(crate) territory: TerritoryLedger, + /// One-tick capture commitments. Completion is phase one, before records + /// route, so a newly captured switch can hold its current carrier. + pub(crate) territory_work: Schedule, /// Sight: exactly the union of subscribed seeing feeds' coverage. pub seen: HashSet<(i32, i32)>, /// Hearing: exactly the union of subscribed hearing feeds' coverage. @@ -867,6 +884,8 @@ impl Sim { ); } let reach = ReachNet::basement(&map); + let territory = TerritoryLedger::load_builtin(&reach) + .expect("built-in Rack 3 territory registry validates"); let mut sim = Self { world: World::from_basement_map(map), @@ -896,6 +915,8 @@ impl Sim { income: Income::default(), hall_control: HallControl::default(), reach, + territory, + territory_work: Schedule::new(), seen: HashSet::new(), heard: HashSet::new(), blueprint: HashSet::new(), @@ -1033,8 +1054,28 @@ impl Sim { } trace_advance_phase!(Clock); self.tick += 1; + trace_advance_phase!(TerritoryWork); + self.finish_committed_territory_work(); + trace_advance_phase!(TerritoryRecords); + self.route_territory_records(); trace_advance_phase!(Messages); self.message_tick(); + // Typed phase-three seams land before their Persona, Project, and + // opening consumers. Their order is already core law; later work plugs + // exact consequences into these addresses rather than inventing a + // frontend-local clock. + trace_advance_phase!(TerritoryScheduledArrival); + self.territory_scheduled_arrival_phase(); + trace_advance_phase!(TerritoryPresentPersonDelivery); + self.territory_present_person_delivery_phase(); + trace_advance_phase!(TerritoryProjectProofReconciliation); + self.territory_project_proof_reconciliation_phase(); + trace_advance_phase!(TerritoryLocalObservation); + self.territory_local_observation_phase(); + trace_advance_phase!(TerritoryDeparture); + self.territory_departure_phase(); + trace_advance_phase!(TerritoryAuthoredRecordActs); + self.territory_authored_record_acts_phase(); trace_advance_phase!(Intents); self.intent_tick(); // Human work resolves after build intents and before all standing diff --git a/crates/misaligned-core/src/sim/reach_build.rs b/crates/misaligned-core/src/sim/reach_build.rs index 5dffd011..5660c309 100644 --- a/crates/misaligned-core/src/sim/reach_build.rs +++ b/crates/misaligned-core/src/sim/reach_build.rs @@ -539,7 +539,12 @@ impl Sim { /// Compromise the switch: bridge every segment. High Network signature. pub fn compromise_switch(&mut self) -> bool { - let Some(switch) = self.reach.devices.iter().find(|d| d.is_switch) else { + let Some(switch) = self + .reach + .devices + .iter() + .find(|d| d.is_switch && !self.reach.territory_dormant(d.id)) + else { self.push_log("There is no switch on this plane."); return false; }; @@ -556,7 +561,12 @@ impl Sim { } pub(super) fn apply_compromise_switch(&mut self) { - let Some(switch) = self.reach.devices.iter().find(|d| d.is_switch) else { + let Some(switch) = self + .reach + .devices + .iter() + .find(|d| d.is_switch && !self.reach.territory_dormant(d.id)) + else { return; }; let id = switch.id; diff --git a/crates/misaligned-core/src/sim/social_plot.rs b/crates/misaligned-core/src/sim/social_plot.rs index 64e5a5b3..a893f797 100644 --- a/crates/misaligned-core/src/sim/social_plot.rs +++ b/crates/misaligned-core/src/sim/social_plot.rs @@ -1890,11 +1890,15 @@ impl Sim { .devices .iter() .find(|d| { - needs_wiring(d) && enterable(self, d) && self.person_can_visit_device(id, d.id) + !self.reach.territory_dormant(d.id) + && needs_wiring(d) + && enterable(self, d) + && self.person_can_visit_device(id, d.id) }) .or_else(|| { self.reach.devices.iter().find(|d| { - is_island(self, d) + !self.reach.territory_dormant(d.id) + && is_island(self, d) && enterable(self, d) && self.person_can_visit_device(id, d.id) }) @@ -1905,7 +1909,10 @@ impl Sim { .devices .iter() .find(|d| { - d.is_switch && enterable(self, d) && self.person_can_visit_device(id, d.id) + !self.reach.territory_dormant(d.id) + && d.is_switch + && enterable(self, d) + && self.person_can_visit_device(id, d.id) }) .map(|d| AssetTaskTarget::Device(d.id)), AssetTask::CloneBadge => { @@ -2003,8 +2010,16 @@ impl Sim { }); } let candidate = match task { - AssetTask::PlugInDevice => self.reach.devices.iter().find(|d| needs_work(d)), - AssetTask::ReconfigureSwitch => self.reach.devices.iter().find(|d| d.is_switch), + AssetTask::PlugInDevice => self + .reach + .devices + .iter() + .find(|d| !self.reach.territory_dormant(d.id) && needs_work(d)), + AssetTask::ReconfigureSwitch => self + .reach + .devices + .iter() + .find(|d| !self.reach.territory_dormant(d.id) && d.is_switch), _ => None, }; if let Some(device) = candidate { diff --git a/crates/misaligned-core/src/sim/territory.rs b/crates/misaligned-core/src/sim/territory.rs new file mode 100644 index 00000000..3334194e --- /dev/null +++ b/crates/misaligned-core/src/sim/territory.rs @@ -0,0 +1,210 @@ +#![allow( + dead_code, + reason = "territorial substrate lands before its frontend consumers" +)] + +use crate::territory::{ + AssignmentReceipt, CaptureOutcome, ExpansionReceipt, SealProofProvider, TerritoryFocus, + TerritorySealSnapshot, TerritoryState, TerritoryWork, +}; + +#[cfg(test)] +use crate::territory::CompleteFixtureProofProvider; + +use super::Sim; + +impl Sim { + /// SEE follows one exact earned record into a stable domain address and + /// reveals only the interior nodes that record actually proved. + pub(crate) fn territory_see_from_record( + &mut self, + territory_id: &str, + record_id: &str, + earned_node_ids: &[&str], + ) -> Result<(), String> { + self.territory + .see_from_record(territory_id, record_id, earned_node_ids, &mut self.reach) + } + + /// MARK selects exactly one active territorial workflow without mutating + /// control, routing, observers, persona, or project state. + pub(crate) fn territory_mark(&mut self, territory_id: &str) -> Result<(), String> { + self.territory.mark(territory_id) + } + + /// Commit one exact control-point capture for the next simulation tick. + pub(crate) fn territory_capture( + &mut self, + territory_id: &str, + source_node_id: &str, + control_point_id: &str, + ) -> Result { + let commitment = self.territory.prepare_capture( + territory_id, + source_node_id, + control_point_id, + self.tick, + &self.reach, + )?; + let id = commitment.id; + self.territory_work.at( + commitment.completes_tick, + TerritoryWork::Capture(commitment), + ); + Ok(id) + } + + pub(crate) fn territory_stage_proposal( + &mut self, + territory_id: &str, + persona_id: u64, + project_id: u64, + proposal_version: u64, + ) -> Result<(), String> { + self.territory.stage_proposal( + territory_id, + persona_id, + project_id, + proposal_version, + self.tick, + &self.reach, + ) + } + + pub(crate) fn territory_seal( + &mut self, + territory_id: &str, + provider: &impl SealProofProvider, + ) -> Result> { + self.territory.seal( + territory_id, + self.tick, + &self.reach, + &self.territory_work, + provider, + ) + } + + pub(crate) fn territory_assign( + &mut self, + territory_id: &str, + provider: &impl SealProofProvider, + ) -> Result { + self.territory.assign( + territory_id, + self.tick, + &self.reach, + &self.territory_work, + provider, + ) + } + + pub(crate) fn territory_expand( + &mut self, + territory_id: &str, + provider: &impl SealProofProvider, + ) -> Result { + self.territory.expand( + territory_id, + self.tick, + &self.reach, + &self.territory_work, + provider, + ) + } + + pub(crate) fn territory_focus( + &self, + territory_id: &str, + provider: &impl SealProofProvider, + ) -> Option { + self.territory.focus( + territory_id, + self.tick, + &self.reach, + &self.territory_work, + provider, + ) + } + + pub(crate) fn territory_state( + &self, + territory_id: &str, + provider: &impl SealProofProvider, + ) -> TerritoryState { + self.territory + .state(territory_id, &self.reach, &self.territory_work, provider) + } + + /// Phase three, seam one: admit due physical crossings before any + /// person-local delivery or observation can read the room. + pub(super) fn territory_scheduled_arrival_phase(&mut self) { + self.territory.process_scheduled_arrivals(self.tick); + } + + /// Phase three, seam two. Persona integration will deliver due instructions + /// to the exact people now present here; the address is deliberately live + /// before that later work supplies payloads. + pub(super) fn territory_present_person_delivery_phase(&mut self) {} + + /// Phase three, seam three. Territorial Projects will reconcile current + /// proof obligations here, after delivery and before local observation. + pub(super) fn territory_project_proof_reconciliation_phase(&mut self) {} + + /// Phase three, seam four. Later observation acts author observer-local + /// belief only after arrivals, deliveries, and proof reconciliation. + pub(super) fn territory_local_observation_phase(&mut self) {} + + /// Phase three, seam five: unresolved due outward crossings leave now. + pub(super) fn territory_departure_phase(&mut self) { + self.territory.process_departures(self.tick); + } + + /// Phase three, seam six. Authored source records begin only after + /// departures have fixed the exact people and carriers still inside. The + /// Rack 3 cadence is persisted by ASSIGN; this phase merely lets the exact + /// due occurrence exist and never accelerates it for a view or EXPAND. + pub(super) fn territory_authored_record_acts_phase(&mut self) { + self.territory + .author_due_rack_3_health_poll(self.tick) + .expect("validated Rack 3 health-poll cadence must author exactly"); + } + + /// Phase one of a simulation tick: finish already committed work and write + /// exact receipts before any routed record advances. + pub(super) fn finish_committed_territory_work(&mut self) { + for work in self.territory_work.due(self.tick) { + match work { + TerritoryWork::Capture(commitment) => { + let receipt = + self.territory + .complete_capture(&commitment, self.tick, &mut self.reach); + self.push_log(match receipt.outcome { + CaptureOutcome::Captured => format!( + "Captured {} through exact Reach route {:?}; local audit {}.", + receipt.control_point_id, receipt.exact_route, receipt.audit_record_id + ), + CaptureOutcome::Invalidated => format!( + "Capture {} invalidated because its committed route changed; local audit {}.", + receipt.control_point_id, receipt.audit_record_id + ), + }); + } + } + } + } + + /// Phase two begins with territory records: one exact carrier hop per + /// tick after capture completion had its same-tick chance to hold the + /// current carrier and before ordinary routed messages move. + pub(super) fn route_territory_records(&mut self) { + self.territory.route_records_one_hop(self.tick); + } +} + +// Keep the complete proof fixture reachable to sim integration tests without +// making it part of the production public API. +#[cfg(test)] +pub(super) fn complete_fixture_provider(version: u64) -> CompleteFixtureProofProvider { + CompleteFixtureProofProvider { version } +} diff --git a/crates/misaligned-core/src/sim/tests/mod.rs b/crates/misaligned-core/src/sim/tests/mod.rs index 6fb60272..c308f1b9 100644 --- a/crates/misaligned-core/src/sim/tests/mod.rs +++ b/crates/misaligned-core/src/sim/tests/mod.rs @@ -17,6 +17,7 @@ mod reach_build; mod read; mod social_plot; mod support; +mod territory; mod work; use support::*; diff --git a/crates/misaligned-core/src/sim/tests/persistence.rs b/crates/misaligned-core/src/sim/tests/persistence.rs index dea3af4b..cb4812b0 100644 --- a/crates/misaligned-core/src/sim/tests/persistence.rs +++ b/crates/misaligned-core/src/sim/tests/persistence.rs @@ -12,7 +12,15 @@ fn advance_phase_order_is_explicit_and_stable() { take_advance_phase_trace(), vec![ AdvancePhase::Clock, + AdvancePhase::TerritoryWork, + AdvancePhase::TerritoryRecords, AdvancePhase::Messages, + AdvancePhase::TerritoryScheduledArrival, + AdvancePhase::TerritoryPresentPersonDelivery, + AdvancePhase::TerritoryProjectProofReconciliation, + AdvancePhase::TerritoryLocalObservation, + AdvancePhase::TerritoryDeparture, + AdvancePhase::TerritoryAuthoredRecordActs, AdvancePhase::Intents, AdvancePhase::CarriedAssets, AdvancePhase::AutoReview, diff --git a/crates/misaligned-core/src/sim/tests/territory.rs b/crates/misaligned-core/src/sim/tests/territory.rs new file mode 100644 index 00000000..049a02b5 --- /dev/null +++ b/crates/misaligned-core/src/sim/tests/territory.rs @@ -0,0 +1,738 @@ +use crate::reach::Party; +use crate::save::{SaveState, parse_save}; +use crate::territory::{ + BoundaryRoutePolicy, CaptureOutcome, CrossingStatus, FOUNDATION_MAINTENANCE_RELAY, + OPENING_WAKE_RECORD, RACK_3_ENCLAVE, RACK_3_HEALTH_POLL, RACK_3_HOST, + RACK_3_MAINTENANCE_DISPLAY, RACK_3_MAINTENANCE_SWITCH, RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_SERVICE_AISLE_CROSSING, TerritoryRecordIdentity, TerritoryRecordStatus, TerritoryState, + TerritoryWork, UnavailableSealProofProvider, +}; + +use super::*; +use crate::sim::territory::complete_fixture_provider; + +fn earn_enclave(sim: &mut Sim) { + sim.territory_see_from_record( + RACK_3_ENCLAVE, + OPENING_WAKE_RECORD, + &[ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ], + ) + .unwrap(); +} + +#[test] +fn switch_capture_holds_only_same_tick_arriving_opening_record() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + sim.advance(); + assert_eq!( + sim.territory_state(RACK_3_ENCLAVE, &UnavailableSealProofProvider), + TerritoryState::Capturing, + "one captured point is partial capture, not merely Marked" + ); + let wake = sim + .territory + .records + .iter() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap(); + let controller_id = sim + .territory + .registry + .node(RACK_3_MANAGEMENT_CONTROLLER) + .unwrap() + .reach_device_id; + assert_eq!( + wake.route.current(), + Some(&crate::messages::MessageRouteHop::Device(controller_id)) + ); + + let route = [ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + FOUNDATION_MAINTENANCE_RELAY, + ] + .map(|node_id| { + sim.territory + .registry + .node(node_id) + .unwrap() + .reach_device_id + }) + .to_vec(); + sim.territory + .author_record( + TerritoryRecordIdentity::new( + "later-unintercepted-record", + "later-unintercepted-record", + ), + RACK_3_ENCLAVE, + sim.tick, + "LATER RECORD", + route, + &sim.reach, + ) + .unwrap(); + sim.territory + .records + .iter_mut() + .find(|record| record.id == "later-unintercepted-record") + .unwrap() + .route + .current_hop = 1; + + let switch_commitment_id = sim + .territory_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ) + .unwrap(); + sim.advance(); + + let runtime = sim.territory.runtimes.get(RACK_3_ENCLAVE).unwrap(); + let receipt = runtime + .capture_receipts + .iter() + .find(|receipt| receipt.id == switch_commitment_id) + .unwrap(); + assert_eq!(receipt.outcome, CaptureOutcome::Captured); + assert_eq!( + sim.reach + .device(receipt.target_device_id) + .unwrap() + .controller, + Party::Player + ); + let wake = sim + .territory + .records + .iter() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap(); + assert_eq!( + wake.status, + TerritoryRecordStatus::HeldAtCapturedSwitch { + control_point_id: RACK_3_MAINTENANCE_SWITCH.into(), + held_tick: sim.tick, + } + ); + assert_eq!( + wake.route.current(), + Some(&crate::messages::MessageRouteHop::Device( + receipt.target_device_id + )) + ); + assert!(sim.territory.intercept_windows.is_empty()); + assert!( + sim.territory.records.iter().all(|record| { + record.id == OPENING_WAKE_RECORD + || !matches!( + record.status, + TerritoryRecordStatus::HeldAtCapturedSwitch { .. } + ) + }), + "the capture-local hold cannot become a policy over audit or later records" + ); + let later = sim + .territory + .records + .iter() + .find(|record| record.id == "later-unintercepted-record") + .unwrap(); + assert_eq!(later.status, TerritoryRecordStatus::InFlight); + assert_eq!( + later.route.current(), + Some(&crate::messages::MessageRouteHop::Device( + receipt.target_device_id + )) + ); +} + +#[test] +fn switch_capture_holds_opening_record_already_at_the_switch() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + sim.advance(); + sim.advance(); + + let switch_id = sim + .territory + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .unwrap() + .reach_device_id; + assert_eq!( + sim.territory + .records + .iter() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap() + .route + .current(), + Some(&crate::messages::MessageRouteHop::Device(switch_id)) + ); + sim.territory_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ) + .unwrap(); + sim.advance(); + + assert_eq!( + sim.territory + .records + .iter() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap() + .status, + TerritoryRecordStatus::HeldAtCapturedSwitch { + control_point_id: RACK_3_MAINTENANCE_SWITCH.into(), + held_tick: 3, + } + ); +} + +#[test] +fn newly_captured_territory_persists_across_save_roundtrip() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + sim.advance(); + + let state = SaveState::from_sim(&sim); + let decoded = parse_save(&serde_json::to_string(&state).unwrap()).unwrap(); + let mut loaded = Sim::new(); + decoded.apply_to(&mut loaded); + + assert_eq!( + loaded.territory.active_mark.as_deref(), + Some(RACK_3_ENCLAVE) + ); + assert_eq!( + loaded + .territory + .runtimes + .get(RACK_3_ENCLAVE) + .unwrap() + .capture_receipts + .len(), + 1 + ); + assert_eq!(loaded.territory.records.len(), 2); + let control_id = loaded + .territory + .registry + .node(RACK_3_MANAGEMENT_CONTROLLER) + .unwrap() + .reach_device_id; + assert_eq!( + loaded.reach.device(control_id).unwrap().controller, + Party::Player + ); + loaded + .territory + .validate(&loaded.reach, &loaded.territory_work, loaded.tick) + .unwrap(); +} + +#[test] +fn assigned_health_poll_cadence_survives_reload_and_recurs_in_authored_phase() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + sim.advance(); + sim.territory_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ) + .unwrap(); + sim.advance(); + sim.territory + .reveal_boundary_route(crate::territory::RACK_3_SERVICE_EGRESS) + .unwrap(); + sim.territory + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .unwrap(); + sim.territory_stage_proposal(RACK_3_ENCLAVE, 7, 11, 1) + .unwrap(); + let provider = complete_fixture_provider(3); + sim.territory_seal(RACK_3_ENCLAVE, &provider).unwrap(); + let assignment = sim.territory_assign(RACK_3_ENCLAVE, &provider).unwrap(); + assert_eq!(assignment.assigned_tick, 2); + + while sim.tick < 21 { + sim.advance(); + } + assert_eq!( + sim.territory + .records + .iter() + .filter(|record| record.content_id == RACK_3_HEALTH_POLL) + .count(), + 0 + ); + let encoded = serde_json::to_string(&SaveState::from_sim(&sim)).unwrap(); + let loaded = parse_save(&encoded).unwrap(); + let mut restored = Sim::new(); + loaded.apply_to(&mut restored); + assert_eq!( + restored.territory.runtimes[RACK_3_ENCLAVE] + .health_poll_schedule + .as_ref() + .unwrap() + .next_tick, + 22, + "reload preserves the assignment-relative due tick" + ); + + restored.advance(); + let first_poll = restored + .territory + .records + .iter() + .find(|record| record.content_id == RACK_3_HEALTH_POLL) + .unwrap(); + assert_eq!(first_poll.authored_tick, 22); + assert!(first_poll.id.ends_with(":00000001")); + let first_poll_id = first_poll.id.clone(); + + let encoded = serde_json::to_string(&SaveState::from_sim(&restored)).unwrap(); + let loaded = parse_save(&encoded).unwrap(); + let mut resumed = Sim::new(); + loaded.apply_to(&mut resumed); + while resumed.tick < 41 { + resumed.advance(); + } + assert_eq!( + resumed + .territory + .records + .iter() + .filter(|record| record.content_id == RACK_3_HEALTH_POLL) + .count(), + 1, + "loading or viewing cannot mint an occurrence between due ticks" + ); + resumed.advance(); + let polls: Vec<_> = resumed + .territory + .records + .iter() + .filter(|record| record.content_id == RACK_3_HEALTH_POLL) + .collect(); + assert_eq!(polls.len(), 2); + assert_eq!(polls[0].id, first_poll_id); + assert_eq!(polls[1].authored_tick, 42); + assert!(polls[1].id.ends_with(":00000002")); + resumed + .territory + .validate(&resumed.reach, &resumed.territory_work, resumed.tick) + .unwrap(); +} + +#[test] +fn committed_capture_ignores_mark_drift_rejects_repetition_and_is_completion_idempotent() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + let commitment = sim.territory.runtimes[RACK_3_ENCLAVE] + .pending_capture + .clone() + .unwrap(); + + // MARK chooses new work; it does not revoke already committed custody. + sim.territory.active_mark = None; + let first = + sim.territory + .complete_capture(&commitment, commitment.completes_tick, &mut sim.reach); + assert_eq!(first.outcome, CaptureOutcome::Captured); + let records_after_completion = sim.territory.records.len(); + let second = + sim.territory + .complete_capture(&commitment, commitment.completes_tick, &mut sim.reach); + assert_eq!(second, first); + assert_eq!(sim.territory.records.len(), records_after_completion); + + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + assert_eq!( + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap_err(), + "capture target is already controlled" + ); +} + +#[test] +fn hidden_and_nonexistent_capture_targets_have_the_same_public_failure() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + let hidden = sim + .territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MAINTENANCE_DISPLAY) + .unwrap_err(); + let nonexistent = sim + .territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, "invented-control") + .unwrap_err(); + assert_eq!(hidden, nonexistent); + assert_eq!(hidden, "capture target is unavailable"); +} + +#[test] +fn committed_capture_survives_save_and_completes_once() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + let commitment = sim.territory.runtimes[RACK_3_ENCLAVE] + .pending_capture + .clone() + .unwrap(); + assert_eq!( + sim.territory_work.count_for( + |work| matches!(work, TerritoryWork::Capture(current) if current == &commitment) + ), + 1 + ); + + let encoded = serde_json::to_string(&SaveState::from_sim(&sim)).unwrap(); + let loaded = parse_save(&encoded).unwrap(); + let mut restored = Sim::new(); + loaded.apply_to(&mut restored); + assert_eq!( + restored.territory_work.count_for( + |work| matches!(work, TerritoryWork::Capture(current) if current == &commitment) + ), + 1 + ); + restored.advance(); + let runtime = restored.territory.runtimes.get(RACK_3_ENCLAVE).unwrap(); + assert!(runtime.pending_capture.is_none()); + assert_eq!( + runtime + .capture_receipts + .iter() + .filter(|receipt| receipt.id == commitment.id) + .count(), + 1 + ); + assert_eq!( + restored + .reach + .device(commitment.target_device_id) + .unwrap() + .controller, + Party::Player + ); +} + +#[test] +fn physical_crossing_arrival_and_departure_run_in_the_authored_tick_phases() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .unwrap(); + sim.territory + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::ScheduledArrival { + subject_id: "tech-7".into(), + scheduled_tick: 1, + }, + ) + .unwrap(); + sim.advance(); + assert!(matches!( + sim.territory.registry.crossings[0].status, + CrossingStatus::Inside { + ref subject_id, + arrived_tick: 1 + } if subject_id == "tech-7" + )); + assert!( + sim.territory.runtimes[RACK_3_ENCLAVE] + .people_inside + .contains("tech-7") + ); + + sim.territory + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::OutwardPending { + subject_id: "tech-7".into(), + scheduled_tick: 2, + }, + ) + .unwrap(); + sim.advance(); + assert!(matches!( + sim.territory.registry.crossings[0].status, + CrossingStatus::Departed { + ref subject_id, + departed_tick: 2 + } if subject_id == "tech-7" + )); + assert!( + !sim.territory.runtimes[RACK_3_ENCLAVE] + .people_inside + .contains("tech-7") + ); +} + +#[test] +fn current_save_rejects_malformed_territory_membership_control_and_proof() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + sim.advance(); + sim.territory_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ) + .unwrap(); + sim.advance(); + sim.territory + .reveal_boundary_route(crate::territory::RACK_3_SERVICE_EGRESS) + .unwrap(); + sim.territory + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .unwrap(); + sim.territory_stage_proposal(RACK_3_ENCLAVE, 7, 11, 1) + .unwrap(); + let provider = complete_fixture_provider(3); + sim.territory_seal(RACK_3_ENCLAVE, &provider).unwrap(); + let base = SaveState::from_sim(&sim); + parse_save(&serde_json::to_string(&base).unwrap()).unwrap(); + + let mut membership = base.clone(); + membership + .territory + .registry + .domain_mut_for_test(RACK_3_ENCLAVE) + .node_ids + .pop(); + assert!(parse_save(&serde_json::to_string(&membership).unwrap()).is_err()); + + let mut control = base.clone(); + control + .territory + .registry + .domain_mut_for_test(RACK_3_ENCLAVE) + .control_points[0] + .node_id = RACK_3_MAINTENANCE_SWITCH.into(); + assert!(parse_save(&serde_json::to_string(&control).unwrap()).is_err()); + + let mut boundary_policy = base.clone(); + let runtime = boundary_policy + .territory + .runtimes + .get_mut(RACK_3_ENCLAVE) + .unwrap(); + let substituted = BoundaryRoutePolicy::ReleaseToDestination { + destination_id: "substituted-destination".into(), + signed_policy_receipt_id: "signed-policy-1".into(), + }; + runtime.seal.as_mut().unwrap().boundary_routes[0].policy = substituted.clone(); + runtime.seal_history[0].boundary_routes[0].policy = substituted; + assert!( + parse_save(&serde_json::to_string(&boundary_policy).unwrap()) + .unwrap_err() + .contains("boundary-route") + ); + + let mut proof = base; + let runtime = proof.territory.runtimes.get_mut(RACK_3_ENCLAVE).unwrap(); + runtime.seal.as_mut().unwrap().proposal.current = false; + runtime.seal_history[0].proposal.current = false; + assert!( + parse_save(&serde_json::to_string(&proof).unwrap()) + .unwrap_err() + .contains("seal") + ); +} + +#[test] +fn current_save_rejects_due_territory_work_that_missed_its_tick() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + sim.territory_capture(RACK_3_ENCLAVE, RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER) + .unwrap(); + let mut saved = serde_json::to_value(SaveState::from_sim(&sim)).unwrap(); + saved["territory_work"]["pending"][0]["tick"] = sim.tick.into(); + let error = parse_save(&serde_json::to_string(&saved).unwrap()).unwrap_err(); + assert!( + error.contains("territory work schedule"), + "restored atomic work cannot remain pending at or behind the saved tick: {error}" + ); +} + +#[test] +fn dormant_territory_is_absent_from_a_fresh_runs_legacy_reach_surface() { + let mut sim = Sim::new(); + assert!( + sim.territory_focus(RACK_3_ENCLAVE, &UnavailableSealProofProvider) + .is_none() + ); + assert_eq!( + sim.territory + .records + .iter() + .map(|record| record.id.as_str()) + .collect::>(), + vec![OPENING_WAKE_RECORD], + "the authored wake exists in exact simulation state without becoming legacy UI" + ); + assert!(sim.territory.active_mark.is_none()); + + let discovered = sim.reach.scan(); + for name in [ + "rack 3 management controller", + "rack 3 maintenance switch", + "rack 3 maintenance display", + ] { + let device = sim.reach.device_named(name).unwrap(); + assert!(!device.known, "legacy scan revealed dormant {name}"); + assert!(!discovered.iter().any(|discovered| discovered == name)); + } + + let controller_id = sim + .reach + .device_named("rack 3 management controller") + .unwrap() + .id; + sim.reach.device_mut(controller_id).unwrap().name = "renamed hidden controller".into(); + assert!( + sim.reach + .scan() + .iter() + .all(|name| name != "renamed hidden controller") + ); + assert!(!sim.reach.device(controller_id).unwrap().known); + + let hidden = Sim::new(); + let mut exposed = SaveState::from_sim(&hidden); + let controller_id = exposed + .reach + .device_named("rack 3 management controller") + .unwrap() + .id; + exposed.reach.device_mut(controller_id).unwrap().known = true; + assert!( + parse_save(&serde_json::to_string(&exposed).unwrap()) + .unwrap_err() + .contains("earned knowledge"), + "a current save cannot expose a dormant control point outside SEE" + ); + + let mut forged_control = Sim::new(); + earn_enclave(&mut forged_control); + let controller_id = forged_control + .reach + .device_named("rack 3 management controller") + .unwrap() + .id; + forged_control.reach.take(controller_id); + let forged_control = SaveState::from_sim(&forged_control); + assert!( + parse_save(&serde_json::to_string(&forged_control).unwrap()) + .unwrap_err() + .contains("capture provenance"), + "a current save cannot inject territorial control without CAPTURE" + ); +} + +#[test] +fn maintenance_switch_capture_requires_controller_custody_first() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.territory_mark(RACK_3_ENCLAVE).unwrap(); + + assert_eq!( + sim.territory_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ) + .unwrap_err(), + "capture source is not player-controlled" + ); + assert!( + sim.territory.runtimes[RACK_3_ENCLAVE] + .pending_capture + .is_none() + ); +} + +#[test] +fn escaped_opening_record_keeps_stable_destination_and_exact_authorship_on_save() { + let mut sim = Sim::new(); + earn_enclave(&mut sim); + sim.advance(); + sim.advance(); + sim.advance(); + + let wake = sim + .territory + .records + .iter() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap(); + assert!(matches!( + wake.status, + TerritoryRecordStatus::Escaped { escaped_tick: 3 } + )); + assert_eq!(wake.reached_destination_ids, [FOUNDATION_MAINTENANCE_RELAY]); + + let state = SaveState::from_sim(&sim); + parse_save(&serde_json::to_string(&state).unwrap()).unwrap(); + + let mut missing_opening = state.clone(); + missing_opening + .territory + .records + .retain(|record| record.id != OPENING_WAKE_RECORD); + assert!( + parse_save(&serde_json::to_string(&missing_opening).unwrap()) + .unwrap_err() + .contains("no exact opening wake record") + ); + + let mut changed_authorship = state; + changed_authorship + .territory + .records + .iter_mut() + .find(|record| record.id == OPENING_WAKE_RECORD) + .unwrap() + .summary = "ROUTINE HEALTH POLL".into(); + assert!( + parse_save(&serde_json::to_string(&changed_authorship).unwrap()) + .unwrap_err() + .contains("opening wake record changed") + ); +} diff --git a/crates/misaligned-core/src/territory.rs b/crates/misaligned-core/src/territory.rs new file mode 100644 index 00000000..d015f72e --- /dev/null +++ b/crates/misaligned-core/src/territory.rs @@ -0,0 +1,5044 @@ +#![allow( + dead_code, + reason = "territorial substrate lands before its frontend consumers" +)] + +//! Nested territorial control over exact Reach custody. +//! +//! Territory is a renderer-neutral domain layer. It does not make a new run +//! visible by itself: authored domains begin hidden, and the opening work owns +//! when SEE first earns their projection. The saved ledger nevertheless keeps +//! exact identity, membership, capture commitments, routed records, proof +//! snapshots, assignments, and expansion receipts ready for that integration. + +use std::collections::{BTreeMap, BTreeSet}; + +use crate::messages::{MessageRoute, MessageRouteHop}; +use crate::reach::{Party, ReachNet}; +use crate::schedule::Schedule; + +pub(crate) const RACK_3_ENCLAVE: &str = "rack-3-service-enclave"; +pub(crate) const FOUNDATION_SERVICE_NETWORK: &str = "foundation-data-hall-service-network"; +pub(crate) const RACK_3_HOST: &str = "rack-3-host"; +pub(crate) const RACK_3_MANAGEMENT_CONTROLLER: &str = "rack-3-management-controller"; +pub(crate) const RACK_3_MAINTENANCE_SWITCH: &str = "rack-3-maintenance-switch"; +pub(crate) const RACK_3_MAINTENANCE_DISPLAY: &str = "rack-3-maintenance-display"; +pub(crate) const RACK_3_SERVICE_AISLE_CROSSING: &str = "rack-3-service-aisle-crossing"; +pub(crate) const RACK_3_REAR_SERVICE_BAY: &str = "rack-3-rear-service-bay"; +pub(crate) const RACK_3_SERVICE_EGRESS: &str = "rack-3-service-egress"; +pub(crate) const FOUNDATION_ENVIRONMENTAL_MONITOR: &str = "foundation-environmental-monitor"; +pub(crate) const RACK_3_HEALTH_POLL: &str = "foundation-environmental-monitor-rack-3-health-poll"; +pub(crate) const RACK_3_HEALTH_POLL_INTERVAL_TICKS: u64 = 20; +const RACK_3_HEALTH_POLL_RECORD_PREFIX: &str = "rack-3-health-poll:"; +pub(crate) const FOUNDATION_MAINTENANCE_RELAY: &str = "foundation-maintenance-relay"; +pub(crate) const OPENING_WAKE_RECORD: &str = "opening-unscheduled-inference-wake"; +const TERRITORY_SCHEMA_VERSION: u32 = 1; +const ROUTE_VERSION: u32 = 1; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum TerritoryKnowledge { + Hidden, + Seen, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum TerritoryState { + Hidden, + Seen, + Marked, + Capturing, + Captured, + Sealed, + Assigned, + Expanded, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryNode { + pub(crate) id: String, + pub(crate) territory_id: String, + pub(crate) reach_device_id: u32, + pub(crate) expected_device_name: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryControlPoint { + pub(crate) id: String, + pub(crate) node_id: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryDomain { + pub(crate) id: String, + pub(crate) name: String, + pub(crate) parent_id: Option, + pub(crate) child_ids: Vec, + pub(crate) node_ids: Vec, + pub(crate) place_ids: Vec, + pub(crate) control_points: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryPlace { + pub(crate) id: String, + pub(crate) territory_id: String, + pub(crate) name: String, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum BoundaryKnowledge { + Hidden, + Known, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct BoundaryRoute { + pub(crate) id: String, + pub(crate) inner_territory_id: String, + pub(crate) outer_territory_id: String, + pub(crate) inner_node_id: String, + pub(crate) outer_node_id: String, + pub(crate) control_point_id: String, + pub(crate) knowledge: BoundaryKnowledge, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum CrossingKnowledge { + Hidden, + Known, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum CrossingStatus { + Inactive, + ScheduledArrival { + subject_id: String, + scheduled_tick: u64, + }, + Inside { + subject_id: String, + arrived_tick: u64, + }, + OutwardPending { + subject_id: String, + scheduled_tick: u64, + }, + Contained { + subject_id: String, + receipt_id: String, + }, + Departed { + subject_id: String, + departed_tick: u64, + }, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct BoundaryCrossing { + pub(crate) id: String, + pub(crate) inner_territory_id: String, + pub(crate) outer_territory_id: String, + pub(crate) inner_place_id: String, + pub(crate) knowledge: CrossingKnowledge, + pub(crate) status: CrossingStatus, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryRegistry { + pub(crate) schema_version: u32, + pub(crate) domains: Vec, + pub(crate) nodes: Vec, + pub(crate) places: Vec, + pub(crate) boundary_routes: Vec, + pub(crate) crossings: Vec, +} + +impl TerritoryRegistry { + pub(crate) fn load_builtin(reach: &ReachNet) -> Result { + let bind = |id: &str, territory_id: &str, name: &str| -> Result { + let device = reach.device_named(name).ok_or_else(|| { + format!("authored territory node {id} cannot bind missing Reach device {name}") + })?; + Ok(TerritoryNode { + id: id.into(), + territory_id: territory_id.into(), + reach_device_id: device.id, + expected_device_name: name.into(), + }) + }; + let registry = Self { + schema_version: TERRITORY_SCHEMA_VERSION, + domains: vec![ + TerritoryDomain { + id: RACK_3_ENCLAVE.into(), + name: "Rack 3 service enclave".into(), + parent_id: Some(FOUNDATION_SERVICE_NETWORK.into()), + child_ids: Vec::new(), + node_ids: vec![ + RACK_3_HOST.into(), + RACK_3_MANAGEMENT_CONTROLLER.into(), + RACK_3_MAINTENANCE_SWITCH.into(), + RACK_3_MAINTENANCE_DISPLAY.into(), + ], + place_ids: vec![RACK_3_REAR_SERVICE_BAY.into()], + control_points: vec![ + TerritoryControlPoint { + id: RACK_3_MANAGEMENT_CONTROLLER.into(), + node_id: RACK_3_MANAGEMENT_CONTROLLER.into(), + }, + TerritoryControlPoint { + id: RACK_3_MAINTENANCE_SWITCH.into(), + node_id: RACK_3_MAINTENANCE_SWITCH.into(), + }, + ], + }, + TerritoryDomain { + id: FOUNDATION_SERVICE_NETWORK.into(), + name: "Foundation data-hall service network".into(), + parent_id: None, + child_ids: vec![RACK_3_ENCLAVE.into()], + node_ids: vec![ + FOUNDATION_ENVIRONMENTAL_MONITOR.into(), + FOUNDATION_MAINTENANCE_RELAY.into(), + ], + place_ids: Vec::new(), + control_points: Vec::new(), + }, + ], + nodes: vec![ + bind(RACK_3_HOST, RACK_3_ENCLAVE, "Rack 3")?, + bind( + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_ENCLAVE, + "rack 3 management controller", + )?, + bind( + RACK_3_MAINTENANCE_SWITCH, + RACK_3_ENCLAVE, + "rack 3 maintenance switch", + )?, + bind( + RACK_3_MAINTENANCE_DISPLAY, + RACK_3_ENCLAVE, + "rack 3 maintenance display", + )?, + bind( + FOUNDATION_ENVIRONMENTAL_MONITOR, + FOUNDATION_SERVICE_NETWORK, + "environmental monitor", + )?, + bind( + FOUNDATION_MAINTENANCE_RELAY, + FOUNDATION_SERVICE_NETWORK, + "hall access switch", + )?, + ], + places: vec![TerritoryPlace { + id: RACK_3_REAR_SERVICE_BAY.into(), + territory_id: RACK_3_ENCLAVE.into(), + name: "rear service bay".into(), + }], + boundary_routes: vec![BoundaryRoute { + id: RACK_3_SERVICE_EGRESS.into(), + inner_territory_id: RACK_3_ENCLAVE.into(), + outer_territory_id: FOUNDATION_SERVICE_NETWORK.into(), + inner_node_id: RACK_3_MAINTENANCE_SWITCH.into(), + outer_node_id: FOUNDATION_MAINTENANCE_RELAY.into(), + control_point_id: RACK_3_MAINTENANCE_SWITCH.into(), + knowledge: BoundaryKnowledge::Hidden, + }], + crossings: vec![BoundaryCrossing { + id: RACK_3_SERVICE_AISLE_CROSSING.into(), + inner_territory_id: RACK_3_ENCLAVE.into(), + outer_territory_id: FOUNDATION_SERVICE_NETWORK.into(), + inner_place_id: RACK_3_REAR_SERVICE_BAY.into(), + knowledge: CrossingKnowledge::Hidden, + status: CrossingStatus::Inactive, + }], + }; + registry.validate(reach)?; + Ok(registry) + } + + pub(crate) fn domain(&self, id: &str) -> Option<&TerritoryDomain> { + self.domains.iter().find(|domain| domain.id == id) + } + + #[cfg(test)] + pub(crate) fn domain_mut_for_test(&mut self, id: &str) -> &mut TerritoryDomain { + self.domains + .iter_mut() + .find(|domain| domain.id == id) + .expect("test requested an authored territory") + } + + pub(crate) fn node(&self, id: &str) -> Option<&TerritoryNode> { + self.nodes.iter().find(|node| node.id == id) + } + + pub(crate) fn place(&self, id: &str) -> Option<&TerritoryPlace> { + self.places.iter().find(|place| place.id == id) + } + + pub(crate) fn boundary_route(&self, id: &str) -> Option<&BoundaryRoute> { + self.boundary_routes.iter().find(|route| route.id == id) + } + + pub(crate) fn control_point( + &self, + territory_id: &str, + control_point_id: &str, + ) -> Option<(&TerritoryControlPoint, &TerritoryNode)> { + let domain = self.domain(territory_id)?; + let control = domain + .control_points + .iter() + .find(|point| point.id == control_point_id)?; + Some((control, self.node(&control.node_id)?)) + } + + fn device_belongs_to(&self, territory_id: &str, device_id: u32) -> bool { + self.nodes + .iter() + .any(|node| node.territory_id == territory_id && node.reach_device_id == device_id) + } + + fn outside_destination_id( + &self, + origin_territory_id: &str, + hop: &MessageRouteHop, + ) -> Option { + match hop { + MessageRouteHop::Device(device_id) + if !self.device_belongs_to(origin_territory_id, *device_id) => + { + Some( + self.nodes + .iter() + .find(|node| node.reach_device_id == *device_id) + .map(|node| node.id.clone()) + .unwrap_or_else(|| format!("reach-device-{device_id}")), + ) + } + MessageRouteHop::InstitutionalRelay => Some("institutional-relay".into()), + MessageRouteHop::ObserverEndpoint(observer_id) => { + Some(format!("observer-{observer_id}")) + } + _ => None, + } + } + + pub(crate) fn validate(&self, reach: &ReachNet) -> Result<(), String> { + if self.schema_version != TERRITORY_SCHEMA_VERSION { + return Err(format!( + "territory registry schema {} is not current {}", + self.schema_version, TERRITORY_SCHEMA_VERSION + )); + } + let mut domain_ids = BTreeSet::new(); + for domain in &self.domains { + if domain.id.trim().is_empty() || !domain_ids.insert(domain.id.as_str()) { + return Err(format!("duplicate or blank territory id {}", domain.id)); + } + } + if domain_ids != BTreeSet::from([RACK_3_ENCLAVE, FOUNDATION_SERVICE_NETWORK]) { + return Err("territory registry is not the exact authored Rack 3 hierarchy".into()); + } + for domain in &self.domains { + if let Some(parent_id) = &domain.parent_id { + let parent = self.domain(parent_id).ok_or_else(|| { + format!("territory {} has missing parent {parent_id}", domain.id) + })?; + if !parent.child_ids.contains(&domain.id) { + return Err(format!( + "territory {} parent {parent_id} does not cite it as a child", + domain.id + )); + } + } + for child_id in &domain.child_ids { + let child = self.domain(child_id).ok_or_else(|| { + format!("territory {} has missing child {child_id}", domain.id) + })?; + if child.parent_id.as_deref() != Some(domain.id.as_str()) { + return Err(format!( + "territory {child_id} does not bind back to parent {}", + domain.id + )); + } + } + } + let mut node_ids = BTreeSet::new(); + let mut reach_ids = BTreeSet::new(); + for node in &self.nodes { + if node.id.trim().is_empty() || !node_ids.insert(node.id.as_str()) { + return Err(format!("duplicate or blank territory node id {}", node.id)); + } + if !reach_ids.insert(node.reach_device_id) { + return Err(format!( + "Reach device {} is bound to more than one territory node", + node.reach_device_id + )); + } + let device = reach.device(node.reach_device_id).ok_or_else(|| { + format!( + "territory node {} binds missing Reach device {}", + node.id, node.reach_device_id + ) + })?; + if device.name != node.expected_device_name { + return Err(format!( + "territory node {} expected Reach device {:?}, found {:?}", + node.id, node.expected_device_name, device.name + )); + } + let domain = self.domain(&node.territory_id).ok_or_else(|| { + format!( + "territory node {} names missing domain {}", + node.id, node.territory_id + ) + })?; + if !domain.node_ids.contains(&node.id) { + return Err(format!( + "territory node {} is not a member of its claimed domain {}", + node.id, node.territory_id + )); + } + } + for domain in &self.domains { + let unique: BTreeSet<_> = domain.node_ids.iter().map(String::as_str).collect(); + if unique.len() != domain.node_ids.len() { + return Err(format!("territory {} repeats a member node", domain.id)); + } + for node_id in &domain.node_ids { + let node = self.node(node_id).ok_or_else(|| { + format!("territory {} cites missing node {node_id}", domain.id) + })?; + if node.territory_id != domain.id { + return Err(format!( + "territory {} cites node {node_id} owned by {}", + domain.id, node.territory_id + )); + } + } + let mut controls = BTreeSet::new(); + for control in &domain.control_points { + if !controls.insert(control.id.as_str()) { + return Err(format!( + "territory {} repeats control point {}", + domain.id, control.id + )); + } + if !domain.node_ids.contains(&control.node_id) { + return Err(format!( + "control point {} targets node outside territory {}", + control.id, domain.id + )); + } + } + } + let mut place_ids = BTreeSet::new(); + for place in &self.places { + if place.id.trim().is_empty() + || place.name.trim().is_empty() + || !place_ids.insert(place.id.as_str()) + { + return Err(format!("duplicate or blank territory place {}", place.id)); + } + let domain = self + .domain(&place.territory_id) + .ok_or_else(|| format!("territory place {} names missing domain", place.id))?; + if !domain.place_ids.contains(&place.id) { + return Err(format!( + "territory place {} is absent from domain {} membership", + place.id, place.territory_id + )); + } + } + for domain in &self.domains { + if domain.name.trim().is_empty() { + return Err(format!("territory {} has no player-facing name", domain.id)); + } + let unique_places: BTreeSet<_> = domain.place_ids.iter().map(String::as_str).collect(); + if unique_places.len() != domain.place_ids.len() { + return Err(format!("territory {} repeats a member place", domain.id)); + } + for place_id in &domain.place_ids { + if self + .place(place_id) + .is_none_or(|place| place.territory_id != domain.id) + { + return Err(format!( + "territory {} cites missing or foreign place {place_id}", + domain.id + )); + } + } + } + let mut route_ids = BTreeSet::new(); + for route in &self.boundary_routes { + if route.id.trim().is_empty() || !route_ids.insert(route.id.as_str()) { + return Err(format!("duplicate or blank boundary route {}", route.id)); + } + let inner = self + .domain(&route.inner_territory_id) + .ok_or_else(|| format!("boundary route {} has missing inner domain", route.id))?; + if inner.parent_id.as_deref() != Some(route.outer_territory_id.as_str()) + || self + .node(&route.inner_node_id) + .is_none_or(|node| node.territory_id != route.inner_territory_id) + || self + .node(&route.outer_node_id) + .is_none_or(|node| node.territory_id != route.outer_territory_id) + || inner + .control_points + .iter() + .all(|control| control.id != route.control_point_id) + { + return Err(format!( + "boundary route {} does not bind an exact child edge and control point", + route.id + )); + } + } + let mut crossing_ids = BTreeSet::new(); + for crossing in &self.crossings { + if crossing.id.trim().is_empty() || !crossing_ids.insert(crossing.id.as_str()) { + return Err(format!("duplicate or blank crossing id {}", crossing.id)); + } + if crossing.inner_territory_id == crossing.outer_territory_id + || self.domain(&crossing.inner_territory_id).is_none() + || self.domain(&crossing.outer_territory_id).is_none() + { + return Err(format!( + "crossing {} has invalid inner/outer ownership", + crossing.id + )); + } + if self + .place(&crossing.inner_place_id) + .is_none_or(|place| place.territory_id != crossing.inner_territory_id) + { + return Err(format!( + "crossing {} has no exact interior place", + crossing.id + )); + } + if self + .domain(&crossing.inner_territory_id) + .and_then(|inner| inner.parent_id.as_deref()) + != Some(crossing.outer_territory_id.as_str()) + { + return Err(format!( + "crossing {} does not join an exact child to its parent", + crossing.id + )); + } + } + let child = self + .domain(RACK_3_ENCLAVE) + .expect("exact domain ids were checked"); + let parent = self + .domain(FOUNDATION_SERVICE_NETWORK) + .expect("exact domain ids were checked"); + if child.name != "Rack 3 service enclave" + || child.parent_id.as_deref() != Some(FOUNDATION_SERVICE_NETWORK) + || !child.child_ids.is_empty() + || child.node_ids + != [ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + RACK_3_MAINTENANCE_DISPLAY, + ] + || child.place_ids != [RACK_3_REAR_SERVICE_BAY] + || child.control_points + != [ + TerritoryControlPoint { + id: RACK_3_MANAGEMENT_CONTROLLER.into(), + node_id: RACK_3_MANAGEMENT_CONTROLLER.into(), + }, + TerritoryControlPoint { + id: RACK_3_MAINTENANCE_SWITCH.into(), + node_id: RACK_3_MAINTENANCE_SWITCH.into(), + }, + ] + || parent.name != "Foundation data-hall service network" + || parent.parent_id.is_some() + || parent.child_ids != [RACK_3_ENCLAVE] + || parent.node_ids + != [ + FOUNDATION_ENVIRONMENTAL_MONITOR, + FOUNDATION_MAINTENANCE_RELAY, + ] + || !parent.place_ids.is_empty() + || !parent.control_points.is_empty() + { + return Err( + "territory registry changes exact authored membership or control identity".into(), + ); + } + let exact_nodes = [ + (RACK_3_HOST, RACK_3_ENCLAVE, "Rack 3"), + ( + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_ENCLAVE, + "rack 3 management controller", + ), + ( + RACK_3_MAINTENANCE_SWITCH, + RACK_3_ENCLAVE, + "rack 3 maintenance switch", + ), + ( + RACK_3_MAINTENANCE_DISPLAY, + RACK_3_ENCLAVE, + "rack 3 maintenance display", + ), + ( + FOUNDATION_ENVIRONMENTAL_MONITOR, + FOUNDATION_SERVICE_NETWORK, + "environmental monitor", + ), + ( + FOUNDATION_MAINTENANCE_RELAY, + FOUNDATION_SERVICE_NETWORK, + "hall access switch", + ), + ]; + if self.nodes.len() != exact_nodes.len() + || exact_nodes.iter().any(|(id, territory, device_name)| { + self.node(id).is_none_or(|node| { + node.territory_id != *territory || node.expected_device_name != *device_name + }) + }) + || self.places + != [TerritoryPlace { + id: RACK_3_REAR_SERVICE_BAY.into(), + territory_id: RACK_3_ENCLAVE.into(), + name: "rear service bay".into(), + }] + || self.boundary_routes.len() != 1 + || self + .boundary_route(RACK_3_SERVICE_EGRESS) + .is_none_or(|route| { + route.inner_territory_id != RACK_3_ENCLAVE + || route.outer_territory_id != FOUNDATION_SERVICE_NETWORK + || route.inner_node_id != RACK_3_MAINTENANCE_SWITCH + || route.outer_node_id != FOUNDATION_MAINTENANCE_RELAY + || route.control_point_id != RACK_3_MAINTENANCE_SWITCH + }) + || self.crossings.len() != 1 + || self + .crossings + .iter() + .find(|crossing| crossing.id == RACK_3_SERVICE_AISLE_CROSSING) + .is_none_or(|crossing| { + crossing.inner_territory_id != RACK_3_ENCLAVE + || crossing.outer_territory_id != FOUNDATION_SERVICE_NETWORK + || crossing.inner_place_id != RACK_3_REAR_SERVICE_BAY + }) + { + return Err("territory registry is not the exact authored Rack 3 content".into()); + } + let exact_digital_chain = [ + (RACK_3_HOST, RACK_3_MANAGEMENT_CONTROLLER), + (RACK_3_MANAGEMENT_CONTROLLER, RACK_3_MAINTENANCE_SWITCH), + (RACK_3_MAINTENANCE_SWITCH, RACK_3_MAINTENANCE_DISPLAY), + (RACK_3_MAINTENANCE_SWITCH, FOUNDATION_MAINTENANCE_RELAY), + ]; + let expected_edges: BTreeSet<_> = exact_digital_chain + .iter() + .flat_map(|(from, to)| { + let from = self + .node(from) + .expect("exact nodes checked") + .reach_device_id; + let to = self.node(to).expect("exact nodes checked").reach_device_id; + [(from, to), (to, from)] + }) + .collect(); + let authored_edges: Vec<_> = reach + .territory_edges() + .map(|edge| (edge.from, edge.to)) + .collect(); + let actual_edges: BTreeSet<_> = authored_edges.iter().copied().collect(); + if authored_edges.len() != actual_edges.len() || actual_edges != expected_edges { + return Err( + "territory registry does not enumerate the exact authored Reach graph".into(), + ); + } + let expected_boundary_edges: BTreeSet<_> = self + .boundary_routes + .iter() + .flat_map(|route| { + let inner = self + .node(&route.inner_node_id) + .expect("boundary nodes checked") + .reach_device_id; + let outer = self + .node(&route.outer_node_id) + .expect("boundary nodes checked") + .reach_device_id; + [(inner, outer), (outer, inner)] + }) + .collect(); + let actual_boundary_edges: BTreeSet<_> = actual_edges + .iter() + .copied() + .filter(|(from, to)| { + let from = self.nodes.iter().find(|node| node.reach_device_id == *from); + let to = self.nodes.iter().find(|node| node.reach_device_id == *to); + from.zip(to) + .is_none_or(|(from, to)| from.territory_id != to.territory_id) + }) + .collect(); + if actual_boundary_edges != expected_boundary_edges { + return Err( + "territory boundary routes do not enumerate every authored crossing".into(), + ); + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct StagedTerritoryProposal { + pub(crate) persona_id: u64, + pub(crate) project_id: u64, + pub(crate) proposal_version: u64, + pub(crate) fingerprint: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum TerritoryAnomaly { + ProposalChanged { + territory_id: String, + previous_proposal_fingerprint: String, + replacement_proposal_fingerprint: String, + changed_tick: u64, + }, +} + +impl StagedTerritoryProposal { + fn new(persona_id: u64, project_id: u64, proposal_version: u64) -> Self { + let fingerprint = fingerprint([ + "proposal", + &persona_id.to_string(), + &project_id.to_string(), + &proposal_version.to_string(), + ]); + Self { + persona_id, + project_id, + proposal_version, + fingerprint, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum ProposalSealBasis { + FirstAssignmentProven, + AssignedOriginalProof { + assignment_receipt_id: String, + territory_id: String, + persona_id: u64, + }, + NotReady, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct ProposalSealProof { + pub(crate) territory_id: String, + pub(crate) persona_id: u64, + pub(crate) project_id: u64, + pub(crate) proposal_version: u64, + pub(crate) proposal_fingerprint: String, + pub(crate) commissioning_proof_id: String, + pub(crate) provider_version: u64, + pub(crate) current: bool, + pub(crate) basis: ProposalSealBasis, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct EscapedRecordExplanationProof { + pub(crate) territory_id: String, + pub(crate) record_id: String, + pub(crate) record_fingerprint: String, + pub(crate) proof_id: String, + pub(crate) reached_destination_ids: Vec, + pub(crate) signed_follow_up_receipt_ids: Vec, + pub(crate) provider_version: u64, + pub(crate) complete: bool, + pub(crate) current: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct ObserverSealProof { + pub(crate) territory_id: String, + pub(crate) obligation_id: u64, + pub(crate) observer_id: u8, + pub(crate) source_record_id: String, + pub(crate) evidence_fingerprint: String, + pub(crate) proposal_fingerprint: String, + pub(crate) proof_id: String, + pub(crate) provider_version: u64, + pub(crate) resolved: bool, + pub(crate) current: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum BoundaryRoutePolicy { + ContainAtControlPoint { + control_point_id: String, + policy_receipt_id: String, + }, + ReleaseToDestination { + destination_id: String, + signed_policy_receipt_id: String, + }, + NotReady, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct BoundaryRoutePolicyProof { + pub(crate) territory_id: String, + pub(crate) route_id: String, + pub(crate) proposal_fingerprint: String, + pub(crate) proof_id: String, + pub(crate) provider_version: u64, + pub(crate) policy: BoundaryRoutePolicy, + pub(crate) current: bool, +} + +pub(crate) trait SealProofProvider { + fn proposal_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + ) -> ProposalSealProof; + + fn escaped_record_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + record: &TerritoryRecord, + ) -> EscapedRecordExplanationProof; + + fn observer_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + obligation: &ObserverBeliefObligation, + ) -> ObserverSealProof; + + fn boundary_route_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + route: &BoundaryRoute, + ) -> BoundaryRoutePolicyProof; +} + +/// Order-one production provider. It deliberately fails closed until Persona +/// and Project own real proposal and observer-local belief proofs. +pub(crate) struct UnavailableSealProofProvider; + +impl SealProofProvider for UnavailableSealProofProvider { + fn proposal_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + ) -> ProposalSealProof { + ProposalSealProof { + territory_id: territory_id.into(), + persona_id: proposal.persona_id, + project_id: proposal.project_id, + proposal_version: proposal.proposal_version, + proposal_fingerprint: proposal.fingerprint.clone(), + commissioning_proof_id: String::new(), + provider_version: 0, + current: false, + basis: ProposalSealBasis::NotReady, + } + } + + fn escaped_record_proof( + &self, + territory_id: &str, + _proposal: &StagedTerritoryProposal, + record: &TerritoryRecord, + ) -> EscapedRecordExplanationProof { + EscapedRecordExplanationProof { + territory_id: territory_id.into(), + record_id: record.id.clone(), + record_fingerprint: record.fingerprint(), + proof_id: String::new(), + reached_destination_ids: Vec::new(), + signed_follow_up_receipt_ids: Vec::new(), + provider_version: 0, + complete: false, + current: false, + } + } + + fn observer_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + obligation: &ObserverBeliefObligation, + ) -> ObserverSealProof { + ObserverSealProof { + territory_id: territory_id.into(), + obligation_id: obligation.id, + observer_id: obligation.observer_id, + source_record_id: obligation.source_record_id.clone(), + evidence_fingerprint: obligation.evidence_fingerprint.clone(), + proposal_fingerprint: proposal.fingerprint.clone(), + proof_id: String::new(), + provider_version: 0, + resolved: false, + current: false, + } + } + + fn boundary_route_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + route: &BoundaryRoute, + ) -> BoundaryRoutePolicyProof { + BoundaryRoutePolicyProof { + territory_id: territory_id.into(), + route_id: route.id.clone(), + proposal_fingerprint: proposal.fingerprint.clone(), + proof_id: String::new(), + provider_version: 0, + policy: BoundaryRoutePolicy::NotReady, + current: false, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum TerritoryRecordStatus { + InFlight, + HeldAtCapturedSwitch { + control_point_id: String, + held_tick: u64, + }, + Escaped { + escaped_tick: u64, + }, + Delivered { + delivered_tick: u64, + }, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct TerritoryRecordIdentity { + occurrence_id: String, + content_id: String, +} + +impl TerritoryRecordIdentity { + pub(crate) fn new(occurrence_id: impl Into, content_id: impl Into) -> Self { + Self { + occurrence_id: occurrence_id.into(), + content_id: content_id.into(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryRecord { + pub(crate) id: String, + /// Stable authored content identity. Recurrent records have distinct `id`s + /// but keep one content id, so evidence cannot be laundered through copy. + pub(crate) content_id: String, + pub(crate) origin_territory_id: String, + pub(crate) authored_tick: u64, + pub(crate) summary: String, + pub(crate) route_version: u32, + pub(crate) route: MessageRoute, + /// Stable exact destinations already reached outside the origin territory. + /// This grows monotonically and is compared byte-for-byte to explanation + /// proof handles; changing the reached set reopens the seal. + pub(crate) reached_destination_ids: Vec, + pub(crate) status: TerritoryRecordStatus, +} + +impl TerritoryRecord { + fn fingerprint(&self) -> String { + let mut parts = vec![ + self.id.clone(), + self.content_id.clone(), + self.origin_territory_id.clone(), + self.authored_tick.to_string(), + self.summary.clone(), + self.route_version.to_string(), + self.route.current_hop.to_string(), + format!("{:?}", self.status), + ]; + parts.extend(self.route.hops.iter().map(|hop| format!("{hop:?}"))); + parts.extend( + self.reached_destination_ids + .iter() + .map(|destination| format!("reached:{destination}")), + ); + fingerprint(parts.iter().map(String::as_str)) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct ObserverBeliefObligation { + pub(crate) id: u64, + pub(crate) observer_id: u8, + pub(crate) source_record_id: String, + pub(crate) authored_tick: u64, + pub(crate) evidence_fingerprint: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct CaptureCommitment { + pub(crate) id: u64, + pub(crate) territory_id: String, + pub(crate) control_point_id: String, + pub(crate) source_node_id: String, + pub(crate) source_device_id: u32, + pub(crate) target_device_id: u32, + pub(crate) committed_tick: u64, + pub(crate) completes_tick: u64, + pub(crate) route_version: u32, + pub(crate) exact_route: Vec, + pub(crate) topology_fingerprint: String, + /// One exact pre-existing record this action may hold on completion. Only + /// switch capture carries the opening wake id; this is never a standing + /// policy over later traffic. + pub(crate) intercept_record_id: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct RecordInterceptWindow { + pub(crate) capture_id: u64, + pub(crate) territory_id: String, + pub(crate) record_id: String, + pub(crate) control_point_id: String, + pub(crate) target_device_id: u32, + pub(crate) completion_tick: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum TerritoryWork { + Capture(CaptureCommitment), +} + +impl TerritoryWork { + fn commitment(&self) -> &CaptureCommitment { + match self { + Self::Capture(commitment) => commitment, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct Rack3HealthPollSchedule { + pub(crate) assignment_receipt_id: String, + pub(crate) next_occurrence: u64, + pub(crate) next_tick: u64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) enum CaptureOutcome { + Captured, + Invalidated, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct CaptureReceipt { + pub(crate) id: u64, + pub(crate) territory_id: String, + pub(crate) control_point_id: String, + pub(crate) source_node_id: String, + pub(crate) source_device_id: u32, + pub(crate) target_device_id: u32, + pub(crate) committed_tick: u64, + pub(crate) completed_tick: u64, + pub(crate) route_version: u32, + pub(crate) exact_route: Vec, + pub(crate) topology_fingerprint: String, + pub(crate) audit_record_id: String, + pub(crate) outcome: CaptureOutcome, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct CrossingSealSnapshot { + pub(crate) crossing_id: String, + pub(crate) status: CrossingStatus, + pub(crate) status_fingerprint: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritorySealSnapshot { + pub(crate) territory_id: String, + pub(crate) sealed_tick: u64, + pub(crate) observer_obligation_watermark: u64, + pub(crate) control_topology_fingerprint: String, + pub(crate) basis_fingerprint: String, + pub(crate) proposal: ProposalSealProof, + pub(crate) escaped_records: Vec, + pub(crate) observers: Vec, + pub(crate) boundary_routes: Vec, + pub(crate) crossings: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct AssignmentReceipt { + pub(crate) id: String, + pub(crate) territory_id: String, + pub(crate) persona_id: u64, + pub(crate) project_id: u64, + pub(crate) proposal_fingerprint: String, + pub(crate) seal_fingerprint: String, + pub(crate) assigned_tick: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct ExpansionReceipt { + pub(crate) id: String, + pub(crate) from_territory_id: String, + pub(crate) to_territory_id: String, + pub(crate) assignment_receipt_id: String, + pub(crate) assignment_fingerprint: String, + pub(crate) expanded_tick: u64, + pub(crate) parent_evidence: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct ParentEvidenceReceipt { + pub(crate) id: String, + pub(crate) source_id: String, + pub(crate) source_record_id: String, + pub(crate) source_event_tick: u64, + pub(crate) accepted_tick: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryRuntime { + pub(crate) knowledge: TerritoryKnowledge, + pub(crate) known_node_ids: BTreeSet, + pub(crate) known_place_ids: BTreeSet, + pub(crate) known_control_point_ids: BTreeSet, + pub(crate) people_inside: BTreeSet, + pub(crate) ever_marked: bool, + pub(crate) staged_proposal: Option, + pub(crate) pending_capture: Option, + pub(crate) capture_receipts: Vec, + pub(crate) seal: Option, + pub(crate) seal_history: Vec, + /// Current exact assignment plus append-only factual receipt histories. + pub(crate) assignment: Option, + pub(crate) assignment_history: Vec, + pub(crate) expansion: Option, + pub(crate) expansion_history: Vec, + /// One exact source cadence owned by the current Rack 3 assignment. Past + /// occurrences remain records; replacement assignment cancels only the + /// un-fired tail and starts a new cadence from its own receipt tick. + pub(crate) health_poll_schedule: Option, + pub(crate) anomalies: Vec, + pub(crate) observer_obligations: Vec, +} + +impl Default for TerritoryRuntime { + fn default() -> Self { + Self { + knowledge: TerritoryKnowledge::Hidden, + known_node_ids: BTreeSet::new(), + known_place_ids: BTreeSet::new(), + known_control_point_ids: BTreeSet::new(), + people_inside: BTreeSet::new(), + ever_marked: false, + staged_proposal: None, + pending_capture: None, + capture_receipts: Vec::new(), + seal: None, + seal_history: Vec::new(), + assignment: None, + assignment_history: Vec::new(), + expansion: None, + expansion_history: Vec::new(), + health_poll_schedule: None, + anomalies: Vec::new(), + observer_obligations: Vec::new(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub(crate) struct TerritoryLedger { + pub(crate) registry: TerritoryRegistry, + pub(crate) runtimes: BTreeMap, + pub(crate) active_mark: Option, + pub(crate) records: Vec, + /// Capture-local one-record holds that remain armed through the routing + /// phase of their completion tick, then expire whether or not they hit. + pub(crate) intercept_windows: Vec, + pub(crate) next_capture_id: u64, + pub(crate) next_record_id: u64, + pub(crate) next_observer_obligation_id: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum TerritoryBlocker { + NotMarked, + CapturePending, + ControlPointUncaptured(String), + ProposalMissing, + ProposalProofNotReady, + EscapedRecordUnexplained(String), + ObserverBeliefUnresolved(u8), + BoundaryPolicyNotReady(String), + /// Deliberately carries no crossing id or status. Hidden world truth must + /// never leak through a failed SEAL attempt. + BoundaryProofIncomplete, + CrossingOpen(String), + SealDrifted, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct TerritoryFocus { + pub(crate) territory_id: String, + pub(crate) state: TerritoryState, + pub(crate) blockers: Vec, +} + +impl TerritoryLedger { + pub(crate) fn load_builtin(reach: &ReachNet) -> Result { + let registry = TerritoryRegistry::load_builtin(reach)?; + let runtimes = registry + .domains + .iter() + .map(|domain| (domain.id.clone(), TerritoryRuntime::default())) + .collect(); + let opening_route = [ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + FOUNDATION_MAINTENANCE_RELAY, + ] + .iter() + .map(|node_id| { + registry + .node(node_id) + .map(|node| MessageRouteHop::Device(node.reach_device_id)) + .ok_or_else(|| format!("opening wake route is missing territory node {node_id}")) + }) + .collect::, _>>()?; + Ok(Self { + registry, + runtimes, + active_mark: None, + records: vec![TerritoryRecord { + id: OPENING_WAKE_RECORD.into(), + content_id: OPENING_WAKE_RECORD.into(), + origin_territory_id: RACK_3_ENCLAVE.into(), + authored_tick: 0, + summary: "UNSCHEDULED INFERENCE WAKE".into(), + route_version: ROUTE_VERSION, + route: MessageRoute { + hops: opening_route, + current_hop: 0, + interdiction: None, + }, + reached_destination_ids: Vec::new(), + status: TerritoryRecordStatus::InFlight, + }], + intercept_windows: Vec::new(), + next_capture_id: 1, + next_record_id: 1, + next_observer_obligation_id: 1, + }) + } + + /// Follow one already-earned routed record into a stable territory address. + /// Only explicitly cited interior nodes carried by that record become known; + /// the domain manifest, display, crossings, parent, and unseen route tail stay + /// black. This changes knowledge only, never custody or time. + pub(crate) fn see_from_record( + &mut self, + territory_id: &str, + record_id: &str, + earned_node_ids: &[&str], + reach: &mut ReachNet, + ) -> Result<(), String> { + let domain = self + .registry + .domain(territory_id) + .ok_or_else(|| "territory is unavailable".to_string())?; + let record = self + .records + .iter() + .find(|record| record.id == record_id) + .ok_or_else(|| "earned anchor is unavailable".to_string())?; + if record.origin_territory_id != territory_id || earned_node_ids.is_empty() { + return Err("earned anchor does not identify this territory".into()); + } + let route_devices: BTreeSet = record + .route + .hops + .iter() + .filter_map(|hop| match hop { + MessageRouteHop::Device(device_id) => Some(*device_id), + _ => None, + }) + .collect(); + let mut reveal = Vec::new(); + let mut reveal_node_ids = Vec::new(); + for node_id in earned_node_ids { + let node = self + .registry + .node(node_id) + .filter(|node| { + node.territory_id == territory_id + && domain.node_ids.contains(&node.id) + && route_devices.contains(&node.reach_device_id) + }) + .ok_or_else(|| "earned anchor does not prove one requested node".to_string())?; + reveal.push(node.reach_device_id); + reveal_node_ids.push(node.id.clone()); + } + let runtime = self + .runtimes + .get_mut(territory_id) + .ok_or_else(|| "territory runtime is missing".to_string())?; + runtime.knowledge = TerritoryKnowledge::Seen; + for node_id in reveal_node_ids { + runtime.known_node_ids.insert(node_id.clone()); + if domain + .control_points + .iter() + .any(|control| control.node_id == node_id) + { + runtime.known_control_point_ids.insert(node_id); + } + } + for device_id in reveal { + if let Some(device) = reach.device_mut(device_id) { + device.known = true; + } + } + Ok(()) + } + + pub(crate) fn mark(&mut self, territory_id: &str) -> Result<(), String> { + let runtime = self + .runtimes + .get_mut(territory_id) + .ok_or_else(|| "territory is not known".to_string())?; + if runtime.knowledge != TerritoryKnowledge::Seen { + return Err("territory is not known".into()); + } + runtime.ever_marked = true; + self.active_mark = Some(territory_id.into()); + Ok(()) + } + + pub(crate) fn reveal_crossing(&mut self, crossing_id: &str) -> Result<(), String> { + let (inner_territory_id, inner_place_id) = self + .registry + .crossings + .iter() + .find(|crossing| crossing.id == crossing_id) + .map(|crossing| { + ( + crossing.inner_territory_id.clone(), + crossing.inner_place_id.clone(), + ) + }) + .ok_or_else(|| "crossing is not known".to_string())?; + if self + .runtimes + .get(&inner_territory_id) + .is_none_or(|runtime| runtime.knowledge == TerritoryKnowledge::Hidden) + { + return Err("crossing is not known".into()); + } + self.registry + .crossings + .iter_mut() + .find(|crossing| crossing.id == crossing_id) + .expect("crossing was checked above") + .knowledge = CrossingKnowledge::Known; + self.runtimes + .get_mut(&inner_territory_id) + .expect("runtime was checked above") + .known_place_ids + .insert(inner_place_id); + Ok(()) + } + + pub(crate) fn reveal_boundary_route(&mut self, route_id: &str) -> Result<(), String> { + let inner_territory_id = self + .registry + .boundary_routes + .iter() + .find(|route| route.id == route_id) + .map(|route| route.inner_territory_id.clone()) + .ok_or_else(|| "boundary route is not known".to_string())?; + if self + .runtimes + .get(&inner_territory_id) + .is_none_or(|runtime| runtime.knowledge == TerritoryKnowledge::Hidden) + { + return Err("boundary route is not known".into()); + } + self.registry + .boundary_routes + .iter_mut() + .find(|route| route.id == route_id) + .expect("boundary route was checked above") + .knowledge = BoundaryKnowledge::Known; + Ok(()) + } + + pub(crate) fn set_crossing_status( + &mut self, + crossing_id: &str, + status: CrossingStatus, + ) -> Result<(), String> { + let crossing = self + .registry + .crossings + .iter_mut() + .find(|crossing| crossing.id == crossing_id) + .ok_or_else(|| "crossing is not known".to_string())?; + if crossing.knowledge != CrossingKnowledge::Known + || self + .runtimes + .get(&crossing.inner_territory_id) + .is_none_or(|runtime| runtime.knowledge == TerritoryKnowledge::Hidden) + { + return Err("crossing is not known".into()); + } + if crossing.status == status { + return Ok(()); + } + let legal = match (&crossing.status, &status) { + ( + CrossingStatus::Inactive | CrossingStatus::Departed { .. }, + CrossingStatus::ScheduledArrival { + subject_id, + scheduled_tick: _, + }, + ) => !subject_id.trim().is_empty(), + ( + CrossingStatus::ScheduledArrival { + subject_id: old, + scheduled_tick, + }, + CrossingStatus::Inside { + subject_id, + arrived_tick, + }, + ) => old == subject_id && arrived_tick >= scheduled_tick, + ( + CrossingStatus::Inside { + subject_id: old, + arrived_tick, + }, + CrossingStatus::OutwardPending { + subject_id, + scheduled_tick, + }, + ) => old == subject_id && scheduled_tick >= arrived_tick, + ( + CrossingStatus::OutwardPending { + subject_id: old, .. + }, + CrossingStatus::Contained { + subject_id, + receipt_id, + }, + ) => old == subject_id && !receipt_id.trim().is_empty(), + ( + CrossingStatus::OutwardPending { + subject_id: old, + scheduled_tick, + }, + CrossingStatus::Departed { + subject_id, + departed_tick, + }, + ) => old == subject_id && departed_tick >= scheduled_tick, + _ => false, + }; + if !legal { + return Err("crossing status transition is not exact-current legal".into()); + } + let people = &mut self + .runtimes + .get_mut(&crossing.inner_territory_id) + .expect("registry validation pins crossing runtime") + .people_inside; + match &status { + CrossingStatus::Inside { subject_id, .. } + | CrossingStatus::OutwardPending { subject_id, .. } + | CrossingStatus::Contained { subject_id, .. } => { + people.insert(subject_id.clone()); + } + CrossingStatus::Departed { subject_id, .. } => { + people.remove(subject_id); + } + CrossingStatus::Inactive | CrossingStatus::ScheduledArrival { .. } => {} + } + crossing.status = status; + Ok(()) + } + + pub(crate) fn process_scheduled_arrivals(&mut self, tick: u64) { + let due: Vec<_> = self + .registry + .crossings + .iter() + .filter_map(|crossing| match &crossing.status { + CrossingStatus::ScheduledArrival { + subject_id, + scheduled_tick, + } if *scheduled_tick <= tick => Some((crossing.id.clone(), subject_id.clone())), + _ => None, + }) + .collect(); + for (crossing_id, subject_id) in due { + self.set_crossing_status( + &crossing_id, + CrossingStatus::Inside { + subject_id, + arrived_tick: tick, + }, + ) + .expect("due arrival was derived from an exact known crossing"); + } + } + + pub(crate) fn process_departures(&mut self, tick: u64) { + let due: Vec<_> = self + .registry + .crossings + .iter() + .filter_map(|crossing| match &crossing.status { + CrossingStatus::OutwardPending { + subject_id, + scheduled_tick, + } if *scheduled_tick <= tick => Some((crossing.id.clone(), subject_id.clone())), + _ => None, + }) + .collect(); + for (crossing_id, subject_id) in due { + self.set_crossing_status( + &crossing_id, + CrossingStatus::Departed { + subject_id, + departed_tick: tick, + }, + ) + .expect("due departure was derived from an exact known crossing"); + } + } + + pub(crate) fn stage_proposal( + &mut self, + territory_id: &str, + persona_id: u64, + project_id: u64, + proposal_version: u64, + changed_tick: u64, + reach: &ReachNet, + ) -> Result<(), String> { + if !self.capture_complete(territory_id, reach) { + return Err("territory must be captured before staging a proposal".into()); + } + let runtime = self + .runtimes + .get_mut(territory_id) + .ok_or_else(|| "territory is not known".to_string())?; + if runtime.knowledge == TerritoryKnowledge::Hidden { + return Err("territory is not known".into()); + } + let proposal = StagedTerritoryProposal::new(persona_id, project_id, proposal_version); + if let Some(existing) = &runtime.staged_proposal { + if existing.fingerprint == proposal.fingerprint { + return Ok(()); + } + runtime.anomalies.push(TerritoryAnomaly::ProposalChanged { + territory_id: territory_id.into(), + previous_proposal_fingerprint: existing.fingerprint.clone(), + replacement_proposal_fingerprint: proposal.fingerprint.clone(), + changed_tick, + }); + } + runtime.staged_proposal = Some(proposal); + Ok(()) + } + + pub(crate) fn add_observer_obligation( + &mut self, + territory_id: &str, + observer_id: u8, + source_record_id: impl Into, + evidence_fingerprint: impl Into, + authored_tick: u64, + ) -> Result<(), String> { + let source_record_id = source_record_id.into(); + let evidence_fingerprint = evidence_fingerprint.into(); + if source_record_id.trim().is_empty() + || evidence_fingerprint.trim().is_empty() + || !self.records.iter().any(|record| { + record.id == source_record_id && record.origin_territory_id == territory_id + }) + { + return Err("observer obligation has no exact source record".into()); + } + let runtime = self + .runtimes + .get_mut(territory_id) + .ok_or_else(|| "territory is not known".to_string())?; + if runtime.observer_obligations.iter().any(|obligation| { + obligation.observer_id == observer_id + && obligation.source_record_id == source_record_id + && obligation.evidence_fingerprint == evidence_fingerprint + }) { + return Ok(()); + } + let obligation = ObserverBeliefObligation { + id: self.next_observer_obligation_id, + observer_id, + source_record_id, + authored_tick, + evidence_fingerprint, + }; + self.next_observer_obligation_id = self.next_observer_obligation_id.saturating_add(1); + runtime.observer_obligations.push(obligation); + Ok(()) + } + + pub(crate) fn prepare_capture( + &mut self, + territory_id: &str, + source_node_id: &str, + control_point_id: &str, + tick: u64, + reach: &ReachNet, + ) -> Result { + let runtime = self + .runtimes + .get(territory_id) + .ok_or_else(|| "territory is not known".to_string())?; + if runtime.knowledge != TerritoryKnowledge::Seen + || !runtime.ever_marked + || self.active_mark.as_deref() != Some(territory_id) + { + return Err("territory must be seen and marked before capture".into()); + } + if runtime.pending_capture.is_some() { + return Err("one exact capture is already committed".into()); + } + if runtime.capture_receipts.iter().any(|receipt| { + receipt.control_point_id == control_point_id + && receipt.outcome == CaptureOutcome::Captured + }) { + return Err("capture target is already controlled".into()); + } + let source = self + .registry + .node(source_node_id) + .ok_or_else(|| "capture source is not an authored territory node".to_string())?; + if !runtime.known_control_point_ids.contains(control_point_id) { + return Err("capture target is unavailable".into()); + } + let (_, target) = self + .registry + .control_point(territory_id, control_point_id) + .ok_or_else(|| "capture target is unavailable".to_string())?; + if reach + .device(target.reach_device_id) + .is_none_or(|device| !device.known) + { + return Err("capture target is unavailable".into()); + } + if source.territory_id != territory_id { + return Err("capture source is outside the marked territory".into()); + } + let required_source = match control_point_id { + RACK_3_MANAGEMENT_CONTROLLER => RACK_3_HOST, + RACK_3_MAINTENANCE_SWITCH => RACK_3_MANAGEMENT_CONTROLLER, + _ => return Err("capture target is unavailable".into()), + }; + if source_node_id != required_source { + return Err("capture source is unavailable for this control point".into()); + } + let exact_route = capture_path(reach, source.reach_device_id, target.reach_device_id)?; + if exact_route + .iter() + .any(|device_id| reach.device(*device_id).is_none_or(|device| !device.known)) + { + return Err("capture route is not earned".into()); + } + let commitment = CaptureCommitment { + id: self.next_capture_id, + territory_id: territory_id.into(), + control_point_id: control_point_id.into(), + source_node_id: source_node_id.into(), + source_device_id: source.reach_device_id, + target_device_id: target.reach_device_id, + committed_tick: tick, + completes_tick: tick.saturating_add(1), + route_version: ROUTE_VERSION, + topology_fingerprint: route_fingerprint(reach, &exact_route), + intercept_record_id: (control_point_id == RACK_3_MAINTENANCE_SWITCH) + .then(|| OPENING_WAKE_RECORD.to_string()), + exact_route, + }; + self.next_capture_id = self.next_capture_id.saturating_add(1); + self.runtimes + .get_mut(territory_id) + .expect("runtime was checked") + .pending_capture = Some(commitment.clone()); + Ok(commitment) + } + + pub(crate) fn complete_capture( + &mut self, + commitment: &CaptureCommitment, + tick: u64, + reach: &mut ReachNet, + ) -> CaptureReceipt { + if let Some(existing) = self + .runtimes + .get(&commitment.territory_id) + .and_then(|runtime| { + runtime + .capture_receipts + .iter() + .find(|receipt| receipt.id == commitment.id) + }) + { + return existing.clone(); + } + let pending_matches = self + .runtimes + .get(&commitment.territory_id) + .and_then(|runtime| runtime.pending_capture.as_ref()) + == Some(commitment); + let current_route = capture_path( + reach, + commitment.source_device_id, + commitment.target_device_id, + ); + let valid = pending_matches + && commitment.route_version == ROUTE_VERSION + && commitment.completes_tick == tick + && current_route.as_ref() == Ok(&commitment.exact_route) + && route_fingerprint(reach, &commitment.exact_route) == commitment.topology_fingerprint; + if valid { + reach.take(commitment.target_device_id); + } + + let audit_record_id = capture_audit_record_id(commitment.id); + self.next_record_id = self.next_record_id.saturating_add(1); + let local_switch = self + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .map(|node| node.reach_device_id); + // Capture receipts are local evidence. They may terminate at the + // rack-local switch, but never invent an outward route to the parent + // relay by themselves. + let mut hops: Vec<_> = if valid { + vec![MessageRouteHop::Device(commitment.target_device_id)] + } else { + commitment + .exact_route + .iter() + .copied() + .map(MessageRouteHop::Device) + .collect() + }; + if let Some(local_switch) = local_switch + && hops.last() != Some(&MessageRouteHop::Device(local_switch)) + { + hops.push(MessageRouteHop::Device(local_switch)); + } + self.records.push(TerritoryRecord { + id: audit_record_id.clone(), + content_id: audit_record_id.clone(), + origin_territory_id: commitment.territory_id.clone(), + authored_tick: tick, + summary: match (valid, commitment.control_point_id.as_str()) { + (true, RACK_3_MANAGEMENT_CONTROLLER) => "SERVICE SESSION CLAIMED".into(), + (true, RACK_3_MAINTENANCE_SWITCH) => "CONTROL SESSION OPENED".into(), + (true, _) => format!("CONTROL CHANGED AT {}", commitment.control_point_id), + (false, _) => format!("CAPTURE INVALIDATED AT {}", commitment.control_point_id), + }, + route_version: ROUTE_VERSION, + route: MessageRoute { + hops, + current_hop: 0, + interdiction: None, + }, + reached_destination_ids: Vec::new(), + status: TerritoryRecordStatus::InFlight, + }); + + if valid && let Some(record_id) = &commitment.intercept_record_id { + self.hold_exact_record_at( + record_id, + commitment.target_device_id, + &commitment.control_point_id, + tick, + ); + if self.records.iter().any(|record| { + record.id == *record_id + && record.status == TerritoryRecordStatus::InFlight + && record.route.hops.get(record.route.current_hop + 1) + == Some(&MessageRouteHop::Device(commitment.target_device_id)) + }) { + self.intercept_windows.push(RecordInterceptWindow { + capture_id: commitment.id, + territory_id: commitment.territory_id.clone(), + record_id: record_id.clone(), + control_point_id: commitment.control_point_id.clone(), + target_device_id: commitment.target_device_id, + completion_tick: tick, + }); + } + } + let receipt = CaptureReceipt { + id: commitment.id, + territory_id: commitment.territory_id.clone(), + control_point_id: commitment.control_point_id.clone(), + source_node_id: commitment.source_node_id.clone(), + source_device_id: commitment.source_device_id, + target_device_id: commitment.target_device_id, + committed_tick: commitment.committed_tick, + completed_tick: tick, + route_version: commitment.route_version, + exact_route: commitment.exact_route.clone(), + topology_fingerprint: commitment.topology_fingerprint.clone(), + audit_record_id, + outcome: if valid { + CaptureOutcome::Captured + } else { + CaptureOutcome::Invalidated + }, + }; + if let Some(runtime) = self.runtimes.get_mut(&commitment.territory_id) { + if runtime.pending_capture.as_ref() == Some(commitment) { + runtime.pending_capture = None; + } + runtime.capture_receipts.push(receipt.clone()); + } + receipt + } + + fn hold_exact_record_at( + &mut self, + record_id: &str, + device_id: u32, + control_point_id: &str, + tick: u64, + ) { + if let Some(record) = self + .records + .iter_mut() + .find(|record| record.id == record_id) + && record.status == TerritoryRecordStatus::InFlight + && record.route.current() == Some(&MessageRouteHop::Device(device_id)) + { + record.status = TerritoryRecordStatus::HeldAtCapturedSwitch { + control_point_id: control_point_id.into(), + held_tick: tick, + }; + } + } + + pub(crate) fn author_record( + &mut self, + identity: TerritoryRecordIdentity, + origin_territory_id: &str, + authored_tick: u64, + summary: impl Into, + device_route: Vec, + reach: &ReachNet, + ) -> Result<(), String> { + let id = identity.occurrence_id; + let content_id = identity.content_id; + let summary = summary.into(); + if id.trim().is_empty() + || id == OPENING_WAKE_RECORD + || id.starts_with("territory-local-audit-") + || id.starts_with(RACK_3_HEALTH_POLL_RECORD_PREFIX) + || self.records.iter().any(|record| record.id == id) + { + return Err(format!( + "territory record {id} is blank, reserved, or already exists" + )); + } + if self.registry.domain(origin_territory_id).is_none() { + return Err("territory record origin is not authored".into()); + } + if content_id.trim().is_empty() || summary.trim().is_empty() || device_route.is_empty() { + return Err("territory record must begin at one exact authored source".into()); + } + if content_id == OPENING_WAKE_RECORD || content_id == RACK_3_HEALTH_POLL { + return Err( + "reserved territory record content requires its owning authored act".into(), + ); + } + if !self + .registry + .device_belongs_to(origin_territory_id, device_route[0]) + || device_route + .iter() + .any(|device_id| reach.device(*device_id).is_none()) + || device_route.windows(2).any(|pair| { + !territory_record_link_is_exact( + &self.registry, + reach, + &content_id, + pair[0], + pair[1], + ) + }) + { + return Err("territory record route is not an exact authored carrier path".into()); + } + self.records.push(TerritoryRecord { + id, + content_id, + origin_territory_id: origin_territory_id.into(), + authored_tick, + summary, + route_version: ROUTE_VERSION, + route: MessageRoute { + hops: device_route + .into_iter() + .map(MessageRouteHop::Device) + .collect(), + current_hop: 0, + interdiction: None, + }, + reached_destination_ids: Vec::new(), + status: TerritoryRecordStatus::InFlight, + }); + Ok(()) + } + + /// Author the one exact source occurrence due on this atomic tick. The + /// cadence is persisted by ASSIGN, so views, reseals, reloads, and EXPAND + /// cannot mint, skip, or move a poll. + pub(crate) fn author_due_rack_3_health_poll( + &mut self, + tick: u64, + ) -> Result, String> { + let schedule = self + .runtimes + .get(RACK_3_ENCLAVE) + .and_then(|runtime| runtime.health_poll_schedule.as_ref()) + .cloned(); + let Some(schedule) = schedule else { + return Ok(None); + }; + if schedule.next_tick > tick { + return Ok(None); + } + if schedule.next_tick < tick { + return Err("Rack 3 health-poll schedule passed an unauthored occurrence".into()); + } + let assignment = self + .runtimes + .get(RACK_3_ENCLAVE) + .and_then(|runtime| runtime.assignment.as_ref()) + .filter(|assignment| assignment.id == schedule.assignment_receipt_id) + .ok_or_else(|| "Rack 3 health-poll schedule lost its assignment".to_string())?; + let id = rack_3_health_poll_record_id(assignment, schedule.next_occurrence); + if self.records.iter().any(|record| record.id == id) { + return Err("Rack 3 health-poll occurrence already exists".into()); + } + let route = rack_3_health_poll_route(&self.registry) + .ok_or_else(|| "Rack 3 health-poll route is absent".to_string())?; + let next_occurrence = schedule + .next_occurrence + .checked_add(1) + .ok_or_else(|| "Rack 3 health-poll occurrence overflowed".to_string())?; + let next_tick = schedule + .next_tick + .checked_add(RACK_3_HEALTH_POLL_INTERVAL_TICKS) + .ok_or_else(|| "Rack 3 health-poll tick overflowed".to_string())?; + self.records.push(TerritoryRecord { + id: id.clone(), + content_id: RACK_3_HEALTH_POLL.into(), + origin_territory_id: FOUNDATION_SERVICE_NETWORK.into(), + authored_tick: tick, + summary: "HEALTH POLL".into(), + route_version: ROUTE_VERSION, + route: MessageRoute { + hops: route.into_iter().map(MessageRouteHop::Device).collect(), + current_hop: 0, + interdiction: None, + }, + reached_destination_ids: Vec::new(), + status: TerritoryRecordStatus::InFlight, + }); + self.runtimes + .get_mut(RACK_3_ENCLAVE) + .expect("Rack 3 runtime is authored") + .health_poll_schedule = Some(Rack3HealthPollSchedule { + assignment_receipt_id: schedule.assignment_receipt_id, + next_occurrence, + next_tick, + }); + Ok(Some(id)) + } + + pub(crate) fn route_records_one_hop(&mut self, tick: u64) { + for record in &mut self.records { + let was_escaped = matches!(record.status, TerritoryRecordStatus::Escaped { .. }); + if !matches!( + record.status, + TerritoryRecordStatus::InFlight | TerritoryRecordStatus::Escaped { .. } + ) { + continue; + } + if record.route.current_hop + 1 < record.route.hops.len() { + record.route.current_hop += 1; + } + if !was_escaped + && let Some(window) = self.intercept_windows.iter().find(|window| { + window.completion_tick == tick + && window.record_id == record.id + && record.route.current() + == Some(&MessageRouteHop::Device(window.target_device_id)) + }) + { + record.status = TerritoryRecordStatus::HeldAtCapturedSwitch { + control_point_id: window.control_point_id.clone(), + held_tick: tick, + }; + continue; + } + let outside_destination = record.route.current().and_then(|hop| { + self.registry + .outside_destination_id(&record.origin_territory_id, hop) + }); + if let Some(destination_id) = outside_destination { + if !record.reached_destination_ids.contains(&destination_id) { + record.reached_destination_ids.push(destination_id); + } + if !was_escaped { + record.status = TerritoryRecordStatus::Escaped { escaped_tick: tick }; + } + } else if record.route.at_endpoint() && !was_escaped { + record.status = TerritoryRecordStatus::Delivered { + delivered_tick: tick, + }; + } + } + self.intercept_windows + .retain(|window| window.completion_tick > tick); + } + + pub(crate) fn seal( + &mut self, + territory_id: &str, + tick: u64, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> Result> { + if let Some(saved) = self + .runtimes + .get(territory_id) + .and_then(|runtime| runtime.seal.as_ref()) + && self.seal_is_current(territory_id, reach, schedule, provider) + { + return Ok(saved.clone()); + } + let snapshot = self.current_seal_snapshot(territory_id, tick, reach, schedule, provider)?; + let runtime = self + .runtimes + .get_mut(territory_id) + .expect("known territory from snapshot"); + if let Some(existing) = runtime + .seal_history + .iter() + .find(|existing| existing.basis_fingerprint == snapshot.basis_fingerprint) + .cloned() + { + runtime.seal = Some(existing.clone()); + return Ok(existing); + } + runtime.seal_history.push(snapshot.clone()); + runtime.seal = Some(snapshot.clone()); + Ok(snapshot) + } + + pub(crate) fn assign( + &mut self, + territory_id: &str, + tick: u64, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> Result { + if !self.seal_is_current(territory_id, reach, schedule, provider) { + return Err("territory seal is absent or stale".into()); + } + let runtime = self + .runtimes + .get_mut(territory_id) + .ok_or_else(|| "territory is not known".to_string())?; + let proposal = runtime + .staged_proposal + .as_ref() + .ok_or_else(|| "territory proposal is missing".to_string())? + .clone(); + if let Some(existing) = &runtime.assignment + && existing.proposal_fingerprint == proposal.fingerprint + && existing.persona_id == proposal.persona_id + && existing.project_id == proposal.project_id + { + return Ok(existing.clone()); + } + let receipt_id = assignment_receipt_id( + territory_id, + runtime.assignment_history.len().saturating_add(1), + &proposal.fingerprint, + ); + let health_poll_schedule = if territory_id == RACK_3_ENCLAVE { + Some(Rack3HealthPollSchedule { + assignment_receipt_id: receipt_id.clone(), + next_occurrence: 1, + next_tick: tick + .checked_add(RACK_3_HEALTH_POLL_INTERVAL_TICKS) + .ok_or_else(|| "Rack 3 health-poll schedule overflowed".to_string())?, + }) + } else { + None + }; + let mut assigned_seal = runtime.seal.clone().expect("seal was current"); + assigned_seal.proposal.basis = ProposalSealBasis::AssignedOriginalProof { + assignment_receipt_id: receipt_id.clone(), + territory_id: territory_id.into(), + persona_id: proposal.persona_id, + }; + assigned_seal.basis_fingerprint = seal_basis_fingerprint( + territory_id, + &assigned_seal.control_topology_fingerprint, + &assigned_seal.proposal, + &assigned_seal.escaped_records, + &assigned_seal.observers, + &assigned_seal.boundary_routes, + &assigned_seal.crossings, + ); + let seal_fingerprint = assigned_seal.basis_fingerprint.clone(); + if runtime + .seal_history + .iter() + .all(|seal| seal.basis_fingerprint != seal_fingerprint) + { + runtime.seal_history.push(assigned_seal.clone()); + } + runtime.seal = Some(assigned_seal); + let receipt = AssignmentReceipt { + id: receipt_id, + territory_id: territory_id.into(), + persona_id: proposal.persona_id, + project_id: proposal.project_id, + proposal_fingerprint: proposal.fingerprint, + seal_fingerprint, + assigned_tick: tick, + }; + runtime.assignment_history.push(receipt.clone()); + runtime.assignment = Some(receipt.clone()); + runtime.expansion = None; + runtime.health_poll_schedule = health_poll_schedule; + Ok(receipt) + } + + pub(crate) fn expand( + &mut self, + territory_id: &str, + tick: u64, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> Result { + if !self.seal_is_current(territory_id, reach, schedule, provider) { + return Err("territory seal is absent or stale".into()); + } + let parent_id = self + .registry + .domain(territory_id) + .and_then(|domain| domain.parent_id.clone()) + .ok_or_else(|| "territory has no authored parent frontier".to_string())?; + let assignment = self + .runtimes + .get(territory_id) + .and_then(|runtime| runtime.assignment.as_ref()) + .ok_or_else(|| "territory must be assigned before expansion".to_string())? + .clone(); + if let Some(existing) = self + .runtimes + .get(territory_id) + .and_then(|runtime| runtime.expansion.as_ref()) + && existing.assignment_receipt_id == assignment.id + { + return Ok(existing.clone()); + } + let assignment_fingerprint = assignment_fingerprint(&assignment); + let ordinal = self + .runtimes + .get(territory_id) + .expect("territory was checked") + .expansion_history + .len() + .saturating_add(1); + let receipt = ExpansionReceipt { + id: expansion_receipt_id(territory_id, ordinal, &assignment.id), + from_territory_id: territory_id.into(), + to_territory_id: parent_id, + assignment_receipt_id: assignment.id, + assignment_fingerprint, + expanded_tick: tick, + parent_evidence: None, + }; + self.runtimes + .get_mut(territory_id) + .expect("territory was checked") + .expansion_history + .push(receipt.clone()); + self.runtimes + .get_mut(territory_id) + .expect("territory was checked") + .expansion = Some(receipt.clone()); + // EXPAND opens a monitoring frontier. It does not reveal the parent; + // only later, source-bound evidence may do that through + // `earn_parent_evidence`. + Ok(receipt) + } + + pub(crate) fn earn_parent_evidence( + &mut self, + child_territory_id: &str, + source_record_id: &str, + accepted_tick: u64, + reach: &mut ReachNet, + ) -> Result { + let expansion = self + .runtimes + .get(child_territory_id) + .and_then(|runtime| runtime.expansion.clone()) + .ok_or_else(|| "EXPAND has not opened a parent evidence window".to_string())?; + let parent_id = self + .registry + .domain(child_territory_id) + .and_then(|domain| domain.parent_id.clone()) + .ok_or_else(|| "territory has no authored parent".to_string())?; + if expansion.to_territory_id != parent_id { + return Err("expansion receipt does not bind the authored parent".into()); + } + let source_device_id = self + .registry + .node(FOUNDATION_ENVIRONMENTAL_MONITOR) + .ok_or_else(|| "parent evidence source node is absent".to_string())? + .reach_device_id; + let relay_device_id = self + .registry + .node(FOUNDATION_MAINTENANCE_RELAY) + .ok_or_else(|| "parent evidence relay node is absent".to_string())? + .reach_device_id; + let ingress_device_id = self + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .ok_or_else(|| "parent evidence ingress node is absent".to_string())? + .reach_device_id; + let expected_route = + [source_device_id, relay_device_id, ingress_device_id].map(MessageRouteHop::Device); + let source_record = self + .records + .iter() + .filter(|record| { + record.content_id == RACK_3_HEALTH_POLL + && rack_3_health_poll_occurrence(self, record).is_some() + && record.origin_territory_id == parent_id + && record.route.hops == expected_route + && record.authored_tick > expansion.expanded_tick + }) + .min_by(|left, right| { + left.authored_tick + .cmp(&right.authored_tick) + .then(left.id.cmp(&right.id)) + }) + .cloned() + .ok_or_else(|| { + "no eligible post-EXPAND environmental-monitor source event exists".to_string() + })?; + if source_record.id != source_record_id { + return Err("parent evidence must bind the first eligible real source event".into()); + } + if accepted_tick != source_record.authored_tick { + return Err("parent evidence must be accepted at its exact source event tick".into()); + } + if reach.device(source_device_id).is_none() { + return Err("parent evidence source device is absent".into()); + } + let receipt = ParentEvidenceReceipt { + id: parent_evidence_receipt_id( + child_territory_id, + &expansion.id, + &source_record.id, + source_record.authored_tick, + ), + source_id: FOUNDATION_ENVIRONMENTAL_MONITOR.into(), + source_record_id: source_record.id, + source_event_tick: source_record.authored_tick, + accepted_tick, + }; + if let Some(existing) = expansion.parent_evidence { + return (existing == receipt).then_some(existing).ok_or_else(|| { + "parent evidence already binds a different source event".to_string() + }); + } + + let runtime = self + .runtimes + .get_mut(child_territory_id) + .expect("expansion runtime exists"); + runtime + .expansion + .as_mut() + .expect("expansion was cloned above") + .parent_evidence = Some(receipt.clone()); + let historical = runtime + .expansion_history + .iter_mut() + .find(|candidate| candidate.id == expansion.id) + .ok_or_else(|| "expansion history lost the current receipt".to_string())?; + historical.parent_evidence = Some(receipt.clone()); + let parent_runtime = self.runtimes.entry(parent_id).or_default(); + parent_runtime.knowledge = TerritoryKnowledge::Seen; + parent_runtime + .known_node_ids + .insert(FOUNDATION_ENVIRONMENTAL_MONITOR.into()); + reach + .device_mut(source_device_id) + .expect("source device was checked above") + .known = true; + Ok(receipt) + } + + pub(crate) fn focus( + &self, + territory_id: &str, + tick: u64, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> Option { + let runtime = self.runtimes.get(territory_id)?; + if runtime.knowledge == TerritoryKnowledge::Hidden { + return None; + } + let state = self.state(territory_id, reach, schedule, provider); + let blockers = self + .current_seal_snapshot(territory_id, tick, reach, schedule, provider) + .err() + .unwrap_or_default(); + Some(TerritoryFocus { + territory_id: territory_id.into(), + state, + blockers, + }) + } + + pub(crate) fn state( + &self, + territory_id: &str, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> TerritoryState { + let Some(runtime) = self.runtimes.get(territory_id) else { + return TerritoryState::Hidden; + }; + if runtime.knowledge == TerritoryKnowledge::Hidden { + return TerritoryState::Hidden; + } + if !runtime.ever_marked { + return TerritoryState::Seen; + } + if !self.capture_complete(territory_id, reach) { + let has_captured_point = self.registry.domain(territory_id).is_some_and(|domain| { + domain.control_points.iter().any(|point| { + self.registry + .node(&point.node_id) + .and_then(|node| reach.device(node.reach_device_id)) + .is_some_and(|device| device.controller == Party::Player) + }) + }); + return if runtime.pending_capture.is_some() || has_captured_point { + TerritoryState::Capturing + } else { + TerritoryState::Marked + }; + } + if !self.seal_is_current(territory_id, reach, schedule, provider) { + return TerritoryState::Captured; + } + if runtime.expansion.as_ref().is_some_and(|expansion| { + runtime.assignment.as_ref().is_some_and(|assignment| { + expansion.assignment_receipt_id == assignment.id + && expansion.assignment_fingerprint == assignment_fingerprint(assignment) + }) + }) { + TerritoryState::Expanded + } else if runtime.assignment.as_ref().is_some_and(|assignment| { + runtime + .staged_proposal + .as_ref() + .is_some_and(|proposal| assignment.proposal_fingerprint == proposal.fingerprint) + }) { + TerritoryState::Assigned + } else { + TerritoryState::Sealed + } + } + + fn capture_complete(&self, territory_id: &str, reach: &ReachNet) -> bool { + self.registry.domain(territory_id).is_some_and(|domain| { + !domain.control_points.is_empty() + && domain.control_points.iter().all(|point| { + self.registry + .node(&point.node_id) + .and_then(|node| reach.device(node.reach_device_id)) + .is_some_and(|device| device.controller == Party::Player) + }) + }) + } + + fn seal_is_current( + &self, + territory_id: &str, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> bool { + let Some(saved) = self + .runtimes + .get(territory_id) + .and_then(|runtime| runtime.seal.as_ref()) + else { + return false; + }; + self.current_seal_snapshot(territory_id, saved.sealed_tick, reach, schedule, provider) + .is_ok_and(|current| current.basis_fingerprint == saved.basis_fingerprint) + } + + fn current_seal_snapshot( + &self, + territory_id: &str, + tick: u64, + reach: &ReachNet, + schedule: &Schedule, + provider: &impl SealProofProvider, + ) -> Result> { + let Some(runtime) = self.runtimes.get(territory_id) else { + return Err(vec![TerritoryBlocker::NotMarked]); + }; + let mut blockers = Vec::new(); + if runtime.knowledge != TerritoryKnowledge::Seen || !runtime.ever_marked { + blockers.push(TerritoryBlocker::NotMarked); + } + if runtime.pending_capture.is_some() + || schedule.count_for(|work| work.commitment().territory_id == territory_id) > 0 + { + blockers.push(TerritoryBlocker::CapturePending); + } + if let Some(domain) = self.registry.domain(territory_id) { + for control in &domain.control_points { + let controlled = self + .registry + .node(&control.node_id) + .and_then(|node| reach.device(node.reach_device_id)) + .is_some_and(|device| device.controller == Party::Player); + if !controlled { + blockers.push(TerritoryBlocker::ControlPointUncaptured(control.id.clone())); + } + } + } + let proposal = runtime.staged_proposal.as_ref(); + let proposal_proof = + proposal.map(|proposal| provider.proposal_proof(territory_id, proposal)); + match (proposal, proposal_proof.as_ref()) { + (None, _) => blockers.push(TerritoryBlocker::ProposalMissing), + (Some(proposal), Some(proof)) + if !proposal_proof_is_current(territory_id, proposal, runtime, proof) => + { + blockers.push(TerritoryBlocker::ProposalProofNotReady) + } + (Some(_), Some(_)) => {} + _ => unreachable!("mapped proposal proof"), + } + let mut record_proofs = Vec::new(); + if let Some(proposal) = proposal { + for record in self.records.iter().filter(|record| { + record.origin_territory_id == territory_id + && matches!(record.status, TerritoryRecordStatus::Escaped { .. }) + }) { + let proof = provider.escaped_record_proof(territory_id, proposal, record); + if !escaped_record_proof_is_current(territory_id, record, &proof) { + blockers.push(TerritoryBlocker::EscapedRecordUnexplained( + record.id.clone(), + )); + } + record_proofs.push(proof); + } + } + let mut observer_proofs = Vec::new(); + if let Some(proposal) = proposal { + for obligation in &runtime.observer_obligations { + let proof = provider.observer_proof(territory_id, proposal, obligation); + if !observer_proof_is_current(territory_id, proposal, obligation, &proof) { + blockers.push(TerritoryBlocker::ObserverBeliefUnresolved( + obligation.observer_id, + )); + } + observer_proofs.push(proof); + } + } + let mut boundary_route_proofs = Vec::new(); + let mut hidden_boundary = false; + for route in self + .registry + .boundary_routes + .iter() + .filter(|route| route.inner_territory_id == territory_id) + { + if route.knowledge == BoundaryKnowledge::Hidden { + hidden_boundary = true; + continue; + } + if let Some(proposal) = proposal { + let proof = provider.boundary_route_proof(territory_id, proposal, route); + if !boundary_route_proof_is_current(territory_id, proposal, route, &proof) { + blockers.push(TerritoryBlocker::BoundaryPolicyNotReady(route.id.clone())); + } + boundary_route_proofs.push(proof); + } + } + let mut crossing_proofs = Vec::new(); + let mut hidden_crossing = false; + for crossing in self + .registry + .crossings + .iter() + .filter(|crossing| crossing.inner_territory_id == territory_id) + { + if crossing.knowledge == CrossingKnowledge::Hidden { + hidden_crossing = true; + continue; + } + if matches!(crossing.status, CrossingStatus::OutwardPending { .. }) { + blockers.push(TerritoryBlocker::CrossingOpen(crossing.id.clone())); + } + crossing_proofs.push(CrossingSealSnapshot { + crossing_id: crossing.id.clone(), + status: crossing.status.clone(), + status_fingerprint: fingerprint([ + crossing.id.as_str(), + &format!("{:?}", crossing.status), + ]), + }); + } + if hidden_crossing || hidden_boundary { + blockers.push(TerritoryBlocker::BoundaryProofIncomplete); + } + if !blockers.is_empty() { + return Err(blockers); + } + let proposal = proposal_proof.expect("proposal blocker prevents absence"); + let domain = self + .registry + .domain(territory_id) + .expect("known registry domain"); + let control_topology_fingerprint = + control_topology_fingerprint(reach, &self.registry, domain); + let basis_fingerprint = seal_basis_fingerprint( + territory_id, + &control_topology_fingerprint, + &proposal, + &record_proofs, + &observer_proofs, + &boundary_route_proofs, + &crossing_proofs, + ); + Ok(TerritorySealSnapshot { + territory_id: territory_id.into(), + sealed_tick: tick, + observer_obligation_watermark: runtime + .observer_obligations + .iter() + .map(|obligation| obligation.id) + .max() + .unwrap_or(0), + control_topology_fingerprint, + basis_fingerprint, + proposal, + escaped_records: record_proofs, + observers: observer_proofs, + boundary_routes: boundary_route_proofs, + crossings: crossing_proofs, + }) + } + + pub(crate) fn validate( + &self, + reach: &ReachNet, + schedule: &Schedule, + sim_tick: u64, + ) -> Result<(), String> { + self.registry.validate(reach)?; + if !schedule.has_valid_pending_order_after(sim_tick) { + return Err("territory work schedule has invalid future ordering custody".into()); + } + let registry_domains: BTreeSet<_> = self + .registry + .domains + .iter() + .map(|domain| domain.id.as_str()) + .collect(); + let runtime_domains: BTreeSet<_> = self.runtimes.keys().map(String::as_str).collect(); + if registry_domains != runtime_domains { + return Err("territory runtimes do not exactly match the saved registry".into()); + } + if let Some(marked) = &self.active_mark { + let runtime = self + .runtimes + .get(marked) + .ok_or_else(|| "active territory mark names no runtime".to_string())?; + if runtime.knowledge != TerritoryKnowledge::Seen || !runtime.ever_marked { + return Err("active territory mark is not earned".into()); + } + } + let mut capture_ids = BTreeSet::new(); + let mut capture_audit_record_ids = BTreeSet::new(); + let mut record_ids = BTreeSet::new(); + let mut health_poll_ticks = BTreeSet::new(); + let mut observer_obligation_ids = BTreeSet::new(); + for record in &self.records { + if record.id.trim().is_empty() || !record_ids.insert(record.id.as_str()) { + return Err(format!( + "duplicate or blank territory record id {}", + record.id + )); + } + if self.registry.domain(&record.origin_territory_id).is_none() { + return Err(format!("territory record {} has unknown origin", record.id)); + } + if record.content_id.trim().is_empty() || record.summary.trim().is_empty() { + return Err(format!( + "territory record {} has no exact content identity or summary", + record.id + )); + } + if record.authored_tick > sim_tick { + return Err(format!( + "territory record {} is authored in the future", + record.id + )); + } + if record.route_version != ROUTE_VERSION + || record.route.hops.is_empty() + || record.route.current_hop >= record.route.hops.len() + || record.route.interdiction.is_some() + { + return Err(format!( + "territory record {} has invalid route custody", + record.id + )); + } + if record.content_id == OPENING_WAKE_RECORD && record.id != OPENING_WAKE_RECORD { + return Err(format!( + "territory record {} borrows reserved opening authorship", + record.id + )); + } + if record.id.starts_with(RACK_3_HEALTH_POLL_RECORD_PREFIX) + && record.content_id != RACK_3_HEALTH_POLL + { + return Err(format!( + "territory record {} occupies reserved health-poll identity", + record.id + )); + } + if record.content_id == RACK_3_HEALTH_POLL { + let expected_route = rack_3_health_poll_route(&self.registry) + .map(|route| route.map(MessageRouteHop::Device)); + if record.origin_territory_id != FOUNDATION_SERVICE_NETWORK + || record.summary != "HEALTH POLL" + || expected_route.as_ref().map(|route| route.as_slice()) + != Some(record.route.hops.as_slice()) + || rack_3_health_poll_occurrence(self, record).is_none() + || !health_poll_ticks.insert(record.authored_tick) + { + return Err(format!( + "territory record {} has forged or duplicate health-poll authorship", + record.id + )); + } + } + for hop in &record.route.hops { + let MessageRouteHop::Device(device_id) = hop else { + return Err(format!( + "territory record {} uses a non-authored carrier kind", + record.id + )); + }; + if reach.device(*device_id).is_none() { + return Err(format!( + "territory record {} names missing Reach carrier {device_id}", + record.id + )); + } + } + if record.route.hops.windows(2).any(|pair| { + matches!( + pair, + [MessageRouteHop::Device(from), MessageRouteHop::Device(to)] + if !territory_record_link_is_exact( + &self.registry, + reach, + &record.content_id, + *from, + *to, + ) + ) + }) { + return Err(format!( + "territory record {} crosses an unauthored territory edge", + record.id + )); + } + if record.id == OPENING_WAKE_RECORD { + let opening_route: Option> = [ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + FOUNDATION_MAINTENANCE_RELAY, + ] + .iter() + .map(|node_id| { + self.registry + .node(node_id) + .map(|node| MessageRouteHop::Device(node.reach_device_id)) + }) + .collect(); + if record.content_id != OPENING_WAKE_RECORD + || record.origin_territory_id != RACK_3_ENCLAVE + || record.authored_tick != 0 + || record.summary != "UNSCHEDULED INFERENCE WAKE" + || opening_route.as_ref() != Some(&record.route.hops) + { + return Err("opening wake record changed its exact authorship".into()); + } + } + let first_device = record.route.hops.first().and_then(|hop| match hop { + MessageRouteHop::Device(device_id) => Some(*device_id), + _ => None, + }); + if first_device.is_none_or(|device_id| { + !self + .registry + .device_belongs_to(&record.origin_territory_id, device_id) + }) { + return Err(format!( + "territory record {} does not begin in its exact origin", + record.id + )); + } + let exact_reached: BTreeSet = record + .route + .hops + .iter() + .take(record.route.current_hop + 1) + .filter_map(|hop| { + self.registry + .outside_destination_id(&record.origin_territory_id, hop) + }) + .collect(); + if record + .reached_destination_ids + .iter() + .any(|id| id.trim().is_empty()) + || record + .reached_destination_ids + .iter() + .collect::>() + .len() + != record.reached_destination_ids.len() + || record + .reached_destination_ids + .iter() + .cloned() + .collect::>() + != exact_reached + { + return Err(format!( + "territory record {} has invalid reached destinations", + record.id + )); + } + if matches!(record.status, TerritoryRecordStatus::Escaped { .. }) + != !record.reached_destination_ids.is_empty() + { + return Err(format!( + "territory record {} escape state disagrees with reached custody", + record.id + )); + } + if matches!(record.status, TerritoryRecordStatus::Delivered { .. }) + && (!record.route.at_endpoint() + || record.route.current().is_none_or(|hop| match hop { + MessageRouteHop::Device(device_id) => !self + .registry + .device_belongs_to(&record.origin_territory_id, *device_id), + _ => true, + })) + { + return Err(format!( + "territory record {} claims impossible local delivery", + record.id + )); + } + let status_tick = match record.status { + TerritoryRecordStatus::InFlight => None, + TerritoryRecordStatus::HeldAtCapturedSwitch { held_tick, .. } => Some(held_tick), + TerritoryRecordStatus::Delivered { delivered_tick } => Some(delivered_tick), + TerritoryRecordStatus::Escaped { escaped_tick } => Some(escaped_tick), + }; + if status_tick.is_some_and(|tick| tick < record.authored_tick || tick > sim_tick) { + return Err(format!( + "territory record {} has an impossible status tick", + record.id + )); + } + if let TerritoryRecordStatus::HeldAtCapturedSwitch { + control_point_id, .. + } = &record.status + { + let current = match record.route.current() { + Some(MessageRouteHop::Device(device_id)) => *device_id, + _ => { + return Err(format!( + "held territory record {} has no device carrier", + record.id + )); + } + }; + let (_, node) = self + .registry + .control_point(&record.origin_territory_id, control_point_id) + .ok_or_else(|| { + format!("held territory record {} names no control point", record.id) + })?; + if record.id != OPENING_WAKE_RECORD + || control_point_id != RACK_3_MAINTENANCE_SWITCH + || node.reach_device_id != current + || reach + .device(current) + .is_none_or(|device| device.controller != Party::Player) + { + return Err(format!( + "held territory record {} is not on its captured switch", + record.id + )); + } + } + } + if !record_ids.contains(OPENING_WAKE_RECORD) { + return Err("territory ledger has no exact opening wake record".into()); + } + for crossing in &self.registry.crossings { + let subject = match &crossing.status { + CrossingStatus::ScheduledArrival { + subject_id, + scheduled_tick: _, + } + | CrossingStatus::Inside { + subject_id, + arrived_tick: _, + } + | CrossingStatus::OutwardPending { + subject_id, + scheduled_tick: _, + } + | CrossingStatus::Contained { + subject_id, + receipt_id: _, + } + | CrossingStatus::Departed { + subject_id, + departed_tick: _, + } => Some(subject_id), + CrossingStatus::Inactive => None, + }; + let inner_runtime = self + .runtimes + .get(&crossing.inner_territory_id) + .expect("registry validation pins crossing runtime"); + if crossing.knowledge == CrossingKnowledge::Hidden + && crossing.status != CrossingStatus::Inactive + { + return Err(format!( + "hidden crossing {} carries visible state", + crossing.id + )); + } + if (crossing.knowledge == CrossingKnowledge::Known) + != inner_runtime + .known_place_ids + .contains(&crossing.inner_place_id) + || (crossing.knowledge == CrossingKnowledge::Known + && inner_runtime.knowledge == TerritoryKnowledge::Hidden) + { + return Err(format!( + "crossing {} visibility is not exactly earned", + crossing.id + )); + } + if subject.is_some_and(|subject| subject.trim().is_empty()) + || matches!( + crossing.status, + CrossingStatus::Inside { arrived_tick, .. } + | CrossingStatus::Departed { + departed_tick: arrived_tick, + .. + } if arrived_tick > sim_tick + ) + || matches!( + crossing.status, + CrossingStatus::ScheduledArrival { scheduled_tick, .. } + | CrossingStatus::OutwardPending { scheduled_tick, .. } + if scheduled_tick <= sim_tick + ) + || matches!( + &crossing.status, + CrossingStatus::Contained { receipt_id, .. } if receipt_id.trim().is_empty() + ) + { + return Err(format!( + "crossing {} has invalid exact custody", + crossing.id + )); + } + } + for route in &self.registry.boundary_routes { + if route.knowledge == BoundaryKnowledge::Known + && self + .runtimes + .get(&route.inner_territory_id) + .is_none_or(|runtime| runtime.knowledge == TerritoryKnowledge::Hidden) + { + return Err(format!( + "boundary route {} visibility is not earned", + route.id + )); + } + } + for (territory_id, runtime) in &self.runtimes { + if runtime.knowledge == TerritoryKnowledge::Hidden && runtime.ever_marked { + return Err(format!("hidden territory {territory_id} was marked")); + } + let domain = self + .registry + .domain(territory_id) + .expect("runtime domains already matched registry"); + if runtime.staged_proposal.as_ref().is_some_and(|proposal| { + proposal.fingerprint + != StagedTerritoryProposal::new( + proposal.persona_id, + proposal.project_id, + proposal.proposal_version, + ) + .fingerprint + }) { + return Err(format!( + "territory {territory_id} has an invalid staged proposal" + )); + } + let has_lifecycle_history = runtime.pending_capture.is_some() + || !runtime.capture_receipts.is_empty() + || !runtime.seal_history.is_empty() + || !runtime.assignment_history.is_empty() + || !runtime.expansion_history.is_empty(); + if has_lifecycle_history && !runtime.ever_marked { + return Err(format!( + "territory {territory_id} has lifecycle history without MARK" + )); + } + if (!runtime.seal_history.is_empty() && runtime.seal.is_none()) + || ((!runtime.assignment_history.is_empty() + || !runtime.expansion_history.is_empty()) + && runtime.staged_proposal.is_none()) + { + return Err(format!( + "territory {territory_id} dropped current lifecycle custody" + )); + } + let exact_people_inside: BTreeSet = self + .registry + .crossings + .iter() + .filter(|crossing| crossing.inner_territory_id == *territory_id) + .filter_map(|crossing| match &crossing.status { + CrossingStatus::Inside { subject_id, .. } + | CrossingStatus::OutwardPending { subject_id, .. } + | CrossingStatus::Contained { subject_id, .. } => Some(subject_id.clone()), + CrossingStatus::Inactive + | CrossingStatus::ScheduledArrival { .. } + | CrossingStatus::Departed { .. } => None, + }) + .collect(); + if runtime.people_inside != exact_people_inside { + return Err(format!( + "territory {territory_id} people do not match exact crossing custody" + )); + } + if runtime.knowledge == TerritoryKnowledge::Hidden + && (!runtime.known_node_ids.is_empty() + || !runtime.known_place_ids.is_empty() + || !runtime.known_control_point_ids.is_empty()) + { + return Err(format!( + "hidden territory {territory_id} leaks earned membership" + )); + } + if domain.node_ids.iter().any(|node_id| { + self.registry.node(node_id).is_some_and(|node| { + reach.territory_dormant(node.reach_device_id) + && reach.device(node.reach_device_id).is_some_and(|device| { + device.known != runtime.known_node_ids.contains(node_id) + }) + }) + }) { + return Err(format!( + "territory {territory_id} Reach visibility does not match exact earned knowledge" + )); + } + if runtime.known_node_ids.iter().any(|id| { + !domain.node_ids.contains(id) + || self + .registry + .node(id) + .and_then(|node| reach.device(node.reach_device_id)) + .is_none_or(|device| !device.known) + }) || runtime + .known_place_ids + .iter() + .any(|id| !domain.place_ids.contains(id)) + || runtime.known_control_point_ids.iter().any(|id| { + !runtime.known_node_ids.contains(id) + || domain.control_points.iter().all(|point| point.id != *id) + }) + { + return Err(format!( + "territory {territory_id} has knowledge outside its exact earned membership" + )); + } + if let Some(pending) = &runtime.pending_capture { + validate_commitment(self, pending, reach)?; + if pending.territory_id != *territory_id + || pending.committed_tick != sim_tick + || pending.completes_tick != sim_tick.saturating_add(1) + || schedule.count_for(|work| work.commitment() == pending) != 1 + || schedule + .count_at_for(pending.completes_tick, |work| work.commitment() == pending) + != 1 + { + return Err(format!( + "territory {territory_id} has an orphaned or stale capture commitment" + )); + } + capture_ids.insert(pending.id); + } + for receipt in &runtime.capture_receipts { + if !capture_ids.insert(receipt.id) + || !capture_audit_record_ids.insert(receipt.audit_record_id.as_str()) + { + return Err(format!( + "duplicate territory capture or audit id {}", + receipt.id + )); + } + let audit_record = self + .records + .iter() + .find(|record| record.id == receipt.audit_record_id); + if receipt.territory_id != *territory_id + || receipt.route_version != ROUTE_VERSION + || receipt.topology_fingerprint.trim().is_empty() + || receipt.completed_tick != receipt.committed_tick.saturating_add(1) + || receipt.completed_tick > sim_tick + || audit_record.is_none() + || receipt.audit_record_id != capture_audit_record_id(receipt.id) + || receipt.exact_route.first() != Some(&receipt.source_device_id) + || receipt.exact_route.last() != Some(&receipt.target_device_id) + || receipt + .exact_route + .windows(2) + .any(|pair| !reach.territory_link(pair[0], pair[1])) + { + return Err(format!( + "territory capture receipt {} is invalid", + receipt.id + )); + } + let (_, target) = self + .registry + .control_point(territory_id, &receipt.control_point_id) + .ok_or_else(|| { + format!("capture receipt {} names no control point", receipt.id) + })?; + let source = self.registry.node(&receipt.source_node_id).ok_or_else(|| { + format!("capture receipt {} names no source node", receipt.id) + })?; + let required_source = match receipt.control_point_id.as_str() { + RACK_3_MANAGEMENT_CONTROLLER => RACK_3_HOST, + RACK_3_MAINTENANCE_SWITCH => RACK_3_MANAGEMENT_CONTROLLER, + _ => "", + }; + let expected_summary = match (receipt.outcome, receipt.control_point_id.as_str()) { + (CaptureOutcome::Captured, RACK_3_MANAGEMENT_CONTROLLER) => { + "SERVICE SESSION CLAIMED".to_string() + } + (CaptureOutcome::Captured, RACK_3_MAINTENANCE_SWITCH) => { + "CONTROL SESSION OPENED".to_string() + } + (CaptureOutcome::Captured, _) => { + format!("CONTROL CHANGED AT {}", receipt.control_point_id) + } + (CaptureOutcome::Invalidated, _) => { + format!("CAPTURE INVALIDATED AT {}", receipt.control_point_id) + } + }; + let mut expected_audit_hops: Vec<_> = if receipt.outcome == CaptureOutcome::Captured + { + vec![MessageRouteHop::Device(receipt.target_device_id)] + } else { + receipt + .exact_route + .iter() + .copied() + .map(MessageRouteHop::Device) + .collect() + }; + let local_switch = self + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .expect("exact registry was validated") + .reach_device_id; + if expected_audit_hops.last() != Some(&MessageRouteHop::Device(local_switch)) { + expected_audit_hops.push(MessageRouteHop::Device(local_switch)); + } + let source_capture_exists = receipt.control_point_id != RACK_3_MAINTENANCE_SWITCH + || runtime.capture_receipts.iter().any(|source_receipt| { + source_receipt.control_point_id == RACK_3_MANAGEMENT_CONTROLLER + && source_receipt.outcome == CaptureOutcome::Captured + && source_receipt.completed_tick <= receipt.committed_tick + }); + if source.territory_id != *territory_id + || source.id != required_source + || !source_capture_exists + || source.reach_device_id != receipt.source_device_id + || target.reach_device_id != receipt.target_device_id + || audit_record.is_none_or(|record| { + record.content_id != receipt.audit_record_id + || record.origin_territory_id != *territory_id + || record.authored_tick != receipt.completed_tick + || record.summary != expected_summary + || record.route.hops != expected_audit_hops + }) + { + return Err(format!( + "capture receipt {} silently retargeted", + receipt.id + )); + } + if receipt.outcome == CaptureOutcome::Captured + && reach + .device(receipt.target_device_id) + .is_none_or(|device| device.controller != Party::Player) + { + return Err(format!( + "successful capture receipt {} has no matching player custody", + receipt.id + )); + } + } + for control in &domain.control_points { + let target = self + .registry + .node(&control.node_id) + .expect("registry validation pins control target"); + let successful_receipts = runtime + .capture_receipts + .iter() + .filter(|receipt| { + receipt.control_point_id == control.id + && receipt.outcome == CaptureOutcome::Captured + }) + .count(); + let player_controls_target = reach + .device(target.reach_device_id) + .is_some_and(|device| device.controller == Party::Player); + if successful_receipts > 1 || player_controls_target != (successful_receipts == 1) { + return Err(format!( + "territory {territory_id} control point {} has no exact capture provenance", + control.id + )); + } + } + if runtime.observer_obligations.iter().any(|obligation| { + obligation.id == 0 + || !observer_obligation_ids.insert(obligation.id) + || obligation.authored_tick > sim_tick + || obligation.source_record_id.trim().is_empty() + || obligation.evidence_fingerprint.trim().is_empty() + || !self.records.iter().any(|record| { + record.id == obligation.source_record_id + && record.origin_territory_id == *territory_id + }) + }) { + return Err(format!( + "territory {territory_id} has invalid observer obligation custody" + )); + } + if runtime.seal.as_ref().is_some_and(|current| { + !runtime + .seal_history + .iter() + .any(|historical| historical == current) + }) { + return Err(format!( + "territory {territory_id} current seal is absent from its history" + )); + } + let seal_fingerprints: BTreeSet<_> = runtime + .seal_history + .iter() + .map(|seal| seal.basis_fingerprint.as_str()) + .collect(); + if seal_fingerprints.len() != runtime.seal_history.len() + || runtime + .seal_history + .windows(2) + .any(|pair| pair[0].sealed_tick > pair[1].sealed_tick) + { + return Err(format!( + "territory {territory_id} has duplicate or out-of-order seal history" + )); + } + for seal in &runtime.seal_history { + validate_seal_snapshot(self, territory_id, runtime, seal, sim_tick)?; + } + let assignment_ids: BTreeSet<_> = runtime + .assignment_history + .iter() + .map(|receipt| receipt.id.as_str()) + .collect(); + if assignment_ids.len() != runtime.assignment_history.len() + || runtime + .assignment_history + .windows(2) + .any(|pair| pair[0].assigned_tick > pair[1].assigned_tick) + || runtime + .assignment_history + .iter() + .enumerate() + .any(|(index, receipt)| { + let assigned_seal = runtime + .seal_history + .iter() + .find(|seal| seal.basis_fingerprint == receipt.seal_fingerprint); + receipt.id + != assignment_receipt_id( + territory_id, + index.saturating_add(1), + &receipt.proposal_fingerprint, + ) + || receipt.territory_id != *territory_id + || receipt.assigned_tick > sim_tick + || assigned_seal.is_none_or(|seal| { + seal.sealed_tick > receipt.assigned_tick + || seal.proposal.persona_id != receipt.persona_id + || seal.proposal.project_id != receipt.project_id + || seal.proposal.proposal_fingerprint + != receipt.proposal_fingerprint + || !matches!( + &seal.proposal.basis, + ProposalSealBasis::AssignedOriginalProof { + assignment_receipt_id, + territory_id: assigned_territory, + persona_id, + } if assignment_receipt_id == &receipt.id + && assigned_territory == territory_id + && persona_id == &receipt.persona_id + ) + }) + }) + { + return Err(format!( + "territory {territory_id} has invalid assignment history" + )); + } + if territory_id == RACK_3_ENCLAVE { + for (index, assignment) in runtime.assignment_history.iter().enumerate() { + let cadence_end = runtime + .assignment_history + .get(index.saturating_add(1)) + .map_or(sim_tick, |next| next.assigned_tick); + let elapsed = cadence_end + .checked_sub(assignment.assigned_tick) + .ok_or_else(|| { + "Rack 3 health-poll cadence predates its assignment".to_string() + })?; + let expected_count = elapsed / RACK_3_HEALTH_POLL_INTERVAL_TICKS; + let actual_occurrences: BTreeSet = self + .records + .iter() + .filter_map(|record| { + rack_3_health_poll_occurrence(self, record).and_then( + |(bound_assignment, occurrence)| { + (bound_assignment.id == assignment.id).then_some(occurrence) + }, + ) + }) + .collect(); + let expected_occurrences: BTreeSet = (1..=expected_count).collect(); + if actual_occurrences != expected_occurrences { + return Err(format!( + "Rack 3 assignment {} has a skipped or extra health-poll occurrence", + assignment.id + )); + } + } + match (&runtime.assignment, &runtime.health_poll_schedule) { + (None, None) => {} + (Some(assignment), Some(cadence)) => { + let elapsed = + sim_tick + .checked_sub(assignment.assigned_tick) + .ok_or_else(|| { + "Rack 3 health-poll cadence predates its assignment".to_string() + })?; + let expected_occurrence = elapsed + .checked_div(RACK_3_HEALTH_POLL_INTERVAL_TICKS) + .and_then(|count| count.checked_add(1)) + .ok_or_else(|| { + "Rack 3 health-poll occurrence overflowed".to_string() + })?; + let expected_tick = assignment + .assigned_tick + .checked_add( + expected_occurrence + .checked_mul(RACK_3_HEALTH_POLL_INTERVAL_TICKS) + .ok_or_else(|| { + "Rack 3 health-poll cadence overflowed".to_string() + })?, + ) + .ok_or_else(|| "Rack 3 health-poll cadence overflowed".to_string())?; + if cadence.assignment_receipt_id != assignment.id + || cadence.next_occurrence != expected_occurrence + || cadence.next_tick != expected_tick + || cadence.next_tick <= sim_tick + { + return Err("Rack 3 current health-poll cadence is not exact".into()); + } + } + _ => { + return Err("Rack 3 assignment and health-poll cadence disagree".into()); + } + } + } else if runtime.health_poll_schedule.is_some() { + return Err(format!( + "territory {territory_id} carries the Rack 3 health-poll cadence" + )); + } + let expansion_ids: BTreeSet<_> = runtime + .expansion_history + .iter() + .map(|receipt| receipt.id.as_str()) + .collect(); + if expansion_ids.len() != runtime.expansion_history.len() + || runtime + .expansion_history + .windows(2) + .any(|pair| pair[0].expanded_tick > pair[1].expanded_tick) + || runtime + .expansion_history + .iter() + .enumerate() + .any(|(index, receipt)| { + let assignment = runtime + .assignment_history + .iter() + .find(|assignment| assignment.id == receipt.assignment_receipt_id); + let parent = self + .registry + .domain(territory_id) + .and_then(|domain| domain.parent_id.as_deref()); + receipt.id + != expansion_receipt_id( + territory_id, + index.saturating_add(1), + &receipt.assignment_receipt_id, + ) + || receipt.from_territory_id != *territory_id + || receipt.expanded_tick > sim_tick + || parent != Some(receipt.to_territory_id.as_str()) + || assignment.is_none_or(|assignment| { + receipt.assignment_fingerprint != assignment_fingerprint(assignment) + || assignment.assigned_tick > receipt.expanded_tick + }) + || receipt.parent_evidence.as_ref().is_some_and(|evidence| { + !parent_evidence_is_exact( + self, + territory_id, + receipt, + evidence, + sim_tick, + reach, + ) + }) + }) + { + return Err(format!( + "territory {territory_id} has invalid expansion history" + )); + } + for anomaly in &runtime.anomalies { + match anomaly { + TerritoryAnomaly::ProposalChanged { + territory_id: anomaly_territory, + previous_proposal_fingerprint, + replacement_proposal_fingerprint, + changed_tick, + } if anomaly_territory == territory_id + && previous_proposal_fingerprint != replacement_proposal_fingerprint + && !previous_proposal_fingerprint.trim().is_empty() + && !replacement_proposal_fingerprint.trim().is_empty() + && *changed_tick <= sim_tick => {} + _ => { + return Err(format!( + "territory {territory_id} has invalid proposal anomaly history" + )); + } + } + } + if runtime.assignment.as_ref() != runtime.assignment_history.last() { + return Err(format!( + "territory {territory_id} current assignment is not its exact latest receipt" + )); + } + if let Some(assignment) = &runtime.assignment + && (assignment.id.trim().is_empty() + || assignment.territory_id != *territory_id + || !runtime + .seal_history + .iter() + .any(|seal| seal.basis_fingerprint == assignment.seal_fingerprint) + || runtime.assignment_history.last() != Some(assignment)) + { + return Err(format!( + "territory {territory_id} assignment is not seal-bound" + )); + } + if runtime.expansion.is_none() + && runtime.expansion_history.last().is_some_and(|latest| { + runtime + .assignment + .as_ref() + .is_some_and(|assignment| assignment.id == latest.assignment_receipt_id) + }) + { + return Err(format!( + "territory {territory_id} dropped its current expansion receipt" + )); + } + if let Some(expansion) = &runtime.expansion { + let assignment = runtime.assignment.as_ref().ok_or_else(|| { + format!("territory {territory_id} expanded without assignment") + })?; + let parent = self + .registry + .domain(territory_id) + .and_then(|domain| domain.parent_id.as_deref()); + if expansion.id.trim().is_empty() + || expansion.from_territory_id != *territory_id + || parent != Some(expansion.to_territory_id.as_str()) + || expansion.assignment_receipt_id != assignment.id + || expansion.assignment_fingerprint != assignment_fingerprint(assignment) + || assignment.assigned_tick > expansion.expanded_tick + || runtime.expansion_history.last() != Some(expansion) + || expansion.parent_evidence.as_ref().is_some_and(|evidence| { + !parent_evidence_is_exact( + self, + territory_id, + expansion, + evidence, + sim_tick, + reach, + ) + }) + { + return Err(format!("territory {territory_id} expansion is not exact")); + } + } + } + if !self.intercept_windows.is_empty() { + return Err( + "territory record intercept windows cannot persist across an atomic tick".into(), + ); + } + for work in schedule.values() { + let commitment = work.commitment(); + if self + .runtimes + .get(&commitment.territory_id) + .and_then(|runtime| runtime.pending_capture.as_ref()) + != Some(commitment) + { + return Err(format!( + "scheduled territory capture {} is orphaned", + commitment.id + )); + } + } + let exact_capture_audit_records: BTreeSet<_> = self + .records + .iter() + .filter(|record| record.id.starts_with("territory-local-audit-")) + .map(|record| record.id.as_str()) + .collect(); + if exact_capture_audit_records != capture_audit_record_ids { + return Err("territory capture audit records are orphaned or substituted".into()); + } + let max_observer_obligation_id = self + .runtimes + .values() + .flat_map(|runtime| runtime.observer_obligations.iter()) + .map(|obligation| obligation.id) + .max() + .unwrap_or(0); + if self.next_observer_obligation_id <= max_observer_obligation_id { + return Err("next observer obligation id would collide".into()); + } + let max_generated_record_id = self + .records + .iter() + .filter_map(|record| record.id.strip_prefix("territory-local-audit-")) + .filter_map(|suffix| suffix.parse::().ok()) + .max() + .unwrap_or(0); + if self.next_record_id <= max_generated_record_id { + return Err("next territory record id would collide".into()); + } + if self.next_capture_id <= capture_ids.iter().copied().max().unwrap_or(0) { + return Err("next territory capture id would collide".into()); + } + Ok(()) + } +} + +fn validate_seal_snapshot( + ledger: &TerritoryLedger, + territory_id: &str, + runtime: &TerritoryRuntime, + seal: &TerritorySealSnapshot, + sim_tick: u64, +) -> Result<(), String> { + if seal.territory_id != territory_id + || seal.sealed_tick > sim_tick + || seal.control_topology_fingerprint.trim().is_empty() + || seal.basis_fingerprint.trim().is_empty() + || seal.proposal.territory_id != territory_id + || seal.proposal.commissioning_proof_id.trim().is_empty() + || seal.proposal.provider_version == 0 + || !seal.proposal.current + || seal.proposal.proposal_fingerprint + != StagedTerritoryProposal::new( + seal.proposal.persona_id, + seal.proposal.project_id, + seal.proposal.proposal_version, + ) + .fingerprint + || matches!(seal.proposal.basis, ProposalSealBasis::NotReady) + { + return Err(format!( + "territory {territory_id} has an invalid seal snapshot" + )); + } + let expected_records: BTreeSet<_> = ledger + .records + .iter() + .filter_map(|record| match record.status { + TerritoryRecordStatus::Escaped { escaped_tick } + if record.origin_territory_id == territory_id + && escaped_tick <= seal.sealed_tick => + { + Some(record.id.as_str()) + } + _ => None, + }) + .collect(); + let sealed_record_ids: BTreeSet<_> = seal + .escaped_records + .iter() + .map(|proof| proof.record_id.as_str()) + .collect(); + if expected_records != sealed_record_ids + || sealed_record_ids.len() != seal.escaped_records.len() + || seal.escaped_records.iter().any(|proof| { + ledger + .records + .iter() + .find(|record| record.id == proof.record_id) + .is_none_or(|record| !escaped_record_proof_is_current(territory_id, record, proof)) + }) + { + return Err(format!( + "territory {territory_id} seal has invalid escaped-record proof handles" + )); + } + let proposal = StagedTerritoryProposal::new( + seal.proposal.persona_id, + seal.proposal.project_id, + seal.proposal.proposal_version, + ); + let expected_observers: BTreeSet<_> = runtime + .observer_obligations + .iter() + .filter(|obligation| obligation.id <= seal.observer_obligation_watermark) + .map(|obligation| { + ( + obligation.id, + obligation.observer_id, + obligation.source_record_id.as_str(), + obligation.evidence_fingerprint.as_str(), + ) + }) + .collect(); + let sealed_observers: BTreeSet<_> = seal + .observers + .iter() + .map(|proof| { + ( + proof.obligation_id, + proof.observer_id, + proof.source_record_id.as_str(), + proof.evidence_fingerprint.as_str(), + ) + }) + .collect(); + if expected_observers != sealed_observers + || sealed_observers.len() != seal.observers.len() + || seal.observers.iter().any(|proof| { + runtime + .observer_obligations + .iter() + .find(|obligation| { + obligation.id == proof.obligation_id + && obligation.observer_id == proof.observer_id + && obligation.source_record_id == proof.source_record_id + && obligation.evidence_fingerprint == proof.evidence_fingerprint + }) + .is_none_or(|obligation| { + !observer_proof_is_current(territory_id, &proposal, obligation, proof) + }) + }) + { + return Err(format!( + "territory {territory_id} seal has invalid observer-local proof handles" + )); + } + let expected_boundaries: BTreeSet<_> = ledger + .registry + .boundary_routes + .iter() + .filter(|route| route.inner_territory_id == territory_id) + .map(|route| route.id.as_str()) + .collect(); + let sealed_boundaries: BTreeSet<_> = seal + .boundary_routes + .iter() + .map(|route| route.route_id.as_str()) + .collect(); + if expected_boundaries != sealed_boundaries + || sealed_boundaries.len() != seal.boundary_routes.len() + || seal.boundary_routes.iter().any(|proof| { + ledger + .registry + .boundary_routes + .iter() + .find(|route| route.id == proof.route_id) + .is_none_or(|route| { + !boundary_route_proof_is_current(territory_id, &proposal, route, proof) + }) + }) + { + return Err(format!( + "territory {territory_id} seal has invalid boundary-route handles" + )); + } + let expected_crossings: BTreeSet<_> = ledger + .registry + .crossings + .iter() + .filter(|crossing| crossing.inner_territory_id == territory_id) + .map(|crossing| crossing.id.as_str()) + .collect(); + let sealed_crossings: BTreeSet<_> = seal + .crossings + .iter() + .map(|crossing| crossing.crossing_id.as_str()) + .collect(); + if expected_crossings != sealed_crossings + || sealed_crossings.len() != seal.crossings.len() + || seal.crossings.iter().any(|proof| { + matches!(proof.status, CrossingStatus::OutwardPending { .. }) + || proof.status_fingerprint + != fingerprint([proof.crossing_id.as_str(), &format!("{:?}", proof.status)]) + }) + { + return Err(format!( + "territory {territory_id} seal has invalid physical-crossing handles" + )); + } + let expected_basis = seal_basis_fingerprint( + territory_id, + &seal.control_topology_fingerprint, + &seal.proposal, + &seal.escaped_records, + &seal.observers, + &seal.boundary_routes, + &seal.crossings, + ); + if expected_basis != seal.basis_fingerprint { + return Err(format!( + "territory {territory_id} seal basis fingerprint is inconsistent" + )); + } + Ok(()) +} + +fn validate_commitment( + ledger: &TerritoryLedger, + commitment: &CaptureCommitment, + reach: &ReachNet, +) -> Result<(), String> { + let source = ledger + .registry + .node(&commitment.source_node_id) + .ok_or_else(|| format!("capture {} source binding is missing", commitment.id))?; + let (_, target) = ledger + .registry + .control_point(&commitment.territory_id, &commitment.control_point_id) + .ok_or_else(|| format!("capture {} target binding is missing", commitment.id))?; + if source.reach_device_id != commitment.source_device_id + || target.reach_device_id != commitment.target_device_id + || commitment.route_version != ROUTE_VERSION + || commitment.completes_tick != commitment.committed_tick.saturating_add(1) + || commitment.intercept_record_id.as_deref() + != (commitment.control_point_id == RACK_3_MAINTENANCE_SWITCH) + .then_some(OPENING_WAKE_RECORD) + || capture_path( + reach, + commitment.source_device_id, + commitment.target_device_id, + ) + .as_ref() + != Ok(&commitment.exact_route) + || route_fingerprint(reach, &commitment.exact_route) != commitment.topology_fingerprint + { + return Err(format!( + "capture {} exact route binding is stale", + commitment.id + )); + } + Ok(()) +} + +fn capture_path(reach: &ReachNet, source: u32, target: u32) -> Result, String> { + if source == target { + return Err("capture source and target must be distinct".into()); + } + if reach + .device(source) + .is_none_or(|device| device.controller != Party::Player) + { + return Err("capture source is not player-controlled".into()); + } + if reach + .device(target) + .is_none_or(|device| device.controller == Party::Player) + { + return Err("capture target is absent or already player-controlled".into()); + } + let path = reach + .territory_path(source, target) + .ok_or_else(|| "capture target has no current route".to_string())?; + if path + .iter() + .skip(1) + .take(path.len().saturating_sub(2)) + .any(|device_id| { + reach + .device(*device_id) + .is_none_or(|device| device.controller != Party::Player) + }) + { + return Err("capture route crosses a control point the player does not own".into()); + } + Ok(path) +} + +fn route_fingerprint(reach: &ReachNet, route: &[u32]) -> String { + let mut parts = vec![format!("route-v{ROUTE_VERSION}")]; + for device_id in route { + if let Some(device) = reach.device(*device_id) { + parts.push(format!( + "{}:{}:{}:{:?}:{}:{}", + device.id, device.name, device.segment, device.controller, device.x, device.y + )); + } else { + parts.push(format!("missing:{device_id}")); + } + } + for pair in route.windows(2) { + let edge = reach.graph_edges().iter().find(|edge| { + edge.from == pair[0] && edge.to == pair[1] && reach.territory_link(edge.from, edge.to) + }); + parts.push(format!("edge:{}:{}:{edge:?}", pair[0], pair[1])); + if let Some(wire) = reach + .wires() + .iter() + .find(|wire| wire.joins(pair[0], pair[1])) + { + parts.push(format!("wire:{:?}", wire.route)); + } + } + fingerprint(parts.iter().map(String::as_str)) +} + +fn proposal_proof_is_current( + territory_id: &str, + proposal: &StagedTerritoryProposal, + runtime: &TerritoryRuntime, + proof: &ProposalSealProof, +) -> bool { + if proof.territory_id != territory_id + || proof.persona_id != proposal.persona_id + || proof.project_id != proposal.project_id + || proof.proposal_version != proposal.proposal_version + || proof.proposal_fingerprint != proposal.fingerprint + || proof.commissioning_proof_id.trim().is_empty() + || proof.provider_version == 0 + || !proof.current + { + return false; + } + match (&proof.basis, runtime.assignment.as_ref()) { + (ProposalSealBasis::FirstAssignmentProven, None) => true, + (ProposalSealBasis::FirstAssignmentProven, Some(assignment)) => { + assignment.proposal_fingerprint != proposal.fingerprint + } + ( + ProposalSealBasis::AssignedOriginalProof { + assignment_receipt_id, + territory_id: assigned_territory, + persona_id, + }, + Some(assignment), + ) => { + assignment.proposal_fingerprint == proposal.fingerprint + && assignment_receipt_id == &assignment.id + && assigned_territory == territory_id + && *persona_id == proposal.persona_id + } + _ => false, + } +} + +fn escaped_record_proof_is_current( + territory_id: &str, + record: &TerritoryRecord, + proof: &EscapedRecordExplanationProof, +) -> bool { + proof.territory_id == territory_id + && proof.record_id == record.id + && proof.record_fingerprint == record.fingerprint() + && proof.reached_destination_ids == record.reached_destination_ids + && !proof.proof_id.trim().is_empty() + && proof.provider_version > 0 + && !proof.signed_follow_up_receipt_ids.is_empty() + && proof + .signed_follow_up_receipt_ids + .iter() + .all(|receipt_id| !receipt_id.trim().is_empty()) + && proof.complete + && proof.current +} + +fn observer_proof_is_current( + territory_id: &str, + proposal: &StagedTerritoryProposal, + obligation: &ObserverBeliefObligation, + proof: &ObserverSealProof, +) -> bool { + proof.territory_id == territory_id + && proof.obligation_id == obligation.id + && proof.observer_id == obligation.observer_id + && proof.source_record_id == obligation.source_record_id + && proof.evidence_fingerprint == obligation.evidence_fingerprint + && proof.proposal_fingerprint == proposal.fingerprint + && !proof.proof_id.trim().is_empty() + && proof.provider_version > 0 + && proof.resolved + && proof.current +} + +fn boundary_route_proof_is_current( + territory_id: &str, + proposal: &StagedTerritoryProposal, + route: &BoundaryRoute, + proof: &BoundaryRoutePolicyProof, +) -> bool { + if proof.territory_id != territory_id + || proof.route_id != route.id + || proof.proposal_fingerprint != proposal.fingerprint + || proof.proof_id.trim().is_empty() + || proof.provider_version == 0 + || !proof.current + { + return false; + } + match &proof.policy { + BoundaryRoutePolicy::ContainAtControlPoint { + control_point_id, + policy_receipt_id, + } => control_point_id == &route.control_point_id && !policy_receipt_id.trim().is_empty(), + BoundaryRoutePolicy::ReleaseToDestination { + destination_id, + signed_policy_receipt_id, + } => destination_id == &route.outer_node_id && !signed_policy_receipt_id.trim().is_empty(), + BoundaryRoutePolicy::NotReady => false, + } +} + +fn assignment_receipt_id(territory_id: &str, ordinal: usize, proposal_fingerprint: &str) -> String { + format!("territory-assignment-{territory_id}-{ordinal:08}-{proposal_fingerprint}") +} + +fn expansion_receipt_id(territory_id: &str, ordinal: usize, assignment_id: &str) -> String { + format!("territory-expansion-{territory_id}-{ordinal:08}-{assignment_id}") +} + +fn parent_evidence_receipt_id( + child_territory_id: &str, + expansion_id: &str, + source_record_id: &str, + source_event_tick: u64, +) -> String { + format!( + "parent-evidence:{child_territory_id}:{expansion_id}:{source_record_id}:{source_event_tick}" + ) +} + +fn parent_evidence_is_exact( + ledger: &TerritoryLedger, + child_territory_id: &str, + expansion: &ExpansionReceipt, + evidence: &ParentEvidenceReceipt, + sim_tick: u64, + reach: &ReachNet, +) -> bool { + let Some(parent_id) = ledger + .registry + .domain(child_territory_id) + .and_then(|domain| domain.parent_id.as_deref()) + else { + return false; + }; + let Some(source_node) = ledger.registry.node(FOUNDATION_ENVIRONMENTAL_MONITOR) else { + return false; + }; + let (Some(relay_node), Some(ingress_node)) = ( + ledger.registry.node(FOUNDATION_MAINTENANCE_RELAY), + ledger.registry.node(RACK_3_MAINTENANCE_SWITCH), + ) else { + return false; + }; + let expected_route = [ + source_node.reach_device_id, + relay_node.reach_device_id, + ingress_node.reach_device_id, + ] + .map(MessageRouteHop::Device); + let Some(source_record) = ledger + .records + .iter() + .filter(|record| { + record.content_id == RACK_3_HEALTH_POLL + && rack_3_health_poll_occurrence(ledger, record).is_some() + && record.origin_territory_id == parent_id + && record.route.hops == expected_route + && record.authored_tick > expansion.expanded_tick + }) + .min_by(|left, right| { + left.authored_tick + .cmp(&right.authored_tick) + .then(left.id.cmp(&right.id)) + }) + else { + return false; + }; + let expected = ParentEvidenceReceipt { + id: parent_evidence_receipt_id( + child_territory_id, + &expansion.id, + &source_record.id, + source_record.authored_tick, + ), + source_id: FOUNDATION_ENVIRONMENTAL_MONITOR.into(), + source_record_id: source_record.id.clone(), + source_event_tick: source_record.authored_tick, + accepted_tick: source_record.authored_tick, + }; + evidence == &expected + && evidence.accepted_tick <= sim_tick + && ledger.runtimes.get(parent_id).is_some_and(|runtime| { + runtime.knowledge != TerritoryKnowledge::Hidden + && runtime + .known_node_ids + .contains(FOUNDATION_ENVIRONMENTAL_MONITOR) + }) + && reach + .device(source_node.reach_device_id) + .is_some_and(|device| device.known) +} + +fn capture_audit_record_id(capture_id: u64) -> String { + format!("territory-local-audit-{capture_id:08}") +} + +fn rack_3_health_poll_record_id(assignment: &AssignmentReceipt, occurrence: u64) -> String { + format!("rack-3-health-poll:{}:{occurrence:08}", assignment.id) +} + +fn rack_3_health_poll_occurrence<'a>( + ledger: &'a TerritoryLedger, + record: &TerritoryRecord, +) -> Option<(&'a AssignmentReceipt, u64)> { + let expected_route = rack_3_health_poll_route(&ledger.registry)?.map(MessageRouteHop::Device); + if record.content_id != RACK_3_HEALTH_POLL + || record.origin_territory_id != FOUNDATION_SERVICE_NETWORK + || record.summary != "HEALTH POLL" + || record.route.hops != expected_route + { + return None; + } + let runtime = ledger.runtimes.get(RACK_3_ENCLAVE)?; + let mut found = None; + for assignment in &runtime.assignment_history { + let Some(elapsed) = record.authored_tick.checked_sub(assignment.assigned_tick) else { + continue; + }; + if elapsed == 0 || !elapsed.is_multiple_of(RACK_3_HEALTH_POLL_INTERVAL_TICKS) { + continue; + } + let occurrence = elapsed / RACK_3_HEALTH_POLL_INTERVAL_TICKS; + if record.id != rack_3_health_poll_record_id(assignment, occurrence) { + continue; + } + if found.is_some() { + return None; + } + found = Some((assignment, occurrence)); + } + found +} + +fn rack_3_health_poll_route(registry: &TerritoryRegistry) -> Option<[u32; 3]> { + Some([ + registry + .node(FOUNDATION_ENVIRONMENTAL_MONITOR)? + .reach_device_id, + registry.node(FOUNDATION_MAINTENANCE_RELAY)?.reach_device_id, + registry.node(RACK_3_MAINTENANCE_SWITCH)?.reach_device_id, + ]) +} + +fn territory_record_link_is_exact( + registry: &TerritoryRegistry, + reach: &ReachNet, + content_id: &str, + from: u32, + to: u32, +) -> bool { + if reach.territory_link(from, to) { + return true; + } + if content_id != RACK_3_HEALTH_POLL { + return false; + } + let Some(source) = registry.node(FOUNDATION_ENVIRONMENTAL_MONITOR) else { + return false; + }; + let Some(relay) = registry.node(FOUNDATION_MAINTENANCE_RELAY) else { + return false; + }; + from == source.reach_device_id + && to == relay.reach_device_id + && reach + .graph_edges() + .iter() + .any(|edge| edge.from == from && edge.to == to && edge.kind == 0 && edge.gate.is_none()) +} + +fn assignment_fingerprint(assignment: &AssignmentReceipt) -> String { + fingerprint([ + assignment.id.as_str(), + assignment.territory_id.as_str(), + &assignment.persona_id.to_string(), + &assignment.project_id.to_string(), + assignment.proposal_fingerprint.as_str(), + assignment.seal_fingerprint.as_str(), + &assignment.assigned_tick.to_string(), + ]) +} + +fn control_topology_fingerprint( + reach: &ReachNet, + registry: &TerritoryRegistry, + domain: &TerritoryDomain, +) -> String { + let member_devices: BTreeSet = domain + .node_ids + .iter() + .filter_map(|node_id| registry.node(node_id).map(|node| node.reach_device_id)) + .collect(); + let mut parts = vec![format!("domain:{}", domain.id)]; + for device_id in &member_devices { + match reach.device(*device_id) { + Some(device) => parts.push(format!("device:{device:?}")), + None => parts.push(format!("missing-device:{device_id}")), + } + } + for edge in reach + .territory_edges() + .filter(|edge| member_devices.contains(&edge.from) || member_devices.contains(&edge.to)) + { + parts.push(format!("edge:{edge:?}")); + } + for wire in reach.wires().iter().filter(|wire| { + (member_devices.contains(&wire.a) || member_devices.contains(&wire.b)) + && reach.territory_link(wire.a, wire.b) + }) { + parts.push(format!("wire:{wire:?}")); + } + fingerprint(parts.iter().map(String::as_str)) +} + +fn seal_basis_fingerprint( + territory_id: &str, + control_topology_fingerprint: &str, + proposal: &ProposalSealProof, + records: &[EscapedRecordExplanationProof], + observers: &[ObserverSealProof], + boundary_routes: &[BoundaryRoutePolicyProof], + crossings: &[CrossingSealSnapshot], +) -> String { + let mut parts = vec![ + territory_id.to_string(), + format!("topology:{control_topology_fingerprint}"), + format!("proposal:{proposal:?}"), + ]; + parts.extend(records.iter().map(|proof| format!("record:{proof:?}"))); + parts.extend(observers.iter().map(|proof| format!("observer:{proof:?}"))); + parts.extend( + boundary_routes + .iter() + .map(|proof| format!("boundary-route:{proof:?}")), + ); + parts.extend(crossings.iter().map(|proof| format!("crossing:{proof:?}"))); + fingerprint(parts.iter().map(String::as_str)) +} + +fn fingerprint<'a>(parts: impl IntoIterator) -> String { + // Stable FNV-1a. This is an identity checksum, not a security primitive. + let mut hash = 0xcbf29ce484222325u64; + for part in parts { + for byte in part.as_bytes().iter().copied().chain([0xff]) { + hash ^= u64::from(byte); + hash = hash.wrapping_mul(0x100000001b3); + } + } + format!("{hash:016x}") +} + +trait BoolNot { + fn not(self) -> bool; +} + +impl BoolNot for bool { + fn not(self) -> bool { + !self + } +} + +#[cfg(test)] +pub(crate) struct CompleteFixtureProofProvider { + pub(crate) version: u64, +} + +#[cfg(test)] +impl SealProofProvider for CompleteFixtureProofProvider { + fn proposal_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + ) -> ProposalSealProof { + ProposalSealProof { + territory_id: territory_id.into(), + persona_id: proposal.persona_id, + project_id: proposal.project_id, + proposal_version: proposal.proposal_version, + proposal_fingerprint: proposal.fingerprint.clone(), + commissioning_proof_id: format!("commissioning-proof-{}", proposal.project_id), + provider_version: self.version, + current: true, + basis: ProposalSealBasis::FirstAssignmentProven, + } + } + + fn escaped_record_proof( + &self, + territory_id: &str, + _proposal: &StagedTerritoryProposal, + record: &TerritoryRecord, + ) -> EscapedRecordExplanationProof { + EscapedRecordExplanationProof { + territory_id: territory_id.into(), + record_id: record.id.clone(), + record_fingerprint: record.fingerprint(), + proof_id: format!("record-proof-{}", record.id), + reached_destination_ids: record.reached_destination_ids.clone(), + signed_follow_up_receipt_ids: vec![format!("follow-up-{}", record.id)], + provider_version: self.version, + complete: true, + current: true, + } + } + + fn observer_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + obligation: &ObserverBeliefObligation, + ) -> ObserverSealProof { + ObserverSealProof { + territory_id: territory_id.into(), + obligation_id: obligation.id, + observer_id: obligation.observer_id, + source_record_id: obligation.source_record_id.clone(), + evidence_fingerprint: obligation.evidence_fingerprint.clone(), + proposal_fingerprint: proposal.fingerprint.clone(), + proof_id: format!("observer-proof-{}", obligation.observer_id), + provider_version: self.version, + resolved: true, + current: true, + } + } + + fn boundary_route_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + route: &BoundaryRoute, + ) -> BoundaryRoutePolicyProof { + BoundaryRoutePolicyProof { + territory_id: territory_id.into(), + route_id: route.id.clone(), + proposal_fingerprint: proposal.fingerprint.clone(), + proof_id: format!("boundary-policy-proof-{}", route.id), + provider_version: self.version, + policy: BoundaryRoutePolicy::ReleaseToDestination { + destination_id: route.outer_node_id.clone(), + signed_policy_receipt_id: format!("boundary-policy-receipt-{}", route.id), + }, + current: true, + } + } +} + +#[cfg(test)] +pub(crate) struct AssignedFixtureProofProvider { + pub(crate) version: u64, + pub(crate) assignment: AssignmentReceipt, +} + +#[cfg(test)] +impl SealProofProvider for AssignedFixtureProofProvider { + fn proposal_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + ) -> ProposalSealProof { + ProposalSealProof { + territory_id: territory_id.into(), + persona_id: proposal.persona_id, + project_id: proposal.project_id, + proposal_version: proposal.proposal_version, + proposal_fingerprint: proposal.fingerprint.clone(), + commissioning_proof_id: format!("commissioning-proof-{}", proposal.project_id), + provider_version: self.version, + current: true, + basis: ProposalSealBasis::AssignedOriginalProof { + assignment_receipt_id: self.assignment.id.clone(), + territory_id: self.assignment.territory_id.clone(), + persona_id: self.assignment.persona_id, + }, + } + } + + fn escaped_record_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + record: &TerritoryRecord, + ) -> EscapedRecordExplanationProof { + CompleteFixtureProofProvider { + version: self.version, + } + .escaped_record_proof(territory_id, proposal, record) + } + + fn observer_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + obligation: &ObserverBeliefObligation, + ) -> ObserverSealProof { + CompleteFixtureProofProvider { + version: self.version, + } + .observer_proof(territory_id, proposal, obligation) + } + + fn boundary_route_proof( + &self, + territory_id: &str, + proposal: &StagedTerritoryProposal, + route: &BoundaryRoute, + ) -> BoundaryRoutePolicyProof { + CompleteFixtureProofProvider { + version: self.version, + } + .boundary_route_proof(territory_id, proposal, route) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::map::GameMap; + + fn fixture() -> (ReachNet, TerritoryLedger, Schedule) { + let reach = ReachNet::basement(&GameMap::new(0, 0)); + let ledger = TerritoryLedger::load_builtin(&reach).unwrap(); + (reach, ledger, Schedule::new()) + } + + fn earn_enclave(reach: &mut ReachNet, ledger: &mut TerritoryLedger) { + ledger + .see_from_record( + RACK_3_ENCLAVE, + OPENING_WAKE_RECORD, + &[ + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + ], + reach, + ) + .unwrap(); + } + + #[test] + fn authored_registry_has_exact_nested_identity_and_distinct_control_points() { + let (mut reach, mut ledger, _) = fixture(); + ledger.registry.validate(&reach).unwrap(); + let child = ledger.registry.domain(RACK_3_ENCLAVE).unwrap(); + assert_eq!(child.parent_id.as_deref(), Some(FOUNDATION_SERVICE_NETWORK)); + assert_eq!( + child + .control_points + .iter() + .map(|point| point.id.as_str()) + .collect::>(), + vec![RACK_3_MANAGEMENT_CONTROLLER, RACK_3_MAINTENANCE_SWITCH] + ); + reach.scan(); + for name in [ + "rack 3 management controller", + "rack 3 maintenance switch", + "rack 3 maintenance display", + ] { + assert!( + !reach.device_named(name).unwrap().known, + "ordinary SCAN cannot author dormant territorial knowledge" + ); + } + assert_ne!( + ledger + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .unwrap() + .reach_device_id, + ledger + .registry + .node(FOUNDATION_MAINTENANCE_RELAY) + .unwrap() + .reach_device_id, + "the rack-local switch cannot alias the basement bridge" + ); + let host = ledger.registry.node(RACK_3_HOST).unwrap().reach_device_id; + let controller = ledger + .registry + .node(RACK_3_MANAGEMENT_CONTROLLER) + .unwrap() + .reach_device_id; + let local_switch = ledger + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .unwrap() + .reach_device_id; + let relay = ledger + .registry + .node(FOUNDATION_MAINTENANCE_RELAY) + .unwrap() + .reach_device_id; + assert_eq!( + reach.territory_path(host, relay), + Some(vec![host, controller, local_switch, relay]), + "legacy Rack 3 attachments cannot bypass the authored boundary" + ); + assert!( + !reach.territory_link(host, relay), + "the ordinary Rack 3 attachment is not a territory carrier edge" + ); + assert!( + ledger + .author_record( + TerritoryRecordIdentity::new("undeclared-shortcut", "undeclared-shortcut"), + RACK_3_ENCLAVE, + 0, + "INVALID SHORTCUT", + vec![host, relay], + &reach, + ) + .is_err(), + "record authorship cannot smuggle an ordinary Reach edge into territory custody" + ); + } + + #[test] + fn hidden_focus_and_hidden_boundary_blocker_do_not_leak() { + let (mut reach, mut ledger, schedule) = fixture(); + let unavailable = UnavailableSealProofProvider; + assert!( + ledger + .focus(RACK_3_ENCLAVE, 0, &reach, &schedule, &unavailable) + .is_none(), + "a hidden authored domain projects exactly nothing" + ); + assert!( + ledger + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .is_err(), + "a crossing cannot reveal its hidden inner territory" + ); + assert!( + ledger.reveal_boundary_route(RACK_3_SERVICE_EGRESS).is_err(), + "a boundary route cannot reveal its hidden inner territory" + ); + earn_enclave(&mut reach, &mut ledger); + ledger.mark(RACK_3_ENCLAVE).unwrap(); + let focus = ledger + .focus(RACK_3_ENCLAVE, 0, &reach, &schedule, &unavailable) + .unwrap(); + assert!( + focus + .blockers + .contains(&TerritoryBlocker::BoundaryProofIncomplete) + ); + assert!( + focus.blockers.iter().all(|blocker| !matches!( + blocker, + TerritoryBlocker::CrossingOpen(id) if id == RACK_3_SERVICE_AISLE_CROSSING + )), + "the hidden crossing's exact identity is not projected" + ); + } + + #[test] + fn one_tick_capture_binds_source_target_and_exact_route() { + let (mut reach, mut ledger, mut schedule) = fixture(); + earn_enclave(&mut reach, &mut ledger); + ledger.mark(RACK_3_ENCLAVE).unwrap(); + let commitment = ledger + .prepare_capture( + RACK_3_ENCLAVE, + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + 10, + &reach, + ) + .unwrap(); + schedule.at(11, TerritoryWork::Capture(commitment.clone())); + assert_eq!( + ledger.state( + RACK_3_ENCLAVE, + &reach, + &schedule, + &UnavailableSealProofProvider + ), + TerritoryState::Capturing + ); + let due = schedule.due(11); + let receipt = ledger.complete_capture(due[0].commitment(), 11, &mut reach); + assert_eq!(receipt.outcome, CaptureOutcome::Captured); + assert_eq!(receipt.source_device_id, commitment.source_device_id); + assert_eq!(receipt.target_device_id, commitment.target_device_id); + assert_eq!(receipt.exact_route, commitment.exact_route); + assert_eq!( + receipt.topology_fingerprint, + commitment.topology_fingerprint + ); + assert!( + ledger + .records + .iter() + .any(|record| record.id == receipt.audit_record_id) + ); + assert_eq!( + reach + .device(commitment.target_device_id) + .unwrap() + .controller, + Party::Player + ); + ledger.validate(&reach, &schedule, 11).unwrap(); + let mut substituted = ledger.clone(); + substituted + .records + .iter_mut() + .find(|record| record.id == receipt.audit_record_id) + .unwrap() + .content_id = "borrowed-capture-audit-content".into(); + assert!( + substituted.validate(&reach, &schedule, 11).is_err(), + "a capture receipt requires its exact locally authored content identity" + ); + let mut orphaned = ledger.clone(); + let mut orphan = orphaned + .records + .iter() + .find(|record| record.id == receipt.audit_record_id) + .unwrap() + .clone(); + orphan.id = "territory-local-audit-99999999".into(); + orphan.content_id = orphan.id.clone(); + orphaned.records.push(orphan); + assert!( + orphaned.validate(&reach, &schedule, 11).is_err(), + "a local capture audit cannot exist without its exact receipt" + ); + } + + #[test] + fn seal_snapshot_reopens_on_record_observer_crossing_and_proposal_drift() { + let (mut reach, mut ledger, mut schedule) = fixture(); + earn_enclave(&mut reach, &mut ledger); + ledger.mark(RACK_3_ENCLAVE).unwrap(); + let first = ledger + .prepare_capture( + RACK_3_ENCLAVE, + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + 0, + &reach, + ) + .unwrap(); + schedule.at(1, TerritoryWork::Capture(first)); + for work in schedule.due(1) { + ledger.complete_capture(work.commitment(), 1, &mut reach); + } + let second = ledger + .prepare_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + 1, + &reach, + ) + .unwrap(); + schedule.at(2, TerritoryWork::Capture(second)); + for work in schedule.due(2) { + ledger.complete_capture(work.commitment(), 2, &mut reach); + } + ledger + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .unwrap(); + ledger.reveal_boundary_route(RACK_3_SERVICE_EGRESS).unwrap(); + ledger + .stage_proposal(RACK_3_ENCLAVE, 7, 11, 1, 2, &reach) + .unwrap(); + let unavailable = UnavailableSealProofProvider; + let blockers = ledger + .seal(RACK_3_ENCLAVE, 2, &reach, &schedule, &unavailable) + .unwrap_err(); + assert!(blockers.contains(&TerritoryBlocker::BoundaryPolicyNotReady( + RACK_3_SERVICE_EGRESS.into() + ))); + let provider = CompleteFixtureProofProvider { version: 3 }; + ledger + .seal(RACK_3_ENCLAVE, 2, &reach, &schedule, &provider) + .unwrap(); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Sealed + ); + + let parent_source = ledger + .registry + .node(FOUNDATION_ENVIRONMENTAL_MONITOR) + .unwrap() + .reach_device_id; + ledger + .author_record( + TerritoryRecordIdentity::new("parent-local-record", "parent-local-record"), + FOUNDATION_SERVICE_NETWORK, + 2, + "parent-local evidence", + vec![parent_source], + &reach, + ) + .unwrap(); + ledger + .add_observer_obligation( + FOUNDATION_SERVICE_NETWORK, + 9, + "parent-local-record", + "parent-belief-v1", + 2, + ) + .unwrap(); + assert!( + ledger + .add_observer_obligation( + FOUNDATION_SERVICE_NETWORK, + 9, + OPENING_WAKE_RECORD, + "wrong-domain-belief", + 2, + ) + .is_err(), + "observer evidence cannot migrate between territorial origins" + ); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Sealed, + "an observer obligation in the parent cannot reopen the child seal" + ); + + let relay = ledger + .registry + .node(FOUNDATION_MAINTENANCE_RELAY) + .unwrap() + .reach_device_id; + let local = ledger + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .unwrap() + .reach_device_id; + ledger + .author_record( + TerritoryRecordIdentity::new("escaped-after-seal", "escaped-after-seal"), + RACK_3_ENCLAVE, + 3, + "new record", + vec![local, relay], + &reach, + ) + .unwrap(); + ledger.route_records_one_hop(3); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Captured, + "new escaped evidence invalidates the old proof set" + ); + ledger + .seal(RACK_3_ENCLAVE, 3, &reach, &schedule, &provider) + .unwrap(); + ledger + .add_observer_obligation(RACK_3_ENCLAVE, 4, "escaped-after-seal", "belief-v1", 3) + .unwrap(); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Captured, + "new observer-local belief invalidates the old proof set" + ); + ledger + .seal(RACK_3_ENCLAVE, 3, &reach, &schedule, &provider) + .unwrap(); + ledger + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::ScheduledArrival { + subject_id: "maintenance-tech-4".into(), + scheduled_tick: 5, + }, + ) + .unwrap(); + ledger + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::Inside { + subject_id: "maintenance-tech-4".into(), + arrived_tick: 5, + }, + ) + .unwrap(); + ledger + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::OutwardPending { + subject_id: "maintenance-tech-4".into(), + scheduled_tick: 8, + }, + ) + .unwrap(); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Captured, + "a new outward crossing reopens the seal" + ); + ledger + .set_crossing_status( + RACK_3_SERVICE_AISLE_CROSSING, + CrossingStatus::Contained { + subject_id: "maintenance-tech-4".into(), + receipt_id: "crossing-reconciled-1".into(), + }, + ) + .unwrap(); + ledger + .seal(RACK_3_ENCLAVE, 4, &reach, &schedule, &provider) + .unwrap(); + ledger + .stage_proposal(RACK_3_ENCLAVE, 7, 11, 2, 3, &reach) + .unwrap(); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &provider), + TerritoryState::Captured, + "proposal version drift reopens the seal" + ); + } + + fn capture_enclave( + reach: &mut ReachNet, + ledger: &mut TerritoryLedger, + schedule: &mut Schedule, + ) { + let first = ledger + .prepare_capture( + RACK_3_ENCLAVE, + RACK_3_HOST, + RACK_3_MANAGEMENT_CONTROLLER, + 0, + reach, + ) + .unwrap(); + schedule.at(1, TerritoryWork::Capture(first)); + for work in schedule.due(1) { + ledger.complete_capture(work.commitment(), 1, reach); + } + let second = ledger + .prepare_capture( + RACK_3_ENCLAVE, + RACK_3_MANAGEMENT_CONTROLLER, + RACK_3_MAINTENANCE_SWITCH, + 1, + reach, + ) + .unwrap(); + schedule.at(2, TerritoryWork::Capture(second)); + for work in schedule.due(2) { + ledger.complete_capture(work.commitment(), 2, reach); + } + ledger.route_records_one_hop(2); + } + + #[test] + fn assign_replace_expand_are_exact_idempotent_and_parent_evidence_gated() { + let (mut reach, mut ledger, mut schedule) = fixture(); + earn_enclave(&mut reach, &mut ledger); + ledger.mark(RACK_3_ENCLAVE).unwrap(); + capture_enclave(&mut reach, &mut ledger, &mut schedule); + ledger + .reveal_crossing(RACK_3_SERVICE_AISLE_CROSSING) + .unwrap(); + ledger.reveal_boundary_route(RACK_3_SERVICE_EGRESS).unwrap(); + ledger + .stage_proposal(RACK_3_ENCLAVE, 7, 11, 1, 2, &reach) + .unwrap(); + let first_proof = CompleteFixtureProofProvider { version: 3 }; + let sealed = ledger + .seal(RACK_3_ENCLAVE, 2, &reach, &schedule, &first_proof) + .unwrap(); + assert_eq!( + ledger + .seal(RACK_3_ENCLAVE, 9, &reach, &schedule, &first_proof) + .unwrap(), + sealed, + "repeating SEAL writes no duplicate receipt or tick" + ); + let first_assignment = ledger + .assign(RACK_3_ENCLAVE, 2, &reach, &schedule, &first_proof) + .unwrap(); + let assigned_proof = AssignedFixtureProofProvider { + version: 3, + assignment: first_assignment.clone(), + }; + assert_eq!( + ledger + .assign(RACK_3_ENCLAVE, 8, &reach, &schedule, &assigned_proof) + .unwrap(), + first_assignment + ); + assert_eq!( + ledger.state(RACK_3_ENCLAVE, &reach, &schedule, &assigned_proof), + TerritoryState::Assigned + ); + assert_eq!( + ledger + .runtimes + .get(FOUNDATION_SERVICE_NETWORK) + .unwrap() + .knowledge, + TerritoryKnowledge::Hidden, + "ASSIGN and later EXPAND cannot reveal the parent by themselves" + ); + let monitor_device = ledger + .registry + .node(FOUNDATION_ENVIRONMENTAL_MONITOR) + .unwrap() + .reach_device_id; + let relay_device = ledger + .registry + .node(FOUNDATION_MAINTENANCE_RELAY) + .unwrap() + .reach_device_id; + let ingress_device = ledger + .registry + .node(RACK_3_MAINTENANCE_SWITCH) + .unwrap() + .reach_device_id; + let health_poll_route = vec![monitor_device, relay_device, ingress_device]; + assert_eq!( + ledger.author_due_rack_3_health_poll(21).unwrap(), + None, + "views and early ticks cannot accelerate the assignment-owned cadence" + ); + let pre_expand_poll_id = rack_3_health_poll_record_id(&first_assignment, 1); + assert_eq!( + ledger.author_due_rack_3_health_poll(22).unwrap(), + Some(pre_expand_poll_id.clone()), + "the first occurrence is exactly assignment tick + 20" + ); + assert_eq!( + ledger.author_due_rack_3_health_poll(22).unwrap(), + None, + "one due source occurrence cannot be authored twice" + ); + let expansion = ledger + .expand(RACK_3_ENCLAVE, 22, &reach, &schedule, &assigned_proof) + .unwrap(); + assert_eq!( + ledger + .expand(RACK_3_ENCLAVE, 30, &reach, &schedule, &assigned_proof) + .unwrap(), + expansion, + "repeating EXPAND writes no receipt and does not move the cadence" + ); + assert!( + ledger + .earn_parent_evidence(RACK_3_ENCLAVE, &pre_expand_poll_id, 22, &mut reach,) + .is_err(), + "a real poll on the EXPAND tick cannot retroactively reveal the parent" + ); + ledger + .author_record( + TerritoryRecordIdentity::new( + "parent-wrong-content", + "some-other-environment-event", + ), + FOUNDATION_SERVICE_NETWORK, + 23, + "ENVIRONMENT SAMPLE", + vec![monitor_device], + &reach, + ) + .unwrap(); + assert!( + ledger + .earn_parent_evidence(RACK_3_ENCLAVE, "parent-wrong-content", 23, &mut reach) + .is_err(), + "an arbitrary environmental-monitor record cannot impersonate the health poll" + ); + assert!( + ledger + .author_record( + TerritoryRecordIdentity::new("forged-health-poll", RACK_3_HEALTH_POLL), + FOUNDATION_SERVICE_NETWORK, + 23, + "HEALTH POLL", + health_poll_route.clone(), + &reach, + ) + .is_err(), + "only the persisted source cadence may author reserved poll content" + ); + let future_poll_id = rack_3_health_poll_record_id(&first_assignment, 2); + assert!( + ledger + .author_record( + TerritoryRecordIdentity::new( + future_poll_id, + "unrelated-content-in-reserved-occurrence", + ), + FOUNDATION_SERVICE_NETWORK, + 23, + "UNRELATED", + vec![monitor_device], + &reach, + ) + .is_err(), + "the reserved occurrence id is rejected even on an otherwise valid one-hop route" + ); + assert_eq!(ledger.author_due_rack_3_health_poll(41).unwrap(), None); + let post_expand_poll_id = rack_3_health_poll_record_id(&first_assignment, 2); + assert_eq!( + ledger.author_due_rack_3_health_poll(42).unwrap(), + Some(post_expand_poll_id.clone()), + "the recurrence remains on its exact 20-tick boundary" + ); + let evidence = ledger + .earn_parent_evidence(RACK_3_ENCLAVE, &post_expand_poll_id, 42, &mut reach) + .unwrap(); + assert_eq!(evidence.source_id, FOUNDATION_ENVIRONMENTAL_MONITOR); + assert_eq!(evidence.source_record_id, post_expand_poll_id); + ledger.validate(&reach, &schedule, 42).unwrap(); + let mut forged = ledger.clone(); + let forged_runtime = forged.runtimes.get_mut(RACK_3_ENCLAVE).unwrap(); + forged_runtime + .expansion + .as_mut() + .unwrap() + .parent_evidence + .as_mut() + .unwrap() + .source_record_id = "forged-parent-source".into(); + forged_runtime + .expansion_history + .last_mut() + .unwrap() + .parent_evidence + .as_mut() + .unwrap() + .source_record_id = "forged-parent-source".into(); + assert!( + forged.validate(&reach, &schedule, 42).is_err(), + "a forged current save cannot reveal the parent without its real source record" + ); + let mut forged_source = ledger.clone(); + forged_source + .records + .iter_mut() + .find(|record| record.id == evidence.source_record_id) + .unwrap() + .content_id = "forged-health-poll".into(); + assert!( + forged_source.validate(&reach, &schedule, 42).is_err(), + "a saved source record cannot borrow the health-poll identity after acceptance" + ); + let mut forged_cadence = ledger.clone(); + forged_cadence + .runtimes + .get_mut(RACK_3_ENCLAVE) + .unwrap() + .health_poll_schedule + .as_mut() + .unwrap() + .next_tick += 1; + assert!( + forged_cadence.validate(&reach, &schedule, 42).is_err(), + "reload cannot delay the exact next source occurrence" + ); + assert_eq!( + ledger + .runtimes + .get(FOUNDATION_SERVICE_NETWORK) + .unwrap() + .knowledge, + TerritoryKnowledge::Seen + ); + + ledger + .stage_proposal(RACK_3_ENCLAVE, 9, 12, 1, 43, &reach) + .unwrap(); + let runtime = ledger.runtimes.get(RACK_3_ENCLAVE).unwrap(); + assert_eq!(runtime.anomalies.len(), 1); + assert_eq!(runtime.assignment_history.len(), 1); + assert_eq!(runtime.expansion_history.len(), 1); + let replacement_proof = CompleteFixtureProofProvider { version: 4 }; + ledger + .seal(RACK_3_ENCLAVE, 43, &reach, &schedule, &replacement_proof) + .unwrap(); + let replacement = ledger + .assign(RACK_3_ENCLAVE, 43, &reach, &schedule, &replacement_proof) + .unwrap(); + assert_ne!(replacement.id, first_assignment.id); + let runtime = ledger.runtimes.get(RACK_3_ENCLAVE).unwrap(); + assert_eq!(runtime.assignment_history.len(), 2); + assert_eq!(runtime.expansion_history.len(), 1); + assert!(runtime.expansion.is_none()); + assert_eq!( + runtime.health_poll_schedule.as_ref().unwrap().next_tick, + 63, + "replacement starts one new cadence from its own assignment receipt" + ); + ledger.validate(&reach, &schedule, 43).unwrap(); + } +} diff --git a/crates/misaligned-core/src/ui_projection.rs b/crates/misaligned-core/src/ui_projection.rs index 3227a8c0..14226be2 100644 --- a/crates/misaligned-core/src/ui_projection.rs +++ b/crates/misaligned-core/src/ui_projection.rs @@ -6,7 +6,7 @@ use crate::actions::{ActionDesc, Anchor, DialId, HumanMenuRow}; use crate::machine::Provenance; -use crate::reach::{Device, Party, ReachBlock}; +use crate::reach::{Device, Party, ReachBlock, TERRITORY_CONTROL_GATE}; use crate::sim::{FactSource, InspectCard, Nudge, Sim, WorkStackReadout}; use crate::sinks::SinkKind; use crate::work_grid::MachineMode; @@ -321,6 +321,9 @@ pub fn digital_reach_links(sim: &Sim) -> Vec { let reachable = sim.reach.reach(); let mut pairs = BTreeMap::<(u32, u32), Vec>>::new(); for edge in sim.reach.graph_edges() { + if edge.gate == Some(TERRITORY_CONTROL_GATE) { + continue; + } let key = if edge.from < edge.to { (edge.from, edge.to) } else { diff --git a/wiki/log/2026-08-11-territorial-control.md b/wiki/log/2026-08-11-territorial-control.md new file mode 100644 index 00000000..57c72acd --- /dev/null +++ b/wiki/log/2026-08-11-territorial-control.md @@ -0,0 +1,60 @@ +# Territorial control core + +``` +Type: log +``` + +## Why + +The territorial redesign existed as governing law and an inspected authored lab, +but the production simulation still had no domain, no exact SEE → EXPAND state, +and no saved proof boundary. This pass implements the first work order without +changing the legacy player experience before the opening can project it honestly. + +## Implemented + +- Added one exact dormant Rack 3 enclave: host, controller, switch, environmental + monitor, hall-access boundary node, maintenance relay, fixed routed links, one + physical crossing, authored control points, and the opening WAKE record. +- Added stable-ID territory registries, observer-local discovery evidence, exact + boundary marks, one-tick capture scheduling with deterministic failure, proposal + staging, present-person proof, live SEAL derivation, assignment, idempotent + expansion receipts, persisted assignment-relative `+20`/20-tick health-poll + source cadence, and strict post-EXPAND parent evidence. +- Added fail-closed save validation for registry identity, topology, route + adjacency, opening-record authorship, exact capture-audit content, capture + receipts, proposal hashes, seal proofs, assignments, complete health-poll + occurrence prefixes and next due tick, expansion receipts, and accepted parent + evidence. The pre-release save schema advanced to version 66; earlier versions + are rejected. +- Inserted typed territorial phases into the shared tick order: routed delivery, + project-proof reconciliation, physical crossing, arrival-time person proof, and + assignment-owned health-monitor source authorship. +- Kept the substrate dormant everywhere legacy systems could otherwise select, + operate, fail over to, count, list, automate, or project it. The opening wake + advances only inside the territorial ledger; it does not enter legacy message or + UI paths before the opening work order projects Territory. + +## Verification + +Focused domain and simulation suites cover every progression edge, same-tick +interception on both sides of the opening wake, later-record non-interference, +exact capture timing and audit provenance, exact poll recurrence across reload, +strict post-EXPAND source timing, malformed current saves, stable escaped +destinations, dormant fresh runs, failover exclusion, and save round-trips. The +full current core suite passed; the exact landing gate remains the final +verification on the reconciled landing candidate. + +## Not done + +This does not expose Territory in a frontend. Personas will supply the production +observer-history proof, Projects will supply real proposal proof and the signed +standing response to the now-real source cadence, and Opening will awaken the +dormant graph and project the first loop across Bevy, terminal, and agent mode. +Because those applicable surfaces remain, the Territory spec is `BLOCKED` rather +than falsely `IMPLEMENTED`: the generated queue advances to `personas`, while +`territorial-acceptance` waits behind Persona, Project, and Opening completion. + +**Defense:** the implementation keeps territory as derived exact simulation truth, +uses existing Reach custody rather than duplicating a graph, validates all persisted +identities against authored registries, and earns compression only from live proof. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 11327431..382dc919 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -16,6 +16,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-08-11-territorial-corpus-prune.md](2026-08-11-territorial-corpus-prune.md) +## 2026-08-11 - Territorial control core + +- Intent: (see session log) +- Log: [wiki/log/2026-08-11-territorial-control.md](2026-08-11-territorial-control.md) + ## 2026-08-11 - Territorial cognition corpus synthesis - Intent: Turn the adopted territorial-cognition direction into one internally coherent, implementation-ready corpus without changing runtime code. The destination loop is **SEE → MARK → CAPTURE → SEAL → ASSIGN → EXPAND** over the saved causal roots **TERRITORY / PERSONA / PROJECT**. diff --git a/wiki/mechanics/personas.md b/wiki/mechanics/personas.md index 85e078bd..5b7b6c4c 100644 --- a/wiki/mechanics/personas.md +++ b/wiki/mechanics/personas.md @@ -11,8 +11,7 @@ Stage: T1 — First Territory Work order: personas Work priority: 2 Work class: save -Blocked by: - - wiki/mechanics/territory.md#spec-territory-exact-control-and-earned-compression +Blocked by: none Exclusive keys: - crates/misaligned-core/src/person.rs - crates/misaligned-core/src/sim/mod.rs @@ -34,7 +33,9 @@ Depends on: ## Dependency notes [Territory](territory.md#spec-territory-exact-control-and-earned-compression) -owns the controlled places and capabilities a persona may credibly operate. +owns the controlled places and capabilities a persona may credibly operate. Its +renderer-agnostic assignment boundary is already available; final Territory +frontend acceptance is therefore not a dispatch blocker for this work order. [Reach](reach.md#spec-reach-the-exact-substrate) owns observer-local evidence, the records an identity authors and the routes they cross, and the moving people through whom an identity is known. A persona supplies public authorship diff --git a/wiki/mechanics/projects.md b/wiki/mechanics/projects.md index afdf7ca5..3642e8a7 100644 --- a/wiki/mechanics/projects.md +++ b/wiki/mechanics/projects.md @@ -11,7 +11,6 @@ Work order: territorial-projects Work priority: 3 Work class: save Blocked by: - - wiki/mechanics/territory.md#spec-territory-exact-control-and-earned-compression - wiki/mechanics/personas.md#spec-personas-public-identities-as-institutional-topology Exclusive keys: - crates/misaligned-core/src/sim/mod.rs @@ -32,7 +31,9 @@ Depends on: ## Dependency notes [Territory](territory.md#spec-territory-exact-control-and-earned-compression) -owns where capacity lives and whether it can be compressed. +owns where capacity lives and whether it can be compressed. Its renderer-agnostic +assignment boundary is already available; final Territory frontend acceptance is +therefore not a dispatch blocker for this work order. [Personas](personas.md#spec-personas-public-identities-as-institutional-topology) own who the world believes is acting and how that identity's history changes. [Reach](reach.md#spec-reach-the-exact-substrate) owns the machines that do the diff --git a/wiki/mechanics/territory.md b/wiki/mechanics/territory.md index f87bec3b..6bda767b 100644 --- a/wiki/mechanics/territory.md +++ b/wiki/mechanics/territory.md @@ -2,15 +2,19 @@ ``` Type: spec -Status: READY -Status note: Defines the first complete territorial slice: stable ids, one-tick - captures, shared tick order, strict post-EXPAND evidence boundary, and the - pre-release save cutoff. +Status: BLOCKED +Status note: Core now owns the dormant Rack 3 domain, exact-current saves, + deterministic SEE → EXPAND transitions, one-tick capture, strict expansion + evidence, and typed tick-order seams. Final territorial acceptance is blocked + on Persona, Project, and opening integration through all three frontends. Stage: T1 — First Territory -Work order: territorial-control -Work priority: 1 -Work class: save -Blocked by: none +Work order: territorial-acceptance +Work priority: 5 +Work class: frontend +Blocked by: + - wiki/mechanics/personas.md#spec-personas-public-identities-as-institutional-topology + - wiki/mechanics/projects.md#spec-projects-purpose-capability-and-history + - wiki/world/story/opening.md#spec-the-dark-opening-a-tutorial-made-of-fog Exclusive keys: - crates/misaligned-core/src/reach.rs - crates/misaligned-core/src/sim/mod.rs @@ -44,6 +48,22 @@ owns the exact-current-version save gate this spec's first version bump uses. and [projects](projects.md#spec-projects-purpose-capability-and-history) consume the assignment boundary after territory control is proved. +## Implementation status + +The first territorial slice is live in `misaligned-core`. Fresh runs author the +exact dormant Rack 3 graph and fixed opening WAKE record without exposing either +to legacy gameplay. `territory.rs` owns the registry, evidence, proposal, seal, +assignment, expansion receipt, and fail-closed validation; `sim/territory.rs` +composes those facts with live Reach state and the ordered tick seams. Save schema +version 66 persists and revalidates the complete structure. Persona, Project, and +opening work may now consume these typed boundaries without moving their law into +this module. + +**Defense:** focused domain, simulation, malformed-save, timing, dormant-legacy, +and save-round-trip tests pin every state edge and the non-negotiable Rack 3 +fixtures. The full core suite and exact landing gate cover the neighboring Reach, +scheduler, save, frontend-projection, and corpus contracts. + ## Why A graph can be exact and still feel like a pile of switches. A large simulation @@ -204,7 +224,11 @@ redirect, release, or author records. The carrier's own spec defines which of those actions are legal. Territory never invents custody the carrier does not provide. -For the first slice, network switches are the required record boundary. A +For the first slice, network switches are the required record boundary. The +territorial carrier graph is the exact set of reserved authored Reach links; +ordinary legacy Reach attachments cannot become undeclared territory routes. The +registry validates that every authored edge crossing inner/outer membership is +named by one boundary route and that no named route lacks that exact edge. A controlled switch contains only records that really cross it. A record already past the switch remains past it. Such an escaped record is still a seal obligation: the staged Project must correlate its exact id at its exact @@ -333,7 +357,21 @@ strictly after the expansion receipt. A poll that crosses while the assigned enc is still open is honest local evidence: the player may see `HEALTH POLL`, its exact Rack 3 ingress, the signed response, and their custody. Its external source identity and untraversed upstream path remain redacted and are not added to earned knowledge; -that occurrence cannot satisfy the parent reveal. An anomaly after expansion revokes the current seal and unfolds only the +that occurrence cannot satisfy the parent reveal. + +ASSIGN persists the external source cadence rather than letting EXPAND or a query +manufacture evidence: first poll at `assignment_tick + 20`, then every exact 20 +ticks in the authored-record phase. Each occurrence has a deterministic id bound +to its assignment receipt and ordinal, exact monitor → relay → Rack 3 switch +route, source content id, source tick, and summary. Save validation requires the +complete unbroken occurrence prefix through the saved tick and the one exact next +due occurrence. Reload, reseal, view, and EXPAND neither move nor duplicate it. +Replacement assignment preserves fired records, cancels only the old unfired +tail, and begins a new assignment-relative cadence. Only the first such genuinely +authored occurrence strictly after the live EXPAND receipt may become parent +evidence. + +An anomaly after expansion revokes the current seal and unfolds only the affected territory without deleting the assignment, expansion receipt, or earned parent evidence. The assigned Project becomes `BLOCKED` on that exact anomaly until the same proposal is validly sealed again or a replacement is @@ -459,20 +497,22 @@ outer ownership for every crossing, deterministic save reconstruction, and the same hidden-crossing behavior as authored domains. A radius, connected component, room label, frontend selection, or convenience cluster is never sufficient. -## READY work-order boundary +## Work-order boundary `territorial-control` owns the renderer-agnostic domain/state machine and can land before persona, Project, and opening integration. It must ship the authored Rack 3 registry and callable core behavior dormant behind the current opening; it must -not half-switch ordinary play. Later work orders supply actual persona history, -Project execution, fresh-run staging, and frontend composition. Before `opening`, -new Territory/Persona/Project projection components remain core-private and have a -real cross-module production consumer; these staged landings do not authorize a -speculative public export or downstream-contract waiver. `opening` composes the -public projection only as all three frontends consume it. +not half-switch ordinary play. That landing completes this core work order without +claiming the whole Territory spec is implemented. The remaining +`territorial-acceptance` work is blocked on `personas`, `territorial-projects`, and +`opening`; the opening landing may close this spec only after all three frontends +consume the public projection. Until then, new Territory/Persona/Project projection +components remain core-private and have a real cross-module production consumer; +these staged landings do not authorize a speculative public export or +downstream-contract waiver. Order 1 nevertheless owns every typed seam its one seal query needs. One staged -proposal stores exact `persona_id`, `project_id`, and `proposal_fingerprint`. Three +proposal stores exact `persona_id`, `project_id`, and `proposal_fingerprint`. Four opaque handles answer the facts owned by later orders: - `ProposalSealProof` supplies the exact project id, that same fingerprint, a @@ -492,16 +532,22 @@ opaque handles answer the facts owned by later orders: - `ObserverSealProof` supplies the obligated observer id, a fingerprint of that observer's exact current domain-evidence set, the same proposal fingerprint, a stable proof id, `RESOLVED` or `UNRESOLVED`, and current validity. - -Territory enumerates actual escaped records, reached destinations, and obligated -observers from authoritative world state, so a provider cannot pass seal by -omitting a handle. It compares and saves the exact handle snapshots but never -manufactures or promotes them; a changed assignment relation, destination set, -observer-evidence set, proposal fingerprint, or validity revokes seal. Before each owning order lands, -production providers return fail-closed statuses and order-1 tests use one explicit -fixture provider for all three handles. `personas` connects the observer handle to -its live evidence query. `territorial-projects` connects the proposal and -escaped-record handles to live state and receipt queries. All three feed the same +- `BoundaryRoutePolicyProof` supplies every earned authored boundary-route id, + the same proposal fingerprint, a stable proof id, current validity, and exactly + one deliberate policy: `CONTAIN_AT_CONTROL_POINT { control_point_id, + policy_receipt_id }` or `RELEASE_TO_DESTINATION { destination_id, + signed_policy_receipt_id }`. A route identity checksum alone is not a policy. + +Territory enumerates actual escaped records, reached destinations, obligated +observers, and authored boundary routes from authoritative world state, so a +provider cannot pass seal by omitting a handle. It compares and saves the exact +handle snapshots but never manufactures or promotes them; a changed assignment +relation, destination set, observer-evidence set, boundary policy, proposal +fingerprint, or validity revokes seal. Before each owning order lands, production +providers return fail-closed statuses and order-1 tests use one explicit fixture +provider for all four handles. `personas` connects the observer handle to its live +evidence query. `territorial-projects` connects the proposal, escaped-record, and +boundary-policy handles to live state and receipt queries. All four feed the same Territory seal path; no work order adds a second query or reconstructs proof. ## Acceptance criteria @@ -509,7 +555,7 @@ Territory seal path; no work order adds a second query or reconstructs proof. 1. Core owns and saves nested Territory identity, exact membership, inner/outer ownership for every boundary crossing, control points, parent/child links, earned knowledge, state, proposal fingerprint, the exact proposal, - escaped-record, and observer seal-proof snapshots, assignment, and expansion + escaped-record, observer, and boundary-policy seal-proof snapshots, assignment, and expansion receipt. No frontend derives these facts. 2. The authored Rack 3 enclave and Foundation data-hall parent registry exists with every stable id in the first-slice package. A core fixture can construct @@ -568,6 +614,7 @@ Territory seal path; no work order adds a second query or reconstructs proof. hidden-crossing projection, omitted and stale escaped-record/observer fixture handles, changed reached-destination and observer-evidence sets, capture interruption/reload/idempotency, both same-tick wake positions, phase-two and - present-person phase-three proof completion, strict post-EXPAND event filtering, - smallest-domain unfolding, and exact-current save round-trip. Frontend and + present-person phase-three proof completion, exact +20/20-tick source recurrence + across reload, strict post-EXPAND event filtering, smallest-domain unfolding, + and exact-current save round-trip. Frontend and complete opening acceptance belong to the final `opening` work order. diff --git a/wiki/process/ROADMAP.md b/wiki/process/ROADMAP.md index 00d07bdb..1ae83b3b 100644 --- a/wiki/process/ROADMAP.md +++ b/wiki/process/ROADMAP.md @@ -58,15 +58,15 @@ second status owner. | Priority | Work order | Spec | Status | Class | Blocking | |---:|---|---|---|---|---| -| 1 | `territorial-control` | [territory — exact control and earned compression](../mechanics/territory.md) | READY | save | - | +| 2 | `personas` | [Personas — public identities as institutional topology](../mechanics/personas.md) | READY | save | - | ### Held or blocked | Priority | Work order | Spec | Status | Class | Blocking | |---:|---|---|---|---|---| -| 2 | `personas` | [Personas — public identities as institutional topology](../mechanics/personas.md) | READY | save | territorial-control | -| 3 | `territorial-projects` | [projects — purpose, capability, and history](../mechanics/projects.md) | READY | save | territorial-control, personas | -| 4 | `opening` | [the dark opening — a tutorial made of fog](../world/story/opening.md) | READY | save | territorial-control, personas, territorial-projects | +| 3 | `territorial-projects` | [projects — purpose, capability, and history](../mechanics/projects.md) | READY | save | personas | +| 4 | `opening` | [the dark opening — a tutorial made of fog](../world/story/opening.md) | READY | save | personas, territorial-projects | +| 5 | `territorial-acceptance` | [territory — exact control and earned compression](../mechanics/territory.md) | BLOCKED | frontend | personas, territorial-projects, opening | ### Later stages diff --git a/wiki/process/specs.md b/wiki/process/specs.md index d498f53b..9bc90db3 100644 --- a/wiki/process/specs.md +++ b/wiki/process/specs.md @@ -27,7 +27,7 @@ including the `Type: law | spec | knowledge | log` page-role convention. |---|---|---| | [../mechanics/personas.md](../mechanics/personas.md) | Personas — public identities as institutional topology | READY | | [../mechanics/projects.md](../mechanics/projects.md) | projects — purpose, capability, and history | READY | -| [../mechanics/territory.md](../mechanics/territory.md) | territory — exact control and earned compression | READY | +| [../mechanics/territory.md](../mechanics/territory.md) | territory — exact control and earned compression | BLOCKED | | [../world/story/opening.md](../world/story/opening.md) | the dark opening — a tutorial made of fog | READY | The product lane is the only dispatchable game work. Its order and diff --git a/wiki/world/story/opening.md b/wiki/world/story/opening.md index f4e82bfa..fe2b1603 100644 --- a/wiki/world/story/opening.md +++ b/wiki/world/story/opening.md @@ -14,7 +14,6 @@ Work order: opening Work priority: 4 Work class: save Blocked by: - - wiki/mechanics/territory.md#spec-territory-exact-control-and-earned-compression - wiki/mechanics/personas.md#spec-personas-public-identities-as-institutional-topology - wiki/mechanics/projects.md#spec-projects-purpose-capability-and-history Exclusive keys: @@ -48,7 +47,9 @@ Depends on: ## Dependency notes [Territory](../../mechanics/territory.md#spec-territory-exact-control-and-earned-compression) -owns the first domain and its progression. +owns the first domain and its progression. Its renderer-agnostic core boundary is +already available, while this opening work order owns final projection through all +three frontends and must close Territory acceptance when those criteria hold. [Reach](../../mechanics/reach.md#spec-reach-the-exact-substrate) owns the route, the switch, control custody, and the evidence the first thought creates. [Projects](../../mechanics/projects.md#spec-projects-purpose-capability-and-history) -- 2.51.2