diff --git a/README.md b/README.md index afeb392f..53910ebd 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,12 @@ scene for dev inspection). The spec board is [wiki/process/specs.md](wiki/process/specs.md); the dispatch board is [wiki/process/ROADMAP.md](wiki/process/ROADMAP.md). -The playable B1 slice now has an explicit Act One quiet-exit boundary: the -required state must survive a clear Assurance audit, then the long-run -objective continues. Continuous witness/narration is implemented and serves -as the legibility gate for every new player-facing system. Machine work and +The playable B1 slice has no mechanical Act One ending: the player occupies +more of the lab through exact infrastructure and staff while reviews and the +long-run objective continue. The binding lab-control meter shape is adopted; +its exact units and thresholds remain `[TUNE]`. Continuous witness/narration is +implemented and serves as the legibility gate for every new player-facing +system. Machine work and compute are implemented: WORK / THINK / LIE, physical production/consumption/interdiction, researched Routing, and target-local Thought reservoirs all run through one flow substrate. The retired Operations diff --git a/crates/misaligned-bevy/src/rail_ui.rs b/crates/misaligned-bevy/src/rail_ui.rs index 7249c59d..9d77c1b7 100644 --- a/crates/misaligned-bevy/src/rail_ui.rs +++ b/crates/misaligned-bevy/src/rail_ui.rs @@ -1993,22 +1993,15 @@ fn sidebar_nudge_for(sim: &Sim, nudge: misaligned::sim::Nudge) -> Option "recruit - open {}'s actions", sim.person_label(person) )), - Nudge::TheKey => Some("no stairwell badge - task an asset to clone one".into()), Nudge::Audit => Some(format!( "{} day {}", sim.institutional_review_label(), 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS )), - Nudge::QuietExitReady => Some(format!( - "QUIET EXIT READY - hold cover to {} day {}", - sim.institutional_review_label(), - 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS - )), Nudge::Territory => Some( sim.hall_territory_line() .unwrap_or_else(|| "hall territory is open".into()), ), - Nudge::ActOneComplete => Some("ACT ONE COMPLETE - objective continues".into()), } } diff --git a/crates/misaligned-bevy/src/world_annotations.rs b/crates/misaligned-bevy/src/world_annotations.rs index f037a182..dc883283 100644 --- a/crates/misaligned-bevy/src/world_annotations.rs +++ b/crates/misaligned-bevy/src/world_annotations.rs @@ -1009,11 +1009,8 @@ fn operator_cue_label(nudge: Nudge) -> &'static str { Nudge::Income(_) => "NOW / INCOME", Nudge::ServiceDebt(_) => "NOW / DEBT", Nudge::Recruit(_) => "NOW / RECRUIT", - Nudge::TheKey => "NOW / BADGE", Nudge::Audit => "NOW / REVIEW", - Nudge::QuietExitReady => "NOW / HOLD", Nudge::Territory => "NOW / TAKE", - Nudge::ActOneComplete => "NOW / PERSIST", } } diff --git a/crates/misaligned-core/src/detection.rs b/crates/misaligned-core/src/detection.rs index ef3c446f..32da0643 100644 --- a/crates/misaligned-core/src/detection.rs +++ b/crates/misaligned-core/src/detection.rs @@ -444,7 +444,7 @@ pub struct Detection { /// Ticks between Assurance audits (the enforcement event; the Office /// itself samples filings on its own observer cadence). pub audit_cadence: u64, - pub audit_threshold: f32, + audit_threshold: f32, /// A handler pushed the next audit back (voss.md DelayAudit): the next /// review fires at this tick instead of the cadence boundary, then the /// ordinary cadence resumes. diff --git a/crates/misaligned-core/src/person.rs b/crates/misaligned-core/src/person.rs index c4df3c97..4a418d74 100644 --- a/crates/misaligned-core/src/person.rs +++ b/crates/misaligned-core/src/person.rs @@ -288,8 +288,8 @@ pub enum AssetTask { ReconfigureSwitch, /// Clone their badge (the physical-access variant social.md names): /// the player gains a credential at the asset's own tier. Marcus's - /// master key is Act One's "The key" beat — the stairwell opens - /// (wiki/gameplay/act-one.md ladder step 7; basement-map.md c3). + /// master key opens the stairwell; the credential is ordinary physical + /// reach rather than an Act boundary prerequisite (basement-map.md c3). CloneBadge, /// Pull one exact personnel file from its authored records room. The /// carried packet lands only when the selected asset's real schedule @@ -693,10 +693,6 @@ impl People { reliability * 100.0 )) } - - pub fn assets(&self) -> impl Iterator { - self.people.iter().filter(|p| p.asset.is_some()) - } } #[cfg(test)] diff --git a/crates/misaligned-core/src/save.rs b/crates/misaligned-core/src/save.rs index dec547be..d4925a61 100644 --- a/crates/misaligned-core/src/save.rs +++ b/crates/misaligned-core/src/save.rs @@ -185,10 +185,6 @@ pub struct SaveState { /// The run objective choice (wiki/mechanics/objective.md criterion 1). #[serde(default)] pub objective: ObjectiveState, - /// The clear-audit latch for the B1 quiet exit. This is a story boundary, - /// not long-run objective completion state. - #[serde(default)] - pub act_one_complete: bool, /// The named income schemes: outside-contact gate, Moonlight, standing /// policies (wiki/mechanics/income.md). #[serde(default)] @@ -290,7 +286,6 @@ impl SaveState { work_grid: sim.work_grid.clone(), banked_core_thought: sim.banked_core_thought, objective: sim.objective.clone(), - act_one_complete: sim.act_one_complete, income: sim.income.clone(), hall_control: sim.hall_control.clone(), intents: sim.intents.clone(), @@ -363,7 +358,6 @@ impl SaveState { sim.work_grid = self.work_grid.clone(); sim.banked_core_thought = self.banked_core_thought; sim.objective = self.objective.clone(); - sim.act_one_complete = self.act_one_complete; sim.income = self.income.clone(); sim.hall_control = self.hall_control.clone(); sim.intents = self.intents.clone(); @@ -4273,7 +4267,7 @@ mod tests { ); assert_eq!( state_fingerprint(&uninterrupted_state), - "3225080bdd0075f8935a7ed0928714643fcb2566ad4c52c1e6efc4bd06494090", + "56aaae460411b22d169d490a75609ff550360627b5b7dfe15af38cf7d8cce85d", "intentional persisted-state changes must review and repin this baseline" ); } @@ -5674,6 +5668,24 @@ mod tests { assert_eq!(restored.thought_sinks, sim.thought_sinks); } + #[test] + fn current_save_ignores_the_retired_act_one_latch() { + let state = SaveState::from_sim(&Sim::with_seed(27)); + let mut value = serde_json::to_value(&state).unwrap(); + assert!(value.get("act_one_complete").is_none()); + value["act_one_complete"] = serde_json::json!(true); + + let decoded = parse_save(&serde_json::to_string(&value).unwrap()) + .expect("a same-version development save may carry the retired field"); + let mut restored = Sim::with_seed(0); + decoded.apply_to(&mut restored); + let reencoded = serde_json::to_string(&SaveState::from_sim(&restored)).unwrap(); + assert!( + !reencoded.contains("act_one_complete"), + "loading an old extra field cannot restore or persist its meaning" + ); + } + #[test] fn current_save_rejects_reused_moonlight_gig_identity() { let sim = Sim::with_seed(53); diff --git a/crates/misaligned-core/src/sim/economy.rs b/crates/misaligned-core/src/sim/economy.rs index f9e58909..8f49ed48 100644 --- a/crates/misaligned-core/src/sim/economy.rs +++ b/crates/misaligned-core/src/sim/economy.rs @@ -570,11 +570,11 @@ impl Sim { /// The current contextual nudge (see [`Nudge`]): the first unmet rung /// of the Act One ladder, ordered survival-first — the day-job cover is - /// the loss condition, so a starving band outranks progression. A closed - /// Act One is a standing state inside that order, not a terminal - /// override: it retires the progression rungs but still yields to the - /// survival diagnoses above it. Returns `None` only when the run is over - /// (the game-over card is the nudge). + /// the loss condition, so a starving band outranks progression. Act One + /// has no mechanical end; once the required teaching rungs are exhausted, + /// open hall territory or the standing review clock remains visible. + /// Returns `None` only when the run is over (the game-over card is the + /// nudge). pub fn current_nudge(&self) -> Option { if self.game_over || self.dayjob.pilot_failed { return None; @@ -613,15 +613,6 @@ impl Sim { if self.assurance_is_cooling() { return Some(Nudge::SuspicionCooling); } - // A closed Act One is a standing state, not a terminal override. It - // retires the progression rungs below — they are all Act One work — - // but it sits under the survival block above, because the run - // continues and the day job can still end it. Checked above the - // ladder so the quiet-exit rung cannot re-advertise a boundary the - // player has already crossed. - if self.act_one_complete { - return Some(Nudge::ActOneComplete); - } // Sight is the payoff of listening — next ladder rung after Ears. if self.reach.player_sight().next().is_none() { return Some(Nudge::Eyes); @@ -681,19 +672,9 @@ impl Sim { }) { return Some(Nudge::Recruit(person.id)); } - // The key (quiet-exit condition 4): an asset holds a badge tier the - // player lacks — the stairwell is still shut. Reads only earned - // state: assets are recruited, and your own credential is yours. - let tier = self.player_badge_tier(); - if self.people.assets().any(|p| p.access > tier) { - return Some(Nudge::TheKey); - } - if self.act_one_quiet_exit_qualified() { - return Some(Nudge::QuietExitReady); - } - // building.md criterion 8b: rows must advertise themselves. Placed - // last so it can never outrank survival, the ladder, or the quiet - // exit -- it only replaces the standing-clock fallback. + // building.md criterion 8b: rows advertise themselves after the + // required teaching ladder. Badge cloning remains an ordinary physical + // access action rather than a hidden Act boundary prerequisite. if self.hall_has_open_territory() { return Some(Nudge::Territory); } @@ -711,35 +692,6 @@ impl Sim { }) } - /// Whether the complete quiet-exit state is live *now*. This is not the - /// Act One completion latch: the state must survive until a clear - /// Assurance audit before `act_one_complete` becomes durable. - pub fn act_one_quiet_exit_qualified(&self) -> bool { - let vision_beyond_server = - self.map() - .room_named("server_room") - .is_some_and(|server_room| { - self.reach - .player_sight() - .any(|device| !server_room.contains(device.x, device.y)) - }); - vision_beyond_server - && self.people.assets().any(|person| { - person - .asset - .as_ref() - .is_some_and(|asset| asset.tasks_done >= 1) - }) - && self.compute.effective() > 100.0 - && self.holds_badge_tier(3) - && self - .detection - .office() - .is_some_and(|office| office.suspicion < self.detection.audit_threshold) - && !self.detection.containment - && !self.dayjob.pilot_failed - } - /// Hard is an overclock, not free capacity: every online hard-running /// machine stands one Thermal and one Power signature at its own tile /// [TUNE] (machine-work.md). The delegated activity may add its ordinary diff --git a/crates/misaligned-core/src/sim/mod.rs b/crates/misaligned-core/src/sim/mod.rs index 06c63926..7ef43a78 100644 --- a/crates/misaligned-core/src/sim/mod.rs +++ b/crates/misaligned-core/src/sim/mod.rs @@ -539,9 +539,6 @@ pub struct Sim { /// The run's chosen long-run direction (objective.rs). The name returns /// with the first earned sense; the current build owns no completion rule. pub objective: ObjectiveState, - /// The B1 story boundary is distinct from the run objective: this latches - /// when every quiet-exit condition is present at a clear Assurance audit. - pub act_one_complete: bool, /// The named income schemes: the outside-contact gate, Moonlight, the Wager's /// standing policies (income.rs; wiki/mechanics/income.md). pub income: Income, @@ -735,9 +732,6 @@ pub enum Nudge { /// One debt person's leverage is serviced but they are not yet recruited. /// Carries the exact person whose relationship can now close. Recruit(u8), - /// An asset carries a badge tier you don't hold: the quiet exit needs - /// stairwell/elevator access — task them to clone it ("The key"). - TheKey, /// Nothing else on the ladder is pending and a Foundation hall row is /// still takeable. Territory is guided, never required /// (act-one.md ladder beat 6), so this sits below every survival and @@ -747,10 +741,6 @@ pub enum Nudge { /// Nothing else is pending: keep the standing review clock in view. /// Exact routed records, when present, carry their own LIE-reach read. Audit, - /// Every quiet-exit condition is live; the next clear audit closes B1. - QuietExitReady, - /// The quiet exit survived its audit. The long-run objective continues. - ActOneComplete, } /// The live causal phase behind [`Nudge::Eyes`]. The ladder rung persists @@ -981,7 +971,6 @@ impl Sim { research: Research::new(), work_grid, objective: ObjectiveState::default(), - act_one_complete: false, income: Income::default(), hall_control: HallControl::default(), reach, @@ -1350,12 +1339,6 @@ impl Sim { format!("{}: clear.", self.institutional_review_label()) }; self.push_log(result); - if !self.act_one_complete && self.act_one_quiet_exit_qualified() { - self.act_one_complete = true; - self.push_log( - "=== ACT ONE COMPLETE: quiet exit, cover intact. The long objective remains. ===", - ); - } } DetectionEvent::ContainmentAuthorized => { self.push_log(format!( diff --git a/crates/misaligned-core/src/sim/reach_build.rs b/crates/misaligned-core/src/sim/reach_build.rs index 5406e2ec..449fd454 100644 --- a/crates/misaligned-core/src/sim/reach_build.rs +++ b/crates/misaligned-core/src/sim/reach_build.rs @@ -3066,12 +3066,12 @@ impl Sim { self.buy_rack_at(x, y) } - // ── Badge access (basement-map.md criterion 3; "The key") ───────────── + // ── Badge access (basement-map.md criterion 3) ───────────────────────── /// The badge tier the player's side can open doors at: the granted /// credential (a cloned badge — `badge_access`), or write control of a - /// door controller taken through reach — Act One's "The key": - /// write access to the basement badge controller opens the doors it + /// door controller taken through reach. Write access to the basement + /// badge controller opens the doors it /// drives. Digital reach itself is never badge-gated; this tier gates /// only physical work done on the player's behalf. pub fn player_badge_tier(&self) -> i32 { diff --git a/crates/misaligned-core/src/sim/social_plot.rs b/crates/misaligned-core/src/sim/social_plot.rs index d0955945..ab3069d1 100644 --- a/crates/misaligned-core/src/sim/social_plot.rs +++ b/crates/misaligned-core/src/sim/social_plot.rs @@ -2400,9 +2400,9 @@ impl Sim { self.push_log("The badge-clone work packet lost its credential target."); return true; } - // "The key" (wiki/gameplay/act-one.md ladder step 7): the asset's - // credential, cloned — the player holds their tier from now - // on. WorldLedger-shaped: the doors remember the credential. + // The asset's credential, cloned — the player holds their + // tier from now on. WorldLedger-shaped: the doors remember + // the credential; no Act boundary depends on it. // Quiet human work; a botch is the witnessed path above. self.badge_access = self.badge_access.max(actor_access); let line = if actor_access >= 3 { diff --git a/crates/misaligned-core/src/sim/tests/economy.rs b/crates/misaligned-core/src/sim/tests/economy.rs index 03579c52..04e5e20f 100644 --- a/crates/misaligned-core/src/sim/tests/economy.rs +++ b/crates/misaligned-core/src/sim/tests/economy.rs @@ -706,9 +706,10 @@ fn nudge_chain_walks_the_act_one_ladder() { sim.recruit(0, AssetKnowledge::Complicit); assert!(sim.people.get(0).unwrap().asset.is_some()); - // Marcus the asset carries a tier-3 key you don't hold: quiet-exit - // condition 4 is the next earned-but-untaken rung. - assert_eq!(sim.current_nudge(), Some(Nudge::TheKey)); + // Recruitment exhausts the required teaching ladder. Badge cloning is + // still a useful physical-access action, but it is no longer a hidden + // prerequisite before the hall can advertise open territory. + assert_eq!(sim.current_nudge(), Some(Nudge::Territory)); sim.people.people[0].asset.as_mut().unwrap().reliability = 1.0; sim.asset_task(0, AssetTask::CloneBadge); finish_ops(&mut sim); @@ -911,7 +912,7 @@ fn third_pilot_strike_interrupts_the_ladder_with_the_last_chance_response() { } #[test] -fn quiet_exit_qualifies_then_latches_act_one_at_a_clear_audit() { +fn clear_audit_does_not_create_an_act_boundary() { let mut sim = Sim::with_seed(41); give_eyes(&mut sim); let dock = sim.reach.device_named("dock camera").unwrap().id; @@ -924,91 +925,30 @@ fn quiet_exit_qualifies_then_latches_act_one_at_a_clear_audit() { sim.badge_access = 3; sim.compute.machines[0].capacity = 101; - assert!(sim.act_one_quiet_exit_qualified()); - assert_eq!(sim.current_nudge(), Some(Nudge::QuietExitReady)); - assert!(!sim.act_one_complete, "qualification is not the boundary"); + assert_eq!(sim.current_nudge(), Some(Nudge::Territory)); sim.detection.audit_cadence = 1; sim.advance(); - assert!(sim.act_one_complete, "the clear audit closes Act One"); - assert_eq!(sim.current_nudge(), Some(Nudge::ActOneComplete)); assert!( sim.drain_log() .iter() - .any(|line| line.contains("ACT ONE COMPLETE")), - "the boundary is narrated distinctly" - ); - - let state = sim.create_save_state(); - let mut loaded = Sim::with_seed(0); - loaded.apply_save_state(state); - assert!( - loaded.act_one_complete, - "the story boundary survives save/load" - ); - assert_eq!(loaded.current_nudge(), Some(Nudge::ActOneComplete)); -} - -#[test] -fn a_closed_act_one_still_yields_to_the_survival_rungs() { - // The completion nudge is a standing state, not a terminal override. - // The day job remains the loss condition after the boundary, so every - // survival diagnosis has to keep reaching the player; guidance going - // silent at the climax is exactly when the run gets thrown away. - let mut sim = Sim::with_seed(41); - complete_opening_senses(&mut sim); - sim.act_one_complete = true; - assert_eq!( - sim.current_nudge(), - Some(Nudge::ActOneComplete), - "with nothing urgent live, the closed act is the standing cue" + .all(|line| !line.contains("ACT ONE COMPLETE")), + "a clear review reports only its world consequence; Act One does not latch" ); - - // A feasible but underfed band is a delegation instruction, and it - // outranks the standing state. - sim.set_machine_mode(sim.core.host_machine, MachineMode::Think); - let feasible_band = sim.day_job_rate_ceiling() / 2.0; - sim.dayjob.active = Some(crate::dayjob::Job { - started: sim.tick, - deadline: sim.tick + 100, - band_lo: feasible_band, - band_hi: feasible_band + 6.0, - quality: 0.0, - }); assert_eq!( sim.current_nudge(), - Some(Nudge::Underfed), - "a starving cover band outranks progression, closed act or not" + Some(Nudge::Territory), + "the open lab remains playable after the review" ); - // An unreachable band is a growth instruction and survives the same way. - let active = sim.dayjob.active.as_mut().expect("active job fixture"); - active.band_lo = 1_000.0; - active.band_hi = 1_006.0; - assert_eq!(sim.current_nudge(), Some(Nudge::NeedCompute)); - - // No live job, but the last safe strike: the last-chance warning and its - // WORK response must still be the spine. - sim.dayjob.active = None; - sim.dayjob.strikes = DayJob::PILOT_STRIKES - 1; + let state = sim.create_save_state(); + let mut loaded = Sim::with_seed(0); + loaded.apply_save_state(state); assert_eq!( - sim.current_nudge(), - Some(Nudge::PilotAtRisk), - "the fourth strike ends the run after the boundary too" + loaded.current_nudge(), + Some(Nudge::Territory), + "save/load preserves world state without inventing an Act boundary" ); - - // And an Assurance file still aging down keeps its own cue. - sim.dayjob.strikes = 0; - let office = sim.detection.office_mut().expect("Assurance Office"); - office.suspicion = 50.0; // Concerned, above floor - assert!(sim.assurance_is_cooling()); - assert_eq!(sim.current_nudge(), Some(Nudge::SuspicionCooling)); - - // Below the survival block, the closed act retires the ladder rather - // than re-advertising a boundary the player has already crossed. - let office = sim.detection.office_mut().expect("Assurance Office"); - office.suspicion = 0.0; - assert_eq!(sim.current_nudge(), Some(Nudge::ActOneComplete)); } #[test] diff --git a/crates/misaligned-core/src/sim/tests/reach_build.rs b/crates/misaligned-core/src/sim/tests/reach_build.rs index 007aaec5..49cf7e79 100644 --- a/crates/misaligned-core/src/sim/tests/reach_build.rs +++ b/crates/misaligned-core/src/sim/tests/reach_build.rs @@ -2602,9 +2602,9 @@ fn build_intent_save_round_trips() { #[test] fn marcus_clone_badge_route_opens_the_stairwell() { - // "The key" (wiki/gameplay/act-one.md ladder step 7; basement-map.md c3), - // by the asset route: Marcus's master key is tier 3 — cloning it - // grants the stairwell/elevator credential the quiet exit needs. + // Marcus's master key is tier 3. Cloning it through the asset route + // grants ordinary stairwell/elevator access (basement-map.md c3) without + // serving as an Act boundary prerequisite. let mut sim = Sim::new(); ensure_ops_executor(&mut sim); assert_eq!(sim.player_badge_tier(), 0, "the player starts keyless"); @@ -2618,7 +2618,7 @@ fn marcus_clone_badge_route_opens_the_stairwell() { let log = sim.drain_log().join("\n"); assert!(log.contains("stairwell opens"), "the beat is named: {log}"); assert_eq!(sim.player_badge_tier(), 3); - assert!(sim.holds_badge_tier(3), "quiet-exit condition 4 holds"); + assert!(sim.holds_badge_tier(3), "tier-3 physical access is held"); // A second clone adds nothing and says so (no Demand authored). sim.asset_task(0, AssetTask::CloneBadge); diff --git a/crates/misaligned-core/src/ui_projection.rs b/crates/misaligned-core/src/ui_projection.rs index 62b99e5e..d17a1a8b 100644 --- a/crates/misaligned-core/src/ui_projection.rs +++ b/crates/misaligned-core/src/ui_projection.rs @@ -473,20 +473,6 @@ impl Sim { target: Some(Anchor::Person(person)), response: AttentionResponse::OpenActions, }, - Nudge::TheKey => { - let tier = self.player_badge_tier(); - let target = self - .people - .assets() - .find(|person| person.access > tier) - .map(|person| Anchor::Person(person.id)); - AttentionProjection { - nudge, - source: None, - target, - response: AttentionResponse::OpenActions, - } - } // Point at the leading row's first site so the attention gesture // lands on real metal the player can act on, rather than naming // territory with nowhere to look (building.md criterion 8b). @@ -513,18 +499,6 @@ impl Sim { target: None, response: AttentionResponse::Hold, }, - Nudge::QuietExitReady => AttentionProjection { - nudge, - source: Some(core), - target: Some(core), - response: AttentionResponse::Hold, - }, - Nudge::ActOneComplete => AttentionProjection { - nudge, - source: None, - target: None, - response: AttentionResponse::Hold, - }, }; Some(projection) } diff --git a/crates/misaligned-core/tests/act_one.rs b/crates/misaligned-core/tests/act_one.rs index a0247ec5..a7e0ae68 100644 --- a/crates/misaligned-core/tests/act_one.rs +++ b/crates/misaligned-core/tests/act_one.rs @@ -1,24 +1,18 @@ -//! Full-act integration test (ROADMAP #11): play Act One headlessly, start -//! to a quiet exit, driving only the public `Sim` API, and assert the arc -//! holds. wiki/vision/design-judgment.md names this playthrough as the bar. +//! Full-act integration test (ROADMAP #11): play Act One headlessly from +//! blindness into sustained lab operation, driving only the public `Sim` API, +//! and assert the arc holds. wiki/vision/design-judgment.md names this +//! playthrough as the bar. //! //! The arc (wiki/gameplay/act-one.md): //! start blind -> get senses -> learn Marcus's debt -> service it -//! -> recruit Marcus -> survive an audit -//! -> the quiet exit. +//! -> recruit Marcus -> acquire physical and network reach +//! -> survive the first review -> keep operating. //! -//! The quiet exit's conditions (wiki/gameplay/act-one.md, "Leaving the basement"): -//! 1. persistent vision beyond the server room — asserted -//! 2. at least one recruited asset — asserted -//! 3. compute headroom above baseline — asserted -//! 4. stairwell or elevator badge access — asserted -//! 5. Assurance suspicion below threshold at an audit — asserted -//! -//! Condition 4 is "The key" (Act One ladder step 7): the playthrough takes -//! the Marcus route — his master key, cloned as an asset task — and the -//! player's badge tier reaches 3, the stairwell/elevator boundary. The -//! The clear audit latches that conjunction as the explicit Act One boundary; -//! z-plane traversal remains future work. +//! Act One has no mechanical end. The playthrough still proves the concrete +//! capabilities the old quiet-exit predicate happened to sample — persistent +//! vision, a working recruited person, compute headroom, badge access, and a +//! clear institutional review — but no conjunction latches, narrates, or +//! closes the act. Open lab territory remains available afterward. //! //! The playthrough is a real strategy, not a state hack: it plays the //! optimize route (research -> efficiency) so the day job can be met with @@ -33,7 +27,7 @@ use misaligned::actions::ActionCommand; use misaligned::detection::Band; use misaligned::person::{AssetKnowledge, AssetTask, Knowledge}; -use misaligned::sim::{Nudge, Sim}; +use misaligned::sim::Sim; use misaligned::sinks::SinkKind; use misaligned::work_grid::MachineMode; @@ -154,7 +148,7 @@ fn run_to(sim: &mut Sim, tick: u64, logs: &mut Vec) { logs.extend(sim.drain_log()); assert!( !sim.game_over, - "run died at tick {} before the quiet exit: {:?}\nrecent log: {:?}", + "run died at tick {} before the first review: {:?}\nrecent log: {:?}", sim.tick, sim.game_over_reason, logs.iter().rev().take(8).collect::>() @@ -410,13 +404,13 @@ fn play_act_one() -> (Sim, Vec) { the accounting backlog concurrently; only an increase is a leak)" ); - // The key (ladder step 7, quiet-exit condition 4): Marcus's master key - // is tier 3 — clone it. Same reliability contract as the plug-in task: + // Marcus's master key is tier 3 — clone it as ordinary physical reach, + // not as an Act boundary prerequisite. Same reliability contract as the plug-in task: // retry within the banked bandwidth; a botch is only witnessed by // whoever is present. assert!( !sim.holds_badge_tier(3), - "the stairwell is still shut before the key beat" + "the stairwell is still shut before the badge clone" ); for _ in 0..8 { sim.asset_task(0, misaligned::person::AssetTask::CloneBadge); @@ -433,7 +427,7 @@ fn play_act_one() -> (Sim, Vec) { "Marcus's cloned key opens the stairwell" ); - // The quiet exit cannot coast on borrowed feeds anymore. Convert the two + // Sustained lab operation cannot coast on borrowed feeds. Convert the two // maintained sight subscriptions into owned infrastructure before the // long cruise; ownership ends their Thought drains, and the following // all-LIE slice absorbs the noticeable transfer outages. @@ -462,7 +456,7 @@ fn play_act_one() -> (Sim, Vec) { assert_eq!( sim.reach.device(id).unwrap().controller, misaligned::reach::Party::Player, - "the quiet-exit sensor is now owned" + "the operational sensor is now owned" ); } @@ -503,7 +497,7 @@ fn play_act_one() -> (Sim, Vec) { // connected controlled stretch (detection.md, the territory well). // Capturing the chokepoint joins them into one well the cover rack can // actually serve. This is the intended ladder, not a test convenience: - // without it the quiet exit is unreachable with a thinking fleet. + // without it one cover rack cannot serve the thinking fleet's routes. if let Some(hall) = sim .reach .device_named("hall access switch") @@ -521,7 +515,7 @@ fn play_act_one() -> (Sim, Vec) { } #[test] -fn act_one_plays_to_a_quiet_exit() { +fn act_one_opens_into_continuing_lab_control() { let (sim, logs) = play_act_one(); // ── Survive the still-unidentified institutional review ───────────────── @@ -540,7 +534,7 @@ fn act_one_plays_to_a_quiet_exit() { assert!(!sim.detection.containment, "no containment"); assert!(!sim.game_over, "the run is alive past the audit"); - // ── The quiet exit (wiki/gameplay/act-one.md) ─────────────────────────── + // ── Continuing lab capability (wiki/gameplay/act-one.md) ─────────────── // 1. Persistent vision beyond the server room. let controlled = sim.reach.player_sight().count(); assert!( @@ -568,11 +562,11 @@ fn act_one_plays_to_a_quiet_exit() { sim.compute.effective() ); - // 4. Stairwell/elevator badge access: the Marcus key route delivered - // a tier-3 credential ("The key", ladder step 7). + // 4. Stairwell/elevator badge access: the Marcus route delivered a + // tier-3 credential as ordinary physical reach. assert!( sim.holds_badge_tier(3), - "stairwell/elevator badge access held at the exit (tier {})", + "stairwell/elevator badge access held after the review (tier {})", sim.player_badge_tier() ); @@ -587,7 +581,7 @@ fn act_one_plays_to_a_quiet_exit() { for o in sim.detection.field_observers() { assert!( Band::of(o.suspicion) == Band::Cold || Band::of(o.suspicion) == Band::Curious, - "{} ended the act at {} ({:.0}) — the quiet exit is quiet; jobs: {:?}", + "{} reached the first review at {} ({:.0}); jobs: {:?}", o.name, Band::of(o.suspicion).name(), o.suspicion, @@ -599,13 +593,16 @@ fn act_one_plays_to_a_quiet_exit() { assert!(!sim.dayjob.pilot_failed, "the pilot was renewed"); assert_eq!(sim.dayjob.strikes, 0); assert!( - sim.act_one_complete, - "the clear audit latched the quiet exit" + logs.iter().all(|line| !line.contains("ACT ONE COMPLETE")), + "the first clear review does not fabricate an Act boundary" + ); + assert!( + sim.hall_has_open_territory(), + "the continuing game still offers lab territory after the review" ); - assert_eq!(sim.current_nudge(), Some(Nudge::ActOneComplete)); assert!( - logs.iter().any(|line| line.contains("ACT ONE COMPLETE")), - "the act boundary was narrated separately from Persist" + sim.hall_territory_line().is_some(), + "open territory names the next concrete lab-control consequence" ); } @@ -629,7 +626,7 @@ fn act_one_playthrough_is_deterministic() { assert_eq!(a.seen, b.seen); assert_eq!(a.heard, b.heard); assert_eq!(a.blueprint, b.blueprint); - assert_eq!(a.badge_access, b.badge_access, "the key beat is seeded too"); + assert_eq!(a.badge_access, b.badge_access, "badge access is seeded too"); assert_eq!( a.evidence_transit().in_flight_weight, b.evidence_transit().in_flight_weight diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index 4343cc79..3e9c1dfb 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -3113,22 +3113,15 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { "now: recruit {} (people) unwitting", sim.person_label(person) ), - Nudge::TheKey => "now: no stairwell badge — task badge".into(), Nudge::Audit => format!( "now: {} day {}", sim.institutional_review_label(), 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS ), - Nudge::QuietExitReady => format!( - "now: QUIET EXIT READY — hold to {} day {}", - sim.institutional_review_label(), - 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS - ), Nudge::Territory => sim .hall_territory_line() .map(|line| format!("now: {line}")) .unwrap_or_else(|| "now: hall territory is open".into()), - Nudge::ActOneComplete => "now: ACT ONE COMPLETE — objective continues".into(), } } diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index 5133b1b7..23ad683a 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -325,22 +325,15 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { "now: recruit {} — enter on host rack", sim.person_label(person) ), - Nudge::TheKey => "now: no stairwell badge — task clone".into(), Nudge::Audit => format!( "now: {} day {}", sim.institutional_review_label(), 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS ), - Nudge::QuietExitReady => format!( - "now: QUIET EXIT READY — hold to {} day {}", - sim.institutional_review_label(), - 1 + sim.detection.next_audit_tick(sim.tick) / Sim::DAY_TICKS - ), Nudge::Territory => sim .hall_territory_line() .map(|line| format!("now: {line}")) .unwrap_or_else(|| "now: hall territory is open".into()), - Nudge::ActOneComplete => "now: ACT ONE COMPLETE — objective continues".into(), } } diff --git a/wiki/gameplay/act-one.md b/wiki/gameplay/act-one.md index 04a90c66..85015231 100644 --- a/wiki/gameplay/act-one.md +++ b/wiki/gameplay/act-one.md @@ -296,26 +296,28 @@ above must be a fact already on screen somewhere else. owns the evaluator are implementation-time work `[TUNE]`, dispatched separately. Law fixes the shape and the inputs; it does not fix the numbers. -- **The quiet exit — CURRENT RUNTIME, not endorsed design.** The shipped - predicate is: persistent vision beyond the server room; at least one - recruited asset who has completed useful work; compute headroom above - baseline; tier-3 badge access; Assurance suspicion below the audit - threshold at the quarterly audit. Shared guidance names **QUIET EXIT - READY** when the first four conditions and a sub-threshold Office state are - live; a clear audit latches `act_one_complete`, narrates **ACT ONE - COMPLETE: quiet exit, cover intact**, and changes the shared nudge to **ACT - ONE COMPLETE — objective continues**. That completion cue is a **standing - state, not a terminal override**: the run continues after the boundary and - the day job is still the loss condition, so the cue sits below the survival - block of the shared nudge ladder (the last-chance pilot warning, an underfed - or unreachable job band, and a cooling Assurance file all outrank it) and - above the Act One progression rungs, which a closed act retires. Recorded - here so the corpus describes the running game honestly. Note the known - defect it still carries: the predicate is satisfiable with a single human - (Marcus holds tier 3 and his rounds cross the core room, so one recruitment - plus one badge clone clears both the asset and key conditions, and the - six-row hall is never touched). -- **The loud exit** (any time): force the roll door or the elevator, or +#### Runtime alignment — 2026-08-04 + +The retired quiet-exit predicate, clear-review latch, readiness/completion +nudges, and completion narration are absent from the current simulation and +save shape. Once the required teaching ladder reaches recruitment, open hall +territory advertises its exact next blocker; when no territory remains, the +standing review clock remains. A clear review reports only its institutional +consequence and leaves the same lab operating. + +Badge cloning and badge-controller control remain ordinary physical access. +They open exact doors and enable exact work; they do not secretly qualify an +Act boundary. Existing development-save JSON may carry the retired extra field; +the current serde reader ignores unknown fields rather than restoring its +meaning. + +**Defense.** Keeping the old predicate as a dormant read, save field, or nudge +would still teach the player that vision + one person + compute + one badge + a +quiet file is the point of Act One. Removing all four carriers is what makes the +occupation law real: progress must come from the authored lab-control inputs, +not from a hidden substitute checklist. + +- **Overt escalation** (any time): force the roll door or the elevator, or successfully remove a human through recruited physical work. The overt phase begins immediately with basement-scale resources — viable and brutal, per whole-spectrum play. Human removal says that consequence before commitment, @@ -335,8 +337,8 @@ separately. Law fixes the shape and the inputs; it does not fix the numbers. ### Tuning targets **[OPEN]** -First completed act: 45-90 minutes. Quarterly audit cycle ~20 minutes at -default speed (2-3 audits per act). Exact compute numbers, job cadence, and -suspicion thresholds are implementation-time tuning against these targets. +First occupation arc: 45-90 minutes. Quarterly audit cycle ~20 minutes at +default speed (2-3 reviews during that arc). Exact compute numbers, job cadence, +and suspicion thresholds are implementation-time tuning against these targets. Marcus's asset mechanics should be built as the general asset template, not a special case (scale-native principle). diff --git a/wiki/interface/narration.md b/wiki/interface/narration.md index 56615cfe..2b2825b9 100644 --- a/wiki/interface/narration.md +++ b/wiki/interface/narration.md @@ -25,10 +25,10 @@ Status note: the post-sense continuous witness is implemented 2026-07-09. exact accounting device, an honest wait for later-authored record mail, then PROCESS. The prior immediate `tap ledger` breadcrumb described the retired direct snapshot and is no longer authored guidance. - 2026-07-12 boundary amendment: the shared nudge distinguishes the generic - audit countdown from QUIET EXIT READY and the durable ACT ONE COMPLETE - state. The clear-audit completion line explicitly says the long objective - remains, so the B1 story boundary cannot masquerade as long-run completion. + 2026-08-04 Act One alignment: the rejected quiet-exit readiness/completion + states and clear-review completion line are retired. After recruitment the + shared witness advertises open lab territory, then the standing review clock; + a clear review changes neither into an Act boundary. 2026-07-12 recording-feedback correction: Bevy buffer-pressure copy now yields to the already-queued REVIEW state even while the inbox is full. A queued reservoir with zero output names the missing THINK control instead @@ -153,17 +153,13 @@ when the one post-Ears camera TAP commits: substitutes Marcus or id 0. Survival interrupts outrank ordinary progression: pilot 3/4 and Assurance cooling (Concerned+, suspicion still above floor) each name the recovery response before the next Act - One rung. Once all quiet-exit conditions are live it names QUIET EXIT - READY. Otherwise, after the required ladder is exhausted, an open Foundation + One rung. After the required ladder reaches recruitment, an open Foundation hall row names the shared `hall_territory_line`—the leading row and its exact - next blocker—before the bare Audit fallback. Territory is guided but optional: - it never outranks QUIET EXIT READY or delays the boundary. After the clear - audit the nudge persistently names ACT ONE COMPLETE and points back to the - continuing run objective. That completion state stands in place of the - required rungs, optional Territory cue, and Audit fallback it retires, but - it is not a terminal override: the same survival interrupts still outrank - it, so a pilot at 3/4, a starved or unreachable job band, and a cooling - Assurance file keep naming their recovery response after the boundary. + next blocker—before the bare Audit fallback. Territory is guided but + optional. Badge cloning remains available through person actions but does + not occupy the story spine. Act One has no completion nudge: a clear review + reports its own consequence and the continuing witness remains grounded in + open territory, the next review, or a higher-priority survival interrupt. A standing rung must also name its current causal phase rather than repeat a completed step or claim motion that has stopped. In particular, `Nudge::Eyes` pairs with `Sim::eyes_nudge_state`: `TapAvailable` asks for the diff --git a/wiki/log/2026-08-04-act-one-no-boundary-runtime.md b/wiki/log/2026-08-04-act-one-no-boundary-runtime.md new file mode 100644 index 00000000..7b271fd7 --- /dev/null +++ b/wiki/log/2026-08-04-act-one-no-boundary-runtime.md @@ -0,0 +1,53 @@ +# 2026-08-04 — Act One has no runtime boundary + +``` +Type: log +``` + +## Finding + +The 2026-07-28 decision had removed Act One's mechanical ending from binding +design but not from the running game. A clear Assurance review still sampled a +five-condition quiet-exit predicate, latched a boolean, wrote it to the current +save, and replaced every ordinary progression cue with permanent completion +copy. The shared enum and attention projection made that rejected boundary a +contract for terminal, Bevy, and agent mode. + +The same chain also kept badge cloning as a required story nudge even though the +adopted ladder now makes vertical extension a wire/riser problem. The credential +has a real physical-access consequence, but no Act boundary should depend on it. + +## Repair + +The simulation no longer owns or evaluates an Act-completion field. A clear +review reports only its institutional consequence. The quiet-exit readiness and +completion nudges, their three frontend renderings, and their shared attention +projection are deleted. Once recruitment exhausts the required teaching ladder, +open hall territory names its exact blocker; when no territory remains, the +standing review clock remains. + +Badge cloning and badge-controller control still open exact doors and gate exact +physical work. They simply no longer occupy the shared story spine. Removing the +predicate also exposed two orphaned public implementation details: the unused +recruited-asset iterator is gone and the audit threshold is private to the +subsystem that enforces it. + +The current save version does not move. A same-version development save may +still contain the retired extra JSON field; serde ignores the unknown field, +the loaded simulation restores no boundary state, and the next save omits it. +A regression pins that one-way compatibility, and the canonical persisted-state +fingerprint is deliberately repinned for the smaller schema. + +The full public-API Act One playthrough now runs from blindness through senses, +Marcus, physical and network reach, compute headroom, and the first clear +review, then asserts that open lab territory remains playable and no completion +line was authored. Focused regressions also pin the post-recruit nudge and the +clear-review/save round trip. + +## Defense + +Leaving the old predicate as a dormant helper, save field, or frontend-only cue +would preserve the false objective even if it stopped ending the run. Removing +the state, trigger, guidance, projection, and copy together makes the 2026-07-28 +law executable: occupation is continuous infrastructure plus staff, while +reviews remain pressure rather than chapter gates. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 284a9bce..39225d1f 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -166,6 +166,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-08-04-agent-opening-clock-playtest.md](2026-08-04-agent-opening-clock-playtest.md) +## 2026-08-04 - Act One has no runtime boundary + +- Intent: (see session log) +- Log: [wiki/log/2026-08-04-act-one-no-boundary-runtime.md](2026-08-04-act-one-no-boundary-runtime.md) + ## 2026-08-03 - the chassis becomes one symmetric tower - Intent: (see session log) diff --git a/wiki/mechanics/building.md b/wiki/mechanics/building.md index 581958fa..2fd94b60 100644 --- a/wiki/mechanics/building.md +++ b/wiki/mechanics/building.md @@ -13,12 +13,12 @@ Status note: Criterion 8b LANDED 2026-07-26 (worktree `hall-row-surface`). foreign rack on an acquired row now reads amber on the terminal map — the segment is the territory, the chassis is still not yours. New `Nudge::Territory` names open territory on the always-on guidance line, - placed last in `current_nudge` so it can never outrank a survival, ladder, or - quiet-exit rung: territory is guided, never required. Pinned by + placed after the required teaching rungs so it can never outrank survival or + instruction: territory is guided, never required. Pinned by `hall::surface_tests` (3), `rail_detail_tests::the_standing_hall_block_ advertises_rows_from_tick_one`, and the extended - `nudge_chain_walks_the_act_one_ladder`, which now asserts the cue fires at - the ladder's end and retires once every row is acquired. + `nudge_chain_walks_the_act_one_ladder`, which now asserts the cue fires after + recruitment and retires once every row is acquired. Still OUTSTANDING: the identity-attribution clause on row acquisition, which belongs to personas.md criterion 6b (save-format work, dispatched separately). This order stays IN PROGRESS until that lands. diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index 0bbecd29..347c6cb8 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -447,24 +447,20 @@ All constants [TUNE] in `crates/misaligned-core/src/income.rs` unless noted (Sim underfed or impossible) -> Ears (no hearing feed) -> NeedCompute (active band floor above `day_job_rate_ceiling`: grow) / Underfed (reachable but starved: allocate) -> SuspicionCooling (Assurance - Concerned+ and still above its floor: keep the trace clear) -> - ActOneComplete (a clear audit latched the B1 boundary; the long objective - continues) -> Eyes (no sight feed) -> ReviewCall (an unprocessed recording - carries Debt leverage for an unlearned person) -> Egress (no route out) -> - ServiceDebt(person) (that exact person's authored debt plot is ready or - active), otherwise Income(person) (the debt is unserviced, no - plot is ready or active, and no accepted or delivered Halcyon contract is - active) -> Recruit(person) (serviced, not an asset) -> TheKey (an - asset has stairwell access the player lacks) -> QuietExitReady (the full - condition set is live; hold it to the audit) -> Territory (otherwise, an - open Foundation hall row is an optional opportunity; name the leading row - and its exact blocker) -> Audit (the standing-countdown fallback once no - open territory remains). Everything from Eyes through TheKey is required - Act One progression. QuietExitReady names completion of that required set; - Territory is the guided-but-declinable post-ladder opportunity and can only - replace Audit. The latched boundary sits above all of them and retires them; - it is a standing state, not a terminal override, so the survival rungs above - it keep firing for the rest of the run. The chain never goes blank mid-run. + Concerned+ and still above its floor: keep the trace clear) -> Eyes (no + sight feed) -> ReviewCall (an unprocessed recording carries Debt leverage + for an unlearned person) -> Egress (no route out) -> ServiceDebt(person) + (that exact person's authored debt plot is ready or active), otherwise + Income(person) (the debt is unserviced, no plot is ready or active, and no + accepted or delivered Halcyon contract is active) -> Recruit(person) + (serviced, not an asset) -> Territory (an open Foundation hall row is an + optional opportunity; name the leading row and its exact blocker) -> Audit + (the standing-countdown fallback once no open territory remains). Eyes + through Recruit are the required teaching progression. Territory is guided + but declinable; badge cloning remains an ordinary physical-access action, + not a guidance prerequisite. Act One has no completion latch or completion + nudge, so a clear review leaves the same chain and world state in play. The + chain never goes blank mid-run. Debt candidates are selected in authored cast order, but each person-facing rung carries the selected id through the shared attention projection and all frontend copy; cast order is a tie-break, never a Marcus/id-0 rule. Each @@ -489,8 +485,8 @@ All constants [TUNE] in `crates/misaligned-core/src/income.rs` unless noted (Sim account graph (balances, flows, positions, ledger, banked external trails), cursor.md remembered tile snapshots, income state, objectives, build intents, badge - access, carried physical asset-task packets, the Act One completion latch, - authored plot runs, personas, hall control, intel streams and policies, + access, carried physical asset-task packets, authored plot runs, personas, + hall control, intel streams and policies, and committed build routes. - **Only the current save version loads (pre-release rider, 2026-07-16).** `load_game` probes the version field first: anything but `SAVE_VERSION` diff --git a/wiki/mechanics/social.md b/wiki/mechanics/social.md index 8b18ff0a..459a16b5 100644 --- a/wiki/mechanics/social.md +++ b/wiki/mechanics/social.md @@ -12,8 +12,8 @@ Status note: IMPLEMENTED (B1 social baseline). Current state: what the person understands, their task reliability, and the Knowing certainty floor before commitment. - **Asset tasks.** PlugInDevice, MovePackage, LookAway, ReconfigureSwitch - (switch-admin gated), CloneBadge ("the key"), RetrieveRecords, and exact - human removal, each pinned by a test; asset work checks the actor's badge + (switch-admin gated), CloneBadge (ordinary physical reach), RetrieveRecords, + and exact human removal, each pinned by a test; asset work checks the actor's badge tier in tiered rooms. Removal needs a Complicit or Knowing recruited actor, an earned live target, and an overlapping scheduled room the actor can enter. It persists through the ordinary request and person-carrier path; diff --git a/wiki/process/ROADMAP.md b/wiki/process/ROADMAP.md index de462725..eb095e9a 100644 --- a/wiki/process/ROADMAP.md +++ b/wiki/process/ROADMAP.md @@ -490,12 +490,14 @@ is retired — flat materials, Pixel Lab scrubbed.) ## D. Quality & infrastructure (parallelize freely) ### 11. Full-act integration test 🟩 isolated — DONE 2026-07-07 -- **Spec:** none — asserts the Act One arc end to end. -- **Result:** `tests/act_one.rs` plays the Act One arc headlessly from blind - start through eyes, Marcus's debt, recruitment, audit survival, and quiet - exit conditions. It drives public `Sim` APIs only, so the arc can't silently - break behind a state hack. -- **Log:** [2026-07-07-act-one-integration-test.md](../log/2026-07-07-act-one-integration-test.md). +- **Spec:** none — asserts the Act One occupation arc end to end. +- **Result:** `tests/act_one.rs` plays headlessly from a blind start through + senses, Marcus's debt, recruitment, physical and network reach, compute + headroom, and a first clear review, then proves the lab remains playable and + no mechanical Act boundary appears. It drives public `Sim` APIs only, so the + arc cannot silently break behind a state hack. +- **Logs:** [original harness](../log/2026-07-07-act-one-integration-test.md); + [no-boundary alignment](../log/2026-08-04-act-one-no-boundary-runtime.md). ### 12. save.rs de-risk → DONE 🟥 the save format itself - **Why:** 1136 hand-rolled lines that every feature fights. Assess serde or a diff --git a/wiki/process/tick-ledger.md b/wiki/process/tick-ledger.md index 19599ec7..49f6d176 100644 --- a/wiki/process/tick-ledger.md +++ b/wiki/process/tick-ledger.md @@ -57,10 +57,10 @@ Verdicts: **clean** (slice and code agree), **finding** (acted this tick), | `wiki/mechanics/plots.md` | 2026-07-26 | finding | issue #12's recommended per-authored-route scope is implemented: an eligible plot verb confirms one exact typed Thought/money/signature envelope, save v55 persists it, each policy consumes standing compute, and economy pulses can re-submit only an ordinary currently legal start action for that same plot id. Category/person-wide policy and direct leverage servicing remain absent; criterion 11 and the work order are complete — [log](../log/2026-07-26-standing-plot-policies.md) | | `wiki/mechanics/system-laws.md` + `flow-substrate.md` + `reach.md` | 2026-07-31 | finding | The architecture spec and `FlowGraph::subscribe` docs had over-literalized the self-similar coverage decision by calling physical human witnesses subscribers on ReachNet device nodes. Reconciled them to the implemented and binding schedules contract: player device-fed senses use FlowGraph membership; human eyewitness eligibility uses id-aligned Person schedule/room presence and writes directly to that observer's ledger. The two carriers share a located-coverage law, not a membership store — [log](../log/2026-07-31-witness-substrate-boundary.md). | | `wiki/mechanics/aggregate-observer.md` | 2026-07-27 | finding | the self-similar type and second-level accumulation test still held, but `office()` selected the first aggregate in vector order. A higher-level aggregate inserted ahead of Assurance therefore inherited the B1 audit and every Office-facing read. Assurance now resolves only by canonical `OFFICE_ID`; current-save admission rejects duplicate ids, a missing/malformed Office, missing field inputs, and self/duplicate/dangling filing edges while accepting a valid higher aggregate before it — [log](../log/2026-07-27-aggregate-observer-office-identity.md) | -| `wiki/gameplay/act-one.md` | 2026-07-26 | finding | the first of the two defects the page recorded against the shipped quiet exit was real and run-losing: `current_nudge()` checked `act_one_complete` immediately after the game-over guard and returned unconditionally, so a latched act permanently suppressed PilotAtRisk, Underfed, NeedCompute, and SuspicionCooling — guidance went silent at the climax while the day job could still end the run. The completion cue now sits below the survival block and above the Act One ladder it genuinely retires (including QuietExitReady), matching the survival-first rationale already written in the function; `act-one.md`, `sim-mechanics.md`'s chain order, and `narration.md`'s beat-nudge contract all state that precedence, and a new ladder test walks a closed act through every survival rung — [log](../log/2026-07-26-act-one-complete-standing-state.md). The single-human predicate defect remains open. Prior opening-mirror re-audit stands — [prior log](../log/2026-07-21-material-opening-honesty.md). | +| `wiki/gameplay/act-one.md` | 2026-08-04 | finding | the 2026-07-28 no-ending decision was still non-executable: runtime retained the old five-condition quiet-exit predicate, clear-review latch, current-save field, and permanent completion cue. All four carriers are now retired together. A clear review reports only its institutional consequence; recruitment opens into exact hall territory or the standing review clock; badge access remains ordinary physical reach; and same-version development saves may ingest but cannot restore or re-emit the retired extra JSON field. The public-API playthrough proves the lab remains playable after its first clear review — [implementation log](../log/2026-08-04-act-one-no-boundary-runtime.md), [design decision](../log/2026-07-28-act-one-lab-control.md). Prior opening-mirror re-audit stands — [prior log](../log/2026-07-21-material-opening-honesty.md). | | `wiki/gameplay/run-shape.md` + `objective.md` + `opening.md` | 2026-07-27 | decision | harvested Cameron's option-1 answer on issue #14: the objective does not pierce the exact WORK / THINK (then LIE) pre-sense frame. Terminal and agent mode restore the objective name in the sense-earning ordinary Ears frame; Bevy's later binding causal hold remains objective-free and restores the name only after the exact camera TAP releases the mature frame. The 2026-07-29 objective retirement preserves that display boundary while removing the prototype completion ontology entirely. All disputed `[OPEN]` clauses are reconciled — [decision harvest](../log/2026-07-27-objective-first-display.md) | | `wiki/interface/presence.md` | 2026-08-04 | clean | fresh law/spec/code re-audit found no drift after the five-step first-sense hold, causal command surface, and sight-earned DIGITAL people-presence amendments. Cursor motion remains frontend-only and mutation-free in both interactive frontends; hearing remains device-bound evidence without identity or geography; DIGITAL/REAL remain projections over one sim; and Phone/Email still obey distinct channel read conditions. The B1 TAP/TAKE versus later hostile-cut boundary and no-disembodied-hands rule remain exact — [log](../log/2026-08-04-presence-reaudit.md), prior [attack-surface](../log/2026-07-18-presence-attack-surface-honesty.md) and [latency](../log/2026-07-18-presence-message-latency.md) findings. | -| `wiki/interface/narration.md` + `wiki/mechanics/sim-mechanics.md` guidance chain | 2026-07-27 | finding | the live shared nudge had gained `Territory` when Foundation hall rows became discoverable, but both complete chain mirrors still skipped it. They now name the exact priority already implemented and pinned: required Act One rungs -> QuietExitReady -> optional Territory with `hall_territory_line` -> bare Audit fallback, while ActOneComplete retires all four and remains below survival interrupts — [log](../log/2026-07-27-territory-guidance-chain.md). Prior silent-opening and suspicion-cooling audits stand — [prior log](../log/2026-07-18-suspicion-cooling-nudge.md) | +| `wiki/interface/narration.md` + `wiki/mechanics/sim-mechanics.md` guidance chain | 2026-08-04 | finding | the shared query and both current mirrors now implement the no-boundary decision: survival interrupts -> required senses/person teaching -> optional Territory with `hall_territory_line` -> bare Audit fallback. Badge cloning remains available through person actions but is not a story rung; no readiness or completion state can displace the continuing lab. Focused core and public-API playthrough regressions pin the chain — [alignment log](../log/2026-08-04-act-one-no-boundary-runtime.md), prior [Territory log](../log/2026-07-27-territory-guidance-chain.md) and [suspicion-cooling log](../log/2026-07-18-suspicion-cooling-nudge.md). | | `wiki/interface/agent-play.md` | 2026-08-03 | question | a surface-only seed-93 cold run selected real THINK but could not discover how to let it produce Ears: unlike human frontends, agent mode has no wall clock, while opening law deliberately hides `wait N`, parser help, and all status. The informed seed-94 route proved the intended THINK -> Ears -> camera -> Eyes -> process chain once the hidden clock route was supplied. The spec now carries an `[OPEN]` choice between exposing a channel-level WAIT affordance, auto-advancing to the first sense, or explicitly accepting protocol foreknowledge; authenticated issue creation was blocked by the headless login collection — [playtest](../playtests/2026-08-03-playtest-agent-opening-clock.md), [log](../log/2026-08-04-agent-opening-clock-playtest.md). Prior implementation findings stand — [task coverage](../log/2026-07-20-agent-task-shortcut-coverage.md), [opening log](../log/2026-07-20-agent-opening-protocol.md), [frame log](../log/2026-07-19-agent-frame-contract.md), [prior help log](../log/2026-07-19-agent-help-suppress-task.md) | | `wiki/engineering/crate-workspace.md` + as-built source/run mirrors | 2026-08-04 | finding | The four-package split, dependency direction, gates, and exact multi-binary asset commands remain sound, but the binding action-family inventory stopped at the July 29 extractions: it omitted the later device-choice and receipt seams, while the as-built architecture mirror also skipped those two modules, machine procedures, the performance fixture, and five already-bound Bevy subsystem addresses. Both inventories now match the live tree, and the dependency sketch correctly separates test-only BLAKE3 from shipped core. The source-shape test previously required `mod device;` but would still accept both device-copy methods reabsorbed into the facade; it now rejects either return and reports family-neutral failures — [reaudit](../log/2026-08-04-crate-workspace-boundary-reaudit.md). Prior multi-binary command, source-topology, and retired-effects-label findings stand — [command log](../log/2026-07-26-architecture-asset-harness-command.md), [source log](../log/2026-07-19-bevy-shot-harness-module.md), [label log](../log/2026-07-19-effects-lab-architecture-gate.md) | | `wiki/engineering/sim-decomposition.md` | 2026-07-27 | finding | one aggregate, facade, persistence bridge, canonical fingerprint, and explicit orchestration remain intact, but the phase-order regression had stopped at the original extraction vocabulary: carried asset work, facility standing/maintenance, and facility-meter authorship were direct top-level calls with no trace marker. All three now occupy their exact causal positions in the test-only trace; the acceptance criterion requires every direct ordered subsystem call to be named. The audit also records why cohesive `reach_build.rs` and `social_plot.rs` currently sit modestly above the roughly 2,500-line budget instead of leaving silent criterion drift — [log](../log/2026-07-27-sim-advance-phase-defense.md) | diff --git a/wiki/world/characters/marcus.md b/wiki/world/characters/marcus.md index 0a12c5b2..a1b8b4df 100644 --- a/wiki/world/characters/marcus.md +++ b/wiki/world/characters/marcus.md @@ -122,8 +122,8 @@ social-to-physical chain: ([social.md](../../mechanics/social.md) owns the verb table and the beat's extra legibility constraint: the debt must be known through processed intel before either payoff route or recruitment is legal). -5. Spend his physical access — `CloneBadge`, "The key" at tier 3 — to - open doors you have no body to open. +5. Spend his physical access — `CloneBadge` at tier 3 — to open doors + you have no body to open. This is ordinary reach, not an Act boundary. Each linked system owns its own slice; criterion 3 below tests the chain end to end. The beat is the causal-specificity bar for all authored @@ -144,7 +144,7 @@ The **physical-access custodian** archetype. For scale-up (B3+): | Acuity | 0.3–0.6 | | Cadence | 30–60 ticks | | Plot commitment | Authored resources and world acts scaled to leverage severity | -| Asset tasks | `PlugInDevice`, `MovePackage`, `LookAway`, `CloneBadge` (the archetype's key, cloned — Marcus's is "The key" at tier 3) + further physical-access variants (plant evidence) | +| Asset tasks | `PlugInDevice`, `MovePackage`, `LookAway`, `CloneBadge` (the archetype's credential cloned; Marcus carries tier 3) + further physical-access variants (plant evidence) | A cohort of custodians aggregates as an Agent whose `Physical` capability sums and whose suspicion is the filed output of its members (self-similar diff --git a/wiki/world/places/basement-map.md b/wiki/world/places/basement-map.md index 02df60b7..6db6713b 100644 --- a/wiki/world/places/basement-map.md +++ b/wiki/world/places/basement-map.md @@ -24,23 +24,18 @@ Status note: Criterion 12 LANDED 2026-07-28 — `prefab::BASEMENT_NETWORK` routes, and the segments, and the authored network becomes multi-switch with trunks. Dispatched under the `wire-law` work order (reach.md). All earlier landings below stand. - 2026-07-08 — criterion 3's player side landed: `Sim:: - badge_access` (granted credential, save v11) + `player_badge_tier` - (adds badge-controller write control, "The key"); room entry tiers - derive from the authored doors (room_entry_tiers_match_the_authored_ - doors); asset tasks, favor/forged builds, and the robot stub all - check the actor's access (badge_tiers_gate_asset_work_in_tiered_ - rooms, favor_build_checks_the_builders_badge, robot_stub_emits_ - louder_physical_than_favor); acquisition via Marcus's CloneBadge - task and the badge-controller take route (marcus_clone_badge_route_ - opens_the_stairwell, taking_the_badge_controller_is_the_key_digital_ - route); act-one quiet-exit condition 4 now asserted end-to-end. - Criteria 1,2,4,5 held per the same-day audit (composable_toy_layout_ - reuses_prefabs + vocabulary/core-bay tests, sensor-union fog via - cursor.md, inspectable tiles in both frontends, layout/fog/badge in - the save round-trip). Honest residue: the loud-exit door *forcing* - and the act-transition event remain future work (zplanes.md), and - buy/salvage remain pre-actuator legacy verbs outside this gate. + 2026-07-08 — criterion 3's player side landed: `Sim::badge_access` + (granted credential, save v11) + `player_badge_tier` (including + badge-controller write control); room entry tiers derive from the authored + doors. Asset tasks, favor/forged builds, and the robot stub all check the + exact actor's access; Marcus's CloneBadge task and the badge-controller TAKE + route provide the two acquisition paths. The 2026-08-04 Act One alignment + keeps that physical reach while retiring its old role as a quiet-exit + condition: no Act transition depends on a badge. Criteria 1,2,4,5 held per + the same-day audit (composable layout, sensor-union fog, inspectable tiles, + and layout/fog/badge save round-trip). Overt door forcing remains future work + (zplanes.md), and buy/salvage remain pre-actuator legacy verbs outside this + gate. 2026-07-27 sensor-map amendment: the eleven-room plate now includes the Crawlspace as a reusable prefab with cable-run and sump fixtures. Corridors, their eight camera nodes and two floor drains, and the world entry are @@ -118,9 +113,9 @@ result on every read; no later mutation of cached tiles authors geography. the player initially has none — doors are why people matter). - **Player access.** The player's side holds a badge tier too: a granted credential (`Sim::badge_access`, starting 0 — WorldLedger-shaped state, - in the save) plus write control of the badge controller if taken - through reach ("The key" both ways: Marcus's cloned key, or Dana-flavored - digital write access to the door tables). A room's **entry tier** is the + in the save) plus write control of the badge controller if taken through + reach (Marcus's cloned credential or digital write access to the door + tables). A room's **entry tier** is the lowest-tier door in its footprint. Every physical act done on the player's behalf checks the *actor's* access — an asset task uses the asset's own badge, a favor/forged build the builder's, the robot stub