diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index e6a44454..5a50486e 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -1767,24 +1767,14 @@ struct HoverVerbWord { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MachineVerbTone { - Escape, Current, Key, Divider, Rest, } -fn machine_verb_tone( - current_mode: Option, - slot_mode: Option, - active: bool, - control_hint: bool, - label: &str, -) -> MachineVerbTone { - if slot_mode.is_some_and(|mode| current_mode.and_then(MachineMode::panic_escape) == Some(mode)) - { - MachineVerbTone::Escape - } else if active { +fn machine_verb_tone(active: bool, control_hint: bool, label: &str) -> MachineVerbTone { + if active { MachineVerbTone::Current } else if control_hint { MachineVerbTone::Key @@ -9635,8 +9625,7 @@ fn render_hover_verb_bar( let pulse = operator_pulse(time.elapsed_secs(), harness.is_some()); scaled(AMBER, pulse) } else { - match machine_verb_tone(current_mode, slot_mode, active, control_hint, label) { - MachineVerbTone::Escape => AMBER, + match machine_verb_tone(active, control_hint, label) { MachineVerbTone::Current => BONE, MachineVerbTone::Key => scaled(DIM, 0.72), MachineVerbTone::Divider => scaled(DIM, 0.42), @@ -9658,51 +9647,24 @@ mod hover_verb_bar_tests { use misaligned::work_grid::MachineMode; #[test] - fn think_lights_work_but_not_lie_as_the_panic_escape() { - assert_eq!( - machine_verb_tone( - Some(MachineMode::Think), - Some(MachineMode::Work), - false, - true, - "1", - ), - MachineVerbTone::Escape, - ); + fn think_emphasizes_only_the_current_mode() { + assert_eq!(machine_verb_tone(false, true, "1"), MachineVerbTone::Key,); assert_eq!( - machine_verb_tone( - Some(MachineMode::Think), - Some(MachineMode::Work), - false, - false, - "WORK", - ), - MachineVerbTone::Escape, + machine_verb_tone(false, false, "WORK"), + MachineVerbTone::Rest, ); assert_eq!( - machine_verb_tone( - Some(MachineMode::Think), - Some(MachineMode::Think), - true, - false, - "THINK", - ), + machine_verb_tone(true, false, "THINK"), MachineVerbTone::Current, ); assert_eq!( - machine_verb_tone( - Some(MachineMode::Think), - Some(MachineMode::Lie), - false, - false, - "LIE", - ), + machine_verb_tone(false, false, "LIE"), MachineVerbTone::Rest, ); assert_eq!( - machine_verb_tone(Some(MachineMode::Work), None, false, false, "/"), + machine_verb_tone(false, false, "/"), MachineVerbTone::Divider, - "an absent escape cannot light separators or device verbs", + "separators remain quieter than every mode word", ); } diff --git a/crates/misaligned-core/src/work_grid.rs b/crates/misaligned-core/src/work_grid.rs index 1c3fc058..282baa27 100644 --- a/crates/misaligned-core/src/work_grid.rs +++ b/crates/misaligned-core/src/work_grid.rs @@ -47,17 +47,6 @@ impl MachineMode { pub fn is_delegable(self) -> bool { !matches!(self, MachineMode::Relay) } - - /// The immediate mode that safely exits this posture, when the player - /// surface must advertise one. THINK is the first intentional breach of - /// cover, so every frontend points back to WORK while THINK is current; - /// LIE remains a deliberate cleanup choice rather than a panic button. - pub fn panic_escape(self) -> Option { - match self { - MachineMode::Think => Some(MachineMode::Work), - MachineMode::Work | MachineMode::Lie | MachineMode::Relay => None, - } - } } /// Persistent physical effort for one owned machine. Mode answers what the @@ -1122,12 +1111,4 @@ mod tests { assert!(!weights.contains_key(&MachineMode::Relay)); assert_eq!(weights.get(&MachineMode::Work), Some(&100.0)); } - - #[test] - fn think_has_one_shared_panic_escape() { - assert_eq!(MachineMode::Think.panic_escape(), Some(MachineMode::Work)); - assert_eq!(MachineMode::Work.panic_escape(), None); - assert_eq!(MachineMode::Lie.panic_escape(), None); - assert_eq!(MachineMode::Relay.panic_escape(), None); - } } diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index 3b153fcc..e2d64145 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -24,7 +24,7 @@ use misaligned::ui_projection::{ DigitalLinkState, DigitalReachState, digital_reach_links, digital_reach_state, fact_source_label, }; -use misaligned::work_grid::{MachineMode, TokenFamily}; +use misaligned::work_grid::TokenFamily; use std::io::Stdout; const SIDEBAR_W: i32 = 34; @@ -279,16 +279,7 @@ fn threat_text(sim: &Sim) -> String { ) } -/// The pinned mode-control line is the terminal's always-visible equivalent -/// of Bevy's machine-attached grammar. Color supports the cue, but `← EXIT` -/// carries it textually so the panic route never depends on color alone. -fn mode_control_hint(mode: Option) -> (&'static str, bool) { - if mode.and_then(MachineMode::panic_escape) == Some(MachineMode::Work) { - ("1 WORK ← EXIT · 2 THINK · 3 LIE", true) - } else { - ("select: Shift+t · 1-3 modes · i intensity", false) - } -} +const MODE_CONTROL_HINT: &str = "select: Shift+t · 1-3 modes · i intensity"; fn trace_debt_line(sim: &Sim) -> String { let trace = sim.trace_debt(); @@ -1750,14 +1741,9 @@ impl UI { // Controls, pinned to the bottom. let hy = max_y.saturating_sub(6); put(stdout, sx, hy, &"─".repeat(w), pal::FAINT)?; - let focused_mode = projection - .machine - .as_ref() - .and_then(|machine| machine.work.as_ref().map(|work| work.mode)); - let (mode_hint, escape_cue) = mode_control_hint(focused_mode); for (i, (hint, color)) in [ ("enter/e/a menu · ; last » event", pal::FAINT), - (mode_hint, if escape_cue { pal::AMBER } else { pal::FAINT }), + (MODE_CONTROL_HINT, pal::FAINT), ("5-9 acts · r review · R auto · esc clear", pal::FAINT), ("I operations · F3 view · space pause", pal::FAINT), ("+/- speed · q quit · ^s/^l save/load", pal::FAINT), @@ -2352,19 +2338,16 @@ fn object_state_label(state: misaligned::operations_projection::ObjectState) -> } #[cfg(test)] -mod first_think_escape_tests { - use super::mode_control_hint; - use misaligned::work_grid::MachineMode; +mod mode_control_hint_tests { + use super::MODE_CONTROL_HINT; #[test] - fn focused_think_names_work_as_the_one_press_exit() { + fn pinned_mode_controls_never_promote_an_alternate_mode() { assert_eq!( - mode_control_hint(Some(MachineMode::Think)), - ("1 WORK ← EXIT · 2 THINK · 3 LIE", true) + MODE_CONTROL_HINT, + "select: Shift+t · 1-3 modes · i intensity" ); - assert!(!mode_control_hint(Some(MachineMode::Work)).1); - assert!(!mode_control_hint(Some(MachineMode::Lie)).1); - assert!(!mode_control_hint(None).1); + assert!(!MODE_CONTROL_HINT.contains("EXIT")); } } diff --git a/wiki/engineering/env.md b/wiki/engineering/env.md index e17dccc4..bb99543d 100644 --- a/wiki/engineering/env.md +++ b/wiki/engineering/env.md @@ -47,7 +47,7 @@ is sim or frontend state, never an environment variable. | Variable | Surface | Values | Effect | |---|---|---|---| -| `MISALIGNED_SHOT` | `misaligned-bevy` | `flat`, `hall`, `hall-material`, `floor-lights-close`, `wide`, `close`, `dark`, `zoomin`, `zoomout`, `digital-reach`, `build-route-families`, `build-deceive-routes`, `build-committed-route`, `build-switch-digital`, `build-switch-real`, `intel`, `tokens`, `thoughtflow`, `thoughtflow-wide`, `visual-proof`, `person-proof`, `exposure-record`, `exposure-overflow`, `service-shift-real`, `service-shift-digital`, `service-incident-resolved`, `signal`, `ears`, `ears-digital`, `eyes-white`, `eyes-form`, `consume-demand`, `consume-thought`, `produce-think`, `draw-lie`, `opening`, `opening-digital`, `clinical-threat`, `pilot-last-chance`, `operator-pressure`, `hover-menu`, `first-think`, `menu`, `worklight`, `worklightoff`, `wake1`, `wake2`, `wake3` | Dev screenshot harness: stage a deterministic scenario, settle, report the staged `RenderMode` dialect, save one PNG, then exit. `tools/bevy-headless.sh` consumes that runtime dialect rather than maintaining a second kind list: REAL requires the material fog audit, while DIGITAL remains screenshot evidence because material fog has no entity surface there. `hall` / `hall-material` frame all six Foundation rows in the flat/material views with Eyes and one staged owned expansion; `floor-lights-close` uses the same hall staging but approaches the unobstructed southern row at machine/floor scale; `digital-reach` holds controlled, tapped, reachable, closed-segment, and air-gap reach states in one DIGITAL survey frame; `build-route-families`, `build-deceive-routes`, and `build-committed-route` stage the shared network-link family, candidate, and durable receipt pages; `build-switch-digital` / `build-switch-real` stage the same exact inert small-switch footprint on one earned growable pad before any source, actuator, device, or graph effect; `visual-proof` stages one-move/one-slug Thought evidence in an earned room; `person-proof` stages a camera-earned volumetric person; `service-shift-real` / `service-shift-digital` fire one real favor-build reservoir while Marcus's authored shift is off-site, then hold the carried packet at its real hall endpoint in paired view dialects; `service-incident-resolved` advances that exact scenario once so the real graph edge lands and the carried mark disappears; `exposure-record` places six actual Exposure units on the live host in telemetry darkness while `exposure-overflow` places eighteen to prove the fixed seven-slot rack and consolidated final tab; `intel` stages tick-zero intel tiers (no camera tap); `tokens` enqueues D5/T4 on the host; `thoughtflow` / `thoughtflow-wide` stage the THINK fluid (slugs, meniscus, filament snap) at close and wide framing; `signal` focuses the known environmental monitor before any feed tap to capture its cold-signal presence cue; `ears` / `ears-digital` stage the same semantic audio capture in REAL or DIGITAL, pulsing only at the environmental monitor while spatial fog remains unchanged; `eyes-white` / `eyes-form` freeze the first-Eyes source held white and then contracted around the resolving chassis; `consume-demand` / `consume-thought` run the host through a sim-authored WORK queue swallow or passive-core Thought draw; `produce-think` / `draw-lie` capture sim-authored Thought/record production or the rigid record transfer into a staged LIE well; `opening` / `opening-digital` freeze the untouched tick-zero material or DIGITAL view; `clinical-threat` stages that DIGITAL opening with one real pilot strike so the compact rail exception is observable; `pilot-last-chance` stages the third of four strikes so the pinned NEXT line, host WORK cue, and `NOW / PILOT` label can be read together; `operator-pressure` adds one concerned observer and a full recording buffer to the one-strike opening so the compact frame proves a single THREAT, a promoted buffer NEXT, and no stale world cue; `hover-menu` captures the resting WORK/THINK/LIE line beside the server via reticule focus (no pointer), while `first-think` stages the opening Thought route and captures amber `1 WORK` beside current THINK as the panic exit; `menu` opens the context menu on the tapped environmental monitor; `worklight` / `worklightoff` pair the dev work light on and off; `wake1/2/3` freeze the wake choreography at the stutter flash, the column, and the pull-back. | +| `MISALIGNED_SHOT` | `misaligned-bevy` | `flat`, `hall`, `hall-material`, `floor-lights-close`, `wide`, `close`, `dark`, `zoomin`, `zoomout`, `digital-reach`, `build-route-families`, `build-deceive-routes`, `build-committed-route`, `build-switch-digital`, `build-switch-real`, `intel`, `tokens`, `thoughtflow`, `thoughtflow-wide`, `visual-proof`, `person-proof`, `exposure-record`, `exposure-overflow`, `service-shift-real`, `service-shift-digital`, `service-incident-resolved`, `signal`, `ears`, `ears-digital`, `eyes-white`, `eyes-form`, `consume-demand`, `consume-thought`, `produce-think`, `draw-lie`, `opening`, `opening-digital`, `clinical-threat`, `pilot-last-chance`, `operator-pressure`, `hover-menu`, `first-think`, `menu`, `worklight`, `worklightoff`, `wake1`, `wake2`, `wake3` | Dev screenshot harness: stage a deterministic scenario, settle, report the staged `RenderMode` dialect, save one PNG, then exit. `tools/bevy-headless.sh` consumes that runtime dialect rather than maintaining a second kind list: REAL requires the material fog audit, while DIGITAL remains screenshot evidence because material fog has no entity surface there. `hall` / `hall-material` frame all six Foundation rows in the flat/material views with Eyes and one staged owned expansion; `floor-lights-close` uses the same hall staging but approaches the unobstructed southern row at machine/floor scale; `digital-reach` holds controlled, tapped, reachable, closed-segment, and air-gap reach states in one DIGITAL survey frame; `build-route-families`, `build-deceive-routes`, and `build-committed-route` stage the shared network-link family, candidate, and durable receipt pages; `build-switch-digital` / `build-switch-real` stage the same exact inert small-switch footprint on one earned growable pad before any source, actuator, device, or graph effect; `visual-proof` stages one-move/one-slug Thought evidence in an earned room; `person-proof` stages a camera-earned volumetric person; `service-shift-real` / `service-shift-digital` fire one real favor-build reservoir while Marcus's authored shift is off-site, then hold the carried packet at its real hall endpoint in paired view dialects; `service-incident-resolved` advances that exact scenario once so the real graph edge lands and the carried mark disappears; `exposure-record` places six actual Exposure units on the live host in telemetry darkness while `exposure-overflow` places eighteen to prove the fixed seven-slot rack and consolidated final tab; `intel` stages tick-zero intel tiers (no camera tap); `tokens` enqueues D5/T4 on the host; `thoughtflow` / `thoughtflow-wide` stage the THINK fluid (slugs, meniscus, filament snap) at close and wide framing; `signal` focuses the known environmental monitor before any feed tap to capture its cold-signal presence cue; `ears` / `ears-digital` stage the same semantic audio capture in REAL or DIGITAL, pulsing only at the environmental monitor while spatial fog remains unchanged; `eyes-white` / `eyes-form` freeze the first-Eyes source held white and then contracted around the resolving chassis; `consume-demand` / `consume-thought` run the host through a sim-authored WORK queue swallow or passive-core Thought draw; `produce-think` / `draw-lie` capture sim-authored Thought/record production or the rigid record transfer into a staged LIE well; `opening` / `opening-digital` freeze the untouched tick-zero material or DIGITAL view; `clinical-threat` stages that DIGITAL opening with one real pilot strike so the compact rail exception is observable; `pilot-last-chance` stages the third of four strikes so the pinned NEXT line, host WORK cue, and `NOW / PILOT` label can be read together; `operator-pressure` adds one concerned observer and a full recording buffer to the one-strike opening so the compact frame proves a single THREAT, a promoted buffer NEXT, and no stale world cue; `hover-menu` captures the resting WORK/THINK/LIE line beside the server via reticule focus (no pointer), while `first-think` stages the opening Thought route with current THINK bone-bright and WORK/LIE left dim; `menu` opens the context menu on the tapped environmental monitor; `worklight` / `worklightoff` pair the dev work light on and off; `wake1/2/3` freeze the wake choreography at the stutter flash, the column, and the pull-back. | | `MISALIGNED_SHOT` | `misaligned-assets` | `dead`, `foreign`, `idle`, `busy`, `core`, canonical modes `work`, `think`, `lie` plus the legacy screenshot aliases `dayjob` (= work), `research`/`operations`/`ops` (= think), `conceal` (= lie) — each optionally suffixed `_ladder`/`_ring`/`_wash` — `lineup[_