From 96e0a2e7737876df59d2f9a962672d490ecd51d5 Mon Sep 17 00:00:00 2001 From: Cameron Date: Sun, 26 Jul 2026 23:37:30 -0700 Subject: [PATCH] Let the survival rungs outrank a closed Act One MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Sim::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 exactly at the climax, including while the day job walked toward the fourth strike that ends the run. The check now sits below the survival block and above `Eyes`: the completion cue is a standing state that retires the Act One ladder it sits on top of (including QuietExitReady, which must never re-advertise a crossed boundary) and yields to every urgent diagnosis above it. Defense: implements the survival-first ordering the function's own doc comment already claimed — the day-job cover is the loss condition, so a starving band outranks progression — and closes the first of the two defects `wiki/gameplay/act-one.md` recorded against the shipped quiet exit in its "Ending Act One" section. That page is amended to state the new precedence and now names only the remaining single-human predicate defect; `wiki/mechanics/sim-mechanics.md` places ActOneComplete at its real position in the guidance chain, and `wiki/interface/narration.md` binds that the shared survival interrupts still outrank the persistent ACT ONE COMPLETE line. `a_closed_act_one_still_yields_to_the_survival_rungs` pins every rung of that block against a latched act. Observed in the agent frontend under `tools/observed-run.sh`: one save with `act_one_complete` and three strikes reads `now: ACT ONE COMPLETE` on a pre-fix binary and `now: PILOT 3/4 — next miss ends` on this one. --- crates/misaligned-core/src/sim/economy.rs | 19 +++-- .../misaligned-core/src/sim/tests/economy.rs | 63 ++++++++++++++++ wiki/gameplay/act-one.md | 19 ++--- wiki/interface/narration.md | 6 +- ...6-07-26-act-one-complete-standing-state.md | 71 +++++++++++++++++++ wiki/log/DEVLOG.md | 5 ++ wiki/mechanics/sim-mechanics.md | 13 ++-- wiki/process/tick-ledger.md | 11 ++- 8 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 wiki/log/2026-07-26-act-one-complete-standing-state.md diff --git a/crates/misaligned-core/src/sim/economy.rs b/crates/misaligned-core/src/sim/economy.rs index dc566733..968a8fd7 100644 --- a/crates/misaligned-core/src/sim/economy.rs +++ b/crates/misaligned-core/src/sim/economy.rs @@ -541,15 +541,15 @@ 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. Returns - /// `None` only when the run is over (the game-over card is the nudge). + /// 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). pub fn current_nudge(&self) -> Option { if self.game_over || self.dayjob.pilot_failed { return None; } - if self.act_one_complete { - return Some(Nudge::ActOneComplete); - } let active_job_nudge = self.dayjob.active.as_ref().and_then(|job| { if job.band_lo > self.day_job_rate_ceiling() + 0.05 { return Some(Nudge::NeedCompute); @@ -584,6 +584,15 @@ 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); diff --git a/crates/misaligned-core/src/sim/tests/economy.rs b/crates/misaligned-core/src/sim/tests/economy.rs index a35e6c10..0fd6f5b6 100644 --- a/crates/misaligned-core/src/sim/tests/economy.rs +++ b/crates/misaligned-core/src/sim/tests/economy.rs @@ -723,6 +723,69 @@ fn quiet_exit_qualifies_then_latches_act_one_at_a_clear_audit() { 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" + ); + + // 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 { + kind: crate::dayjob::JobKind::DataCleaning, + 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" + ); + + // 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; + assert_eq!( + sim.current_nudge(), + Some(Nudge::PilotAtRisk), + "the fourth strike ends the run after the boundary too" + ); + + // 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] fn current_nudge_never_goes_blank_during_a_live_run() { let mut sim = Sim::with_seed(19); diff --git a/wiki/gameplay/act-one.md b/wiki/gameplay/act-one.md index 04419063..57f19bd4 100644 --- a/wiki/gameplay/act-one.md +++ b/wiki/gameplay/act-one.md @@ -268,14 +268,17 @@ names the direction only. 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**. Recorded here so the corpus describes - the running game honestly. Note two known defects it 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), and - the completion nudge is checked above every other rung, so it suppresses - the pilot-at-risk, underfed, need-compute, and suspicion-cooling warnings - for the rest of the run. + 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 successfully remove a human through recruited physical work. The overt phase begins immediately with basement-scale resources — viable and brutal, per diff --git a/wiki/interface/narration.md b/wiki/interface/narration.md index 3a28aa8e..3ed7226d 100644 --- a/wiki/interface/narration.md +++ b/wiki/interface/narration.md @@ -134,7 +134,11 @@ when the one post-Ears camera TAP commits: 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; after the clear audit it persistently names ACT ONE COMPLETE and - points back to the continuing run objective. + points back to the continuing run objective. That completion state stands + in place of the Act One rungs 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. - **Focused action** — the local context menu on the current spatial anchor or the selected semantic object in Operations (and the equivalent agent `actions` target). diff --git a/wiki/log/2026-07-26-act-one-complete-standing-state.md b/wiki/log/2026-07-26-act-one-complete-standing-state.md new file mode 100644 index 00000000..f65f851d --- /dev/null +++ b/wiki/log/2026-07-26-act-one-complete-standing-state.md @@ -0,0 +1,71 @@ +# A closed Act One is a standing state, not a terminal override + +``` +Type: log +``` + +## Intent + +`wiki/gameplay/act-one.md` recorded two known defects in the shipped quiet-exit +boundary. This is the first of them, and the one that costs runs. + +`Sim::current_nudge` checked `act_one_complete` immediately after the game-over +guard and returned unconditionally. From the moment the act latched, the shared +`now:` line could never again say PilotAtRisk, Underfed, NeedCompute, or +SuspicionCooling. Guidance went silent exactly at the climax — including when +the day job was walking toward the fourth strike that ends the run. The act +closing is the point where the player is most likely to look away from the +cover and lose to it. + +The function's own comment already carried the rationale it was violating: the +ladder is ordered survival-first because the day-job cover is the loss +condition, so a starving band outranks progression. + +## What changed + +- The `act_one_complete` check moved out of the top of `current_nudge` to sit + directly below the survival block: after the last-chance pilot boundary, the + Ears opening beat, the active-job diagnoses, and the Assurance cooling cue, + and above `Eyes` and the rest of the Act One ladder. Everything from `Eyes` + down is Act One progression, which a closed act genuinely retires — including + `QuietExitReady`, which must never re-advertise a boundary already crossed. +- The completion nudge is therefore a standing state, not a terminal override. + It is what the player sees when nothing urgent is live, and it yields to + every urgent diagnosis above it for the rest of the run. +- `act-one.md` now states that precedence in the quiet-exit bullet and drops + the repaired defect from the two it recorded; the single-human predicate + defect remains named and unrepaired. +- `sim-mechanics.md`'s guidance-chain order places `ActOneComplete` at its real + precedence instead of at the end of the list, and says why the rungs below it + are the ones it retires. +- `narration.md`'s beat-nudge contract keeps the persistent ACT ONE COMPLETE + wording but binds that the shared survival interrupts still outrank it. + +## Verification + +`a_closed_act_one_still_yields_to_the_survival_rungs` walks a latched act +through the whole survival block: the standing cue with nothing urgent live, +then Underfed on a feasible starved band, NeedCompute on an unreachable one, +PilotAtRisk at `PILOT_STRIKES - 1` with no active job, SuspicionCooling on a +Concerned Office still above its floor, and back to the standing cue when the +file cools. `quiet_exit_qualifies_then_latches_act_one_at_a_clear_audit` still +pins the boundary itself, including across save/load, and +`nudge_chain_walks_the_act_one_ladder`, +`third_pilot_strike_interrupts_the_ladder_with_the_last_chance_response`, and +`current_nudge_never_goes_blank_during_a_live_run` still pass unchanged. + +Observed in the shipped binary, not only in tests. Under +`tools/observed-run.sh` the agent frontend crossed the real opening, then +loaded a save carrying `act_one_complete` with the day job at three strikes. +The same save was run against a binary built from the pre-fix `economy.rs` and +against the repaired one: + +- pre-fix: `now: ACT ONE COMPLETE — objective ...` while one miss from the end + of the run. +- repaired: `now: PILOT 3/4 — next miss ends ...`. + +With strikes back at zero the repaired binary returns to +`now: ACT ONE COMPLETE`, so the standing state is retained rather than +replaced. Both runs reported the real save directory untouched. + +Recorded on the exact landing commit below. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index e973eb5b..21ff9e1a 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -146,6 +146,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-07-26-act-one-territory-capture.md](2026-07-26-act-one-territory-capture.md) +## 2026-07-26 - A closed Act One is a standing state, not a terminal override + +- Intent: `wiki/gameplay/act-one.md` recorded two known defects in the shipped quiet-exit boundary. This is the first of them, and the one that costs runs. `Sim::current_nudge` checked `act_one_complete` immediately after the game-over guard and returned unconditionally. From the moment... +- Log: [wiki/log/2026-07-26-act-one-complete-standing-state.md](2026-07-26-act-one-complete-standing-state.md) + ## 2026-07-25 - Liturgical UI: five bodies, one control language - Intent: The first constitution pass improved the surfaces but still described and built parts of the interface as named pieces of architecture. This correction makes the hierarchy operational instead: five bodies, one stable order, one meaning for each color, and one restrained select... diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index 35e6c6ee..9353139e 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -440,17 +440,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) -> Eyes - (no sight feed) -> ReviewCall (unprocessed Marcus recording, leverage + 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 (unprocessed Marcus recording, leverage unlearned) -> Egress (no route out) -> ServiceDebt (an authored debt plot is ready or active), otherwise Income (the debt is unserviced, no plot is ready or active, and no accepted or delivered Halcyon contract is active) -> Recruit (serviced, not an asset) -> TheKey (an asset has stairwell access the player lacks) -> Audit (the standing countdown while another quiet-exit condition is absent) -> QuietExitReady - (the full condition set is live; hold it to the audit) -> ActOneComplete - (a clear audit latched the B1 boundary; the long objective continues). The - chain never goes blank mid-run. Each frontend + (the full condition set is live; hold it to the audit). Everything from + Eyes down is Act One progression, which is why the latched boundary sits + above it and retires it; the boundary 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. Each frontend words the rungs in its own keys/verbs; `None` only after game over. - Ineffective commands answer (agent-play.md "every command answers"): `siphon`/`redirect` with a non-flow argument answer `-- err` naming where diff --git a/wiki/process/tick-ledger.md b/wiki/process/tick-ledger.md index df4cfe1b..f3cab2c9 100644 --- a/wiki/process/tick-ledger.md +++ b/wiki/process/tick-ledger.md @@ -44,7 +44,7 @@ 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-22 | finding | JobAnomaly now proves the adopted evidence-is-a-flow law through the existing substrate: the exact host machine/site enters its network-facing device, follows canonical FlowGraph custody to Voss, and shares Filing/Network's scheduler and LIE-body budget; recruited-handler suppression is a separate provenance-preserving state transition, not another router or ambient scrub pool — [log](../log/2026-07-22-job-anomaly-routed-evidence.md). The prior canonical tap-membership repair remains current — [log](../log/2026-07-18-flow-subscription-registry-integration.md). | | `wiki/mechanics/aggregate-observer.md` | 2026-07-18 | clean | re-audit hours after the earned-topology landing: the page absorbed it coherently — the institutional card, `@assurance` addressing, and band are hidden until a captured filing is processed, the two-stage discovery is pinned by `captured_then_processed_filing_earns_the_assurance_office_in_two_stages`, and `WatchedInput::Filings(ids)` still matches the code; prior audits stand — [2026-07-14 log](../log/2026-07-14-aggregate-observer-audit.md) | -| `wiki/gameplay/act-one.md` | 2026-07-21 | finding | opening mirror re-audit: the page still said rack telemetry and a presence beam were visible “at start,” contradicting the later persisted silent boundary and all three frontends. It now states the exact mode-only pre-sense interface, hidden-but-real pre-opened Ears sink, first-hearing retirement, and only-then telemetry/beam/feel progression — [log](../log/2026-07-21-material-opening-honesty.md). The prior direct-witness/Filing custody repair stands — [prior log](../log/2026-07-19-act-one-evidence-law.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/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 name/progress in the sense-earning ordinary Ears frame; Bevy's later binding causal hold remains objective-free and restores them only after the exact camera TAP releases the mature frame. All disputed `[OPEN]` clauses are reconciled and the runtime was already correct — [decision harvest](../log/2026-07-27-objective-first-display.md) | | `wiki/interface/presence.md` | 2026-07-26 | clean | fresh audit against perception-owned visibility, exact device-bound senses, honest anchors, fog precedence, shared DIGITAL/REAL world state, and all three frontend projections found no new drift. The B1 TAP/TAKE and later hostile-cut boundary, channel-specific message latency, and no-disembodied-hands rule remain exact; prior findings stand — [attack-surface log](../log/2026-07-18-presence-attack-surface-honesty.md), [latency log](../log/2026-07-18-presence-message-latency.md) | | `wiki/interface/narration.md` | 2026-07-26 | clean | fresh audit against the silent opening, first-earned-sense transition, shared current nudge, clock/threat precedence, and terminal/Bevy/agent frame projections found no new drift. The pre-sense mode-only exception and the post-perception continuous witness remain exact; prior suspicion-cooling repair stands — [log](../log/2026-07-18-suspicion-cooling-nudge.md) | @@ -98,4 +98,11 @@ Format: `- YYYY-MM-DD · type · slice · one-line statement of the finding`. Types are the five from [tick.md](tick.md): violation, contradiction, question, bug, insecurity — plus `gate` for a checker owed to the recurrence-promotes-to-the-gate rule. -(empty) +- 2026-07-26 · contradiction · `wiki/mechanics/sim-mechanics.md` + `wiki/interface/narration.md` + guidance chain · the `Territory` rung is live in `Sim::current_nudge` (it sits + below `QuietExitReady` and above the `Audit` standing-clock fallback, and + carries `hall_territory_line`), but neither the sim-mechanics chain order nor + the narration beat-nudge contract names it. Seen while repairing the + `ActOneComplete` precedence in the same list; left for its own tick because it + is a separate rung and a separate landing. + -- 2.51.2