diff --git a/crates/misaligned-core/src/sim/tests/reach_build.rs b/crates/misaligned-core/src/sim/tests/reach_build.rs index fe852959..be1553b8 100644 --- a/crates/misaligned-core/src/sim/tests/reach_build.rs +++ b/crates/misaligned-core/src/sim/tests/reach_build.rs @@ -2607,6 +2607,43 @@ fn badge_tiers_gate_asset_work_in_tiered_rooms() { ); } +#[test] +fn digital_tap_ignores_badge_tier_for_generated_sensor() { + let mut sim = Sim::new(); + sim.scan_network(); + finish_ops(&mut sim); + sim.compromise_switch(); + finish_ops(&mut sim); + + assert_eq!( + sim.player_badge_tier(), + 0, + "the player has no physical door credential" + ); + let sensor = sim + .reach + .devices + .iter() + .find(|device| device.name.starts_with("hall door camera (")) + .expect("the population rule places a camera inside a tier-2 hall door") + .id; + + assert!( + sim.tap_device(sensor), + "knowledge, graph reach, and the bridged segment authorize the digital act" + ); + finish_ops(&mut sim); + assert!( + sim.reach.subscribed_by(sensor, Party::Player), + "the camera feed lands without a badge credential" + ); + assert_eq!( + sim.player_badge_tier(), + 0, + "a digital subscription neither requires nor grants physical access" + ); +} + #[test] fn favor_build_checks_the_builders_badge() { // Ray patrols storage_a (schedule reaches an endpoint) but holds a diff --git a/crates/misaligned-core/src/ui_projection.rs b/crates/misaligned-core/src/ui_projection.rs index e187f889..4765dcd2 100644 --- a/crates/misaligned-core/src/ui_projection.rs +++ b/crates/misaligned-core/src/ui_projection.rs @@ -731,6 +731,73 @@ mod tests { ); } + #[test] + fn generated_sensors_remain_legible_behind_the_security_segment() { + let mut sim = Sim::with_seed(7); + sim.reach.scan(); + + let generated: Vec<_> = sim + .reach + .devices + .iter() + .filter(|device| { + device.name == "electrical camera" + || device.name.starts_with("corridor camera (") + || device.name.starts_with("aisle camera (") + || device.name.starts_with("hall door camera (") + }) + .map(|device| (device.id, device.name.clone())) + .collect(); + assert!( + generated + .iter() + .any(|(_, name)| name == "electrical camera"), + "the fixture includes a rule-generated room camera" + ); + assert!( + generated + .iter() + .any(|(_, name)| name.starts_with("corridor camera (")), + "the fixture includes rule-generated corridor cameras" + ); + + let projected_links = digital_reach_links(&sim); + for (id, name) in &generated { + let device = sim.reach.device(*id).unwrap(); + assert_eq!( + digital_reach_state(&sim, device), + Some(DigitalReachState::SegmentBlocked(1)), + "known rule-generated sensor {name} remains visible behind its named segment" + ); + assert!( + projected_links + .iter() + .any(|(a, b, _)| *a == *id || *b == *id), + "known rule-generated sensor {name} retains a visible graph link" + ); + } + + sim.reach.bridge_all(); + for (id, name) in &generated { + assert_eq!( + digital_reach_state(&sim, sim.reach.device(*id).unwrap()), + Some(DigitalReachState::Reachable), + "bridging, not a physical credential, makes {name} digitally reachable" + ); + } + + let room_camera = generated + .iter() + .find(|(_, name)| name == "electrical camera") + .unwrap() + .0; + sim.reach.tap(room_camera); + assert_eq!( + digital_reach_state(&sim, sim.reach.device(room_camera).unwrap()), + Some(DigitalReachState::Tapped) + ); + } + #[test] fn digital_reach_links_are_deduplicated_and_hide_unknown_endpoints() { use std::collections::BTreeSet; diff --git a/wiki/log/2026-07-27-sensor-digital-gates.md b/wiki/log/2026-07-27-sensor-digital-gates.md new file mode 100644 index 00000000..49555bf4 --- /dev/null +++ b/wiki/log/2026-07-27-sensor-digital-gates.md @@ -0,0 +1,26 @@ +# Sensor digital gates + +``` +Type: log +Date: 2026-07-27 +Status: COMPLETE +``` + +The B1 sensor population existed behind the facility security segment, but the +work order did not yet pin its player-facing reach boundary. Criterion 4 now +records the implemented half honestly: SCAN reveals rule-generated room, +corridor, aisle, and hall-door cameras as named segment-blocked nodes rather +than silently omitting them; bridging makes those nodes digitally reachable; +and a camera inside a tier-2 hall door can be tapped while the player still has +no physical badge credential. + +This does not invent the deferred installation channel. Badge tiers will gate +the body-having people who install, maintain, or rewire sensors once that path +exists. Criterion 4 therefore remains partial rather than claiming physical +work that the game cannot yet perform. + +Defense: `generated_sensors_remain_legible_behind_the_security_segment` +protects the renderer-neutral reach projection for the generated population, +and `digital_tap_ignores_badge_tier_for_generated_sensor` drives the ordinary +SCAN, switch-compromise, Thought-reservoir, TAP, subscription, and signature +path with badge tier zero. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index dd7f63d6..9685429d 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -41,6 +41,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-07-27-sensor-population-foundation.md](2026-07-27-sensor-population-foundation.md) +## 2026-07-27 - Sensor digital gates + +- Intent: (see session log) +- Log: [wiki/log/2026-07-27-sensor-digital-gates.md](2026-07-27-sensor-digital-gates.md) + ## 2026-07-27 - Located witnessing owns exact person-local evidence - Intent: (see session log) diff --git a/wiki/mechanics/sensor-network.md b/wiki/mechanics/sensor-network.md index 2c2d0dd9..4290b0b5 100644 --- a/wiki/mechanics/sensor-network.md +++ b/wiki/mechanics/sensor-network.md @@ -16,10 +16,11 @@ Status note: 2026-07-27 — post-landing review keeps every hall-door camera's the authored opening: after SCAN but before bridging, no new ambient seeing sensor is reachable, so the environmental-monitor Eyes beat remains the first obtainable sight. Criterion 1 is not fully complete: badge-reader nodes exist - but do not yet emit passage telemetry. Criteria 4-10 remain pending: - criterion 4 (separate digital and physical gates) is not claimed — the - player-installed sensor path does not exist yet, while digital reach remains - explicitly independent of badge tier (basement-map.md law); criterion 5 + but do not yet emit passage telemetry. Criterion 4 is partial: generated + sensors remain legible behind their named segment, bridging makes them + digitally reachable, and TAP succeeds with no physical badge credential. Its + physical half remains pending because the player-installed sensor path does + not exist yet. Criteria 5-10 remain pending: criterion 5 (dark regions trace to physical causes) is not claimed — the toy no-root test does not implement the full dark-region tracing. Criteria 6-10 (human-occupied room, install @@ -216,10 +217,13 @@ from. definition. — `sight_definition_unchanged_with_dense_sensors`, `no_ambient_sight_reachable_before_bridging` -4. A sensor's digital TAP availability is gated by knowledge, reach, and +4. ◑ A sensor's digital TAP availability is gated by knowledge, reach, and segment, never by badge tier. Badge tiers gate only the body-having people who physically install, maintain, or rewire a sensor. A known-but-unreachable - sensor is legible as such and never silently absent. + sensor is legible as such and never silently absent. (partial: the digital + gate and legibility are pinned; the player-installed physical path does not + exist yet) — `generated_sensors_remain_legible_behind_the_security_segment`, + `digital_tap_ignores_badge_tier_for_generated_sensor` 5. Every dark region traces to a nameable physical cause — air gap, unbridged segment, or an impassable door tier blocking the worker who would install a sensor. No region is dark by authored exception, and no door tier blocks a @@ -239,6 +243,15 @@ from. 10. Save/load round-trips the sensor population, subscription set, and installed-sensor provenance. +Defense: `generated_sensors_remain_legible_behind_the_security_segment` +requires rule-generated room, corridor, aisle, and hall-door sensors to survive +SCAN as named `SECURITY BLOCKED` nodes with visible graph links, then become +reachable only when that segment is bridged. The production-path +`digital_tap_ignores_badge_tier_for_generated_sensor` regression taps a camera +inside a tier-2 hall door while the player remains badge tier zero, protecting +the separate digital and physical gates without pretending the deferred install +channel already exists. + ## Open questions **[OPEN] Is installing a player-owned sensor a new reach verb or an extension