diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 3baa26e8..c86831ba 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -700,9 +700,9 @@ struct SimClock { timer: Timer, } -/// Keyboard/pointer attention inside the DIGITAL held-choice interrupt. -/// Frontend-only: the plot run remains the canonical held state and every -/// option carries its renderer-neutral ActionCommand from core. +/// Keyboard/pointer attention inside the held-choice interrupt (both +/// dialects). Frontend-only: the plot run remains the canonical held state +/// and every option carries its renderer-neutral ActionCommand from core. #[derive(Resource, Default)] struct HeldChoiceUi { selected: usize, @@ -2710,11 +2710,13 @@ fn handle_input( return; } - // A DIGITAL held-choice card is a real modal interrupt, not decorative - // prose. It supersedes any compact world menu and owns keyboard input - // until an option carries attention into the shared Operations confirm - // step. Pointer selection lands in `held_choice_pointer`. - if !mode.material && game.ops.is_none() && game.sim.has_held_choice() { + // A held-choice card is a real modal interrupt in both dialects, not + // decorative prose. It supersedes any compact world menu and owns + // keyboard input until an option carries attention into the shared + // Operations confirm step. Pointer selection lands in + // `held_choice_pointer`. When Operations is already open, that + // workspace owns the rows instead. + if game.ops.is_none() && game.sim.has_held_choice() { game.menu = None; held_choice_keyboard_input(&kb, &mut game, &mut held_choice, &mut mode, &mut exit); game.drain(); @@ -2993,9 +2995,10 @@ fn handle_input( game.drain(); } -/// Keyboard grammar for the DIGITAL held-choice interrupt. Number keys carry -/// the corresponding option straight to the ordinary Operations confirmation; -/// arrows/j/k plus Enter provide focus navigation without a pointer. +/// Keyboard grammar for the held-choice interrupt in both Bevy dialects. +/// Number keys carry the corresponding option straight to the ordinary +/// Operations confirmation; arrows/j/k plus Enter provide focus navigation +/// without a pointer. fn held_choice_keyboard_input( kb: &ButtonInput, game: &mut Game, @@ -3057,9 +3060,8 @@ fn held_choice_keyboard_controls( return false; } - // View and process controls remain honest while time is held. REAL has no - // world card; the same choice remains available on the ACTIVE run in - // Operations, as required by digital-read.md's deferred REAL clause. + // View and process controls remain honest while time is held. F3 flips + // dialect without releasing the hold; the same card stays available. if kb.just_pressed(KeyCode::F3) { mode.flip_view(); let tick = game.sim.tick; @@ -4050,11 +4052,12 @@ fn render_held_choice( else { return; }; - // The read is DIGITAL's treatment; REAL stays deferred (digital-read.md). - // A REAL player still answers a held choice through Operations, as before - // the drill-tier card existed. Operations also owns its own held surface, - // so do not double-draw there either. - let card = (!mode.material && game.ops.is_none()) + // Both dialects draw the interrupt card (digital-read.md criterion 5). + // Operations owns its own held surface when that workspace is open, so + // do not double-draw there. + let card = game + .ops + .is_none() .then(|| game.sim.held_choice_cards().into_iter().next()) .flatten(); let Some(card) = card else { @@ -4135,15 +4138,10 @@ fn render_held_choice( /// selection; press carries that exact option into Operations confirmation. fn held_choice_pointer( mut game: ResMut, - mode: Res, mut ui: ResMut, rows: Query<(&Interaction, &HeldChoiceOption), Changed>, ) { - if game.screen != Screen::Playing - || mode.material - || game.ops.is_some() - || !game.sim.has_held_choice() - { + if game.screen != Screen::Playing || game.ops.is_some() || !game.sim.has_held_choice() { return; } for (interaction, row) in &rows { @@ -5680,6 +5678,27 @@ mod held_choice_input_tests { "number selection still awaits confirm" ); } + + #[test] + fn held_choice_keyboard_opens_confirmation_in_real_view() { + let mut kb = ButtonInput::::default(); + let mut game = held_game(); + let mut mode = RenderMode { + material: true, + ..RenderMode::default() + }; + let mut ui = HeldChoiceUi::default(); + + kb.press(KeyCode::Digit1); + assert!(!held_choice_keyboard_controls( + &kb, &mut game, &mut ui, &mut mode + )); + assert!( + game.ops.is_some(), + "REAL must offer the same held-choice card grammar as DIGITAL" + ); + assert!(mode.material, "answering must not flip the dialect"); + } } #[cfg(test)] diff --git a/wiki/interface/digital-read.md b/wiki/interface/digital-read.md index feda0c4a..279c869e 100644 --- a/wiki/interface/digital-read.md +++ b/wiki/interface/digital-read.md @@ -53,8 +53,12 @@ Status note: IMPLEMENTED. Adopted 2026-07-15 from the Fable playtest as a rendering error. - **Held-choice interrupt (5).** A held plot choice dims the frame and hangs the question with its options as executable bound commands at the - person's anchor; the clock reads HELD and does not advance until the - ordinary Operations confirmation runs. + person's anchor in both Bevy dialects (DIGITAL and REAL); the clock + reads HELD and does not advance until the ordinary Operations + confirmation runs. Amended 2026-07-24: the card is shared interaction + UI, not a DIGITAL-only read surface — a REAL player must not meet HELD + with no answer chrome. Operations remains a valid alternate path when + that workspace is already open. - **Magnitude LOD (6).** Every intel item carries an authored magnitude (1-10; save v32); `read_sentences_at` filters intel by the camera's altitude while pressure, held choices, trace, and standing emissions @@ -70,9 +74,9 @@ Status note: IMPLEMENTED. Adopted 2026-07-15 from the Fable playtest LIE), so no sentence, beam, clock, receipt, or reticle can leak through. Bevy's immediate post-Ears cause/object/verb hold is also true black and withholds the mature read until its exact camera TAP commits. - REAL stays deferred for standing world sentences and the drill-tier card. - The focused action explanation is interaction UI shared by both Bevy - dialects; terminal and agent rows retain their compact projection. + REAL stays deferred for standing world sentences. The held-choice card + and the focused action explanation are interaction UI shared by both + Bevy dialects; terminal and agent rows retain their compact projection. Per-amendment history (D1-D10) is in the dated `wiki/log/` entries from 2026-07-15 onward. Stage: B1 — The Basement @@ -241,9 +245,12 @@ that perception rendered. parity — how humans think versus how agents think, diffable. Ships in the ordinary build as a debug view (no feature flag), excluded from the player-facing default and from the frames-not-dumps contract. -- **REAL stays deferred.** No standing anchor sentences are added to the - material dialect; its diegetic whispers (overheard speech at embers) are - specified intent under presence.md but wait behind the read. +- **REAL stays deferred for standing world sentences.** No standing anchor + sentences are added to the material dialect; its diegetic whispers + (overheard speech at embers) are specified intent under presence.md but + wait behind the read. The held-choice interrupt card is not deferred: it + is shared interaction UI in both dialects so a plot hold never leaves a + REAL player with a stopped clock and no answer surface. ## Player surface @@ -286,11 +293,13 @@ is parity of meaning, not identical composition. visibly consumed by scrub; standing emissions mark their source distinctly from pool debt. 5. A held plot choice interrupts at the person's anchor with its options - as the exact bound commands. Each option is executable by pointer and - keyboard through the ordinary Operations confirmation; the wall clock - remains HELD until that confirmation resolves. The sim's held state, - the surface's held state, and the command selected cannot disagree - (single projection). + as the exact bound commands in both DIGITAL and REAL. Each option is + executable by pointer and keyboard through the ordinary Operations + confirmation; the wall clock remains HELD until that confirmation + resolves. The sim's held state, the surface's held state, and the + command selected cannot disagree (single projection). When Operations + is already open, that workspace owns the held rows and the world card + does not double-draw. 6. Intel items carry a magnitude; a zoomed-out frame surfaces only at-or-above-altitude sentences (fixture-tested at two altitudes with mixed-magnitude intel). diff --git a/wiki/log/2026-07-24-held-choice-both-views.md b/wiki/log/2026-07-24-held-choice-both-views.md new file mode 100644 index 00000000..9fbb9d87 --- /dev/null +++ b/wiki/log/2026-07-24-held-choice-both-views.md @@ -0,0 +1,29 @@ +# 2026-07-24 — Held-choice card in both Bevy dialects + +``` +Type: log +``` + +## Intent + +A REAL play frame stopped on Dana's held plot choice with `HELD` on the +rail and no answer card. The DIGITAL-only gate was a dialect-purity rule +from digital-read D7; Cameron rejected it — there is no reason to hide +mandatory answer chrome behind F3. + +## Changed + +- [digital-read.md](../interface/digital-read.md): criterion 5 and the + status note now treat the held-choice card as shared interaction UI in + DIGITAL and REAL. Standing world sentences stay REAL-deferred. +- Bevy: `render_held_choice`, held keyboard routing, and held pointer + grammar no longer require `!mode.material`. Operations still suppresses + the world card when that workspace is open. +- Decision history: + [decisions/2026-07-24.md](decisions/2026-07-24.md). + +## Defense + +wiki/interface/digital-read.md criterion 5 — a held plot choice must +interrupt with executable options; a dialect flip must not remove the +only answer surface while the wall clock is HELD. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 8f87be77..66e392b3 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -36,6 +36,11 @@ add or amend a session log, then re-run the generator. - Intent: Two asks from play. First: put the keyboard map in the spec. Second: bind `Shift`+arrow, after a survey showed the strongest unclaimed need was not region select but *getting back to a machine you lost* — the Co playtest's core unresolved complaint ("Rack 3 moved out of view a... - Log: [wiki/log/2026-07-24-keymap-and-anchor-jump.md](2026-07-24-keymap-and-anchor-jump.md) +## 2026-07-24 - Held-choice card in both Bevy dialects + +- Intent: A REAL play frame stopped on Dana's held plot choice with `HELD` on the rail and no answer card. The DIGITAL-only gate was a dialect-purity rule from digital-read D7; Cameron rejected it — there is no reason to hide mandatory answer chrome behind F3. +- Log: [wiki/log/2026-07-24-held-choice-both-views.md](2026-07-24-held-choice-both-views.md) + ## 2026-07-24 - An outward filing no longer kills the run - Intent: A live GUI session died with ``` thread 'Compute Task Pool (0)' panicked at sim/communications.rs:369: Filing messages require an observer endpoint ``` taking the run with it. The panic is reachable from shipped content, not from an exotic state. diff --git a/wiki/log/decisions/2026-07-24.md b/wiki/log/decisions/2026-07-24.md new file mode 100644 index 00000000..bcc71f0d --- /dev/null +++ b/wiki/log/decisions/2026-07-24.md @@ -0,0 +1,27 @@ +# Decisions — 2026-07-24 + +``` +Type: log +``` + +## Held-choice card is shared interaction UI in both Bevy dialects + +### DECIDED + +- The held plot-choice interrupt card (dim overlay, prompt, bound option + rows) renders and accepts pointer/keyboard input in both DIGITAL and + REAL. +- A REAL player must not meet a HELD clock with no answer chrome. +- When Operations is already open, that workspace owns the held rows; the + world card does not double-draw. +- Standing world-anchor sentences remain REAL-deferred under + digital-read.md; this decision does not add DIGITAL read prose to the + material dialect. + +### Rejected + +- Keep the card DIGITAL-only and rely on Operations or an F3 flip in REAL. + Rejected: play showed a stopped clock that looked frozen while the rail + still narrated the choice. + +Owner: [digital-read.md](../../interface/digital-read.md) criterion 5.