diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 4c67d5c3..f6ae5c2e 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -1101,7 +1101,7 @@ impl Game { } None => { let tick = self.sim.tick; - self.add_log(tick, "No known map actuator for this object."); + self.add_log(tick, "You do not know where this happens."); } } } diff --git a/crates/misaligned-bevy/src/operations_ui.rs b/crates/misaligned-bevy/src/operations_ui.rs index d800b0f9..33a0825d 100644 --- a/crates/misaligned-bevy/src/operations_ui.rs +++ b/crates/misaligned-bevy/src/operations_ui.rs @@ -490,6 +490,7 @@ mod operations_workspace_tests { #[cfg(test)] mod operations_focus_tests { use super::{Game, OperationsTarget, OperationsView, OpsPane}; + use misaligned::operations_projection::SchemeKind; #[test] fn focus_and_reopen_restore_exact_operations_selection() { @@ -539,6 +540,23 @@ mod operations_focus_tests { Some(1) ); } + + #[test] + fn unknown_focus_location_uses_world_language() { + let mut game = Game::new(); + game.sim.people.has_channel = true; + let target = OperationsTarget::Scheme(SchemeKind::Moonlight); + game.open_operations_at(&target); + assert_eq!(game.sim.operations_actuator(&target), None); + + game.ops_focus_actuator(); + + assert_eq!( + game.log.last().map(|event| event.text.as_str()), + Some("You do not know where this happens.") + ); + assert!(game.ops.is_some(), "a failed focus stays in Operations"); + } } // ─── Operations workspace systems (operations-workspace.md) ───────────────── diff --git a/crates/misaligned-terminal/src/main.rs b/crates/misaligned-terminal/src/main.rs index 919cb2b2..9273048f 100644 --- a/crates/misaligned-terminal/src/main.rs +++ b/crates/misaligned-terminal/src/main.rs @@ -820,9 +820,7 @@ impl App { self.ops_resume = self.ops.take(); self.focus_anchor(anchor); } - None => self - .ui - .add_log(self.sim.tick, "No known map actuator for this object."), + None => self.ui.add_log(self.sim.tick, ui::OPERATIONS_FOCUS_UNKNOWN), } } Command::OpsBack => { @@ -1894,7 +1892,7 @@ mod review_key_tests { #[cfg(test)] mod operations_focus_tests { use super::{App, Command}; - use misaligned::operations_projection::{OperationsTarget, OperationsView}; + use misaligned::operations_projection::{OperationsTarget, OperationsView, SchemeKind}; use misaligned::operations_ui::OpsPane; #[test] @@ -1934,4 +1932,21 @@ mod operations_focus_tests { Some(1) ); } + + #[test] + fn unknown_focus_location_uses_world_language() { + let mut app = App::with_seed(41); + app.sim.people.has_channel = true; + let target = OperationsTarget::Scheme(SchemeKind::Moonlight); + app.open_operations_at(&target); + assert_eq!(app.sim.operations_actuator(&target), None); + + assert!(!app.handle_command(Command::OpsFocus)); + + assert_eq!( + app.ui.last_log_text(), + Some(super::ui::OPERATIONS_FOCUS_UNKNOWN) + ); + assert!(app.ops.is_some(), "a failed focus stays in Operations"); + } } diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index 163b152d..ddccfe5c 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -2554,7 +2554,7 @@ impl UI { dline( stdout, &mut y, - &format!("actuator: {label} · f focus"), + &operations_focus_line(&label), pal::AMBER_DIM, None, )?; @@ -2583,14 +2583,10 @@ impl UI { // The printed key line: no hidden binding is required to complete a // route (operations-workspace.md entry-and-input). put(stdout, 0, bottom, &"─".repeat(w), pal::FAINT)?; - let focus_hint = if ops - .selected_object(sim) - .is_some_and(|object| sim.operations_actuator(&object.target).is_some()) - { - " · f focus actuator" - } else { - "" - }; + let focus_hint = operations_focus_hint( + ops.selected_object(sim) + .is_some_and(|object| sim.operations_actuator(&object.target).is_some()), + ); // A field being written owns the alphabet, so the legend stops // advertising keys that now type characters. The workspace decides // when that happened; Bevy prints the same three states. @@ -2724,9 +2720,19 @@ fn operations_fact_lines(facts: &[String], width: usize) -> Vec { facts.iter().flat_map(|fact| wrap(fact, width)).collect() } +pub(crate) const OPERATIONS_FOCUS_UNKNOWN: &str = "You do not know where this happens."; + +fn operations_focus_line(place: &str) -> String { + format!("where this happens: {place} · f focus") +} + +fn operations_focus_hint(has_place: bool) -> &'static str { + if has_place { " · f go there" } else { "" } +} + #[cfg(test)] mod operations_context_tests { - use super::operations_fact_lines; + use super::{operations_fact_lines, operations_focus_hint, operations_focus_line}; #[test] fn outside_contact_recovery_survives_the_minimum_terminal_detail_width() { @@ -2740,6 +2746,15 @@ mod operations_context_tests { assert!(lines.iter().all(|line| line.chars().count() <= 41)); assert_eq!(lines.join(" "), facts.join(" ")); } + + #[test] + fn focus_location_uses_world_language_not_implementation_ontology() { + let line = operations_focus_line("network switch"); + assert_eq!(line, "where this happens: network switch · f focus"); + assert_eq!(operations_focus_hint(true), " · f go there"); + assert_eq!(operations_focus_hint(false), ""); + assert!(!line.to_ascii_lowercase().contains("actuator")); + } } #[cfg(test)] diff --git a/wiki/interface/operations-workspace.md b/wiki/interface/operations-workspace.md index 9262b429..762be8d0 100644 --- a/wiki/interface/operations-workspace.md +++ b/wiki/interface/operations-workspace.md @@ -59,6 +59,12 @@ Status note: Reopened 2026-08-02 (adopted, not yet implemented): selected OPENS/RELATED pane that pointer hover could reach while j/k navigation could not. Enter follows its exact semantic target; sale and control rows retain their existing commands and confirmation law. + Amended 2026-08-04: Human Operations surfaces no longer expose the internal term + `actuator` while following a strategic object into the physical world. + Terminal names `where this happens: ` and offers `f focus`; the + compact key line says `f go there`. If the selected object has no known map + location, terminal and Bevy say `You do not know where this happens.` and + remain in Operations. Internal actuator bindings remain unchanged. Amended 2026-07-21: ACCOUNTS teaches ordinary TAP on the known accounting device, then waits honestly for later-authored record mail, then offers PROCESS on captured books. The retired second-step `TAP LEDGER` label is not @@ -248,8 +254,9 @@ frontends preserve the same information order: TARGET, BOOKS, FLOW, SCHEME, and ACTIVE. Selecting an edge opens that exact semantic object in its owning view; an unearned object never appears as a speculative link. -4. **Physical actuator** — the known map body carrying the selected object, - when one honestly exists, and the reversible FOCUS control. +4. **Where this happens** — the known map body or place carrying the selected + object, when one honestly exists, and the reversible FOCUS control. The + internal actuator binding is not player copy. 5. **Available actions** — canonical verbs or concrete authored plot titles. 6. **Selected-action explanation** — cost/gain, expected signature and observer band (or explicit `no signature`; a plot row carries neither @@ -870,8 +877,10 @@ Events link to the semantic object they describe: open their exact SCHEMES/ACTIVE object, not the switch merely because the hidden outside connection carried them. -The detail pane still names and can focus a real map actuator when one exists. -Strategic events do not receive dishonest tile coordinates. +The detail pane still names and can focus a real map body or place when one +exists. Strategic events do not receive dishonest tile coordinates. If no +location is known, the interface says `You do not know where this happens.` +rather than exposing the internal actuator lookup. FOCUS is a context toggle, not a navigation reset. Leaving Operations through FOCUS retains the exact view, semantic object selection, semantic related/action @@ -1002,7 +1011,7 @@ state is not saved and never mutates or advances the sim. plain fact, WHAT DOES THIS CHANGE?, exact consequential action, identity/relationship, then provenance/source history. Other strategic objects retain decision-first order: identity/state, related objects, - physical actuator, actions, selected-action explanation/blocker, then + where this happens, actions, selected-action explanation/blocker, then provenance/facts/progress. 15. View-strip badges report semantic attention states rather than raw object counts. Inbox fullness alone creates no badge; imminent loss is stated on diff --git a/wiki/log/2026-08-04-operations-place-language.md b/wiki/log/2026-08-04-operations-place-language.md new file mode 100644 index 00000000..9cf32bb2 --- /dev/null +++ b/wiki/log/2026-08-04-operations-place-language.md @@ -0,0 +1,47 @@ +# 2026-08-04 — Name the place, not the implementation + +``` +Type: log +``` + +## Finding + +Operations correctly kept a renderer-neutral binding from each strategic +object to the physical map body that could enact it. Its human surfaces exposed +that internal model directly: Terminal printed `actuator: ` and both +frontends answered a missing location with `No known map actuator for this +object.` The player was being told that an implementation lookup failed rather +than what they knew about the world. + +## Change + +- Terminal now names `where this happens: ` beside a selected strategic + object and offers the compact `f go there` control. +- When no physical location is known, Terminal and Bevy say `You do not know + where this happens.` and leave Operations open. +- The renderer-neutral actuator binding, exact focus target, resume state, and + simulation behavior remain unchanged. + +## Verification + +Focused Terminal and Bevy regressions enter a scheme with no physical map +location, invoke the production focus command, require the plain knowledge +boundary, and prove the Operations workspace remains open. Terminal helper +coverage also pins the known-place detail and compact key-line language. + +- `cargo fmt --check` +- `cargo test -p misaligned-terminal operations_focus_tests` +- `cargo test -p misaligned-terminal focus_location_uses_world_language_not_implementation_ontology` +- `cargo test -p misaligned-bevy operations_focus_tests` +- `tools/observed-run.sh tools/bevy-headless.sh operations --no-build` after + building the production binary: the REAL Operations frame passed its fog + audit and rendered `WHERE THIS HAPPENS` / `FOCUS network switch [F]`; the + inspected PNG receipt was + `abc5739394d54824f1433700340fa184b875a14ae59bbe047363e8a518fc1eaa`. + +## Defense + +`wiki/vision/scale.md` now states the general boundary: the implementation model +is not player copy. `wiki/interface/operations-workspace.md` requires human +surfaces to ask where an object happens, name an honestly known body or place, +and state the absence of that knowledge without exposing internal lookup terms. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index d11559d7..c7cbc72c 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -11,6 +11,11 @@ add or amend a session log, then re-run the generator. +## 2026-08-04 - Name the place, not the implementation + +- Intent: (see session log) +- Log: [wiki/log/2026-08-04-operations-place-language.md](2026-08-04-operations-place-language.md) + ## 2026-08-04 - Decision index generation defense - Intent: (see session log) diff --git a/wiki/process/tick-ledger.md b/wiki/process/tick-ledger.md index 96c6f830..c7973c41 100644 --- a/wiki/process/tick-ledger.md +++ b/wiki/process/tick-ledger.md @@ -67,7 +67,7 @@ Verdicts: **clean** (slice and code agree), **finding** (acted this tick), | `wiki/gameplay/horizon.md` + B1/B2 core-loss mirrors | 2026-07-29 | finding | the horizon still said B1 woke at its freshest sync and lost subsequent learning, while runtime stores no image and merely moves `core.host_machine` with every other current field intact. `HostLoss::FailedOver`, the ordinary power-loss receipt, DESIGNATE HOST FAILOVER, core/objective/Act One/opening/glossary mirrors, and core criterion 1 now distinguish live current-state host failover from B2's deferred completed-image rollback. A simulation regression and corpus gate defend the boundary — [log](../log/2026-07-29-b1-host-failover-boundary.md). | | `wiki/vision/premise.md` | 2026-07-23 | finding | the preserved machine-axis wording contradiction is repaired: starting embodiment position is an Origin bias, while Objective remains the second chargen axis (means versus ends). No tuning or design direction changed — [log](../log/2026-07-23-origin-bias-wording.md). The prior issue-#14 boundary repair stands — [prior log](../log/2026-07-23-premise-objective-boundary.md) | | `wiki/vision/player-contract.md` | 2026-07-30 | finding | all five binding clauses remain coherent and the local/no-telemetry plus current-save continuity boundaries still hold. The new saturated-B1 benchmark discharges the core-step scale slice but deliberately does not prove modest-hardware or whole-frame responsiveness; `current-build.md` incorrectly still called saturated B1 open. Its status now names generated and saturated core evidence plus production-path durable save/load evidence as live while complete terminal/Bevy frame evidence remains open — [log](../log/2026-07-30-player-contract-performance-status.md) | -| `wiki/vision/scale.md` | 2026-07-20 | finding | re-audit: self-similar types still hold, but ordinary Operations copy violated the page's own implementation/player-language boundary by printing raw information, policy, report-lot, persona-ledger, wager-position, and plot-catalog bindings. Human projection now names world context or visible order while exact targets/commands stay intact for agent mode. The prior maintenance-dispatch trace was also too optimistic: the law itself still presented decay/repair as current, so it now explicitly marks that dependency as adopted later-stage law, not B1 runtime — [log](../log/2026-07-20-scale-human-language.md) | +| `wiki/vision/scale.md` | 2026-08-04 | finding | fresh re-audit found one residual implementation term in ordinary Operations: Terminal labeled a known body `actuator` and both human frontends reported a failed map-actuator lookup when no location was known. Terminal now asks `where this happens`, its compact control says `go there`, and both frontends state the exact knowledge boundary without leaving Operations; the renderer-neutral binding and agent protocol remain unchanged. Focused production-path regressions pin the known and unknown reads — [log](../log/2026-08-04-operations-place-language.md). Prior broad human-language and maintenance-stage repairs stand — [prior](../log/2026-07-20-scale-human-language.md). | | `wiki/vision/design-judgment.md` + continuous-witness law/spec | 2026-07-31 | clean | Re-read the design judgment, continuous-witness law, narration spec, shared nudge/attention projection, and frontend mirrors. The shipped spine and causal-witness contracts agree; the separate lab-control law is candidly marked `[TUNE]` / still owed rather than falsely claimed implemented. | | `wiki/vision/simulation-laws.md` | 2026-07-22 | finding | the device-resident-work clause still assigned JobAnomaly to Dana and described it only as a local emission after the runtime had made it an exact host-machine/device/site record routed to Voss. Corrected the law to separate Priya's pooled Power/Thermal channels from Voss's routed day-job evidence and cadence-owned acquisition — [log](../log/2026-07-22-job-anomaly-routed-evidence.md). Prior placeholder and legibility findings remain closed — [log](../log/2026-07-17-placeholder-registry.md). | | `wiki/process/ROADMAP.md` (work order 27) | 2026-07-29 | finding | re-audit: entry 27's IMPLEMENTED status, DIGITAL-home / F3-to-REAL staging, and paid material debts still match the owning specs and runtime, including the later Seen-only pool defense. Its detailed heading still advertised the retired monolithic `src/bin/bevy.rs` edit surface, however; it now names the live modular `crates/misaligned-bevy` and `misaligned-assets` packages — [log](../log/2026-07-29-roadmap-material-path.md). Prior default-dialect reconciliation: [log](../log/2026-07-13-roadmap-digital-home-reconciliation.md) | diff --git a/wiki/vision/scale.md b/wiki/vision/scale.md index 976e71d5..96393413 100644 --- a/wiki/vision/scale.md +++ b/wiki/vision/scale.md @@ -52,11 +52,14 @@ each type so the aggregate slots in without a rewrite, not speculative generality built early. The implementation model is not player copy. `Agent`, aggregate, cohort, -derived state, and similar terms may name the internal contract, but the +derived state, actuator, and similar terms may name the internal contract, but the interface names the world the player knows: a person, a maintenance team, an office, a company; ask, deceive, buy, move, or connect. The recursion appears as the same simple question and the same choice shape at each level. It does -not appear as a lesson in the code's type system. +not appear as a lesson in the code's type system. When a strategic object can +be followed to a physical place, the human surface asks **where this happens** +and names the known body or place. If no location is known, it says exactly +that; it never reports that an internal actuator lookup failed. **Human language is a projection, not a serialization dump.** Exact internal ids, persistence keys, vector positions, policy ids, report-lot generation or