diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 42f2ca1f..2bcccfb8 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -4339,10 +4339,10 @@ fn setup_ui(mut commands: Commands) { BorderColor::all(scaled(GUNMETAL, 0.62)), )) .with_children(|p| { - // Compact rest carries only orientation, the nearest clock, and - // the one consequential condition. Stable throughput/objective - // telemetry moved to deliberate detail under the operator-frame - // amendment; the world-bound cue and verbs own immediate action. + // Compact rest carries orientation, the standing objective name, + // the nearest clock, and the one consequential condition. Objective + // progress and stable throughput remain deliberate detail; the + // world-bound cue and verbs own immediate action. p.spawn(( Node { width: Val::Percent(100.0), diff --git a/crates/misaligned-bevy/src/rail_ui.rs b/crates/misaligned-bevy/src/rail_ui.rs index fbca5eec..235e1820 100644 --- a/crates/misaligned-bevy/src/rail_ui.rs +++ b/crates/misaligned-bevy/src/rail_ui.rs @@ -1031,9 +1031,9 @@ mod rail_detail_tests { use super::{ COMPACT_SLAB_STRATA, CompactSlabStratum, DEFAULT_WINDOW_WIDTH, HALL_RAIL_ROWS, MIN_WINDOW_WIDTH, RailSection, SIDEBAR_WIDTH, rail_section_visible, rail_threat_relevant, - sidebar_detail_hint_text, sidebar_focus_text, sidebar_hall_text, + sidebar_detail_hint_text, sidebar_focus_text, sidebar_hall_text, sidebar_header_text, }; - use crate::Game; + use crate::{ActionCommand, Game}; use misaligned::sim::Sim; /// building.md criterion 8b: a player who never focuses a rack site still @@ -1092,15 +1092,70 @@ mod rail_detail_tests { } #[test] - fn ordinary_core_focus_carries_objective_name_and_direction() { + fn opening_compact_slab_does_not_leak_objective_name() { + let mut game = Game::new(); + game.start_run(); + + let header = sidebar_header_text(&game, false); + assert!(game.sim.opening_choices_visible()); + assert!(!header.contains("OBJECTIVE"), "{header}"); + assert!(!header.contains("PERSIST"), "{header}"); + } + + #[test] + fn teaching_hold_compact_slab_does_not_leak_objective_name() { + let mut game = Game::new(); + game.start_run(); + let env = game + .sim + .reach + .device_named("environmental monitor") + .expect("opening sensor") + .id; + game.sim + .pour_thought_into_sinks(Sim::device_sink_node(env), Sim::EARS_SINK_TOKENS); + + let header = sidebar_header_text(&game, false); + assert!(game.sim.teaching_lock_active()); + assert!(!header.contains("OBJECTIVE"), "{header}"); + assert!(!header.contains("PERSIST"), "{header}"); + } + + #[test] + fn ordinary_compact_slab_keeps_objective_name() { + let mut game = Game::new(); + game.start_run(); + let env = game + .sim + .reach + .device_named("environmental monitor") + .expect("opening sensor") + .id; + game.sim + .pour_thought_into_sinks(Sim::device_sink_node(env), Sim::EARS_SINK_TOKENS); + assert!(game.sim.teaching_lock_active()); + game.sim.execute_action(&ActionCommand::TapDevice(env)); + assert!(!game.sim.teaching_lock_active()); + + let header = sidebar_header_text(&game, false); + let objective = game.sim.objective.line(); + assert_eq!(header.lines().last(), Some(objective.as_str()), "{header}"); + assert_eq!(header.matches(&objective).count(), 1, "{header}"); + } + + #[test] + fn ordinary_core_focus_carries_direction_without_duplicate_objective_name() { let mut game = Game::new(); game.start_run(); game.sim.opening_stage = misaligned::sim::OpeningStage::World; (game.cursor_x, game.cursor_y) = game.sim.core_position(); + let header = sidebar_header_text(&game, false); let focus = sidebar_focus_text(&game); let prose = focus.split_whitespace().collect::>().join(" "); - assert!(focus.contains("objective: PERSIST"), "{focus}"); + let objective = game.sim.objective.line(); + assert_eq!(header.matches(&objective).count(), 1, "{header}"); + assert!(!focus.contains(&objective), "{focus}"); assert!(focus.contains("direction:"), "{focus}"); assert!(prose.contains(game.sim.objective.kind.fiction()), "{focus}"); assert!(!focus.contains("victory:"), "{focus}"); @@ -1173,11 +1228,17 @@ fn sidebar_ops_crown_text(game: &Game) -> String { Sim::format_ops_per_sec(ops) } -/// Pinned identity only. Throughput is stable telemetry, and the objective -/// currently has no progress unit, so neither earns compact-frame weight. +/// Pinned identity and the standing objective name. The objective remains a +/// witness line rather than a progress meter: it appears only after the blind +/// opening and teaching hold, then survives every ordinary compact frame. fn sidebar_header_text(game: &Game, material: bool) -> String { let mode = if material { "REAL" } else { "DIGITAL" }; - format!("IDENTITY: {mode} | {}", game.sim.process_revision_label()) + let identity = format!("IDENTITY: {mode} | {}", game.sim.process_revision_label()); + if game.sim.opening_choices_visible() || game.sim.teaching_lock_active() { + identity + } else { + format!("{identity}\n{}", game.sim.objective.line()) + } } /// Clock is a separate compact stratum so orientation never has to compete @@ -1477,7 +1538,6 @@ pub(super) fn sidebar_focus_text(game: &Game) -> String { // (wiki/mechanics/objective.md player surface — focus starts here once the // mode-only opening and Bevy's five-step teaching hold have released). if (game.cursor_x, game.cursor_y) == sim.core_position() { - s.push_str(&format!("objective: {}\n", sim.objective.kind.name())); for l in wrap(&format!("direction: {}", sim.objective.kind.fiction()), 34) { s.push_str(&l); s.push('\n'); diff --git a/wiki/interface/liturgical-ui-constitution.md b/wiki/interface/liturgical-ui-constitution.md index 6a58cc8f..b33291d2 100644 --- a/wiki/interface/liturgical-ui-constitution.md +++ b/wiki/interface/liturgical-ui-constitution.md @@ -55,20 +55,25 @@ arithmetic. A thin persistent header inside the instrument slab — never a top bar across the world. It answers only the questions that can change the next move: -- current mode (DIGITAL / REAL) and time/run state; +- current mode (DIGITAL / REAL), process revision, and the objective name once + the opening/teaching boundary releases; +- time/run state; - the nearest ordinary `SCHEDULE`, promoted to crimson `THREAT` only for a real strike, concerned/convinced observer, or known unpaid obligation; - one bone-bright `NEXT` condition; - the Operations entry and a quiet `Tab` disclosure control. -Stable throughput, objective detail, focus facts, observer meters, and the +Stable throughput, objective progress, focus facts, observer meters, and the full input legend do not earn permanent weight here. They remain exact in -expanded detail. The objective name and fiction line hang on focused self; -the current build has no numeric objective progress. The witness line is the story spine — the -thirty-second bar — and nothing else competes at its weight. +expanded detail. The objective name is a second quiet line inside the Identity +stratum from the first ordinary world frame onward; focused self repeats only +the fiction direction, so attention cannot duplicate the standing name. The +current build has no numeric objective progress. The witness line is the story +spine — the thirty-second bar — and nothing else competes at its weight. **Implementation:** The header section inside `setup_ui` in `main.rs`: -`SidebarText::Header` (11.5px DIM), `SidebarText::Schedule` (10.5px DIM, +`SidebarText::Header` (11.5px DIM) owns the mode/revision line and the gated +`OBJECTIVE: ` line, `SidebarText::Schedule` (10.5px DIM, promoted to CRIMSON by `sidebar_schedule_text` when `rail_threat_relevant` returns true), `SidebarText::Nudge` (11.5px BONE), `SidebarText::Read` (10.0px DIM), and the `OperationsRailButton`. The `continuous-witness.md` @@ -88,7 +93,7 @@ bottom: | Stratum | What it answers | Resting read | |---|---|---| -| **Identity** | Who am I and which view am I using? | DIGITAL / REAL and the current process revision | +| **Identity** | Who am I, what direction persists, and which view am I using? | DIGITAL / REAL, the current process revision, then `OBJECTIVE: ` after the opening/teaching boundary | | **Clock** | When is it and is time moving? | day, tick, cadence / held state, and the F3 destination | | **Pressure** | What am I racing? | the nearest SCHEDULE, promoted to THREAT only by a real exception | | **Next** | What condition matters now? | one bone-bright causal sentence | diff --git a/wiki/log/2026-07-31-objective-name-witness.md b/wiki/log/2026-07-31-objective-name-witness.md new file mode 100644 index 00000000..da749983 --- /dev/null +++ b/wiki/log/2026-07-31-objective-name-witness.md @@ -0,0 +1,48 @@ +# 2026-07-31 — Objective name returns to the compact witness + +``` +Type: log +``` + +## Finding + +The accepted objective contract says `OBJECTIVE: PERSIST` is continuously visible +from the first ordinary world frame onward. The Bevy compact slab did not honor that +contract: its Identity stratum showed only `DIGITAL / REAL` and the process revision. +The objective name appeared only when attention happened to rest on the core, so +moving focus across the world made the standing direction disappear. + +Terminal and agent mode already kept the objective name in their ordinary world +frames. The defect was Bevy-local presentation, not simulation state or objective +progress. + +## Repair + +Bevy's compact Identity stratum now has two quiet lines after the opening teaching +boundary releases: + +1. `IDENTITY: DIGITAL|REAL | REVISION 04` +2. `OBJECTIVE: PERSIST` + +The name remains absent during the blind opening and the five-step first-sense +teaching hold. Once ordinary play begins, it survives arbitrary focus changes. +Focused self retains the objective's fiction direction but no longer repeats the +name, preserving one standing source rather than two competing copies. + +No objective progress unit, target, checklist, evaluator, or victory latch was +introduced. + +## Defense + +Defense: `opening_compact_slab_does_not_leak_objective_name` and +`teaching_hold_compact_slab_does_not_leak_objective_name` pin both gates; +`ordinary_compact_slab_keeps_objective_name` drives the real Ears-to-camera-TAP +boundary and requires exactly one final objective line; and +`ordinary_core_focus_carries_direction_without_duplicate_objective_name` proves +core focus keeps the fiction direction without duplicating that standing name. + +The shared compact-slab ordering regression still requires exactly five strata, so +the repair strengthens Identity rather than creating a sixth competing surface. +Focused Bevy tests passed. The exact final 1280×720 DIGITAL frame was then opened +and read: `OBJECTIVE: PERSIST` sits directly beneath the Identity line with intact +spacing, no clipping or collision, and no second objective name on focused self. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 5fc6e34e..d670b49a 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -21,6 +21,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-07-31-people-signal-presence.md](2026-07-31-people-signal-presence.md) +## 2026-07-31 - Objective name returns to the compact witness + +- Intent: (see session log) +- Log: [wiki/log/2026-07-31-objective-name-witness.md](2026-07-31-objective-name-witness.md) + ## 2026-07-30 - Wire-law secondary mirror audit - Intent: (see session log) diff --git a/wiki/mechanics/objective.md b/wiki/mechanics/objective.md index 7f4a7d79..fb9629e1 100644 --- a/wiki/mechanics/objective.md +++ b/wiki/mechanics/objective.md @@ -59,8 +59,11 @@ It is chosen at new-game beside the origin. A no-choice run gets **Persist**: > Reach the state where no single actor can kill you. The choice round-trips through saves. `OBJECTIVE: PERSIST` is continuously -visible after the opening perception boundary, and `objective` / host focus -can repeat the fiction line. That is the entire active contract. +visible after the opening perception boundary. In Bevy, the name occupies the +quiet Identity stratum after the binding teaching hold releases; host focus +repeats only the fiction direction rather than duplicating the name. Terminal, +agent `objective`, and their inspect surfaces retain the same name/direction +contract. That is the entire active contract. The current build has no objective unit, numeric progress, target, concrete predicate, economy-tick evaluator, or victory latch. Older saves that contain @@ -106,8 +109,11 @@ must not create a private subsystem. ## Player surface The objective name appears in both frontends and agent-mode observation from -the first ordinary world frame onward. Inspecting it repeats the fiction line. -No interface shows a numeric objective counter or a fake distant checklist. +the first ordinary world frame onward. In Bevy it is the second quiet line of +the compact Identity stratum and remains there while focus moves; focused self +shows the fiction direction without repeating the standing name. Inspecting the +objective in other surfaces repeats the fiction line. No interface shows a +numeric objective counter or a fake distant checklist. **First-display boundary (decided 2026-07-27, issues #14-15).** Before any sense, the interface contains WORK / THINK (then LIE) as its only standing @@ -126,7 +132,8 @@ releases the hold. picker. 2. The objective name renders in both frontends and agent mode from the first ordinary world frame onward, respecting the exact opening boundary above. - Inspect surfaces repeat the fiction line. + Bevy keeps it in the compact Identity stratum across arbitrary focus without + duplicating it on focused self; inspect surfaces repeat the fiction line. 3. Until ordinary construction can express completion, runtime and interface own no objective progress unit, target, special fact bundle, economy-tick evaluator, numeric counter, concrete predicate, or victory latch.