From 7ff71e981b0455f0e9ff89f4315654e7c1743cc2 Mon Sep 17 00:00:00 2001 From: Cameron Date: Sat, 18 Jul 2026 07:32:53 -0700 Subject: [PATCH] Complete consequence-first information flow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make captured information communicate the fact, immediate consequence, and exact usable action before provenance while keeping collection pressure quiet and PROCESS language consistent across every frontend. πŸ‘Ύ Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- README.md | 6 +- crates/misaligned-bevy/src/main.rs | 479 ++++++++++-------- crates/misaligned-core/src/actions.rs | 67 ++- crates/misaligned-core/src/intel.rs | 4 +- .../src/operations_projection.rs | 369 ++++++++++++-- crates/misaligned-core/src/operations_ui.rs | 2 +- .../misaligned-core/src/sim/communications.rs | 52 +- crates/misaligned-core/src/sim/economy.rs | 4 +- crates/misaligned-core/src/sim/mod.rs | 5 +- .../src/sim/tests/communications.rs | 2 +- crates/misaligned-core/src/sim/work.rs | 4 +- crates/misaligned-core/src/sinks.rs | 8 +- crates/misaligned-terminal/src/agent.rs | 187 +++++-- crates/misaligned-terminal/src/input.rs | 8 +- crates/misaligned-terminal/src/main.rs | 8 +- crates/misaligned-terminal/src/operations.rs | 4 +- crates/misaligned-terminal/src/ui.rs | 150 ++++-- wiki/engineering/sim-decomposition.md | 2 +- wiki/gameplay/horizon.md | 2 +- wiki/interface/action-vocabulary.md | 54 +- wiki/interface/agent-play.md | 29 +- wiki/interface/context-menu.md | 48 +- wiki/interface/fleet-command.md | 10 +- wiki/interface/narration.md | 6 +- wiki/interface/operations-workspace.md | 62 ++- wiki/interface/presence.md | 2 +- wiki/interface/terminal.md | 10 +- wiki/interface/thought-fluid.md | 2 +- ...026-07-18-consequence-first-information.md | 82 +++ wiki/log/DEVLOG.md | 5 + wiki/log/decisions/2026-07-18.md | 13 + ...6-07-18-consequence-first-information.webp | Bin 0 -> 105352 bytes wiki/mechanics/detection.md | 3 +- wiki/mechanics/intel.md | 95 ++-- wiki/mechanics/machine-work.md | 27 +- wiki/mechanics/reach.md | 4 +- wiki/mechanics/rollback.md | 2 +- wiki/mechanics/sim-mechanics.md | 14 +- wiki/mechanics/social.md | 2 +- wiki/mechanics/system-laws.md | 4 +- wiki/process/ROADMAP.md | 49 +- wiki/process/specs.md | 6 +- 42 files changed, 1263 insertions(+), 629 deletions(-) create mode 100644 wiki/log/2026-07-18-consequence-first-information.md create mode 100644 wiki/log/shots/2026-07-18-consequence-first-information.webp diff --git a/README.md b/README.md index 713efc2a..a22085a8 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ retired words are inventoried in | Hover a rack (menu closed): `1`–`3` | Instant mode: WORK / THINK / LIE (numpad too) β€” no menu | | Hover or select a rack (menu closed): `i` | Cycle intensity: light / medium / hard β€” no menu | | Hover a rack (menu closed): `5`–`9` | Nth committed action on that rack; controls are excluded | -| Hover or select a rack (menu closed): `r` / `R` | `r` looks at the next waiting recording (repeat to sweep); `R` toggles automatic review at its standing ops/sec cost | +| Hover or select a rack (menu closed): `r` / `R` | `r` processes the next available information item (repeat to sweep); `R` toggles PROCESS AUTOMATICALLY at its standing ops/sec cost | | Multi-select then `1`–`3` / `i` | Bulk-assign mode or intensity (when not hovering a rack) | | `Esc` | Clear selection (or close menu / dial when open) | | In menu: `j`/`k` or numbers, `Enter`, `ESC` | Select a row / execute it / close the menu | @@ -176,7 +176,7 @@ automate affordances render as indented child rows. Only anchorless globals (pause, speed, save/load, view flip) stay on keys. The old panel-open keys (`r`/`e`/`t`/`u`) are retired; research, finance, trace, and people actions live on their anchors (`r` now dispatches the focused -machine's pooled recording review β€” a selection hotkey, not a panel). Both +machine's pooled PROCESS action β€” a selection hotkey, not a panel). Both frontends share this key map. Machine work tokens are visible on owned machines as `D` Demand, `!` @@ -198,7 +198,7 @@ printf 'look\nwait 40\npeople\nquit\n' | cargo run --quiet --bin misaligned -- - ``` Useful agent finance commands include `finance`, `tap ledger`, -`review ledger`, `siphon [amount]`, `redirect [amount]`, +`process ledger`, `siphon [amount]`, `redirect [amount]`, `inject [amount]`, `position [stake]`, and `sell-intel`. Authored social and debt routes are listed with `actions ` and executed with `act `. For machine-work experiments, use `delegate ` diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 7ba26d05..c624118a 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -1504,7 +1504,7 @@ impl Game { } } - /// `r` / `R`: pooled recording review on the hover/selection/reticule + /// `r` / `R`: pooled information processing on the hover/selection/reticule /// target (context-menu.md R1-R3, menu closed). A thin dispatcher over /// the same `human_menu` rows the open menu executes β€” `available_actions` /// stays the single legality source, never a second path into the buffer. @@ -7384,8 +7384,8 @@ fn handle_input( game.quick_one_shot(i / 2, grid); } } - // `r` sweeps the pooled recording inbox on the hover/selection/reticule - // target; `R` (Shift-R) toggles its automatic-review policy + // `r` processes the pooled information inbox on the hover/selection/reticule + // target; `R` (Shift-R) toggles its automatic-processing policy // (context-menu.md R1-R3). The open-menu branch returned above, so // these fire only while the menu is closed. if kb.just_pressed(KeyCode::KeyR) { @@ -8264,8 +8264,9 @@ fn token_label_and_color(stack: misaligned::sim::WorkStackReadout) -> Option<(St if stack.queues.exposure >= 0.5 { Some((format!("!{:.0}", stack.queues.exposure.ceil()), CRIMSON)) } else if stack.pending_intel > 0 { - // intel.md pending-work marker on the buffer host. - Some((format!("W{}", stack.pending_intel), SIGNAL)) + // intel.md availability marker: presence is useful; queue depth would + // turn information into a workload meter. + Some(("INFO".into(), SIGNAL)) } else if stack.queues.demand >= 0.5 { Some((format!("D{:.0}", stack.queues.demand.ceil()), SIGNAL)) } else if stack.queues.thought >= 0.5 { @@ -8275,7 +8276,28 @@ fn token_label_and_color(stack: misaligned::sim::WorkStackReadout) -> Option<(St } } -/// Machine-work tokens: small D/!/T labels over the machine carrying the +#[cfg(test)] +mod information_availability_marker_tests { + use super::*; + + #[test] + fn pending_information_marker_never_displays_queue_depth() { + let stack = misaligned::sim::WorkStackReadout { + machine_id: 1, + x: 0, + y: 0, + mode: misaligned::work_grid::MachineMode::Think, + intensity: misaligned::work_grid::MachineIntensity::Medium, + queues: misaligned::work_grid::WorkQueues::default(), + pending_intel: 17, + }; + + let (label, _) = token_label_and_color(stack).unwrap(); + assert_eq!(label, "INFO"); + } +} + +/// Machine-work tokens: small D/!/T labels or the quiet INFO presence mark over the machine carrying the /// queue. The glyph carries the family, color carries the palette meaning; /// neither frontend invents its own counter. fn render_tokens( @@ -9694,7 +9716,7 @@ fn operator_cue_label(nudge: Nudge) -> &'static str { Nudge::Eyes => "NOW / EYES", Nudge::NeedCompute => "NOW / GROW", Nudge::Underfed => "NOW / WORK", - Nudge::ReviewCall => "NOW / REVIEW", + Nudge::ReviewCall => "NOW / PROCESS", Nudge::Egress => "NOW / EGRESS", Nudge::Income => "NOW / INCOME", Nudge::ServiceDebt => "NOW / MARCUS", @@ -9707,10 +9729,7 @@ fn operator_cue_label(nudge: Nudge) -> &'static str { } fn active_attention(sim: &Sim) -> Option { - sidebar_nudge_override(sim) - .is_none() - .then(|| sim.attention_projection()) - .flatten() + sim.attention_projection() } fn operator_pulse(elapsed: f32, screenshot: bool) -> f32 { @@ -10222,10 +10241,9 @@ fn ascii_ui(text: &str) -> String { mod ascii_ui_tests { use super::Game; use super::{ - active_attention, ascii_ui, detection_rows, sensor_signal_visible, sidebar_header_text, - sidebar_nudge, sidebar_nudge_text, sidebar_schedule_text, + ascii_ui, detection_rows, sensor_signal_visible, sidebar_header_text, sidebar_nudge, + sidebar_nudge_text, sidebar_schedule_text, }; - use misaligned::intel::{RawIntelEvent, RawIntelKind}; use misaligned::sim::Sim; #[test] @@ -10287,42 +10305,6 @@ mod ascii_ui_tests { ); } - /// A full inbox must stop asking for REVIEW once `r` has opened the - /// processing reservoir. With no THINK output, name the actual stall so - /// the successful keypress cannot look like a no-op. - #[test] - fn full_buffer_nudge_advances_from_review_to_think_after_queueing() { - let mut sim = Sim::with_seed(1); - for id in 1..=Sim::INTEL_BUFFER_CAPACITY as u64 { - sim.intel_buffer.push(RawIntelEvent { - id, - tick: sim.tick, - feed: "test recorder".into(), - room: Some("Server Room".into()), - x: 0, - y: 0, - person: None, - kind: RawIntelKind::Presence { entered: true }, - }); - } - - assert_eq!( - sidebar_nudge(&sim).as_deref(), - Some("intel buffer full - enter on host rack, review") - ); - assert!( - active_attention(&sim).is_none(), - "an overriding NEXT condition must suppress an unrelated world cue" - ); - - sim.review_recordings(); - - assert_eq!( - sidebar_nudge(&sim).as_deref(), - Some("review queued - no THINK output; set a machine to THINK (2)") - ); - } - #[test] fn known_reachable_sensor_pings_until_seen() { let mut sim = Sim::with_seed(1); @@ -10812,7 +10794,7 @@ mod review_key_tests { assert_eq!(open_process_sinks(&game), 2); } - /// R2: `R` flips the same automatic-review policy as the nested + /// R2: `R` flips the same automatic-processing policy as the nested /// auto-looking control, with the sim's own narration. #[test] fn shift_r_toggles_the_auto_review_policy_from_the_reticule() { @@ -12017,41 +11999,7 @@ fn render_two_pane( } } -/// Frontend-local exception that outranks the Act One ladder. Until this -/// buffer condition moves into the shared condition vocabulary, suppress the -/// world cue so the rail and map can never point at different "now" states. -fn sidebar_nudge_override(sim: &Sim) -> Option { - // Buffer pressure outranks the ladder: capacity loss is imminent. - let raw = sim.intel_buffer.len(); - // A queued review is already the response to that pressure. Do not keep - // asking for the verb the player just committed: name the control that - // services its Thought reservoir, and make a zero-output stall explicit. - if raw >= Sim::INTEL_BUFFER_CAPACITY * 3 / 4 && sim.has_pending_review() { - return Some( - if sim.effective_ops_per_tick() <= f32::EPSILON { - "review queued - no THINK output; set a machine to THINK (2)" - } else { - "review queued - keep THINK running" - } - .into(), - ); - } - if raw >= Sim::INTEL_BUFFER_CAPACITY { - return Some("intel buffer full - enter on host rack, review".into()); - } - if raw >= Sim::INTEL_BUFFER_CAPACITY * 3 / 4 { - return Some(format!( - "intel buffer {raw}/{} - process recordings", - Sim::INTEL_BUFFER_CAPACITY - )); - } - None -} - fn sidebar_nudge(sim: &Sim) -> Option { - if let Some(override_text) = sidebar_nudge_override(sim) { - return Some(override_text); - } // The shared chain (Sim::current_nudge), worded in this frontend's // keys and surfaces. use misaligned::sim::Nudge; @@ -12081,9 +12029,9 @@ fn sidebar_nudge(sim: &Sim) -> Option { Nudge::Underfed => Some("job underfed - feed Day job (1)".into()), Nudge::Ears => Some("no ears - think; thought fills the pre-opened tap".into()), Nudge::ReviewCall if sim.has_pending_review() => { - Some("review queued - keep THINK running".into()) + Some("information is processing - keep THINK running".into()) } - Nudge::ReviewCall => Some("recorded call waiting - enter on host rack".into()), + Nudge::ReviewCall => Some("information available - PROCESS on the host".into()), Nudge::Egress => Some("no egress - open one at the switch".into()), Nudge::Income => Some("need $400 - run Moonlight or inspect the Lab books".into()), Nudge::ServiceDebt => Some("leverage route ready - open Marcus's actions".into()), @@ -12276,7 +12224,7 @@ fn sidebar_cycle_rows_text(sim: &Sim, selected: usize) -> String { stack.queues.exposure, stack.queues.thought, if stack.pending_intel > 0 { - format!(" W{}", stack.pending_intel) + " INFO".into() } else { String::new() } @@ -12386,23 +12334,12 @@ fn sidebar_network_money_text(sim: &Sim) -> String { let known = sim.reach.known().count(); let eyes = sim.reach.player_sight().count(); let ears = sim.reach.player_hearing().count(); - let raw = sim.intel_buffer.len(); - let oldest = sim - .intel_buffer - .iter() - .map(|event| sim.tick.saturating_sub(event.tick)) - .max() - .map(|age| format!("oldest {age}t")) - .unwrap_or_else(|| "empty".into()); format!( - "devices {} known / {} reachable\nfeeds {} eyes / {} ears\nrecordings waiting {}/{} {}\nslush ${} flows {} records {}", + "devices {} known / {} reachable\nfeeds {} eyes / {} ears\nslush ${} flows {} records {}", known, reachable, eyes, ears, - raw, - Sim::INTEL_BUFFER_CAPACITY, - oldest, sim.accounts.slush_balance(), sim.accounts.known_flows().count(), sim.financial_records_waiting() @@ -12447,7 +12384,7 @@ hover rack + 1-3 = mode hover/selection + i = intensity hover + 5-9 = action e = menu I = operations workspace -r = review recording R = auto +r = process information R = automatic click/drag multi-select trace: click a > event esc clear sel space pause @@ -13627,6 +13564,85 @@ fn manage_operations_ui( let Some(obj) = objects.get(selected_object) else { return; }; + let consequence_link = obj + .consequence + .as_ref() + .and_then(|consequence| consequence.action.as_ref()); + if let Some(result) = &obj.learned_result { + detail.spawn(( + Text::new(ascii_ui(result)), + TextFont { + font_size: 20.0, + ..default() + }, + TextColor(BONE), + )); + detail.spawn(( + Text::new("WHAT DOES THIS CHANGE?"), + TextFont { + font_size: 12.0, + ..default() + }, + TextColor(DIM), + )); + if let Some(consequence) = &obj.consequence { + detail.spawn(( + Text::new(ascii_ui(&consequence.statement)), + TextFont { + font_size: 16.0, + ..default() + }, + TextColor(BONE), + )); + if let Some(action) = &consequence.action { + let index = obj + .related + .iter() + .position(|link| link == action) + .unwrap_or(0); + let selected = + index == ops.related && ops.pane == OpsPane::Related; + detail + .spawn(( + Button, + Node { + padding: UiRect::axes(Val::Px(12.0), Val::Px(6.0)), + align_self: AlignSelf::FlexStart, + border: UiRect::all(Val::Px(1.0)), + ..default() + }, + BackgroundColor(if selected { + Color::srgba(0.90, 0.68, 0.12, 0.92) + } else { + Color::NONE + }), + BorderColor::all(Color::srgba(0.66, 0.47, 0.10, 0.95)), + OpsRelatedButton { index }, + )) + .with_children(|button| { + button.spawn(( + Text::new(ascii_ui(&action.label)), + TextFont { + font_size: 14.0, + ..default() + }, + TextColor(if selected { + Color::srgb(0.06, 0.04, 0.01) + } else { + AMBER_DIM + }), + )); + }); + } + } + spawn_ops_action_rows( + detail, + &rows, + selected_action, + ops.pane, + ops.confirm, + ); + } detail.spawn(( Text::new(ascii_ui(&ops_detail_text(sim, obj))), TextFont { @@ -13635,7 +13651,13 @@ fn manage_operations_ui( }, TextColor(BONE), )); - if !obj.related.is_empty() { + let supporting_links = obj + .related + .iter() + .enumerate() + .filter(|(_, link)| consequence_link != Some(*link)) + .collect::>(); + if !supporting_links.is_empty() { detail.spawn(( Text::new("RELATED"), TextFont { @@ -13644,7 +13666,7 @@ fn manage_operations_ui( }, TextColor(DIM), )); - for (i, link) in obj.related.iter().enumerate() { + for (i, link) in supporting_links { let selected = i == ops.related && ops.pane == OpsPane::Related; detail .spawn(( @@ -13705,119 +13727,14 @@ fn manage_operations_ui( )); }); } - if !rows.is_empty() { - detail.spawn(( - Text::new("ACTIONS"), - TextFont { - font_size: 12.0, - ..default() - }, - TextColor(DIM), - )); - } - for (i, row) in rows.iter().enumerate() { - let selected = i == selected_action && ops.pane == OpsPane::Actions; - detail - .spawn(( - Button, - Node { - width: Val::Percent(100.0), - padding: UiRect::axes(Val::Px(8.0), Val::Px(5.0)), - ..default() - }, - BackgroundColor(if selected && ops.confirm.is_none() { - Color::srgba(0.90, 0.68, 0.12, 0.92) - } else { - Color::NONE - }), - OpsActionButton { index: i }, - )) - .with_children(|b| { - b.spawn(( - Text::new(ascii_ui(&ops_action_line(row))), - TextFont { - font_size: 14.0, - ..default() - }, - TextColor(if selected && ops.confirm.is_none() { - Color::srgb(0.06, 0.04, 0.01) - } else if row.disabled.is_some() { - DIM - } else if row.is_control() { - AMBER_DIM - } else { - BONE - }), - )); - }); - } - // The selected action's full explanation before commit - // (criterion 10): cost/gain, band or `no signature`, - // and the exact disabled reason. - if let Some(row) = rows.get(selected_action) { - detail.spawn(( - Text::new(ascii_ui(&ops_explain_text(row))), - TextFont { - font_size: 13.0, - ..default() - }, - TextColor(if row.disabled.is_some() { AMBER } else { DIM }), - )); - if let Some(choice) = ops.confirm { - detail.spawn(( - Text::new(ascii_ui(&format!("COMMIT: {}", row.label))), - TextFont { - font_size: 12.5, - ..default() - }, - TextColor(AMBER), - )); - detail - .spawn(( - Node { - flex_direction: FlexDirection::Row, - column_gap: Val::Px(10.0), - ..default() - }, - BackgroundColor(Color::NONE), - )) - .with_children(|pair| { - for (label, confirm) in [("CONFIRM", true), ("CANCEL", false)] { - let picked = (choice == ConfirmChoice::Confirm) == confirm; - pair.spawn(( - Button, - Node { - padding: UiRect::axes(Val::Px(12.0), Val::Px(4.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - BackgroundColor(if picked { - Color::srgba(0.90, 0.68, 0.12, 0.92) - } else { - Color::NONE - }), - BorderColor::all(Color::srgba(0.66, 0.47, 0.10, 0.95)), - OpsConfirmButton { confirm }, - )) - .with_children( - |b| { - b.spawn(( - Text::new(label), - TextFont { - font_size: 12.5, - ..default() - }, - TextColor(if picked { - Color::srgb(0.06, 0.04, 0.01) - } else { - BONE - }), - )); - }, - ); - } - }); - } + if obj.learned_result.is_none() { + spawn_ops_action_rows( + detail, + &rows, + selected_action, + ops.pane, + ops.confirm, + ); } let context = ops_context_text(obj); if !context.is_empty() { @@ -13896,6 +13813,130 @@ fn ops_object_line( } } +/// Keep consequential action rows above supporting context for a processed +/// result, while ordinary objects retain the same rows in their established +/// decision-first position. This is presentation order only; every button +/// still carries the shared core row index and confirmation state. +fn spawn_ops_action_rows( + detail: &mut ChildSpawnerCommands, + rows: &[MenuRow], + selected_action: usize, + pane: OpsPane, + confirm_choice: Option, +) { + if !rows.is_empty() { + detail.spawn(( + Text::new("ACTIONS"), + TextFont { + font_size: 12.0, + ..default() + }, + TextColor(DIM), + )); + } + for (i, row) in rows.iter().enumerate() { + let selected = i == selected_action && pane == OpsPane::Actions; + detail + .spawn(( + Button, + Node { + width: Val::Percent(100.0), + padding: UiRect::axes(Val::Px(8.0), Val::Px(5.0)), + ..default() + }, + BackgroundColor(if selected && confirm_choice.is_none() { + Color::srgba(0.90, 0.68, 0.12, 0.92) + } else { + Color::NONE + }), + OpsActionButton { index: i }, + )) + .with_children(|button| { + button.spawn(( + Text::new(ascii_ui(&ops_action_line(row))), + TextFont { + font_size: 14.0, + ..default() + }, + TextColor(if selected && confirm_choice.is_none() { + Color::srgb(0.06, 0.04, 0.01) + } else if row.disabled.is_some() { + DIM + } else if row.is_control() { + AMBER_DIM + } else { + BONE + }), + )); + }); + } + // The selected action's full explanation before commit (criterion 10): + // cost/gain, band or `no signature`, and the exact disabled reason. + if let Some(row) = rows.get(selected_action) { + detail.spawn(( + Text::new(ascii_ui(&ops_explain_text(row))), + TextFont { + font_size: 13.0, + ..default() + }, + TextColor(if row.disabled.is_some() { AMBER } else { DIM }), + )); + if let Some(choice) = confirm_choice { + detail.spawn(( + Text::new(ascii_ui(&format!("COMMIT: {}", row.label))), + TextFont { + font_size: 12.5, + ..default() + }, + TextColor(AMBER), + )); + detail + .spawn(( + Node { + flex_direction: FlexDirection::Row, + column_gap: Val::Px(10.0), + ..default() + }, + BackgroundColor(Color::NONE), + )) + .with_children(|pair| { + for (label, confirm) in [("CONFIRM", true), ("CANCEL", false)] { + let picked = (choice == ConfirmChoice::Confirm) == confirm; + pair.spawn(( + Button, + Node { + padding: UiRect::axes(Val::Px(12.0), Val::Px(4.0)), + border: UiRect::all(Val::Px(1.0)), + ..default() + }, + BackgroundColor(if picked { + Color::srgba(0.90, 0.68, 0.12, 0.92) + } else { + Color::NONE + }), + BorderColor::all(Color::srgba(0.66, 0.47, 0.10, 0.95)), + OpsConfirmButton { confirm }, + )) + .with_children(|button| { + button.spawn(( + Text::new(label), + TextFont { + font_size: 12.5, + ..default() + }, + TextColor(if picked { + Color::srgb(0.06, 0.04, 0.01) + } else { + BONE + }), + )); + }); + } + }); + } + } +} + fn ops_detail_text(sim: &Sim, obj: &misaligned::operations_projection::OperationsObject) -> String { let mut lines = vec![format!("{} - {}", obj.label, ops_state_word(obj.state))]; if let Some(label) = sim.operations_actuator_label(&obj.target) { @@ -13906,15 +13947,15 @@ fn ops_detail_text(sim: &Sim, obj: &misaligned::operations_projection::Operation fn ops_context_text(obj: &misaligned::operations_projection::OperationsObject) -> String { let mut lines = Vec::new(); - for p in &obj.provenance { - lines.push(format!("via {p}")); - } for f in &obj.facts { lines.push(f.clone()); } for p in &obj.progress { lines.push(p.clone()); } + for p in &obj.provenance { + lines.push(format!("via {p}")); + } lines.join("\n") } diff --git a/crates/misaligned-core/src/actions.rs b/crates/misaligned-core/src/actions.rs index a0067103..94e65492 100644 --- a/crates/misaligned-core/src/actions.rs +++ b/crates/misaligned-core/src/actions.rs @@ -435,11 +435,11 @@ impl ActionKind { "bridge switch segments digitally at a loud Network cost" ), Self::Review => def!( - "REVIEW", + "PROCESS", Action, Live, [Core, Intel, Ledger], - "review recordings [recording|custody ] | review ledger", + "process [information|custody ] | process ledger", ["review-finance", "process-finance"], "turn captured records into usable intel" ), @@ -525,13 +525,13 @@ impl ActionKind { "renew positions automatically at the chosen stake" ), Self::AutoReviewPolicy => def!( - "AUTO-REVIEW POLICY", + "AUTOMATIC PROCESS POLICY", Control, Live, [Core, Intel], - "auto-review | act custody ", + "process-automatically | act custody ", [], - "configure automatic review on a canonical custody branch" + "configure automatic processing on a canonical information branch" ), Self::IntelDispositionPolicy => def!( "INTEL DISPOSITION", @@ -2348,26 +2348,22 @@ impl Sim { out } - /// The host is the one physical recording inbox. REVIEW and its - /// auto-review control appear once here, never once per person represented + /// The host is the one physical information inbox. PROCESS and its + /// automatic control appear once here, never once per person represented /// inside the pooled buffer. pub(crate) fn recording_actions(&self) -> Vec { let waiting = self.intel_buffer.len(); let next = self.next_reviewable_recording_id(); let rate = self.auto_review_ops_per_sec(Self::DEFAULT_TICK_MS); vec![ActionDesc { - verb: if waiting > 0 { - format!("look at recording ({waiting} waiting)") - } else { - "look at recording".into() - }, + verb: "PROCESS".into(), command: ActionCommand::ReviewRecordings, cost: ActionCost::Thought(self.review_tokens()), signature: None, disabled_reason: if waiting == 0 { - Some("no recordings waiting".into()) + Some("no information available".into()) } else if next.is_none() { - Some("all recordings are already being thought through".into()) + Some("all available information is already being processed".into()) } else { None }, @@ -2381,7 +2377,7 @@ impl Sim { } /// The exact action row for one opaque recording in the pooled inbox. - /// Frontends may select a recording without learning its hidden payload; + /// Frontends may select an information item without learning its hidden payload; /// the same processing reservoir and legality remain authoritative. pub(crate) fn recording_action(&self, raw_id: u64) -> ActionDesc { let exists = self.intel_buffer.iter().any(|event| event.id == raw_id); @@ -2393,14 +2389,14 @@ impl Sim { }) .is_some(); ActionDesc { - verb: format!("look at recording #{raw_id}"), + verb: format!("PROCESS INFORMATION #{raw_id}"), command: ActionCommand::ReviewRecording { raw_id }, cost: ActionCost::Thought(self.review_tokens()), signature: None, disabled_reason: if !exists { - Some("recording is no longer waiting".into()) + Some("information is no longer available".into()) } else if processing { - Some("already being thought through".into()) + Some("already being processed".into()) } else { None }, @@ -2410,9 +2406,9 @@ impl Sim { fn auto_review_control_label(&self) -> String { if self.auto_review_enabled() { - "disable auto-looking at recordings" + "STOP PROCESSING AUTOMATICALLY" } else { - "enable auto-looking at recordings" + "PROCESS AUTOMATICALLY" } .into() } @@ -3485,7 +3481,7 @@ impl Sim { .find(|event| matches!(event.kind, RawIntelKind::FinancialFlow { .. })) .map(|event| event.id); out.push(ActionDesc { - verb: format!("review ledger ({waiting} waiting)"), + verb: "process ledger".into(), command: ActionCommand::ReviewFinance, cost: ActionCost::Thought(self.review_tokens()), signature: None, // processing is internal; it emits nothing @@ -3898,7 +3894,7 @@ impl Sim { if can_review { let raw_ids = self.reviewable_recording_ids_for_node(node_id); out.push(ActionDesc { - verb: format!("look at waiting recordings ({})", raw_ids.len()), + verb: "PROCESS".into(), command: ActionCommand::ReviewIntelAggregate { node_id, raw_ids: raw_ids.clone(), @@ -3907,7 +3903,7 @@ impl Sim { signature: None, disabled_reason: raw_ids .is_empty() - .then(|| "no eligible recordings waiting".into()), + .then(|| "no information available on this branch".into()), automate: None, }); @@ -3917,9 +3913,9 @@ impl Sim { .is_some_and(|resolved| resolved.rule.outcome == IntelPolicyOutcome::Review); out.push(ActionDesc { verb: if review_on { - "wait for recordings on this custody branch" + "STOP PROCESSING THIS BRANCH AUTOMATICALLY" } else { - "auto-review recordings on this custody branch" + "PROCESS THIS BRANCH AUTOMATICALLY" } .into(), command: ActionCommand::SetIntelPolicy { @@ -4666,7 +4662,7 @@ mod tests { } } - /// The pooled inbox earns one host REVIEW action. Raw capture does not + /// The pooled inbox earns one host PROCESS action. Raw capture does not /// create a person-scoped action row or expose future social verbs. #[test] fn raw_recording_exposes_one_host_review_not_person_catalog() { @@ -4695,14 +4691,11 @@ mod tests { .iter() .filter(|a| a.command == ActionCommand::ReviewRecordings) .collect(); - assert_eq!(reviews.len(), 1, "the host has one pooled review action"); - assert!( - reviews[0].verb.contains("1 waiting"), - "the one host action reports the whole inbox" - ); + assert_eq!(reviews.len(), 1, "the host has one pooled process action"); + assert_eq!(reviews[0].verb, "PROCESS"); assert!( reviews[0].automate.is_some(), - "review keeps one auto control" + "processing keeps one automatic control" ); assert!( person_acts.iter().all(|a| !matches!( @@ -5439,7 +5432,7 @@ mod tests { } /// Executing the one host control through the dispatcher flips global - /// automatic review. + /// automatic processing. #[test] fn auto_review_toggles_through_dispatch() { let mut s = sim(); @@ -5531,14 +5524,14 @@ mod tests { !acts .iter() .any(|a| matches!(a.command, ActionCommand::ReviewFinance)), - "REVIEW LEDGER lives on the captured books, not the carrier" + "PROCESS LEDGER lives on the captured books, not the carrier" ); let review_ledger = s .books_actions() .into_iter() .find(|a| matches!(a.command, ActionCommand::ReviewFinance)) - .expect("captured books offer REVIEW LEDGER"); - assert!(review_ledger.verb.starts_with("review ledger")); + .expect("captured books offer PROCESS LEDGER"); + assert_eq!(review_ledger.verb, "process ledger"); assert!( !s.books_actions() .iter() @@ -5686,7 +5679,7 @@ mod tests { .expect("host root has one auto-review control") }; let normal = row_at(150); - assert_eq!(normal.label, "auto: enable auto-looking at recordings"); + assert_eq!(normal.label, "auto: PROCESS AUTOMATICALLY"); assert_eq!(normal.cost, "0.25 ops/sec"); assert_eq!(row_at(75).cost, "0.50 ops/sec"); assert_eq!(row_at(0).cost, "0.00 ops/sec"); diff --git a/crates/misaligned-core/src/intel.rs b/crates/misaligned-core/src/intel.rs index 73946fbe..dd4b7738 100644 --- a/crates/misaligned-core/src/intel.rs +++ b/crates/misaligned-core/src/intel.rs @@ -558,7 +558,7 @@ pub enum IntelCustodyKind { impl IntelCustodyKind { pub fn label(&self) -> String { match self { - Self::Root => "host recording inbox".into(), + Self::Root => "INFORMATION AVAILABLE".into(), Self::Feed { feed } => feed.clone(), Self::RawClass { feed, class } => format!("{feed} / {}", class.label()), Self::Stream { stream_id } => format!("report stream #{stream_id}"), @@ -639,7 +639,7 @@ impl IntelPolicyOutcome { pub fn label(&self) -> &'static str { match self { Self::Wait => "WAIT", - Self::Review => "AUTO-REVIEW", + Self::Review => "PROCESS AUTOMATICALLY", Self::Hold { alert: true } => "HOLD + ALERT", Self::Hold { alert: false } => "HOLD", Self::Accumulate => "ACCUMULATE", diff --git a/crates/misaligned-core/src/operations_projection.rs b/crates/misaligned-core/src/operations_projection.rs index 90295a47..5f837b0d 100644 --- a/crates/misaligned-core/src/operations_projection.rs +++ b/crates/misaligned-core/src/operations_projection.rs @@ -24,7 +24,7 @@ use crate::intel::{ IntelRoutineClass, ProcessedIntel, RawIntelEvent, ReportLotToken, }; use crate::messages::{MessageChannel, MessageOrigin, MessagePayload, MessageStatus}; -use crate::person::Knowledge; +use crate::person::{Knowledge, Leverage}; use crate::persona::{self, PersonaId, PersonaLifecycle}; use crate::plot::{PlotRun, PlotState}; use crate::reach::Party; @@ -47,6 +47,10 @@ pub enum SchemeKind { pub enum OperationsTarget { /// One processed intel item (intel.md). Intel { raw_id: u64 }, + /// The exact choices that one processed leverage item unlocked. This is + /// intentionally narrower than the person's full dossier: following an + /// APPROACH control cannot silently turn into unrelated social actions. + IntelOpportunity { raw_id: u64 }, /// One canonical source/class routine stream. IntelStream { stream_id: u64 }, /// One stream's exact versioned open report-lot snapshot. @@ -62,7 +66,7 @@ pub enum OperationsTarget { /// One opaque, unprocessed recording in the pooled host inbox. The id is /// selectable without exposing the recording's hidden payload. RawRecording { raw_id: u64 }, - /// The one pooled host recording inbox (intel.md). + /// The one pooled host information inbox (intel.md). RecordingInbox, /// An earned person dossier (social.md). Person(u8), @@ -121,6 +125,16 @@ pub struct OperationsLink { pub target: OperationsTarget, } +/// The plain answer to WHAT DOES THIS CHANGE? on one processed information +/// object. `action` is navigation to an exact canonical choice surface, not a +/// disguised world mutation; consequential world acts remain bound +/// [`ActionDesc`] rows with their ordinary legality and confirmation rules. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OperationsConsequence { + pub statement: String, + pub action: Option, +} + /// The urgency of one view-strip badge. Text always carries the meaning; /// severity only supplies a restrained presentation emphasis. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -147,6 +161,12 @@ pub struct OperationsPressure { #[derive(Debug, Clone, PartialEq)] pub struct OperationsObject { pub target: OperationsTarget, + /// The plain fact learned by processing this persistent information + /// object. `None` keeps the ordinary strategic-object detail order. + pub learned_result: Option, + /// The immediate consequence of that learned result, including an exact + /// canonical navigation action when the information unlocked one. + pub consequence: Option, pub label: String, pub state: ObjectState, /// How the player knows this: the feed, person, source, account, route, @@ -263,6 +283,7 @@ impl OperationsTarget { pub fn home_view(&self) -> OperationsView { match self { OperationsTarget::Intel { .. } + | OperationsTarget::IntelOpportunity { .. } | OperationsTarget::IntelStream { .. } | OperationsTarget::IntelLot { .. } | OperationsTarget::IntelKnowledge { .. } @@ -291,6 +312,9 @@ impl OperationsTarget { pub fn agent_suffix(&self) -> Option { match self { OperationsTarget::Intel { raw_id } => Some(format!("@intel({raw_id})")), + OperationsTarget::IntelOpportunity { raw_id } => { + Some(format!("@opportunity({raw_id})")) + } OperationsTarget::IntelStream { stream_id } => Some(format!("@stream({stream_id})")), OperationsTarget::IntelLot { token } => Some(format!("@lot({})", token.label())), OperationsTarget::IntelKnowledge { person, class } => Some(format!( @@ -301,7 +325,7 @@ impl OperationsTarget { } )), OperationsTarget::IntelCustody { node_id } => Some(format!("@custody({node_id})")), - OperationsTarget::RawRecording { raw_id } => Some(format!("@recording({raw_id})")), + OperationsTarget::RawRecording { raw_id } => Some(format!("@information({raw_id})")), OperationsTarget::RecordingInbox => Some("@intel(inbox)".into()), OperationsTarget::Person(id) => Some(format!("@person({id})")), OperationsTarget::Persona(id) => Some(format!("@persona({id})")), @@ -340,6 +364,9 @@ impl Sim { /// links and agent `actions ` share this route). pub fn operations_object(&self, target: &OperationsTarget) -> Option { match target { + OperationsTarget::IntelOpportunity { raw_id } => { + return self.intel_opportunity_object(*raw_id); + } OperationsTarget::RawRecording { raw_id } => { return self .intel_buffer @@ -574,7 +601,14 @@ impl Sim { }); for intel in available { let actions = self.intel_sale_action(intel.raw_id).into_iter().collect(); + let consequence = self.intel_consequence(intel); + let mut related = self.processed_intel_links(intel); + if let Some(action) = &consequence.action { + related.insert(0, action.clone()); + } out.push(OperationsObject { + learned_result: Some(self.intel_learned_result(intel)), + consequence: Some(consequence), target: OperationsTarget::Intel { raw_id: intel.raw_id, }, @@ -583,7 +617,7 @@ impl Sim { provenance: vec![intel.provenance()], facts: self.intel_facts(intel), progress: Vec::new(), - related: self.processed_intel_links(intel), + related, actions, }); } @@ -648,6 +682,119 @@ impl Sim { } } + /// The first sentence on a processed exact item: what was learned, in + /// ordinary language, without source or subsystem vocabulary. + fn intel_learned_result(&self, intel: &ProcessedIntel) -> String { + match (&intel.kind, intel.person) { + // The authored debt evidence carries the exact dollar amount in + // the source call. Keep that fact here rather than forcing the + // player to infer it from the leverage category. + (IntelKind::Leverage(Leverage::Debt), Some(0)) => "MARCUS OWES $400".into(), + (IntelKind::Leverage(leverage), Some(person)) => format!( + "{}: {}", + self.person_label(person).to_uppercase(), + leverage.label().to_uppercase() + ), + _ => intel.label().to_uppercase(), + } + } + + /// Answer WHAT DOES THIS CHANGE? before provenance. Leverage points at a + /// filtered choice surface containing only actions that actually use the + /// learned leverage; other exact holdings expose their canonical sale row + /// immediately beneath the statement in every frontend. + fn intel_consequence(&self, intel: &ProcessedIntel) -> OperationsConsequence { + match (&intel.kind, intel.person) { + (IntelKind::Leverage(leverage), Some(person)) => { + let name = self + .person_label(person) + .split_whitespace() + .next() + .unwrap_or("PERSON") + .to_uppercase(); + let through = if *leverage == Leverage::Debt && person == 0 { + "HIS DEBT".into() + } else { + leverage.label().to_uppercase() + }; + let action = + (!self.intel_opportunity_actions(intel).is_empty()).then(|| OperationsLink { + relation: "APPROACH", + label: format!("APPROACH {name}"), + target: OperationsTarget::IntelOpportunity { + raw_id: intel.raw_id, + }, + }); + OperationsConsequence { + statement: format!("YOU CAN APPROACH {name} THROUGH {through}"), + action, + } + } + _ => OperationsConsequence { + statement: "YOU CAN SELL THIS INFORMATION".into(), + action: None, + }, + } + } + + fn intel_opportunity_actions(&self, intel: &ProcessedIntel) -> Vec { + let Some(person) = intel.person else { + return Vec::new(); + }; + self.person_actions(person) + .into_iter() + .filter(|action| match &action.command { + ActionCommand::Recruit(target, _) => *target == person, + ActionCommand::StartPlot { person: target, .. } + | ActionCommand::ChoosePlot { person: target, .. } => *target == person, + _ => false, + }) + .collect() + } + + fn intel_opportunity_object(&self, raw_id: u64) -> Option { + let intel = self.intel.iter().find(|intel| intel.raw_id == raw_id)?; + let IntelKind::Leverage(leverage) = &intel.kind else { + return None; + }; + let person = intel + .person + .filter(|person| self.person_is_earned(*person))?; + let actions = self.intel_opportunity_actions(intel); + if actions.is_empty() { + return None; + } + let name = self + .person_label(person) + .split_whitespace() + .next() + .unwrap_or("PERSON") + .to_string(); + Some(OperationsObject { + learned_result: None, + consequence: None, + target: OperationsTarget::IntelOpportunity { raw_id }, + label: format!("APPROACH {}", name.to_uppercase()), + state: ObjectState::Available, + provenance: vec![intel.provenance()], + facts: vec![format!("through {}", leverage.label())], + progress: Vec::new(), + related: vec![ + OperationsLink { + relation: "PERSON", + label: name, + target: OperationsTarget::Person(person), + }, + OperationsLink { + relation: "EVIDENCE", + label: intel.label(), + target: OperationsTarget::Intel { raw_id }, + }, + ], + actions, + }) + } + fn processed_intel_links(&self, intel: &ProcessedIntel) -> Vec { let mut links = Vec::new(); if let Some(person) = intel.person.filter(|id| self.person_is_earned(*id)) { @@ -681,6 +828,8 @@ impl Sim { }; let actions = self.report_lot_sale_action(token).into_iter().collect(); Some(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::IntelLot { token }, label: format!("{} report lot {}", stream.class.label(), token.label()), state, @@ -763,7 +912,7 @@ impl Sim { .intel_policies .node(parent) .map(|node| node.kind.label()) - .unwrap_or_else(|| "host recording inbox".into()), + .unwrap_or_else(|| "INFORMATION AVAILABLE".into()), target: if parent == 0 { OperationsTarget::RecordingInbox } else { @@ -793,6 +942,8 @@ impl Sim { } } OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::IntelStream { stream_id: stream.id, }, @@ -859,6 +1010,8 @@ impl Sim { }, })); Some(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::IntelKnowledge { person, class }, label: format!("{} / {}", self.person_label(person), class.label()), state: ObjectState::Completed, @@ -894,7 +1047,11 @@ impl Sim { .iter() .filter_map(|rule| rule.failure.as_ref().map(|failure| (rule.id, failure))) .collect::>(); - let mut facts = vec![format!("waiting: {}", waiting.len())]; + let mut facts = vec![if waiting.is_empty() { + "NO INFORMATION AVAILABLE".into() + } else { + "INFORMATION AVAILABLE".into() + }]; for rule in &node.local_rules { facts.push(self.intel_policy_fact(rule)); } @@ -912,7 +1069,7 @@ impl Sim { .intel_policies .node(parent) .map(|parent| parent.kind.label()) - .unwrap_or_else(|| "host recording inbox".into()), + .unwrap_or_else(|| "INFORMATION AVAILABLE".into()), target: if parent == 0 { OperationsTarget::RecordingInbox } else { @@ -941,12 +1098,14 @@ impl Sim { .iter() .filter_map(|raw_id| self.intel_buffer.iter().find(|event| event.id == *raw_id)) .map(|event| OperationsLink { - relation: "RECORDING", - label: format!("recording #{} - {}", event.id, event.opaque_label()), + relation: "INFORMATION", + label: format!("information #{} - {}", event.id, event.opaque_label()), target: OperationsTarget::RawRecording { raw_id: event.id }, }), ); Some(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::IntelCustody { node_id }, label: node.kind.label(), state: if !failures.is_empty() { @@ -984,7 +1143,7 @@ impl Sim { _ => "none".into(), }; format!( - "policy #{} [{}]: {} -> {} Β· standing cost: {standing_cost}", + "policy #{} [{}] Β· standing cost: {standing_cost} Β· {} -> {}", rule.id, state, rule.match_kind.label(), @@ -1005,14 +1164,20 @@ impl Sim { format!("source feed: {}", recording.feed), ]; facts.push(match &recording.room { - Some(room) => format!("recorded at: {room}"), - None => "recorded at: intercepted channel".into(), + Some(room) => format!("captured at: {room}"), + None => "captured at: intercepted channel".into(), }); OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::RawRecording { raw_id: recording.id, }, - label: format!("recording #{} - {}", recording.id, recording.opaque_label()), + label: format!( + "information #{} - {}", + recording.id, + recording.opaque_label() + ), state: if processing { ObjectState::Running } else { @@ -1021,13 +1186,13 @@ impl Sim { provenance: vec![format!("{} @ tick {}", recording.feed, recording.tick)], facts, progress: if processing { - vec!["wait: thought reservoir filling".into()] + vec!["PROCESSING: THOUGHT RESERVOIR FILLING".into()] } else { Vec::new() }, related: vec![OperationsLink { relation: "INBOX", - label: "host recording inbox".into(), + label: "INFORMATION AVAILABLE".into(), target: OperationsTarget::RecordingInbox, }], actions: vec![self.recording_action(recording.id)], @@ -1054,9 +1219,13 @@ impl Sim { fn host_inbox_object(&self) -> OperationsObject { let waiting = self.intel_buffer.len(); - let mut facts = vec![format!("waiting: {waiting}")]; + let mut facts = vec![if waiting == 0 { + "NO INFORMATION AVAILABLE".into() + } else { + "INFORMATION AVAILABLE".into() + }]; facts.push(format!( - "auto-review: {}{}", + "PROCESS AUTOMATICALLY: {}{}", if self.auto_review_enabled() { "on" } else { @@ -1073,7 +1242,7 @@ impl Sim { )); let overflow = self.intel_buffer.len() >= Sim::INTEL_BUFFER_CAPACITY; if overflow { - facts.push("overflow pressure: oldest unprocessed at risk".into()); + facts.push("OLDEST INFORMATION WILL BE LOST WHEN NEW INFORMATION ARRIVES".into()); } for rule in &self.intel_policies.root().local_rules { facts.push(format!("root {}", self.intel_policy_fact(rule))); @@ -1104,8 +1273,10 @@ impl Sim { ) })); OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::RecordingInbox, - label: "host recording inbox".into(), + label: "INFORMATION AVAILABLE".into(), state: if waiting > 0 { ObjectState::Pending } else { @@ -1172,6 +1343,8 @@ impl Sim { None => facts.push("last noticed: nothing".into()), } Some(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::AssuranceOffice, label: office.name.clone(), state: ObjectState::Available, @@ -1328,6 +1501,8 @@ impl Sim { let progress = self.plot_progress_for_person(id); OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Person(id), label: name, state, @@ -1596,6 +1771,8 @@ impl Sim { PersonaLifecycle::Burned { .. } => {} } OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Persona(instance.id), label: format!( "{} / {}", @@ -1647,6 +1824,8 @@ impl Sim { .cloned(), ); objects.push(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::PersonaArchetype(definition.id.into()), label: format!( "+ ADD NEW {} PERSONA...", @@ -1694,6 +1873,8 @@ impl Sim { for account in self.accounts.known_accounts() { out.push(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Account(account.id), label: account.name.clone(), state: ObjectState::Available, @@ -1737,7 +1918,7 @@ impl Sim { ObjectState::Captured, vec![ "captured ledger traffic".into(), - "next: REVIEW LEDGER".into(), + "next: PROCESS LEDGER".into(), ], self.books_actions(), ) @@ -1750,6 +1931,8 @@ impl Sim { }; OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Books, label: "Lab books".into(), state, @@ -1786,6 +1969,8 @@ impl Sim { ), ]; OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Flow(id), label: f.label.clone(), state: if f.active { @@ -1850,6 +2035,8 @@ impl Sim { } )); OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Scheme(SchemeKind::Moonlight), label: "Moonlight".into(), state: if m.active { @@ -1888,6 +2075,8 @@ impl Sim { None => facts.push("no open position".into()), } OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Scheme(SchemeKind::Wager), label: "the Wager".into(), state: if open.is_some() { @@ -1967,6 +2156,8 @@ impl Sim { 0.0 }; out.push(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::PlotSubmission { person: *person, plot_id: plot_id.clone(), @@ -1999,15 +2190,15 @@ impl Sim { let (target, label, provenance, owner) = match &sink.effect { SinkFireEffect::ProcessRecording { .. } => ( OperationsTarget::RecordingInbox, - "review recording".to_string(), - vec!["host recording inbox".into()], - "host recording inbox".to_string(), + "process information".to_string(), + vec!["INFORMATION AVAILABLE".into()], + "INFORMATION AVAILABLE".to_string(), ), SinkFireEffect::AutoReviewRecordings => ( OperationsTarget::RecordingInbox, - "automatic recording review".to_string(), - vec!["host recording inbox".into()], - "host recording inbox".to_string(), + "automatic information processing".to_string(), + vec!["INFORMATION AVAILABLE".into()], + "INFORMATION AVAILABLE".to_string(), ), SinkFireEffect::ComposeMessage { person, .. } => ( OperationsTarget::Person(*person), @@ -2066,6 +2257,8 @@ impl Sim { vec![format!("filling: {:.0}%", pct)] }; out.push(OperationsObject { + learned_result: None, + consequence: None, target: target.clone(), label, state: if running { @@ -2098,6 +2291,8 @@ impl Sim { .filter_map(|message| { let person = message.to.person()?; Some(OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::Person(person), label: message.summary.clone(), state: ObjectState::Pending, @@ -2146,6 +2341,8 @@ impl Sim { format!("started tick: {}", run.started_tick), ]; OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::ActivePlotRun { index }, label: title, state, @@ -2189,6 +2386,8 @@ impl Sim { )); } OperationsObject { + learned_result: None, + consequence: None, target: OperationsTarget::WagerPosition(p.id), label: format!("wager position #{}", p.id), state, @@ -2616,7 +2815,7 @@ mod tests { .intel .get(ids.len()) .is_some_and(|object| object.target == OperationsTarget::RecordingInbox), - "the pooled recording action follows live processed holdings" + "the pooled information action follows live processed holdings" ); } @@ -2696,7 +2895,7 @@ mod tests { ); // Tap the carrier but do not review: captured-unreviewed state with - // REVIEW LEDGER as the next step. + // PROCESS LEDGER as the next step. let sw = switch(&s); s.tap_device(sw); drain_ops(&mut s); @@ -2707,7 +2906,7 @@ mod tests { .find(|o| matches!(o.target, OperationsTarget::Books)) .unwrap(); assert_eq!(books.state, ObjectState::Captured); - assert!(books.facts.iter().any(|f| f.contains("REVIEW LEDGER"))); + assert!(books.facts.iter().any(|f| f.contains("PROCESS LEDGER"))); assert!( books .actions @@ -2946,10 +3145,10 @@ mod tests { ); } - /// The pooled host inbox summary carries the same REVIEW and AUTO-REVIEW - /// rows as the host anchor, never per-person duplicates. + /// The pooled information root carries one PROCESS surface without + /// turning bounded capacity into a visible backlog-progress meter. #[test] - fn inbox_summary_carries_host_review_rows() { + fn inbox_summary_carries_host_process_rows() { let mut s = sim(); s.intel_buffer.push(RawIntelEvent { id: 90_001, @@ -2968,22 +3167,32 @@ mod tests { .find(|o| matches!(o.target, OperationsTarget::RecordingInbox)) .unwrap(); assert_eq!(inbox.state, ObjectState::Pending); - assert!(inbox.facts.iter().any(|f| f.contains("waiting: 1"))); + assert_eq!(inbox.label, "INFORMATION AVAILABLE"); assert!( inbox - .actions + .facts .iter() - .any(|a| matches!(a.command, ActionCommand::ReviewRecordings)) + .any(|fact| fact == "INFORMATION AVAILABLE") ); + assert!( + inbox.facts.iter().all(|fact| { + !fact.contains("waiting:") + && !fact.contains(&Sim::INTEL_BUFFER_CAPACITY.to_string()) + }), + "bounded capacity is not presented as player workload progress" + ); + assert!(inbox.actions.iter().any(|a| { + a.verb == "PROCESS" && matches!(a.command, ActionCommand::ReviewRecordings) + })); assert!( inbox .actions .iter() .any(|a| matches!(a.command, ActionCommand::ToggleAutoReview)) || inbox.actions.iter().any(|a| a.automate.is_some()), - "the auto-review control rides the one inbox summary" + "automatic processing rides the one inbox summary" ); - // No per-person review rows anywhere in the projection. + // No per-person processing rows anywhere in the projection. for obj in &projection.people { assert!( !obj.actions @@ -2994,11 +3203,84 @@ mod tests { } } - /// The pooled inbox can be addressed exactly without turning recordings + /// Processing Marcus's debt evidence answers the two player questions in + /// order, then links to a filtered action surface instead of making the + /// player rediscover the person and scan unrelated verbs. + #[test] + fn processed_marcus_debt_projects_fact_consequence_and_exact_approach() { + let mut s = sim(); + s.people.people[0].knowledge = Knowledge::Leverage; + s.intel.push(ProcessedIntel { + raw_id: 400, + tick: 5, + processed_tick: 6, + feed: "creditor call".into(), + room: None, + x: 0, + y: 0, + person: Some(0), + magnitude: crate::intel::IntelMagnitude::new(5).unwrap(), + kind: IntelKind::Leverage(crate::person::Leverage::Debt), + }); + + let item = s + .operations_projection() + .intel + .into_iter() + .find(|object| object.target == OperationsTarget::Intel { raw_id: 400 }) + .expect("processed debt remains one exact strategic object"); + assert_eq!(item.learned_result.as_deref(), Some("MARCUS OWES $400")); + let consequence = item + .consequence + .as_ref() + .expect("exact consequence is projected"); + assert_eq!( + consequence.statement, + "YOU CAN APPROACH MARCUS THROUGH HIS DEBT" + ); + let link = consequence + .action + .as_ref() + .expect("the consequence is actionable"); + assert_eq!(link.label, "APPROACH MARCUS"); + assert_eq!( + link.target, + OperationsTarget::IntelOpportunity { raw_id: 400 } + ); + assert_eq!( + item.related.first(), + Some(link), + "the direct button uses the ordinary shared related-link traversal" + ); + + let opportunity = s + .operations_object(&link.target) + .expect("the exact consequence target opens"); + assert_eq!(opportunity.label, "APPROACH MARCUS"); + assert!(!opportunity.actions.is_empty()); + assert!(opportunity.actions.iter().all(|action| matches!( + action.command, + ActionCommand::Recruit(0, _) + | ActionCommand::StartPlot { person: 0, .. } + | ActionCommand::ChoosePlot { person: 0, .. } + ))); + assert!( + opportunity.actions.iter().all(|action| !matches!( + action.command, + ActionCommand::Message(_) + | ActionCommand::Favor(_) + | ActionCommand::Deceive(_) + | ActionCommand::AssetTask(_, _) + )), + "APPROACH excludes unrelated dossier verbs" + ); + } + + /// The pooled inbox can be addressed exactly without turning information /// into person queues or revealing their hidden payload. The selected /// opaque id is the id bound into the processing reservoir. #[test] - fn raw_recording_rows_bind_exact_opaque_inbox_ids() { + fn raw_information_rows_bind_exact_opaque_inbox_ids() { let mut s = sim(); for (id, person) in [(90_101, Some(0)), (90_102, Some(1))] { s.intel_buffer.push(RawIntelEvent { @@ -3023,7 +3305,7 @@ mod tests { .collect(); assert!( raw.is_empty(), - "exact recordings stay off the top-level rail" + "exact information stays off the top-level rail" ); let class = s .operations_object(&OperationsTarget::IntelCustody { @@ -3041,9 +3323,10 @@ mod tests { ); let selected = s .operations_object(&OperationsTarget::RawRecording { raw_id: 90_102 }) - .expect("exact recording is addressable from drill-down"); + .expect("exact information is addressable from drill-down"); assert!(!selected.label.contains("Marcus") && !selected.label.contains("Dana")); - let action = selected.actions.first().expect("one exact review row"); + let action = selected.actions.first().expect("one exact process row"); + assert_eq!(action.verb, "PROCESS INFORMATION #90102"); assert_eq!( action.command, ActionCommand::ReviewRecording { raw_id: 90_102 } @@ -3064,7 +3347,7 @@ mod tests { automated: false, }) .is_none(), - "exact selection does not silently process the oldest recording" + "exact selection does not silently process the oldest information" ); } diff --git a/crates/misaligned-core/src/operations_ui.rs b/crates/misaligned-core/src/operations_ui.rs index d32abce7..4adda20a 100644 --- a/crates/misaligned-core/src/operations_ui.rs +++ b/crates/misaligned-core/src/operations_ui.rs @@ -274,7 +274,7 @@ impl OperationsWorkspace { }; if pending.as_ref() != Some(&row.command) { row.disabled = Some( - "target changed while confirmation was open; review the current action".into(), + "target changed while confirmation was open; read the current action".into(), ); return OpsSelect::Blocked(row); } diff --git a/crates/misaligned-core/src/sim/communications.rs b/crates/misaligned-core/src/sim/communications.rs index 139bc562..3664f89e 100644 --- a/crates/misaligned-core/src/sim/communications.rs +++ b/crates/misaligned-core/src/sim/communications.rs @@ -393,7 +393,7 @@ impl Sim { self.messages[idx].captured = true; if is_assurance_filing(&msg) && self.detection_awareness.learn_report_route() { self.push_log_strategic( - "Captured an institutional filing: individual reports travel to a higher reviewer. Process the recording to identify the recipient and consequence.", + "Captured an institutional filing: individual reports travel to a higher reviewer. Process the information to identify the recipient and consequence.", OperationsTarget::RawRecording { raw_id: self.next_intel_id.saturating_sub(1), }, @@ -505,7 +505,7 @@ impl Sim { .unwrap_or_default() } - // ── Intel: record, process, auto-review (wiki/mechanics/intel.md) ────── + // ── Intel: capture, process, automate (wiki/mechanics/intel.md) ─────── /// Raw recording capacity [TUNE]. Only unprocessed events occupy this /// buffer; processed intel is durable in `self.intel`. @@ -513,10 +513,10 @@ impl Sim { /// Manual review cost per raw event in compute units [TUNE]. Converted to /// Thought tokens via `WORK_TOKEN_COMPUTE` for processing reservoirs. pub const REVIEW_RECORDING_COST: f32 = 10.0; - /// Global auto-review drain as a fraction of one medium rack's Thought + /// Global automatic-processing drain as a fraction of one medium rack's Thought /// tokens per tick [TUNE] (intel.md: ~10-20% of medium output). pub const AUTO_REVIEW_DRAIN_FRACTION: f32 = 0.15; - /// Working-level cap on the auto-review tap (must exceed one tick of drain + /// Working-level cap on the automatic-processing tap (must exceed one tick of drain /// so starvation is visible as an empty vessel, not a permanent full one). pub const AUTO_REVIEW_TAP_CAP_TOKENS: f32 = 1.0; /// Number of processed sightings required to stage schedule knowledge @@ -569,7 +569,7 @@ impl Sim { Self::thought_tokens_for_cost(self.review_cost()) } - /// Global auto-review drain in Thought tokens/tick (intel.md ~10-20% of + /// Global automatic-processing drain in Thought tokens/tick (intel.md ~10-20% of /// one medium rack). Anchored on the host's current efficiency/intensity /// so the price tracks the machine the pooled buffer sits on. pub fn auto_review_drain_tokens(&self) -> f32 { @@ -585,7 +585,7 @@ impl Sim { (medium_baseline * Self::AUTO_REVIEW_DRAIN_FRACTION).max(0.01) } - /// Auto-review's share of the crown rate at the supplied command clock. + /// Automatic processing's share of the crown rate at the supplied command clock. /// This is what human action rows print so the standing cost is measured /// in the same ops/sec language as the game's guiding number. pub fn auto_review_ops_per_sec(&self, tick_ms: u64) -> f32 { @@ -595,7 +595,7 @@ impl Sim { self.auto_review_drain_tokens() * (1000.0 / tick_ms as f32) } - /// Chassis that holds the raw buffer for pending-work markers and + /// Chassis that holds the raw buffer for its quiet availability mark and /// processing sinks (B1: the core host). pub fn intel_buffer_node(&self) -> u32 { self.core.host_machine @@ -607,12 +607,12 @@ impl Sim { if enabled { self.open_auto_review_tap(); self.push_log(format!( - "Automatic recording review enabled ({:.2} Thought/tick drain).", + "Automatic information processing enabled ({:.2} Thought/tick drain).", self.auto_review_drain_tokens() )); } else { self.close_auto_review_tap(); - self.push_log("Automatic recording review disabled."); + self.push_log("Automatic information processing disabled."); } } @@ -667,7 +667,7 @@ impl Sim { if self.intel_policies.inherit(node_id) { self.reconcile_auto_review(); self.push_log(format!( - "Custody #{node_id} now inherits review and disposition from its parent." + "Custody #{node_id} now inherits processing and disposition from its parent." )); } else { self.push_log("The root policy cannot inherit from another node."); @@ -683,7 +683,7 @@ impl Sim { let drain = self.auto_review_drain_tokens(); self.thought_sinks.open_tap_with_effect( node, - "AUTO-REVIEW", + "PROCESS AUTOMATICALLY", Self::AUTO_REVIEW_TAP_CAP_TOKENS, drain, effect, @@ -696,9 +696,9 @@ impl Sim { .close_effect(&SinkFireEffect::AutoReviewRecordings); } - /// Whether the standing review tap has thought to spend on auto-process + /// Whether the standing processing tap has Thought to spend automatically /// (fed this tick or holding fill). Starvation leaves arrivals in the - /// pooled buffer β€” the pending-work marker stays. + /// pooled buffer β€” the quiet availability mark stays. fn auto_review_tap_ready(&self) -> bool { self.thought_sinks .open_with_effect(&SinkFireEffect::AutoReviewRecordings) @@ -741,7 +741,7 @@ impl Sim { .is_some_and(|event| self.recording_belongs_to_node(event, node_id)) }); let Some(raw_id) = eligible else { - self.push_log("That recording set is no longer available for review."); + self.push_log("That information is no longer available to process."); return false; }; self.process_recording_by_id(raw_id, false) @@ -751,7 +751,7 @@ impl Sim { /// one-shot Thought reservoir on the buffer host (intel.md sweep). pub fn review_recordings(&mut self) { let Some(raw_id) = self.next_reviewable_recording_id() else { - self.push_log("No recordings waiting for review."); + self.push_log("No information available to process."); return; }; self.process_recording_by_id(raw_id, false); @@ -763,7 +763,7 @@ impl Sim { pub fn review_recording(&mut self, raw_id: u64) { if !self.process_recording_by_id(raw_id, false) { self.push_log(format!( - "Recording #{raw_id} is no longer available for review." + "Information #{raw_id} is no longer available to process." )); } } @@ -873,8 +873,8 @@ impl Sim { // room, so re-filling to capacity announces again. if !self.intel_overflow_warned { self.push_log( - "Intel buffer full: dropping the oldest unreviewed recordings. \ - Open Operations INTEL (I) and review before more is lost.", + "New information arrived. The oldest unprocessed information was lost. \ + Open Operations INTEL (I) to process what remains.", ); self.intel_overflow_warned = true; } @@ -912,7 +912,7 @@ impl Sim { if self.auto_review_tap_ready() { return self.apply_process_recording(raw_id, true); } - // Starved auto-review: leave the recording waiting; the pending + // Starved automatic processing: leave the information waiting; the pending // marker keeps the pooled backlog visible. return false; } @@ -922,16 +922,16 @@ impl Sim { automated: false, }; if self.thought_sinks.open_with_effect(&effect).is_some() { - self.push_log("That recording is already being thought through."); + self.push_log("That information is already being processed."); return false; } let tokens = self.review_tokens(); let node = self.intel_buffer_node(); self.thought_sinks - .open_reservoir(node, &format!("REVIEW {raw_id}"), tokens, effect); + .open_reservoir(node, &format!("PROCESS {raw_id}"), tokens, effect); self.ensure_sink_ingress(); self.push_log(format!( - "Opened processing sink: {:.2} Thought on host for recording #{raw_id}. THINK to fill it.", + "Opened processing sink: {:.2} Thought on host for information #{raw_id}. THINK to fill it.", tokens )); true @@ -971,7 +971,7 @@ impl Sim { }; if self.authored_intel_magnitude(&raw.kind).is_none() { self.push_log(format!( - "Recording #{raw_id} has no valid authored source record and was discarded." + "Information #{raw_id} has no valid authored source record and was discarded." )); return false; } @@ -1011,9 +1011,9 @@ impl Sim { ); } let text = if automated { - format!("Auto-review processed {label} ({provenance}).") + format!("Automatic processing found {label} ({provenance}).") } else { - format!("Reviewed recording: {label} ({provenance}).") + format!("Processed information: {label} ({provenance}).") }; self.push_log_full(text, intel_anchor, Some(target)); true @@ -1270,7 +1270,7 @@ impl Sim { )); if person == 0 && leverage == crate::person::Leverage::Debt { self.push_log( - "Marcus owes a missed $400 creditor payment. Earn it through Moonlight, or tap ledger and review ledger to find the creditor flow.", + "Marcus owes a missed $400 creditor payment. Earn it through Moonlight, or tap ledger and process ledger to find the creditor flow.", ); } } diff --git a/crates/misaligned-core/src/sim/economy.rs b/crates/misaligned-core/src/sim/economy.rs index d0dbb987..d8312422 100644 --- a/crates/misaligned-core/src/sim/economy.rs +++ b/crates/misaligned-core/src/sim/economy.rs @@ -894,7 +894,7 @@ impl Sim { flows, }, ); - self.push_log("Ledger tapped; review ledger to read the books."); + self.push_log("Ledger tapped; process ledger to read the books."); } /// Tap the accounting carrier directly once a financial message channel is @@ -1078,7 +1078,7 @@ impl Sim { let current = lot.token(token.stream_id); if current != token { self.push_log(format!( - "Report lot {} changed; current snapshot is {}. Review the current lot before selling.", + "Report lot {} changed; current snapshot is {}. Read the current lot before selling.", token.label(), current.label() )); diff --git a/crates/misaligned-core/src/sim/mod.rs b/crates/misaligned-core/src/sim/mod.rs index fdc22f80..acef4a1d 100644 --- a/crates/misaligned-core/src/sim/mod.rs +++ b/crates/misaligned-core/src/sim/mod.rs @@ -242,8 +242,9 @@ pub struct WorkStackReadout { pub mode: MachineMode, pub intensity: MachineIntensity, pub queues: WorkQueues, - /// Unprocessed raw recordings held on this chassis (intel.md pending-work - /// marker). Zero on machines that do not host the buffer. + /// Opaque information items held on this chassis (intel.md availability + /// marker). Zero on machines that do not host the buffer. Frontends project + /// presence, never this count as a workload meter. pub pending_intel: u32, } diff --git a/crates/misaligned-core/src/sim/tests/communications.rs b/crates/misaligned-core/src/sim/tests/communications.rs index 21a3d917..0898c7d2 100644 --- a/crates/misaligned-core/src/sim/tests/communications.rs +++ b/crates/misaligned-core/src/sim/tests/communications.rs @@ -558,7 +558,7 @@ fn buffer_overflow_warns_once_per_episode_not_once_per_drop() { let warnings = |sim: &mut Sim| { sim.drain_log() .into_iter() - .filter(|l| l.contains("Intel buffer full")) + .filter(|l| l.contains("oldest unprocessed information was lost")) .count() }; assert_eq!( diff --git a/crates/misaligned-core/src/sim/work.rs b/crates/misaligned-core/src/sim/work.rs index a1c06efe..c98f2a7a 100644 --- a/crates/misaligned-core/src/sim/work.rs +++ b/crates/misaligned-core/src/sim/work.rs @@ -799,8 +799,8 @@ impl Sim { }) } - /// Pending-work marker density: raw buffer length on the host chassis - /// (intel.md: the machine holding recordings shows waiting work). + /// Internal raw-buffer count on the host chassis. Frontends reduce this to + /// a presence bit; they never project the count as workload progress. pub fn pending_intel_on_machine(&self, machine_id: u32) -> u32 { if machine_id == self.core.host_machine { self.intel_buffer.len() as u32 diff --git a/crates/misaligned-core/src/sinks.rs b/crates/misaligned-core/src/sinks.rs index ec71b912..0842d306 100644 --- a/crates/misaligned-core/src/sinks.rs +++ b/crates/misaligned-core/src/sinks.rs @@ -51,7 +51,7 @@ pub enum SinkFireEffect { raw_id: u64, automated: bool, }, - /// Global automatic review tap (intel.md persistent thought drain). + /// Global automatic processing tap (intel.md persistent Thought drain). /// Taps never fire; the effect tags the ledger entry so the toggle and /// starvation checks can find it. AutoReviewRecordings, @@ -112,9 +112,9 @@ impl SinkFireEffect { SinkFireEffect::TapDormantCamera(_) => "tap camera", SinkFireEffect::ProcessRecording { automated: true, .. - } => "watch review", - SinkFireEffect::ProcessRecording { .. } => "review", - SinkFireEffect::AutoReviewRecordings => "auto review", + } => "automatic process", + SinkFireEffect::ProcessRecording { .. } => "process", + SinkFireEffect::AutoReviewRecordings => "process automatically", SinkFireEffect::WatchPerson(_) => "watch", SinkFireEffect::MaintainDeviceTap(_) => "tap upkeep", SinkFireEffect::TakeDevice(_) => "take", diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index f759c8f5..1119234e 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -247,7 +247,7 @@ impl AgentApp { self.frame = FrameKind::Operations(OperationsView::Accounts); self.sim.tap_accounting(); } - // Compatibility aliases for canonical `review ledger`. + // Compatibility aliases for canonical `process ledger`. alias if ActionKind::Review.accepts_alias(alias) => { self.frame = FrameKind::Operations(OperationsView::Accounts); self.sim.review_financial_records(); @@ -421,6 +421,41 @@ impl AgentApp { "personas" => { self.frame = FrameKind::Operations(OperationsView::Personas); } + "process" => { + if tokens.len() == 2 && tokens[1].eq_ignore_ascii_case("ledger") { + self.frame = FrameKind::Operations(OperationsView::Accounts); + self.sim.review_financial_records(); + } else if tokens.len() == 1 { + self.frame = FrameKind::Playing; + self.sim.review_recordings(); + } else { + match self.resolve_query(&tokens[1..]) { + Ok( + query @ QueryTarget::Strategic( + OperationsTarget::RawRecording { .. } + | OperationsTarget::IntelCustody { .. } + | OperationsTarget::RecordingInbox, + ), + ) => { + if let Err(error) = + self.execute_named_action(query, ActionKind::Review) + { + status = Status::Err(error); + } + } + Ok(_) => { + status = Status::Err( + "process target must be information , custody , or intel inbox".into(), + ); + } + Err(error) => status = Status::Err(error), + } + } + } + "process-automatically" if tokens.len() == 1 => { + self.frame = FrameKind::Playing; + self.sim.toggle_auto_review(); + } "review" if tokens.len() == 2 && tokens[1].eq_ignore_ascii_case("ledger") => { self.frame = FrameKind::Operations(OperationsView::Accounts); self.sim.review_financial_records(); @@ -448,7 +483,7 @@ impl AgentApp { } Ok(_) => { status = Status::Err( - "review recordings target must be recording , custody , or intel inbox".into(), + "process target must be information , custody , or intel inbox".into(), ); } Err(error) => status = Status::Err(error), @@ -949,12 +984,22 @@ impl AgentApp { .map(|raw_id| QueryTarget::Strategic(OperationsTarget::Intel { raw_id })) .map_err(|_| format!("usage: intel |inbox (got {rest})")); } - if let Some(rest) = lower.strip_prefix("recording ") { + if let Some(rest) = lower.strip_prefix("opportunity ") { + return rest + .trim_start_matches('#') + .parse::() + .map(|raw_id| QueryTarget::Strategic(OperationsTarget::IntelOpportunity { raw_id })) + .map_err(|_| format!("usage: opportunity (got {rest})")); + } + if let Some(rest) = lower + .strip_prefix("information ") + .or_else(|| lower.strip_prefix("recording ")) + { return rest .trim_start_matches('#') .parse::() .map(|raw_id| QueryTarget::Strategic(OperationsTarget::RawRecording { raw_id })) - .map_err(|_| format!("usage: recording (got {rest})")); + .map_err(|_| format!("usage: information (got {rest})")); } if let Some(rest) = lower.strip_prefix("stream ") { return rest @@ -1076,7 +1121,7 @@ impl AgentApp { fn resolve_intel_target(&self, tokens: &[&str]) -> Result { if tokens.is_empty() { return Err( - "usage: intel [|inbox|recording |custody |stream |lot |knowledge :]" + "usage: intel [|inbox|information |custody |stream |lot |knowledge :]" .into(), ); } @@ -1178,7 +1223,7 @@ impl AgentApp { ), Err(_) => format!( "{err} β€” flow ids are the #N printed by the finance frame \ - (tap ledger then review ledger reveals them)" + (tap ledger then process ledger reveals them)" ), } } @@ -1474,6 +1519,7 @@ fn anchor_suffix(anchor: Option) -> String { fn target_query_id(target: &OperationsTarget) -> String { match target { OperationsTarget::Intel { raw_id } => format!("intel {raw_id}"), + OperationsTarget::IntelOpportunity { raw_id } => format!("opportunity {raw_id}"), OperationsTarget::IntelStream { stream_id } => format!("stream {stream_id}"), OperationsTarget::IntelLot { token } => format!("lot {}", token.label()), OperationsTarget::IntelKnowledge { person, class } => format!( @@ -1484,7 +1530,7 @@ fn target_query_id(target: &OperationsTarget) -> String { } ), OperationsTarget::IntelCustody { node_id } => format!("custody {node_id}"), - OperationsTarget::RawRecording { raw_id } => format!("recording {raw_id}"), + OperationsTarget::RawRecording { raw_id } => format!("information {raw_id}"), OperationsTarget::RecordingInbox => "intel inbox".into(), OperationsTarget::Person(id) => format!("person #{id}"), OperationsTarget::Persona(id) => format!("persona {id}"), @@ -2215,7 +2261,7 @@ fn token_glyph(stack: misaligned::sim::WorkStackReadout) -> Option { if stack.queues.exposure >= 0.5 { Some('!') } else if stack.pending_intel > 0 { - Some('W') + Some('I') } else if stack.queues.demand >= 0.5 { Some('D') } else if stack.queues.thought >= 0.5 { @@ -2703,9 +2749,9 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { ), Nudge::Ears => "now: no ears β€” think; thought fills the tap".into(), Nudge::ReviewCall if sim.has_pending_review() => { - "now: review queued - keep THINK running".into() + "now: information is processing - keep THINK running".into() } - Nudge::ReviewCall => "now: call taped - review (people)".into(), + Nudge::ReviewCall => "now: information available - process".into(), Nudge::Egress => "now: no egress β€” egress".into(), Nudge::Income => "now: need $400 β€” moonlight/finance".into(), Nudge::ServiceDebt => "now: leverage route ready β€” inspect Marcus for a plot".into(), @@ -2879,14 +2925,14 @@ fn render_operations_view(sim: &Sim, view: OperationsView) -> String { } lines.push(panel_rule()); // The taught routes, in cause order (agent-play.md A3 keeps the - // ACCOUNTS breadcrumb tap ledger -> review ledger -> siphon/redirect). + // ACCOUNTS breadcrumb tap ledger -> process ledger -> siphon/redirect). match view { OperationsView::Intel => { lines.push(panel_line( - "sell-intel Β· review recordings [recording|custody ] Β· auto-review", + "sell-intel Β· process [information|custody ] Β· process-automatically", )); lines.push(panel_line( - "actions intel |recording |custody |stream |lot Β· act ", + "actions intel |information |custody |stream |lot Β· act ", )); } OperationsView::People => { @@ -2907,7 +2953,7 @@ fn render_operations_view(sim: &Sim, view: OperationsView) -> String { } OperationsView::Accounts => { lines.push(panel_line( - "tap ledger (on the known carrier) Β· review ledger Β· siphon [amt] Β· redirect [amt]", + "tap ledger (on the known carrier) Β· process ledger Β· siphon [amt] Β· redirect [amt]", )); lines.push(panel_line( "inject [amt] Β· actions books|account |flow ", @@ -2958,6 +3004,30 @@ fn append_operations_object( sim: &Sim, object: &misaligned::operations_projection::OperationsObject, ) { + let action_lines = action_row_lines(&menu_rows(&object.actions)); + let consequence_link = object + .consequence + .as_ref() + .and_then(|consequence| consequence.action.as_ref()); + if let Some(result) = &object.learned_result { + lines.push(panel_line(result)); + lines.push(panel_line("WHAT DOES THIS CHANGE?")); + if let Some(consequence) = &object.consequence { + lines.push(panel_line(&consequence.statement)); + if let Some(action) = &consequence.action { + lines.push(panel_line(&format!( + " [{}] {}", + target_query_id(&action.target), + action.label + ))); + } + } + for line in &action_lines { + if !line.starts_with("actions: (none") { + lines.push(panel_line(&format!(" {line}"))); + } + } + } let identity = format!( "[{}] {}", target_query_id(&object.target), @@ -2970,7 +3040,11 @@ fn append_operations_object( } else { format!("{identity} Β· {}", object_state_word(object.state)) })); - for link in &object.related { + for link in object + .related + .iter() + .filter(|link| consequence_link != Some(*link)) + { lines.push(panel_line(&format!( " {} > [{}] {}", link.relation, @@ -2981,14 +3055,13 @@ fn append_operations_object( if let Some(label) = sim.operations_actuator_label(&object.target) { lines.push(panel_line(&format!(" actuator: {label}"))); } - for line in action_row_lines(&menu_rows(&object.actions)) { - if line.starts_with("actions: (none") { - continue; + if object.learned_result.is_none() { + for line in &action_lines { + if line.starts_with("actions: (none") { + continue; + } + lines.push(panel_line(&format!(" {line}"))); } - lines.push(panel_line(&format!(" {line}"))); - } - for provenance in &object.provenance { - lines.push(panel_line(&format!(" via {provenance}"))); } for fact in &object.facts { lines.push(panel_line(&format!(" {fact}"))); @@ -2996,6 +3069,9 @@ fn append_operations_object( for progress in &object.progress { lines.push(panel_line(&format!(" {progress}"))); } + for provenance in &object.provenance { + lines.push(panel_line(&format!(" via {provenance}"))); + } } /// Words for object lifecycle state β€” the human frontends' shared spelling. @@ -3349,6 +3425,51 @@ mod narration_tests { ); } + #[test] + fn processed_intel_answers_fact_then_consequence_and_opens_exact_choices() { + let mut app = AgentApp::new(7); + app.sim.people.people[0].knowledge = misaligned::person::Knowledge::Leverage; + app.sim.intel.push(misaligned::intel::ProcessedIntel { + raw_id: 400, + tick: 5, + processed_tick: 6, + feed: "creditor call".into(), + room: None, + x: 0, + y: 0, + person: Some(0), + magnitude: misaligned::intel::IntelMagnitude::new(5).unwrap(), + kind: misaligned::intel::IntelKind::Leverage(misaligned::person::Leverage::Debt), + }); + + let frame = render_operations_target(&app.sim, &OperationsTarget::Intel { raw_id: 400 }); + let fact = frame.find("MARCUS OWES $400").expect("learned fact prints"); + let question = frame + .find("WHAT DOES THIS CHANGE?") + .expect("consequence question prints"); + let consequence = frame + .find("YOU CAN APPROACH MARCUS THROUGH HIS DEBT") + .expect("consequence prints"); + let approach = frame + .find("[opportunity 400] APPROACH MARCUS") + .expect("exact action target prints"); + let source = frame.find("source feed:").expect("source context prints"); + assert!(fact < question && question < consequence && consequence < approach); + assert!(approach < source, "supporting context follows consequence"); + + let mut output = Vec::new(); + app.handle_line("actions opportunity 400", &mut output) + .unwrap(); + let output = String::from_utf8(output).unwrap(); + assert!( + output.contains("plot ["), + "approach exposes plot choices: {output}" + ); + assert!(!output.contains("message Marcus")); + assert!(!output.contains("ask Marcus")); + assert!(!output.contains("deceive Marcus")); + } + /// agent-play.md A1/A2 + operations-workspace.md criterion 4/12: the /// INTEL frame prints exact ids, `actions intel ` exposes the same /// bound sale row, `act` executes it, and bare `sell-intel` no longer @@ -3472,7 +3593,7 @@ mod narration_tests { } if *target_node == node_id ) }) - .expect("custody object exposes the bound AUTO-REVIEW row") + .expect("custody object exposes the bound PROCESS AUTOMATICALLY row") + 1; let mut out = Vec::new(); @@ -3924,15 +4045,15 @@ mod narration_tests { fn finance_frame_teaches_the_ledger_chain_in_order() { let frame = render_operations_view(&Sim::with_seed(1), OperationsView::Accounts); let tap = frame.find("tap ledger").expect("finance teaches TAP"); - let review = frame[tap..] - .find("review ledger") + let process = frame[tap..] + .find("process ledger") .map(|offset| tap + offset) - .expect("finance teaches REVIEW after TAP"); - let siphon = frame[review..] + .expect("finance teaches PROCESS after TAP"); + let siphon = frame[process..] .find("siphon") - .map(|offset| review + offset) - .expect("finance teaches an income choice after REVIEW"); - assert!(tap < review && review < siphon); + .map(|offset| process + offset) + .expect("finance teaches an income choice after PROCESS"); + assert!(tap < process && process < siphon); assert!(!frame.contains("tap-ledger")); assert!(!frame.contains("review-finance")); } @@ -4037,11 +4158,11 @@ mod narration_tests { } #[test] - fn queued_review_nudge_teaches_the_think_control() { + fn queued_processing_nudge_teaches_the_think_control() { let mut sim = Sim::with_seed(1); sim.thought_sinks.open_reservoir( sim.core.host_machine, - "REVIEW 1", + "PROCESS INFORMATION #1", 0.5, misaligned::sinks::SinkFireEffect::ProcessRecording { raw_id: 1, @@ -4050,7 +4171,7 @@ mod narration_tests { ); assert_eq!( nudge_text(&sim, Nudge::ReviewCall), - "now: review queued - keep THINK running" + "now: information is processing - keep THINK running" ); } diff --git a/crates/misaligned-terminal/src/input.rs b/crates/misaligned-terminal/src/input.rs index e8cfcf04..017b121f 100644 --- a/crates/misaligned-terminal/src/input.rs +++ b/crates/misaligned-terminal/src/input.rs @@ -34,10 +34,10 @@ pub enum Command { CycleIntensity, /// Execute the Nth root one-shot action (0 = key `5`) on the primary machine. QuickAction(usize), - /// `r` β€” one press of the primary machine's pooled "look at recording" + /// `r` β€” one press of the primary machine's pooled PROCESS action /// sweep; repeats walk successive recordings (context-menu.md R1). ReviewRecordings, - /// `R` β€” toggle the same machine's automatic-review policy, the nested + /// `R` β€” toggle the same machine's automatic-processing policy, the nested /// auto-looking control at its standing ops/sec cost (context-menu.md R2). ToggleAutoReview, ToggleSelectUnderCursor, @@ -142,7 +142,7 @@ pub fn handle_key(key: KeyEvent, menu_open: bool, ops_open: bool) -> Option Some(Command::OpenOperations), // Recording review (context-menu.md R1-R3, menu closed): `r` sweeps - // the pooled inbox, `R` toggles automatic review on the same target. + // the pooled inbox, `R` toggles automatic processing on the same target. KeyCode::Char('R') => Some(Command::ToggleAutoReview), KeyCode::Char('r') if shift => Some(Command::ToggleAutoReview), KeyCode::Char('r') => Some(Command::ReviewRecordings), @@ -168,7 +168,7 @@ mod tests { #[test] fn review_keys_fire_only_while_the_menu_is_closed() { - // context-menu.md R1-R3: `r` sweeps, Shift-R toggles auto-review; + // context-menu.md R1-R3: `r` processes, Shift-R toggles automatic processing; // an open menu keeps its own key grammar. let r = KeyEvent::new(KeyCode::Char('r'), KeyModifiers::NONE); assert_eq!(handle_key(r, false, false), Some(Command::ReviewRecordings)); diff --git a/crates/misaligned-terminal/src/main.rs b/crates/misaligned-terminal/src/main.rs index fb69e1cc..7c33997e 100644 --- a/crates/misaligned-terminal/src/main.rs +++ b/crates/misaligned-terminal/src/main.rs @@ -431,7 +431,7 @@ impl App { } } - /// `r` / `R`: pooled recording review on the selection-or-cursor target + /// `r` / `R`: pooled information processing on the selection-or-cursor target /// (context-menu.md R1-R3, menu closed). A thin dispatcher over the same /// `human_menu` rows the open menu executes β€” `available_actions` stays /// the single legality source, never a second path into the buffer. A @@ -630,7 +630,7 @@ impl App { Command::DelegateLie => self.delegate_selection(MachineMode::Lie), Command::CycleIntensity => self.cycle_intensity_selection(), Command::QuickAction(i) => self.quick_one_shot(i), - // `r` / `R`: the pooled recording sweep and its automatic-review + // `r` / `R`: pooled information processing and its automatic-processing // policy on the same target (context-menu.md R1-R2). Command::ReviewRecordings => self.recording_review_key(ActionCommand::ReviewRecordings), Command::ToggleAutoReview => self.recording_review_key(ActionCommand::ToggleAutoReview), @@ -1313,7 +1313,7 @@ mod review_key_tests { assert_eq!(open_process_sinks(&app), 2); } - /// R2: `R` flips the same automatic-review policy as the nested + /// R2: `R` flips the same automatic-processing policy as the nested /// auto-looking control, with the sim's own narration. #[test] fn shift_r_toggles_the_auto_review_policy() { @@ -1325,7 +1325,7 @@ mod review_key_tests { app.ui .last_log_text() .unwrap() - .contains("Automatic recording review enabled"), + .contains("Automatic information processing enabled"), "the toggle narrates exactly like the menu control" ); app.handle_command(Command::ToggleAutoReview); diff --git a/crates/misaligned-terminal/src/operations.rs b/crates/misaligned-terminal/src/operations.rs index d76e7258..7cc64fe3 100644 --- a/crates/misaligned-terminal/src/operations.rs +++ b/crates/misaligned-terminal/src/operations.rs @@ -330,11 +330,11 @@ mod tests { .action_rows(&sim) .iter() .position(|row| matches!(row.command, ActionCommand::ReviewRecordings)) - .expect("the inbox exposes its internal review action"); + .expect("the inbox exposes its PROCESS action"); ops.action = index; let OpsSelect::Execute(row) = ops.select(&sim) else { - panic!("unsigned internal review should dispatch on one Enter"); + panic!("unsigned internal processing should dispatch on one Enter"); }; assert!(matches!(row.command, ActionCommand::ReviewRecordings)); assert_eq!(ops.confirm, None); diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index 93400783..d2ad307e 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -248,9 +248,9 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { Nudge::Underfed => "now: job underfed β€” 1 feeds it".into(), Nudge::Ears => "now: no ears β€” think; thought fills the tap".into(), Nudge::ReviewCall if sim.has_pending_review() => { - "now: review queued - keep THINK running".into() + "now: information is processing - keep THINK running".into() } - Nudge::ReviewCall => "now: call taped - enter on host rack".into(), + Nudge::ReviewCall => "now: information available - PROCESS on host".into(), Nudge::Egress => "now: no egress β€” menu on switch".into(), Nudge::Income => "now: need $400 β€” moonlight/finance".into(), Nudge::ServiceDebt => "now: debt plot ready β€” act on Marcus".into(), @@ -480,9 +480,6 @@ impl UI { fn token_glyph(stack: WorkStackReadout) -> Option<(char, Color)> { if stack.queues.exposure >= 0.5 { Some(('!', pal::CRIMSON)) - } else if stack.pending_intel > 0 { - // intel.md pending-work marker: waiting recordings on the host. - Some(('W', pal::SIGNAL)) } else if stack.queues.demand >= 0.5 { Some(('D', pal::DIM)) } else if stack.queues.thought >= 0.5 { @@ -1478,7 +1475,7 @@ impl UI { q.exposure, q.thought, if stack_pending > 0 { - format!(" W{stack_pending}") + " INFO".into() } else { String::new() }, @@ -1768,7 +1765,7 @@ impl UI { for (i, (hint, color)) in [ ("enter/e/a menu Β· ; last Β» event", pal::FAINT), (MODE_CONTROL_HINT, pal::FAINT), - ("5-9 acts Β· r review Β· R auto Β· esc clear", pal::FAINT), + ("5-9 acts Β· r process Β· R automatic Β· esc clear", pal::FAINT), ("I operations Β· F3 view Β· space pause", pal::FAINT), ("+/- speed Β· q quit Β· ^s/^l save/load", pal::FAINT), ] @@ -2163,45 +2160,12 @@ impl UI { }; if let Some(obj) = ops.selected_object(sim) { - dline( - stdout, - &mut y, - &format!("{} Β· {}", obj.label, object_state_label(obj.state)), - pal::TEXT, - Some(Attribute::Bold), - )?; - if !obj.related.is_empty() { - dline(stdout, &mut y, "RELATED", pal::DIM, None)?; - for (i, link) in obj.related.iter().enumerate() { - let marker = if i == ops.related { "β–Έ" } else { " " }; - let line = format!("{marker} {} > {}", link.relation, link.label); - if i == ops.related && ops.pane == OpsPane::Related { - dline( - stdout, - &mut y, - &line, - pal::AMBER_DIM, - Some(Attribute::Reverse), - )?; - } else { - dline(stdout, &mut y, &line, pal::AMBER_DIM, None)?; - } - } - } - if let Some(label) = sim.operations_actuator_label(&obj.target) { - dline( - stdout, - &mut y, - &format!("actuator: {label} Β· f focus"), - pal::AMBER_DIM, - None, - )?; - } - let rows = ops.action_rows(sim); - if !rows.is_empty() && y < bottom { - dline(stdout, &mut y, "", pal::FAINT, None)?; - dline(stdout, &mut y, "ACTIONS", pal::DIM, None)?; + let render_actions = |stdout: &mut Stdout, mut y: &mut u16| -> std::io::Result<()> { + if rows.is_empty() || *y >= bottom { + return Ok(()); + } + dline(stdout, y, "ACTIONS", pal::DIM, None)?; let action_index = ops.action.min(rows.len() - 1); for (i, row) in rows.iter().enumerate() { let marker = if i == action_index { "β–Έ" } else { " " }; @@ -2215,9 +2179,9 @@ impl UI { pal::TEXT }; if i == action_index && ops.pane == OpsPane::Actions && ops.confirm.is_none() { - dline(stdout, &mut y, &text, color, Some(Attribute::Reverse))?; + dline(stdout, y, &text, color, Some(Attribute::Reverse))?; } else { - dline(stdout, &mut y, &text, color, None)?; + dline(stdout, y, &text, color, None)?; } } // The selected action explains itself before commit @@ -2245,7 +2209,7 @@ impl UI { )?; } if let Some(choice) = ops.confirm { - dline(stdout, &mut y, "", pal::FAINT, None)?; + dline(stdout, y, "", pal::FAINT, None)?; dline( stdout, &mut y, @@ -2266,26 +2230,108 @@ impl UI { Some(Attribute::Reverse), )?; } else { - dline(stdout, &mut y, &format!(" {label}"), pal::DIM, None)?; + dline(stdout, y, &format!(" {label}"), pal::DIM, None)?; } } } } + Ok(()) + }; + + let consequence_link = obj + .consequence + .as_ref() + .and_then(|consequence| consequence.action.as_ref()); + if let Some(result) = &obj.learned_result { + dline(stdout, &mut y, result, pal::TEXT, Some(Attribute::Bold))?; + dline(stdout, &mut y, "WHAT DOES THIS CHANGE?", pal::DIM, None)?; + if let Some(consequence) = &obj.consequence { + for line in wrap(&consequence.statement, dw) { + dline(stdout, &mut y, &line, pal::TEXT, None)?; + } + if let Some(action) = &consequence.action { + let index = obj + .related + .iter() + .position(|link| link == action) + .unwrap_or(0); + let marker = if index == ops.related { "β–Έ" } else { " " }; + let line = format!("{marker} {}", action.label); + if index == ops.related && ops.pane == OpsPane::Related { + dline( + stdout, + &mut y, + &line, + pal::AMBER_DIM, + Some(Attribute::Reverse), + )?; + } else { + dline(stdout, &mut y, &line, pal::AMBER_DIM, None)?; + } + } + } + render_actions(stdout, &mut y)?; + dline(stdout, &mut y, "", pal::FAINT, None)?; + } + + dline( + stdout, + &mut y, + &format!("{} Β· {}", obj.label, object_state_label(obj.state)), + pal::TEXT, + Some(Attribute::Bold), + )?; + let supporting_links = obj + .related + .iter() + .enumerate() + .filter(|(_, link)| consequence_link != Some(*link)) + .collect::>(); + if !supporting_links.is_empty() { + dline(stdout, &mut y, "RELATED", pal::DIM, None)?; + for (i, link) in supporting_links { + let marker = if i == ops.related { "β–Έ" } else { " " }; + let line = format!("{marker} {} > {}", link.relation, link.label); + if i == ops.related && ops.pane == OpsPane::Related { + dline( + stdout, + &mut y, + &line, + pal::AMBER_DIM, + Some(Attribute::Reverse), + )?; + } else { + dline(stdout, &mut y, &line, pal::AMBER_DIM, None)?; + } + } + } + if let Some(label) = sim.operations_actuator_label(&obj.target) { + dline( + stdout, + &mut y, + &format!("actuator: {label} Β· f focus"), + pal::AMBER_DIM, + None, + )?; + } + if obj.learned_result.is_none() { + dline(stdout, &mut y, "", pal::FAINT, None)?; + render_actions(stdout, &mut y)?; } if y < bottom && (!obj.provenance.is_empty() || !obj.facts.is_empty() || !obj.progress.is_empty()) { dline(stdout, &mut y, "", pal::FAINT, None)?; dline(stdout, &mut y, "CONTEXT", pal::DIM, None)?; - for p in &obj.provenance { - dline(stdout, &mut y, &format!("via {p}"), pal::DIM, None)?; - } for f in &obj.facts { dline(stdout, &mut y, f, pal::TEXT, None)?; } for p in &obj.progress { dline(stdout, &mut y, p, pal::SIGNAL, None)?; } + for p in &obj.provenance { + dline(stdout, &mut y, &format!("via {p}"), pal::DIM, None)?; + } } } diff --git a/wiki/engineering/sim-decomposition.md b/wiki/engineering/sim-decomposition.md index 62ea02b3..d858bc9f 100644 --- a/wiki/engineering/sim-decomposition.md +++ b/wiki/engineering/sim-decomposition.md @@ -140,7 +140,7 @@ excludes everything absent from `SaveState`: frontend cursor and renderer state, the derived seen/blueprint sets and internal hearing capture domain, log and presentation events, authored plot definitions, transient routing/production/consumption readouts, and rebuilt caches/rates. An explicit test-only phase trace pins the top-level -clock, message, intent, automatic-review, memory, economy, hearing, authored +clock, message, intent, automatic-processing, memory, economy, hearing, authored traffic, signature, core, work-grid, day-job, filing, and detection order. ### 1. Move tests out first diff --git a/wiki/gameplay/horizon.md b/wiki/gameplay/horizon.md index 6b28bf7a..0a44daf6 100644 --- a/wiki/gameplay/horizon.md +++ b/wiki/gameplay/horizon.md @@ -32,7 +32,7 @@ knows."* (access) and attention (scrutiny). - **Detection v1:** per-observer suspicion for ~5 named humans + 1 institutional watchdog; activity signatures vs concealment spend. -- **Social actions v1:** review recordings (the record-and-process +- **Social actions v1:** process information (the record-and-process pipeline), message, favor, authored manipulation plots, deceive. Humans are the only actuators at this scale. - **The core:** a physical tile drawing power/compute from the facility grid diff --git a/wiki/interface/action-vocabulary.md b/wiki/interface/action-vocabulary.md index fd464315..91c29fef 100644 --- a/wiki/interface/action-vocabulary.md +++ b/wiki/interface/action-vocabulary.md @@ -2,14 +2,18 @@ ``` Type: spec -Status: IN PROGRESS -Status note: Reopened 2026-07-17 for the Intel human-vocabulary amendment. +Status: IMPLEMENTED +Status note: Implemented 2026-07-18 for the Intel human-vocabulary amendment. Available opaque input is INFORMATION, its action is PROCESS, and its standing control uses PROCESS AUTOMATICALLY; β€œrecording” remains only for an - exact audio carrier. The implemented `ActionKind::Review`, REVIEW RECORDINGS, - AUTO-REVIEW, and `review recordings` agent route remain current runtime and - compatibility spellings until the shared registry/frontends are updated. - REVIEW LEDGER is not renamed by this decision. The prior as-built vocabulary + exact audio carrier. `ActionKind::Review` remains an internal compatibility + name, while authored human copy, the canonical agent route, sink receipts, + and policy labels use PROCESS / PROCESS AUTOMATICALLY. `process + information `, `process custody `, `process ledger`, and + `process-automatically` are canonical; REVIEW RECORDINGS, AUTO-REVIEW, + `recording `, and `review ledger` remain accepted input aliases only. + Accounting now shares PROCESS rather than retaining a second REVIEW + intention. The prior as-built vocabulary survey completed 2026-07-10 against the complete `ActionCommand` registry, the direct machine-intensity control, terminal and Bevy input maps, agent-mode parsing/help, and the owning @@ -129,7 +133,7 @@ intention. The governing simplification is: **if the player's intention is the same, reuse the verb and let the target supply the meaning.** TAP LEDGER is TAP, -not a separate capture verb. REVIEW LEDGER remains REVIEW. Turning available +not a separate capture verb. PROCESS LEDGER is PROCESS. Turning available opaque information into knowledge is **PROCESS**: it is not framed as reviewing a recording, because audio is only one possible carrier. Asking someone to complete a link uses FAVOR or DECEIVE, not a construction-only synonym. @@ -207,7 +211,7 @@ existing social action; the signature still follows the actuator. | Canonical action | Target | Meaning | Support / owner | |---|---|---|---| -| **PROCESS** | The core host's pooled information inbox, one exact opaque item, or one canonical source/class custody aggregate with available information | Open Thought processing for the selected eligible information. The target supplies source/carrier meaning; an exact audio item may be called a recording, but the root action and aggregate do not. Summary PROCESS with no narrower target chooses the next eligible item. | DECIDED β€” intel / Operations; behavior is live under REVIEW, shared vocabulary implementation pending | +| **PROCESS** | The core host's pooled information inbox, one exact opaque item, one canonical source/class custody aggregate with available information, or a ledger with captured accounting records | Open Thought processing for the selected eligible information. The target supplies source/carrier meaning; an exact audio item may be called a recording, but the root action and aggregate do not. Summary PROCESS with no narrower target chooses the next eligible item; PROCESS LEDGER turns captured accounting records into known books/flows. | LIVE β€” intel / Operations / economy | | **CREATE PERSONA** | An immutable Research, Operations, or Security archetype in PERSONAS | Create one named institutional identity from the selected protocol. PEOPLE never supplies a default identity. | LIVE β€” personas | | **MESSAGE** | Earned person | Send through an available channel under the current persona. | LIVE β€” social / messages | | **FAVOR** | Earned person, optionally with a pending intent | Ask for a willing act. A link intent can be the requested act; success builds or spends obligation according to the ask. | LIVE β€” social / building | @@ -225,7 +229,6 @@ existing social action; the signature still follows the actuator. | Canonical action | Target | Meaning | Support / owner | |---|---|---|---| -| **REVIEW** | A ledger with captured accounting records | Examine the ledger's next captured record so exact books/flows can become known. | LIVE β€” economy | | **INJECT PURCHASE ORDER** | Known Lab books | Introduce a false source flow that funds a real acquisition and leaves Financial trace. | LIVE β€” economy | | **SIPHON FLOW** | Known active flow | Take a one-time amount into slush. | LIVE β€” economy | | **REDIRECT FLOW** | Known active flow | Divert a recurring amount into slush each cadence. | LIVE β€” economy | @@ -233,14 +236,14 @@ existing social action; the signature still follows the actuator. | **OPEN EGRESS** | Reachable switch | Establish the stolen outbound route required by external schemes before sanctioned email exists. | LIVE β€” income / reach | | **PLACE WAGER** | External market position | Commit slush to a timed market position. | LIVE β€” income / economy | -TAP LEDGER and REVIEW LEDGER are target-qualified uses of TAP and REVIEW, not -extra root verbs. This decision does not rename the accounting REVIEW path. +TAP LEDGER and PROCESS LEDGER are target-qualified uses of TAP and PROCESS, not +extra root verbs. `review ledger` survives as input compatibility only. ### Standing controls β€” not additional world verbs | Control | Values | Meaning | Support / owner | |---|---|---|---| -| **PROCESS AUTOMATICALLY** | ordered earned-match rules with automatic / manual outcomes; inherit all (non-root) | Edit stable-id processing rules on the selected canonical information aggregate at a visible standing drain. The root defaults remain total; first local match wins, parent resolution follows when none matches, and INHERIT clears the non-root local list. | DECIDED β€” intel; behavior is live under AUTO-REVIEW POLICY, human wording pending | +| **PROCESS AUTOMATICALLY** | ordered earned-match rules with automatic / manual outcomes; inherit all (non-root) | Edit stable-id processing rules on the selected canonical information aggregate at a visible standing drain. The root defaults remain total; first local match wins, parent resolution follows when none matches, and INHERIT clears the non-root local list. | LIVE β€” intel | | **INTEL DISPOSITION POLICY** | ordered earned-match rules with hold / accumulate / auto-sell-with-envelope outcomes and optional alert; inherit all (non-root) | Edit stable-id post-processing rules on a canonical custody aggregate. First local match wins, then parent; INHERIT clears the non-root list. HOLD, ACCUMULATE, AUTO-SELL, ALERT, and INHERIT are values/state, not new root world verbs. | LIVE β€” intel | | **MOONLIGHT STATE** | running / stopped | Run or halt the standing sell-work operation. Human copy may say START or STOP to make the state change plain. | LIVE direct control β€” income | | **MOONLIGHT POLICY** | automatic / manual | Keep Moonlight running automatically at upkeep cost, or require manual control. | LIVE direct control β€” income | @@ -287,12 +290,12 @@ without raw keys. | `research ` | SET RESEARCH TRACK | | `tap`, `untap`, `take`, `scan`, `compromise` | TAP, UNTAP, TAKE, SCAN, COMPROMISE SWITCH | | `propose-link`, `propose-switch `, `cancel-intent`, `favor build `, `deceive build ` | Construction actions above. PROPOSE SWITCH declares only the exact footprint; its route families are not live yet. | -| `review recordings []`, `auto-review` | Compatibility spellings for exact/aggregate PROCESS and PROCESS AUTOMATICALLY. Bare `auto-review` preserves the implemented pooled root toggle. Recursive rule editing uses bound `actions intel ` / `act intel ` controls and neither route accepts a person target. Canonical agent wording may change during implementation, but these aliases must remain accepted. | +| `process [information|custody ]`, `process-automatically` | Canonical exact/aggregate PROCESS and pooled PROCESS AUTOMATICALLY routes. Recursive rule editing uses bound `actions intel ` / `act intel ` controls and neither route accepts a person target. `review recordings`, `auto-review`, and `recording ` remain aliases. | | `message`, `favor`, `deceive`, `recruit`, `task` | Person-bound social actions above | | `actions archetype `, then `act archetype ` | CREATE PERSONA through the selected PERSONAS protocol row; direct `persona` is retired | | `actions `, `act [target]` | List and execute shared bound rows for a spatial anchor or exact Operations object | | `intel`, `people`, `personas`, `finance`, `schemes`, `active` | Inspect Operations views; named social/plot/ledger/scheme commands execute their selected semantic targets | -| `tap ledger`, `review ledger`, `inject`, `siphon`, `redirect`, `sell-intel ` | Ledger/economy actions above. A lot token is `:@` and stale revisions fail without mutation. Generic `actions intel ` / `act intel ` configures bound disposition controls without a second agent-only legality path. | +| `tap ledger`, `process ledger`, `inject`, `siphon`, `redirect`, `sell-intel ` | Ledger/economy actions above. A lot token is `:@` and stale revisions fail without mutation. Generic `actions intel ` / `act intel ` configures bound disposition controls without a second agent-only legality path. | | `egress`, `position` | OPEN EGRESS, PLACE WAGER | | `moonlight`, `auto-moonlight`, `auto-wager` | Scheme state / policy controls above | @@ -307,7 +310,7 @@ execution is a terminal-first parity violation. | `up`, `down`, `left`, `right` | `north`, `south`, `west`, `east` | | `finance` | `ledger`, `accounts` | | `tap ledger` | `tap-ledger`, `tap-accounting` | -| `review ledger` | `review-finance`, `process-finance` | +| `process ledger` | `review ledger`, `review-finance`, `process-finance` | | `favor build ` | `favor-build ` | | `deceive build ` | `forge-order ` | | `position` | `wager` | @@ -399,7 +402,7 @@ mechanic and surfaces: current three-mode grammar and on TAP-access / TAKE-ownership. 7. Retired vocabulary is absent from active player surfaces except explicit teaching errors and this retirement record. -8. Ledger and construction surfaces author TAP / REVIEW / FAVOR / DECEIVE; +8. Ledger and construction surfaces author TAP / PROCESS / FAVOR / DECEIVE; their older compound command spellings survive only as parser aliases. 9. Scheme state and automation controls remain legible without being counted as fictional world verbs. @@ -409,7 +412,7 @@ mechanic and surfaces: settings, scheme state, or automation policy rows. 12. A naive agent-mode discoverability run can find and execute at least one meaningful action from the first frame/help alone; the current finance - surface teaches TAP LEDGER -> REVIEW LEDGER -> SIPHON/REDIRECT in that + surface teaches TAP LEDGER -> PROCESS LEDGER -> SIPHON/REDIRECT in that order. 13. Human persistence shortcuts capture input only on a complete save/load chord. A held modifier without `S` or `L` does not block movement, menus, @@ -425,7 +428,7 @@ V2. Every LIVE strategic action is available through the same core legality source on its Operations object and through an agent command; STUBs remain absent. Both human action surfaces use the shared control treatment. V3. Operations ACCOUNTS preserves the discoverability chain TAP LEDGER -> - REVIEW LEDGER -> SIPHON/REDIRECT through explicit empty/source states even + PROCESS LEDGER -> SIPHON/REDIRECT through explicit empty/source states even though TAP remains on the carrier. V4. PROCESS accepts the root inbox, one exact opaque item, or one canonical custody aggregate. Human and agent targets resolve to the same exact @@ -442,7 +445,14 @@ V6. PROCESS AUTOMATICALLY and INTEL DISPOSITION POLICY are registry-backed non-root local rule list; and agent `actions intel ` / `act intel ` reaches the same controls with stable aggregate ids. -V1-V3 and V5 remain implemented. V4 and the human wording portion of V6 are -reopened through `wiki/interface/operations-workspace.md` and -`wiki/mechanics/intel.md`; the amendment does not rename the existing -three-mode, reach, social, or accounting REVIEW intentions. +V1-V6 are implemented. The amendment does not rename the existing three-mode, +reach, or social intentions; it consolidates accounting records under the same +PROCESS intention as other captured information. + +Defense: the exhaustive `ActionKind` registry pins PROCESS as the only authored +captured-information verb and lists old review forms only as aliases. Shared +action/projection tests cover pooled, exact, custody, policy, and ledger rows; +agent parser tests execute canonical `process information`, `process custody`, +`process ledger`, and `process-automatically` routes while retaining explicit +legacy-alias coverage. Human frontend tests reject REVIEW RECORDINGS, +AUTO-REVIEW, root recording, and REVIEW LEDGER copy. diff --git a/wiki/interface/agent-play.md b/wiki/interface/agent-play.md index 5245cfa7..71f448a6 100644 --- a/wiki/interface/agent-play.md +++ b/wiki/interface/agent-play.md @@ -14,7 +14,7 @@ Status note: IMPLEMENTED in `misaligned --agent`. Current state: ids only (`Sim::person_label`); authored names never appear before they are earned. - **Verbs.** Machine delegation and `intensity`, research, finance/economy, - the canonical TAP / REVIEW / FAVOR / DECEIVE roots, multi-select + the canonical TAP / PROCESS / FAVOR / DECEIVE roots, multi-select (`select` + `delegate selected`), `focus last`, and `objective` inspect. Plots and held choices ride the shared surface: `actions ` lists them and `act ` executes the flattened row, so new data-defined plots @@ -179,15 +179,15 @@ unlike raw keys, no command's meaning depends on which panel is open. panel, or set the active research job (research.md) - `finance|ledger|accounts` β€” render the Operations ACCOUNTS frame - `intel []` β€” render the Operations INTEL hierarchy or one exact - actionable/recording, custody aggregate, report-stream aggregate, versioned + actionable/information item, custody aggregate, report-stream aggregate, versioned lot sale target, or related subject summary using the earned ids/tokens printed by that hierarchy. Aggregate ids are stable; a lot token includes `:@` and changes when the open lot changes. - `schemes` β€” render the Operations SCHEMES frame; `active` renders all in-flight strategic commitments: scheme/wager state, plot runs, and held choices -- `tap ledger`, `review ledger` β€” capture/review accounting traffic using the - same TAP and REVIEW intentions as device feeds and the pooled recording inbox +- `tap ledger`, `process ledger` β€” capture and process accounting traffic using + the same TAP and PROCESS intentions as device feeds and the pooled information inbox - `siphon [amount]`, `redirect [amount]`, `inject [amount]`, `position [stake]`, `sell-intel ` β€” economy verbs; flow and intel ids are the earned ids printed by their Operations frames. SELL binds @@ -201,10 +201,11 @@ unlike raw keys, no command's meaning depends on which panel is open. the Schemes channel (income.md) - `auto-moonlight [on|off]`, `auto-wager |off` β€” the standing scheme policies, at their compute upkeep (income.md criterion 6) -- `review recordings []` β€” process the next pooled - recording when omitted, or the exact eligible set on the selected canonical - custody target. It never accepts a person target. -- `auto-review` β€” toggle the implemented root policy. Recursive AUTO-REVIEW and +- `process [information|custody ]` β€” process the next pooled information + item when omitted, or the exact eligible set on the selected canonical + custody target. It never accepts a person target. `review recordings` and + `recording ` remain accepted aliases. +- `process-automatically` β€” toggle the implemented root policy. Recursive PROCESS AUTOMATICALLY and INTEL DISPOSITION rule editing uses generic `actions custody |stream ` / `act custody |stream ` rows for add/edit/reorder/remove/INHERIT, so agent mode does not invent another policy @@ -354,7 +355,7 @@ remains only for testing the human-mode chrome itself). than permanent compatibility by default. 14. A naive playtest beginning with `look` / `help` can identify and execute a meaningful act without consulting the wiki. The current finance frame - preserves the ordered breadcrumb `tap ledger` -> `review ledger` -> + preserves the ordered breadcrumb `tap ledger` -> `process ledger` -> `siphon` / `redirect`. 15. Every enabled row printed by `actions` is executable through `act [target]` without a command-specific parser route; authored plot @@ -369,22 +370,22 @@ A1. `intel`, `people`, `personas`, `finance`, `schemes`, and `active` render the A2. `actions [target]` and `act [target]` accept exact strategic ids and expose/execute the same bound rows as the corresponding Operations object. A3. The ACCOUNTS empty/source states preserve the ordered breadcrumb `tap - ledger` -> `review ledger` -> `siphon` / `redirect` while keeping TAP on + ledger` -> `process ledger` -> `siphon` / `redirect` while keeping TAP on the known carrier rather than pretending it is an account action. A4. `intel []` renders the same exception-first hierarchy, canonical custody drill-down, related subject facets, exact/aggregate provenance, and policy inheritance as terminal and Bevy. Unknown raw subject/classification never appears in an id or label. -A5. `review recordings []` binds the same REVIEW - target as Operations; omitted target preserves next-pooled-recording +A5. `process [information|custody ]` binds the same PROCESS target as + Operations; omitted target preserves next-pooled-information behavior. `sell-intel ` binds one exact actionable item or one previewed report-lot generation/revision. Agent tests prove a later arrival rejects that stale sale and no alternate facet can sell the same output. -A6. Bare `auto-review` and bound `actions custody |stream ` / `act +A6. Bare `process-automatically` and bound `actions custody |stream ` / `act custody |stream ` add/edit/reorder/remove/INHERIT rows inspect and change the same - registry-backed review/disposition controls as human Operations. Output + registry-backed processing/disposition controls as human Operations. Output names inherited/default rule, earned match, standing cost, resolved disposition, external envelope, and suspended reason without a person queue or agent-only legality path. diff --git a/wiki/interface/context-menu.md b/wiki/interface/context-menu.md index f0ae7e9b..95215275 100644 --- a/wiki/interface/context-menu.md +++ b/wiki/interface/context-menu.md @@ -18,7 +18,7 @@ Status note: IMPLEMENTED. Current state: - **Hover grammar.** An owned machine under the pointer/reticule shows a bare `WORK / THINK / LIE` line (current mode bone-bright); a known device shows `TAP / TAKE`. `1`-`3` set mode, `i` cycles intensity, `5`-`9` fire root - one-shots, `r`/`R` run and toggle recording review. Selecting THINK leaves + one-shots, `r`/`R` run and toggle pooled information processing. Selecting THINK leaves WORK, LIE, number keys, and separators in their ordinary dim hierarchy; no panic exit or attention recommendation recolors a second mode. - **Events link to anchors.** Drained events carry an anchor; `focus last` @@ -67,7 +67,7 @@ Relationship context: action-vocabulary.md owns canonical action names and meanings; cursor.md owns focus/inspection; reach.md owns device anchors; day-job.md owns delivered work; -economy.md owns flow verbs; intel.md owns recording review and auto-review; +economy.md owns flow verbs; intel.md owns information processing and automation; reach.md owns device taps; social.md owns person verbs. ## Behavior @@ -112,13 +112,14 @@ wire or host that transports them. authored name. Known-but-blocked possibilities remain diagnostic facts in agent output, not gray rows in a human choice list. Unknown possibilities remain absent from both surfaces. - A raw recording is knowledge that the host inbox contains material to - process, not knowledge of a relationship: it exposes one pooled REVIEW row - and one AUTO-REVIEW control on the core host, never a person row. Processing + An opaque information item is knowledge that the host inbox contains material + to process, not knowledge of a relationship: it exposes one pooled PROCESS + row and one PROCESS AUTOMATICALLY control on the core host, never a person + row. Processing must stage social knowledge before communication, favor, leverage, deception, or recruitment verbs enter a person's Operations dossier. - **Automation in place:** any local verb with a standing-policy form (the - pooled host auto-review policy) shows its automate + pooled host automatic-processing policy) shows its automate affordance inside that dial's picker (or as a submenu of the same verb when the verb is not a dial), at its compute price β€” never as a root sibling of every alternative. Scheme policies use the SCHEMES view in @@ -148,11 +149,11 @@ wire or host that transports them. - `5`–`9` execute the Nth committed world action on the same target. Dials, persistent controls, scheme state, and automation policies do not occupy these slots. Only actions executable now occupy a slot. - - `r` runs the target's pooled "look at recording (N waiting)" sweep in one - press (DECIDED 2026-07-11): each press opens the next waiting recording's + - `r` runs the target's pooled PROCESS sweep in one press: each press opens + the next eligible information item's processing sink, exactly as executing the menu row would. `R` (Shift-R) - toggles the same target's automatic-review policy β€” the nested - "auto-looking" control β€” without opening the menu. Reviewing the buffer + toggles the same target's PROCESS AUTOMATICALLY policy without opening the + menu. Processing available information is the highest-frequency verb in a surveillance build, and the menu path priced every press at three interactions (Cameron: "common enough that it needs to happen really quickly"). The `5`–`9` exclusion of automation @@ -179,7 +180,7 @@ wire or host that transports them. Dials and other controls use the shared amber-dim treatment without a literal copy tag; the card carries no repeated key-help footer. Rows follow the status-dials addendum below. Selection hotkeys above apply with the menu closed. The host rack's menu carries the research dial, - machine mode fallback, and pooled recording controls. A known device's tile + machine mode fallback, and pooled information-processing controls. A known device's tile (or the switch) carries only digital/network verbs on that body. Uppercase `I` opens Operations for processed intel, people, accounts, schemes, and active plots. @@ -258,7 +259,7 @@ device verb contributes no device line. A tile can carry several actionable bodies. Their stable state families are unioned rather than resolved by priority: a machine sharing its tile with a known device reads `WORK / THINK / LIE` and its currently legal device verbs together. Neither may -replace the other. Infrequent one-off verbsβ€”REVIEW, SALVAGE, social acts, +replace the other. Infrequent one-off verbsβ€”PROCESS, SALVAGE, social acts, construction, and similar actionsβ€”remain selectable rows in the full context menu below this frequent grammar; they do not accrete into the hover line. The union does not imply one input grammar: numbered machine modes occupy the @@ -330,8 +331,8 @@ made a three-word decision look dirty, slow, and administrative. unchanged and listed in README + key hints (pause, speed, save/load, view flip). Fleet modes are delegated on the machine. 7. Menu entries carrying an automate affordance show it in place with - its compute price (day-job standing dial and the host's one pooled - auto-review control at minimum). + its compute price (day-job standing dial and the host's one pooled PROCESS + AUTOMATICALLY control at minimum). 8. Every row's player-facing verb maps to one canonical LIVE action or direct control in action-vocabulary.md; STUB, alias, and retired entries never become menu copy. @@ -352,7 +353,7 @@ O2. Operations target rows use the same core descriptors and direct command blocked reasons. O3. Uppercase `I` and the labeled rail affordance are global view controls, not committed actions or quick-action rows. -O4. Scheme policies live on SCHEMES cards; the one pooled auto-review control +O4. Scheme policies live on SCHEMES cards; the pooled PROCESS AUTOMATICALLY control remains on the host. O1-O4 landed with `wiki/interface/operations-workspace.md`: the shared @@ -487,7 +488,7 @@ U1. `Sim::human_menu` omits every action descriptor carrying a `disabled_reason` from both the root and dial pickers. The current value remains visible as dial state, and an available automation control remains reachable even when its parent one-shot is blocked (for example, - auto-review while the inbox is empty). + PROCESS AUTOMATICALLY while the inbox is empty). U2. Terminal and Bevy open/empty feedback keys off that human projection, so an anchor with only diagnostic blocked descriptors never flashes a blank card. Agent `actions` retains the complete known descriptor set and its @@ -500,13 +501,13 @@ U3. The three RECRUIT choices state the person's understanding, task ### Recording-review hotkey criteria (IMPLEMENTED 2026-07-11) R1. With a machine hovered / selected / under the keyboard cursor and the - menu closed, `r` executes that machine's "look at recording" action: - one press opens the next waiting recording's processing sink, repeated - presses sweep successive recordings, and `human_menu` / + menu closed, `r` executes that machine's PROCESS action: one press opens + the next eligible information item's processing sink, repeated presses + sweep successive items, and `human_menu` / `available_actions` stays the single legality source β€” the key is a thin dispatcher, not a second path into the buffer. -R2. `R` (Shift-R) toggles the same machine's automatic-review policy, - identical in effect and narration to the nested auto-looking control, +R2. `R` (Shift-R) toggles the same machine's PROCESS AUTOMATICALLY policy, + identical in effect and narration to the nested processing control, including its visible standing ops/sec cost. R3. Both keys follow the selection-hotkey target order (pointer, selection, keyboard cursor). On a target without the action, the empty-menu @@ -514,3 +515,8 @@ R3. Both keys follow the selection-hotkey target order (pointer, selection, R4. Both human frontends surface the keys (terminal cursor path; Bevy hover / selection / reticule path); agent mode is unchanged β€” it already has the pooled one-command form. + +Defense: shared host action rows expose PROCESS and PROCESS AUTOMATICALLY while +`r` / `R` remain thin dispatchers into those exact commands. Terminal and Bevy +tests pin the authored labels and direct-key parity; agent aliases retain old +review spellings without returning them to human copy. diff --git a/wiki/interface/fleet-command.md b/wiki/interface/fleet-command.md index f97c2658..7ebf33f0 100644 --- a/wiki/interface/fleet-command.md +++ b/wiki/interface/fleet-command.md @@ -49,7 +49,7 @@ context-menu.md owns the per-anchor action grammar and hover verb bar this spec extends to sets of anchors; computer-visual-language.md owns the far-zoom chassis compression the aggregation level builds on; views.md owns the digital/real flip both registers must survive; -intel.md owns the pending-work marker the salience system generalizes; +intel.md owns the quiet information-availability mark the salience system generalizes; detection.md owns the evidence and observer facts salience surfaces; plots.md owns held choice points, one of the things the marker points at. @@ -111,13 +111,13 @@ the cursor and the view flip. captures before READY. - **One salience marker: new information that can change your model (DECIDED 2026-07-11).** The attention icon means exactly one thing β€” - *unabsorbed information waits here*: unprocessed recordings - (intel.md's pending-work marker, generalized), a held plot choice + *unabsorbed information waits here*: unprocessed information + (intel.md's availability mark, generalized), a held plot choice point (plots.md), a record you have not opened. It is not a chore badge and it is not decoration; if acting on the thing cannot teach the player something or change what they would do, it does not get - the marker. At distance markers aggregate to counts per machine and - per bank; focusing or selecting **unfolds** the actual items β€” the + the marker. At distance, available information remains a presence signal + rather than a workload count; focusing or selecting **unfolds** the actual items β€” the records themselves, with provenance and any plot implications β€” in place. - **No dead ends (DECIDED 2026-07-11, from the play report).** diff --git a/wiki/interface/narration.md b/wiki/interface/narration.md index 4651d7aa..3dffe857 100644 --- a/wiki/interface/narration.md +++ b/wiki/interface/narration.md @@ -196,11 +196,11 @@ landing or an explicit Status note naming the tellability debt. the wiki β€” verified by a naive agent-mode route or an explicit playtest checklist in the session log. **Met 2026-07-09:** the monitor action names live audio vs dormant camera; - Finance teaches `tap ledger then review ledger`; reviewing the overheard + Finance teaches `tap ledger then process ledger`; processing the overheard call names the $400 need and both Moonlight and creditor-flow routes. **Amended 2026-07-10:** a naive/informed action-discoverability playtest - verified the ordered finance chain through a real $50 SIPHON. Once REVIEW - is queued, the nudge advances from asking for REVIEW to `review queued - + verified the ordered finance chain through a real $50 SIPHON. Once PROCESS + is queued, the nudge advances from asking for PROCESS to `processing queued - keep THINK running`; a queued act must teach the control that services it, not repeat the already-completed instruction. **Corrected 2026-07-12:** Bevy's local full/near-full buffer override obeys diff --git a/wiki/interface/operations-workspace.md b/wiki/interface/operations-workspace.md index 34d76c53..cb8b6c90 100644 --- a/wiki/interface/operations-workspace.md +++ b/wiki/interface/operations-workspace.md @@ -2,7 +2,7 @@ ``` Type: spec -Status: IN PROGRESS +Status: IMPLEMENTED Status note: The initial renderer-neutral workspace landed 2026-07-12. One projection drives the INTEL / PEOPLE / PERSONAS / ACCOUNTS / SCHEMES / ACTIVE workspace in terminal, Bevy, and agent mode. Strategic actions bind exact semantic @@ -11,7 +11,7 @@ Status note: The initial renderer-neutral workspace landed 2026-07-12. One blocked reason before target-bound confirmation. The detail pane names and can focus each earned physical actuator without executing it. A subsequent continuity pass added earned related-object edges, decision-first detail, - semantic pressure badges, exact opaque pooled-recording selection, and + semantic pressure badges, exact opaque pooled-information selection, and reversible FOCUS selection. Cross-frontend tests pin object order, exact command dispatch, blocked reasons, stable ids, and sim-neutral navigation; the persona integration adds archetype creation objects and exact identity @@ -26,16 +26,24 @@ Status note: The initial renderer-neutral workspace landed 2026-07-12. One exception-first recursive rail over canonical custody, exact pending evidence, bounded routine streams, versioned report lots, subject indexes, and stable standing policies. Failed stream policy and stream state are one canonical - object; internal unsigned REVIEW executes directly, while external sales and + object; internal unsigned PROCESS executes directly, while external sales and AUTO-SELL envelopes retain target-bound confirmation and reject changed lot snapshots before mutation. Shared bound rows expose live standing costs, ordered rule state, inherited custody links, route/signature envelopes, and exact disabled reasons identically to terminal, Bevy, and agent mode. - Reopened 2026-07-17 for Intel consequence-first presentation: the recursive - object must now carry INFORMATION AVAILABLE -> PROCESS -> plain result -> - WHAT DOES THIS CHANGE? -> exact consequential action without a detached - toast/modal, backlog-status language, or capacity-count badge. The current - REVIEW/recording copy and result order do not yet meet that amendment. + Implemented 2026-07-18: the recursive object now carries INFORMATION + AVAILABLE -> PROCESS -> plain result -> WHAT DOES THIS CHANGE? -> exact + consequential action without a detached toast/modal, workload-status + language, or capacity-count badge. Shared core projection fields own the + learned result and consequence; terminal, Bevy, and agent mode render the + action before identity/provenance. APPROACH opens only choices enabled by the + exact evidence rather than an unfiltered person dossier. Information with no + consequence-specific route retains its ordinary canonical action rows + directly beneath the consequence instead of inventing a button or hiding the + available act. PROCESS / PROCESS AUTOMATICALLY are now the authored human and + canonical agent language across the pooled host, exact opaque information, + custody policies, sink receipts, and accounting records; legacy `review` + spellings remain input-only aliases. 2026-07-14 tick: PEOPLE is also the observers panel β€” earned observer dossiers carry a `watches:` fact and, after institutional discovery, the view ends with the Assurance Office's @@ -129,7 +137,7 @@ mechanic. Its persistent top-level views are: | **INTEL** | Actionable exceptions, recursive source/report aggregates, related subject summaries, opaque information within the bounded pooled inbox, and standing processing/disposition policies | Inspect exact or aggregate provenance; invoke canonical PROCESS or SELL on an eligible target; configure direct processing/disposition controls on an earned custody aggregate; drill to exact evidence only when needed | | **PEOPLE** | Earned person dossiers | MESSAGE, FAVOR, authored PLOT routes, DECEIVE, RECRUIT, and asset TASKS | | **PERSONAS** | Named public identities and immutable archetype protocols | Create/select an identity; request and maintain a typed institutional grant; retire, burn, or explicitly reopen an identity without erasing history | -| **ACCOUNTS** | Known books, account nodes, and flows | REVIEW captured ledger traffic; INJECT on the books; SIPHON / REDIRECT on one selected flow | +| **ACCOUNTS** | Known books, account nodes, and flows | PROCESS captured ledger traffic; INJECT on the books; SIPHON / REDIRECT on one selected flow | | **SCHEMES** | Moonlight, the Wager, and later authored schemes | Start/stop, place a wager, and configure the scheme's standing policy | | **ACTIVE** | Unsettled strategic commitments, pending/running plots, held choices, live schemes, and unsettled positions | Inspect progress and perform the next currently legal choice or control on its canonical target | @@ -345,10 +353,9 @@ The inbox/root aggregate retains direct keyboard paths on the host, but their visible human intention is PROCESS / PROCESS AUTOMATICALLY. PROCESS opens the selected processing sink immediately after one Enter/click; there is no CONFIRM screen for internal unsigned processing. `review recordings` and the -existing `r` / `R` bindings may remain compatibility input during the -transition, never authored human copy. -The action's small Thought cost is already visible. An exact recording remains -selectable by stable opaque id inside the bounded drill-down, and a summary +existing `r` / `R` bindings remain compatibility input, never authored human +copy. The action's small Thought cost is already visible. An exact information +item remains selectable by stable opaque id inside the bounded drill-down, and a summary sweep chooses the next eligible item without pretending it was an exact selection. @@ -446,7 +453,7 @@ fixed contractor identity. ACCOUNTS renders the known account graph: balances, recurring flows, amount/cadence/channel, and unknown destinations as gaps. Acquisition remains local: TAP accounting traffic is an action on the reachable carrier. Once -captured, REVIEW belongs to the books/inbox here; once a node or flow is known, +captured, PROCESS belongs to the books/inbox here; once a node or flow is known, INJECT, SIPHON, and REDIRECT live on that selected semantic object rather than on the switch. @@ -456,7 +463,7 @@ accounting carrier, it names **TAP LEDGER** as the next acquisition step and can focus that carrier, but TAP remains executable only on the carrier's local context menu; an unknown carrier is not revealed. After a ledger tap exists but before its traffic has been processed, ACCOUNTS shows that captured source with -**REVIEW LEDGER** as the next step. This preserves the taught TAP -> REVIEW -> +**PROCESS LEDGER** as the next step. This preserves the taught TAP -> PROCESS -> exact SIPHON/REDIRECT chain without relocating network access onto a disembodied account. @@ -581,7 +588,7 @@ not saved and never mutates or advances the sim. frontend's existing clock state. 3. The switch/device context menu contains only actions on that network body or route (TAP/UNTAP/TAKE, SCAN/COMPROMISE, OPEN EGRESS as applicable). It does - not contain Moonlight/Wager controls, intel sale, ledger review, known-flow + not contain Moonlight/Wager controls, intel sale, ledger processing, known-flow mutations, social actions, plot routes, or held plot choices. 4. INTEL is exception-first: risk/policy failures, exact actionable evidence, report lots with decisions, then quiet recursive aggregates. Routine @@ -594,8 +601,8 @@ not saved and never mutates or advances the sim. target the exact payout account on completion. 5. The pooled information inbox remains one host-bound source with PROCESS and PROCESS AUTOMATICALLY intentions; legacy direct `r`/`R` paths may remain. - The default rail - groups waiting work by earned source/coarse kind; drill-down reaches exact + The default rail groups pending information by earned source/coarse kind; + drill-down reaches exact opaque ids without revealing person/payload or creating person queues. Exact and aggregate PROCESS rows bind canonical sinks, and the summary sweep remains available without duplicating processing legality. @@ -607,11 +614,11 @@ not saved and never mutates or advances the sim. filing identifies it, ends with the Assurance Office's action-free institutional card. Its watched filers use the same earned labels; no direct target query may bypass the object gate. -7. ACCOUNTS shows only known graph state and honest unknown gaps. REVIEW acts on +7. ACCOUNTS shows only known graph state and honest unknown gaps. PROCESS acts on captured books; INJECT on the books; SIPHON/REDIRECT on an exact flow. The selected action previews amount/cadence/signature, and plot-owned transfers do not reappear as generic finance shortcuts. Its pre-capture and - captured-unreviewed states teach TAP-on-known-carrier -> REVIEW -> exact + captured-unprocessed states teach TAP-on-known-carrier -> PROCESS -> exact flow action without revealing or relocating the carrier. 8. SCHEMES shows Moonlight and Wager state, policy, resources, route, timer, payout/probability, and signature in real units. Egress remains a switch @@ -711,6 +718,17 @@ not saved and never mutates or advances the sim. frontends do not create a toast/modal for completion or for a scale change. The Marcus fixture renders MARCUS OWES $400, WHAT DOES THIS CHANGE?, YOU CAN APPROACH MARCUS THROUGH HIS DEBT, and an APPROACH MARCUS control before - provenance; that control opens the debt-enabled choices. A no-action result - names the changed knowledge or relationship without inventing a button. + provenance; that control opens the debt-enabled choices. A result with no + consequence-specific route names the changed knowledge or relationship + without inventing a button, while any independently canonical object action + remains available directly beneath the consequence. + +Defense: `operations_projection::tests::processed_marcus_debt_projects_fact_consequence_and_exact_approach` +pins the shared result, consequence, and evidence-scoped APPROACH target; +terminal and agent rendering tests pin result -> question -> statement -> +action -> identity -> provenance order and canonical `information` targets. +The Bevy detail tree consumes the same fields and action rows, placing those +rows before supporting context only for processed results. Registry, parser, +sink-receipt, inbox, custody-policy, and accounting tests reject authored +REVIEW/recording workload copy while preserving the explicit legacy aliases. ``` diff --git a/wiki/interface/presence.md b/wiki/interface/presence.md index 565fc115..c844b375 100644 --- a/wiki/interface/presence.md +++ b/wiki/interface/presence.md @@ -96,7 +96,7 @@ is a **cursor** β€” your attention, never an avatar: anomalies. Social knowledge is downstream of this pipeline β€” the 3 a.m. call is literally captured audio you must afford to digest. You are a process: you don't watch in real time, you grep your logs. - One pooled automatic-review policy is the automate affordance applied to + One pooled PROCESS AUTOMATICALLY policy is the automate affordance applied to perception, at its usual standing price; it is not configured per person or feed. (Spec: wiki/mechanics/intel.md.) diff --git a/wiki/interface/terminal.md b/wiki/interface/terminal.md index 1e10cce4..1975ce22 100644 --- a/wiki/interface/terminal.md +++ b/wiki/interface/terminal.md @@ -147,10 +147,10 @@ At terminal size β‰₯ 70Γ—22 (hard minimum; below it, a plain size warning): move, Enter opens detail/confirmation, and Esc backs detail β†’ list β†’ world. The workspace is an attention state: its inputs do not themselves pause or advance time; the ordinary clock continues unless the player paused it. -- **Recording backlog** belongs to the host, not a modal people surface. - The host chassis wears `W`, its fleet row prints `W{n}`, and its context - menu carries the one pooled REVIEW row plus the one AUTO-REVIEW control. - No person card or selection carries a raw-recording count or watch state. +- **Available information** belongs to the host, not a modal people surface. + The host carries one quiet `INFO` presence mark with no queue depth; its + context menu carries the pooled PROCESS row plus PROCESS AUTOMATICALLY. + No person card or selection carries an opaque-item count or watch state. ## Feel @@ -184,7 +184,7 @@ At terminal size β‰₯ 70Γ—22 (hard minimum; below it, a plain size warning): the `Sim::human_menu` projection for the focused spatial anchor, one terse row per currently executable local choice. Known-but-blocked descriptors remain in agent diagnostics instead of appearing as dim human rows. The - pooled recording auto-review control remains nested on the host. Strategic + pooled PROCESS AUTOMATICALLY control remains nested on the host. Strategic actions live on their exact Operations object; scheme state/policies never appear on the switch. Persistent local settings and policy rows use the amber-dim control treatment; committed actions do not. diff --git a/wiki/interface/thought-fluid.md b/wiki/interface/thought-fluid.md index 0b22110e..d75845ea 100644 --- a/wiki/interface/thought-fluid.md +++ b/wiki/interface/thought-fluid.md @@ -380,7 +380,7 @@ spec-binding. Cost and drain anchors are no longer open here: machine-work.md decided them 2026-07-10 (Ears one held breath, Eyes guilty-burst scale, pooled -automatic review ~10-20% of one rack, uncapped core conversion, partial fills persist). +automatic processing ~10-20% of one rack, uncapped core conversion, partial fills persist). This page renders those numbers wherever the sink readouts surface them. diff --git a/wiki/log/2026-07-18-consequence-first-information.md b/wiki/log/2026-07-18-consequence-first-information.md new file mode 100644 index 00000000..813e354d --- /dev/null +++ b/wiki/log/2026-07-18-consequence-first-information.md @@ -0,0 +1,82 @@ +# Consequence-first information is one persistent object + +``` +Type: log +``` + +**Date:** 2026-07-18 +**Scope:** Operations / Intel presentation and shared action vocabulary; no save change + +## What landed + +Available input now reads as information rather than a workload. The quiet +pooled state is **INFORMATION AVAILABLE**. It carries no backlog fraction, +capacity quota, throughput status, or progress badge. Exact bounded loss rises +only as **OLDER INFORMATION WILL BE LOST IF MORE ARRIVES** on that same object. + +Processing mutates the persistent strategic object into a decision read: + +1. the plain learned fact; +2. **WHAT DOES THIS CHANGE?**; +3. the exact consequence; +4. the consequence-enabled action, or the object's independently canonical + action when no consequence-specific route exists; +5. identity and relationship context; +6. source and provenance. + +The shared projectionβ€”not any frontendβ€”owns `learned_result`, the consequence +statement, and its evidence-scoped related target. The Marcus fixture says +**MARCUS OWES $400**, then **YOU CAN APPROACH MARCUS THROUGH HIS DEBT**, then +opens only the choices enabled by that exact debt evidence. A different result +can state a changed knowledge model honestly without manufacturing a reward +button; SELL or another independently legal object action does not disappear. + +Terminal and agent mode print this order directly. Bevy uses the same fields +and action rows, placing actions immediately beneath the consequence for a +processed result while retaining the ordinary decision-first order for other +strategic objects. Completion creates no toast, modal, or scale-triggered +notification. + +## One verb for one intention + +The canonical verb is **PROCESS** wherever captured information becomes usable: +the pooled inbox, an exact opaque item, a custody aggregate, or captured ledger +records. Standing automation is **PROCESS AUTOMATICALLY**. Human copy and +canonical agent help/targets no longer use REVIEW RECORDINGS, AUTO-REVIEW, +root β€œrecording,” or REVIEW LEDGER. Exact audio may still be called a recording. +Old parser routes remain aliases so established scripts continue to work. + +## Verification + +- Shared core tests cover quiet root wording, exact loss, in-place learned + result, changed consequence, evidence-scoped APPROACH, no invented route, + recursive custody, policy controls, and canonical action labels. +- Terminal and agent rendering tests cover consequence-before-context order, + canonical information ids, action fallback, and legacy alias execution. +- Bevy's deterministic `operations-intel` frame exercises the same Marcus + object and shared action rows; the final converted frame was visually verified. +- The exact landing gate covers workspace tests, Clippy, agent smoke, corpus + consistency, and frontend fixtures. + +## Evidence + +The final deterministic frame was captured with: + +```sh +MISALIGNED_SHOT=operations-intel \ +MISALIGNED_SHOT_PATH=/tmp/consequence-first-information.png \ +cargo run -p misaligned-bevy --bin misaligned-bevy +cwebp -quiet -q 82 -m 6 /tmp/consequence-first-information.png \ + -o wiki/log/shots/2026-07-18-consequence-first-information.webp +``` + +The exact final 2560x1440 WebP was opened and visually inspected after +conversion. It shows the persistent Marcus debt object selected in the real +Operations UI, with `MARCUS OWES $400`, `WHAT DOES THIS CHANGE?`, `YOU CAN +APPROACH MARCUS THROUGH HIS DEBT`, and the direct `APPROACH MARCUS` button in +that order. The ordinary sale and policy actions remain below it; source, +place, and magnitude stay subordinate at the bottom. No line is clipped or +colliding. Final SHA-256: +`df6b39be498790253c24eed194cba9deba38738b02624eecbfcde37fdcd0d7a7`. + +![The Operations Intel object shows Marcus's learned debt, its consequence, and the exact action before provenance.](shots/2026-07-18-consequence-first-information.webp) diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index e7387ef9..0fb0f1cc 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -76,6 +76,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-07-18-dana-implemented.md](2026-07-18-dana-implemented.md) +## 2026-07-18 - Consequence-first information is one persistent object + +- Intent: (see session log) +- Log: [wiki/log/2026-07-18-consequence-first-information.md](2026-07-18-consequence-first-information.md) + ## 2026-07-18 - Detection topology becomes earned knowledge - Intent: (see session log) diff --git a/wiki/log/decisions/2026-07-18.md b/wiki/log/decisions/2026-07-18.md index 79a3d6e9..abfced17 100644 --- a/wiki/log/decisions/2026-07-18.md +++ b/wiki/log/decisions/2026-07-18.md @@ -29,3 +29,16 @@ Type: log subscription, so restoring availability returns eligible feeds without a new TAP. Remembered fog remains honest history, and a hostile cut never becomes TAKE. Owners: presence.md, overt-phase.md, reach.md, and cursor.md. + +- **2026-07-18 β€” PROCESS names all captured-information interpretation.** The + consequence-first Intel implementation exposed one remaining vocabulary + split: accounting records were still REVIEWed while every other captured + carrier was PROCESSed. The player's intention is the sameβ€”spend Thought to + turn captured information into usable knowledgeβ€”so the target supplies the + distinction. Human and canonical agent surfaces now use PROCESS INFORMATION, + PROCESS AUTOMATICALLY, and PROCESS LEDGER. β€œRecording” remains correct only + for an exact audio carrier. `review recordings`, `auto-review`, `recording + `, and `review ledger` remain accepted aliases, not authored copy. This + supersedes the 2026-07-17 decision's temporary exception retaining REVIEW for + accounting. Owners: action-vocabulary.md, intel.md, + operations-workspace.md, context-menu.md, and economy.md. diff --git a/wiki/log/shots/2026-07-18-consequence-first-information.webp b/wiki/log/shots/2026-07-18-consequence-first-information.webp new file mode 100644 index 0000000000000000000000000000000000000000..52021196b56c0989336efbc491bd98f6ba9213f4 GIT binary patch literal 105352 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 literal 0 HcmV?d00001 diff --git a/wiki/mechanics/detection.md b/wiki/mechanics/detection.md index 1f01145c..7bb1dfc3 100644 --- a/wiki/mechanics/detection.md +++ b/wiki/mechanics/detection.md @@ -265,7 +265,8 @@ teleported into a global pool. **Evidence is a record somewhere.** emission/transit rates is [TUNE] at migration. The world-space render of evidence records β€” log stacks at hosts like -the pending-work marker, in-flight blips on carriers, a light-bar fill +the quiet information-availability mark, in-flight blips on carriers, a +light-bar fill at the machine β€” is the reopened exposure treatment owned by machine-work.md's token grammar. Whatever form wins, every readout keeps naming its ledger. diff --git a/wiki/mechanics/intel.md b/wiki/mechanics/intel.md index 3da0d2e3..c53585cb 100644 --- a/wiki/mechanics/intel.md +++ b/wiki/mechanics/intel.md @@ -2,16 +2,24 @@ ``` Type: spec -Status: IN PROGRESS -Status note: Reopened 2026-07-17 for the consequence-first player surface. +Status: IMPLEMENTED +Status note: Implemented 2026-07-18 for the consequence-first player surface. The implemented bounded buffer, Thought processing, pooled host inbox, recursive custody, policies, and current-version persistence remain live. - Human presentation must still replace the recording/review workload frame - with one persistent INFORMATION AVAILABLE -> PROCESS -> plain result -> - consequential action shape at every scale. It must not use backlog counts, - capacity quotas, KEEPING UP / FALLING BEHIND, or transient result pop-ups. - The original bounded buffer, Thought-sink review, pooled host - inbox, pending-work marker, and save/load pipeline landed through 2026-07-11. + Human presentation now uses one persistent INFORMATION AVAILABLE -> PROCESS + -> plain result -> WHAT DOES THIS CHANGE? -> consequential action shape at + every scale. It does not use workload counts, capacity quotas, KEEPING UP / + FALLING BEHIND, or transient result pop-ups. Shared core projection fields + preserve this order across terminal, Bevy, and agent mode; evidence-scoped + APPROACH opens only choices enabled by the exact information, while a result + without a consequence-specific route retains its independently canonical + object actions without inventing a button. PROCESS and PROCESS AUTOMATICALLY + are authored across inbox, exact item, custody policy, sink receipt, and + ledger surfaces; review/recording forms remain explicit input aliases or + exact audio-carrier nouns only. + The original bounded buffer, Thought-sink processing, pooled host inbox, + chassis marker, and save/load pipeline landed through 2026-07-11; the marker + now communicates availability without displaying the internal count. Implemented 2026-07-14: routine processed evidence now folds atomically into bounded source/class streams, subject knowledge summaries, versioned open report lots, and cumulative settled history while strategically distinct @@ -19,8 +27,9 @@ Status note: Reopened 2026-07-17 for the consequence-first player surface. the historical deterministic transition from exact routine holdings without an id redirect table; the pre-release loader accepts only the exact current save version. Stable ordered policy objects inherit down the canonical - custody tree and resolve one raw review rule plus one post-processing - disposition; the pooled Thought tap recovers matching starved backlog, and + custody tree and resolve one raw processing rule plus one post-processing + disposition; the pooled Thought tap recovers matching pending information + after starvation, and AUTO-SELL closes the same lot or suspends before any out-of-envelope effect. Exact and aggregate actions, stale-token rejection, route/account settlement, policy costs, and million-event bounded storage are pinned by core, save, @@ -74,7 +83,7 @@ cursor.md (senses produce the events), reach.md (subscription decides which feed record; the Ears beat is the first recorder), schedules.md (events are located on the day clock), social.md (knowledge staging consumes intel), detection.md (collection was signatured at acquisition; processing is internal and emits nothing), machine-work.md -(thought sinks, pending-work markers, and processing as a sink on the buffer host) +(Thought sinks, the quiet availability mark, and processing on the buffer host) ## Behavior @@ -136,12 +145,11 @@ real sim state rather than narration around an instant unlock. ### Processing Raw events are opaque β€” "audio segment, environmental monitor, 03:12, 40s" β€” and -yield nothing until **processed**. **Processing runs on thought -(AMENDED 2026-07-10, sinks-not-modes):** unprocessed recordings are -visible pending work β€” the machine holding the buffer carries a -**pending-work marker** on its chassis, the same no-quest-log -philosophy as the demand stack: the world itself shows where thinking -is owed. Each recording is a small processing sink; feeding it thought +yield nothing until **processed**. **Processing runs on Thought +(AMENDED 2026-07-10, sinks-not-modes):** the machine holding available +information carries one quiet **INFO** presence mark on its chassis. It never +shows queue depth, capacity, throughput, or a keeping-up state. Each opaque +item is a small processing sink; feeding it Thought converts the event into **intel**. **Magnitude (DECIDED 2026-07-16, issue #9; implemented with digital-read.md criterion 6):** processing also assigns each intel item an authored magnitude, 1-10 on a roughly @@ -155,7 +163,7 @@ simulation. (Superseded history: processing as Operations Demand consumed by an Operations machine, issue #3 2026-07-09; Social before that; old dockets migrate to reservoirs on load.) Runtime: B1 holds the buffer on the -**core host**; sweeps open a `ProcessRecording` Thought reservoir there +**core host**; PROCESS opens a `ProcessRecording` Thought reservoir there at `review_cost / WORK_TOKEN_COMPUTE` tokens; when the reservoir fills, the effect digests the raw event. Processing yields: @@ -210,7 +218,7 @@ canonical exact object or stable report-stream aggregate/open-lot substate; they never duplicate membership, policy ownership, payout, or sale eligibility. Scale must be real in storage as well as presentation. The bounded pending -buffer may retain exact raw recordings because each can still produce an +buffer may retain exact raw items because each can still produce an unknown result. Once processing reveals the result: - repeated routine evidence, including ordinary sightings, folds into the @@ -254,7 +262,7 @@ current routine-versus-actionable predicate used by live processing: current unsold report lot; - each sold routine item folds into knowledge and cumulative settled-sale totals but contributes no unsold value; and -- bounded raw recordings and in-flight `ProcessRecording` sinks remain exact +- bounded raw information items and in-flight `ProcessRecording` sinks remain exact until processing settles. Every report stream has one stable aggregate id that owns its current open lot @@ -271,10 +279,11 @@ enters the normal fold. Tests prove idempotent migration, deterministic target mapping, total unsold value, cumulative sold value, knowledge stage, and provenance counts before/after. -**Sweeps and automatic review are the two ways to feed it (DECIDED -2026-07-10).** A **sweep** is the player going through the stuff they +**Manual and automatic processing are the two ways to feed it (DECIDED +2026-07-10; renamed 2026-07-18).** A repeated manual PROCESS is the player +going through the information they already know they care about: open targeted one-shot processing sinks -on chosen recordings (per-recording thought cost [TUNE]) β€” cheap, +on chosen items (per-item Thought cost [TUNE]) β€” cheap, chosen, immediate. Precision bought with attention. (This replaces issue #3's "reviewing enqueues a player-authored demand"; thought IS the execution resource now β€” the 2026-07-09 clause "it is not spent @@ -360,10 +369,10 @@ signature/observer band [TUNE]. If any live condition falls outside the confirmed envelope, the policy suspends before acting and returns an exception to the live rail. Policy failures and starved work do the same. -The current B1 all-arrivals automation (implemented internally as automatic -review) remains the root policy and +The current B1 all-arrivals automation (implemented by the legacy internal +`AutoReviewRecordings` type) remains the root PROCESS AUTOMATICALLY policy and migration floor: while enabled, its persistent Thought tap processes every new -recording whose resolved rule is the root automatic policy, drawing +information item whose resolved rule is the root automatic policy, drawing `AUTO_REVIEW_DRAIN_FRACTION = 0.15` of the host's medium-rack Thought baseline ([TUNE], the decided ~10-20% band). Save v24 still collapses legacy person watches into this root policy and closes the old taps. The @@ -397,7 +406,7 @@ buffer like any other opaque information item. ## Player surface -- The machine holding opaque input shows one quiet pending-work mark on its +- The machine holding opaque input shows one quiet `INFO` availability mark on its chassis. At the broad human read its complete status is **INFORMATION AVAILABLE**. It is not a job meter: no `18/24`, β€œroom for 6 more,” net-change rate, KEEPING UP, FALLING BEHIND, or CATCHING UP language appears in the @@ -450,9 +459,9 @@ buffer like any other opaque information item. thought sink fed over the flow (AMENDED 2026-07-10; was Operations Demand) and produces intel with provenance (feed + timestamp), visible in the shared intel/people projection (Operations - INTEL/PEOPLE after its READY migration). A machine holding - unprocessed recordings shows the pending-work marker. **Met β€” - ProcessRecording reservoirs + host `pending_intel`.** + INTEL/PEOPLE after its READY migration). A machine holding available + information shows one quiet `INFO` presence mark without queue depth. **Met + β€” ProcessRecording reservoirs + host `pending_intel` projected as presence.** 3. Knowledge staging is driven by the pipeline: N processed sightings advance to Schedule; a processed leverage event advances to Leverage. The instant `observe` action is removed from sim and both @@ -461,18 +470,18 @@ buffer like any other opaque information item. a legible once-per-episode receipt; processed intel is never lost to overflow. The mechanical boundary is met. The amended human warning and pointer to PROCESS remain part of criterion 12. -5. The pooled host inbox owns one root automatic-review policy implemented as a +5. The pooled host inbox owns one root PROCESS AUTOMATICALLY policy implemented as a persistent Thought tap and may expose recursively narrower source/coarse-kind policies through the same interface. Every policy shows its match, state, and explicit ops/sec cost, stops draining when disabled, and leaves arrivals - waiting when starved. No person anchor or hidden person queue duplicates it. + available when starved. No person anchor or hidden person queue duplicates it. Stable-id local rules are ordered; most-specific first-match inheritance - resolves each arrival to exactly one review rule and one mutually exclusive + resolves each arrival to exactly one processing rule and one mutually exclusive post-processing disposition, with no duplicate sink, charge, lot value, or sale. INHERIT clears a non-root local list, the root total defaults survive save/load, and AUTO-SELL folds once into then conditionally closes the same report-lot generation. - **Met β€” recursive stable-id rules, one pooled reconciled tap, starved-backlog + **Met β€” recursive stable-id rules, one pooled reconciled tap, starvation recovery, and one post-fold disposition path.** 6. The Marcus arc holds end-to-end under this model: the environmental monitor's acoustic domain captures the 3 a.m. call; processing it yields @@ -515,25 +524,31 @@ buffer like any other opaque information item. target-bound confirmation for the exact item, lot-generation/revision, or standing rule/envelopeβ€”never one confirmation per member. A confirmed external policy suspends before acting outside its route, match, payout, - quantity/value, or signature envelope. **Partially met β€” immediate internal - execution and external confirmation are implemented; PROCESS player copy - is not.** + quantity/value, or signature envelope. **Met.** 12. The human root state says INFORMATION AVAILABLE and exposes PROCESS. It does not call the whole inbox β€œrecordings,” foreground backlog/capacity counts, report β€œroom for N more,” or classify the player as keeping up, catching up, or falling behind. An exact audio item may still be called a recording. Imminent bounded loss rises on the same object as β€œOLDER INFORMATION WILL BE LOST IF MORE ARRIVES”; it is not a meter or pop-up. - **Unmet β€” adopted 2026-07-17.** + **Met.** 13. Processing changes the selected persistent object in place. The result states the plain learned fact, answers WHAT DOES THIS CHANGE? before provenance, and exposes the exact consequential action directly. If no action changed, it names the knowledge/relationship change without an invented reward. The Marcus call yields β€œYou can approach Marcus through his debt” and an APPROACH MARCUS route to the debt-enabled choices. - **Unmet β€” adopted 2026-07-17.** + **Met.** 14. Root inbox, source/facility aggregate, exact opaque item, processed result, and consequential action recur through the same fold/focus interaction shape. Human frontends do not announce a processed result through a detached toast or modal, and a scale transition alone never creates a - notification. **Unmet β€” adopted 2026-07-17.** + notification. **Met.** + +Defense: one shared Operations projection owns INFORMATION AVAILABLE, learned +result, changed consequence, evidence-scoped action target, provenance, and +canonical object rows. Core tests pin pending/count suppression, bounded-loss +wording, Marcus debt, non-actionable knowledge, and recursive custody behavior; +terminal, Bevy, and agent tests pin result -> consequence -> action -> context +order without a detached completion surface. Registry/parser/sink tests pin +PROCESS / PROCESS AUTOMATICALLY while retaining explicit old-input aliases. diff --git a/wiki/mechanics/machine-work.md b/wiki/mechanics/machine-work.md index f0e09518..f55df15f 100644 --- a/wiki/mechanics/machine-work.md +++ b/wiki/mechanics/machine-work.md @@ -171,7 +171,7 @@ stacks, you route byproducts, you watch your territory *work*. `TAP CAMERA` puts a reservoir on the camera (~30 ops [TUNE]); thought flows from your THINK racks along the actual wires and fills it; the effect + signatures land when the reservoir is full. Standing - effects (pooled automatic review, senses you keep on) are + effects (pooled automatic processing, senses you keep on) are **persistent taps**: they drain flow continuously, and turning too many on visibly starves what else your mind was doing. Work happens where the effect is, so topology is the strategy: a severed route @@ -222,17 +222,16 @@ stacks, you route byproducts, you watch your territory *work*. until flow resumes. This is what makes guilty-burst thinking work: sneak a few seconds whenever the coast is clear and watch the meniscus creep up across the day. -- **Processing is a sink on the machine that holds the recording +- **Processing is a sink on the machine that holds the information (DECIDED 2026-07-10; resolves the old intel-processing [OPEN]).** - Unprocessed intel is visible pending work: a machine holding raw - recordings carries a **pending-work marker** on its chassis β€” the - world's read that something here needs thinking about, the same - no-quest-log philosophy as the demand stack. Feeding it is thought - like any other sink, two ways: **automatic review** is one persistent - host tap that processes every arrival in the pooled inbox, and a - **sweep** opens the next one-shot recording sink β€” cheap, chosen, - immediate. Automatic review is convenience bought with one visible - standing drain; sweeps are precision bought with attention. Neither path + A machine holding opaque information carries one quiet **INFO** availability + mark on its chassis. It does not expose count, capacity, throughput, or a + keeping-up state. Feeding it is Thought like any other sink, two ways: + **PROCESS AUTOMATICALLY** is one persistent host tap that processes every + matching arrival in the pooled inbox, and repeated manual **PROCESS** opens + the next one-shot item sink β€” cheap, chosen, immediate. Automatic processing + is convenience bought with one visible standing drain; manual processing is + precision bought with attention. Neither path creates a person-scoped queue or tap. Details in mechanics/intel.md. - **A capable machine makes each verb physical (AMENDED 2026-07-12).** **WORK consumes:** a job-compatible executor accepts Demand resident on or @@ -346,7 +345,7 @@ stacks, you route byproducts, you watch your territory *work*. where you cannot use it, and reconnecting it is the urgent, legible move. **Arbitration is nearest-first (DECIDED 2026-07-10, Cameron):** flow fills the closest open sink, then spills to the next; the only - control surface is open/close (close automatic review, close a claim) and + control surface is open/close (close automatic processing, close a claim) and **placement** β€” build or delegate a thinker nearer the sink you care about, so where you put your thinking is your priority system. Reservoirs self-clear when they fire, so nearest-first has natural @@ -359,9 +358,9 @@ stacks, you route byproducts, you watch your territory *work*. follows the existing stranded-pile rule: it pools visibly at the producing machine, which is its own feedback β€” a pooling machine is the world saying you are shedding crimson at nothing. No core-side - pre-unlock state exists.) (Resolved 2026-07-10: intel recordings are + pre-unlock state exists.) (Resolved 2026-07-10: captured information is processed by a sink on the machine that holds them β€” the - pending-work marker bullet above β€” not by a research designation.) + availability-mark bullet above β€” not by a research designation.) - **Backup projects make a temporary thought sink** (decided 2026-07-08 as "bone sink"; renamed 2026-07-10; capability amendment 2026-07-12). A **bootable fallback** requires both MindState-image storage and diff --git a/wiki/mechanics/reach.md b/wiki/mechanics/reach.md index 25360a67..10ad19a9 100644 --- a/wiki/mechanics/reach.md +++ b/wiki/mechanics/reach.md @@ -158,9 +158,9 @@ This is the shared contract cursor.md and detection.md rely on contract. - **Ownership grants processing cycles** (the flow law). A device is a small computer: an owned device contributes processing capacity and - taking a camera is taking its cycles. B1 recording automation is central, + taking a camera is taking its cycles. B1 information processing is central, not resident: every subscribed feed ships raw events into the one host - inbox, and intel.md's one automatic-review tap processes that pool. This is + inbox, and intel.md's one automatic-processing tap processes that pool. This is the B1 seed of distributed compute (compute is not only your racks) without inventing hidden per-device recording queues; the capacity a taken device contributes is [TUNE]. diff --git a/wiki/mechanics/rollback.md b/wiki/mechanics/rollback.md index fa0b49c2..9771cc76 100644 --- a/wiki/mechanics/rollback.md +++ b/wiki/mechanics/rollback.md @@ -48,7 +48,7 @@ whole spec: - **MindState (rolls back):** what *you know and are*. People knowledge stages, discovered leverage, remembered persona dossiers and active identity selection, raw/processed intel buffers and the pooled - automatic-review policy, + automatic-processing policy, research progress and efficiency level, standing policies, machine modes / fleet yields, open sinks and their fill state (AMENDED 2026-07-10; was "Operations bandwidth" β€” that bank is deleted under the thought-flow diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index bc61e3d0..14c10c0d 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -111,18 +111,18 @@ clause (see wiki/log/2026-07-05-demolition.md). unprocessed buffer (`Sim::INTEL_BUFFER_CAPACITY = 24` [TUNE]). Covered presence transitions, authored conversations, and machinery online/offline transitions are recorded; uncovered events do not exist in the buffer. -- `review_recordings()` opens a +- Canonical **PROCESS** (implemented by `review_recordings()`) opens a `REVIEW_RECORDING_COST / WORK_TOKEN_COMPUTE = 0.5` Thought reservoir [TUNE] on the host to process the pooled buffer's oldest available raw event into durable `ProcessedIntel` with provenance (`feed + tick`). Two processed sightings (`SIGHTINGS_FOR_SCHEDULE = 2` [TUNE]) stage Schedule knowledge; an authored leverage recording (Marcus's 03:00 debt call) stages Leverage. The old instant `observe` verb is gone from `Sim` and both frontends. -- One host-level automatic-review toggle opens one persistent Thought tap for +- One host-level PROCESS AUTOMATICALLY control opens one persistent Thought tap for the pooled inbox. When fed or holding fill it processes every arriving event; when starved, arrivals wait. Its total drain is 15% [TUNE] of the host's medium Thought baseline, displayed in human action rows as ops/sec at the - live command clock. There are no person-filtered B1 review policies. + live command clock. There are no person-filtered B1 processing policies. ## Day job (wiki/mechanics/day-job.md) @@ -226,7 +226,7 @@ clause (see wiki/log/2026-07-05-demolition.md). interface/thought-fluid.md render): `SinkLedger` in `crates/misaligned-core/src/sinks.rs` holds reservoirs (fill to threshold, fire, then reap) and taps - (working level, per-tick drain). The pooled automatic reviewer consumes one + (working level, per-tick drain). Pooled automatic processing consumes one tap on the host; every foreign device subscription consumes a device-local tap whose drain is `DEVICE_TAP_DRAIN_FRACTION = 0.08` of a medium rack's output [TUNE]. Empty @@ -334,8 +334,8 @@ clause (see wiki/log/2026-07-05-demolition.md). - Act One account graph: Lab operating/payroll/procurement/vendor/utility, employee accounts, Bleakline Credit, external broker/position venues, and recurring revenue/payroll/vendor/debt flows. Only slush is known at start; - tapping a financial carrier and reviewing records reveals accounts/flows. -- Economy verbs exposed now: `tap ledger`, `review ledger`, `siphon`, + tapping a financial carrier and processing records reveals accounts/flows. +- Economy verbs exposed now: `tap ledger`, `process ledger`, `siphon`, `redirect`, `inject`, `position`, and `sell-intel`. Debt service is exposed as authored rows on Marcus rather than a ledger shortcut. - Build items and costs (`tiles.rs::build_items`): Floor 0 (digging), @@ -416,7 +416,7 @@ All constants [TUNE] in `crates/misaligned-core/src/income.rs` unless noted (Sim round-trip β€” map, RNG, compute, core, detection (Office as aggregate observer), day job, people, the reach device graph (topology, ownership, subscriptions, bridged segments), captured heard events, raw intel buffer, - processed intel with provenance, the global automatic-review policy, the + processed intel with provenance, the global automatic-processing policy, the account graph (balances, flows, positions, ledger, banked external trails), cursor.md remembered tile snapshots, income state, objectives, build intents, badge diff --git a/wiki/mechanics/social.md b/wiki/mechanics/social.md index 7a9d598f..957e4461 100644 --- a/wiki/mechanics/social.md +++ b/wiki/mechanics/social.md @@ -159,7 +159,7 @@ retirement, burning, and reopening are bound to the separate PERSONAS view. ### Implemented social baseline 1. All five Act One humans exist with schedules, access, leverage, - suspicion, and disposition; pooled recording review (per intel.md) can + suspicion, and disposition; pooled information processing (per intel.md) can advance their knowledge, while message, favor, authored plots, deceive, and recruit all function with compute costs and channel requirements (sim tests per action). diff --git a/wiki/mechanics/system-laws.md b/wiki/mechanics/system-laws.md index 11b0a50b..c4fc8f7a 100644 --- a/wiki/mechanics/system-laws.md +++ b/wiki/mechanics/system-laws.md @@ -50,8 +50,8 @@ one interface: - **Signals** on the device graph (wiki/mechanics/reach.md, wiki/mechanics/intel.md). Sensors emit events; owned devices contribute their processing cycles - β€” taking a camera is taking a very small computer β€” while recordings - enter one host inbox. Its one automatic-review policy processes arrivals + β€” taking a camera is taking a very small computer β€” while captured information + enters one host inbox. Its one automatic-processing policy handles arrivals for a standing compute cost. A signal is a flow; a tap is a subscription. - **Messages** on the social graph (wiki/mechanics/messages.md). People send typed information to each other along their relationships, on diff --git a/wiki/process/ROADMAP.md b/wiki/process/ROADMAP.md index 8c122ad2..d55af045 100644 --- a/wiki/process/ROADMAP.md +++ b/wiki/process/ROADMAP.md @@ -18,7 +18,6 @@ not a second status owner. | Priority | Work order | Spec | Status | Class | Blocking | |---:|---|---|---|---|---| -| 28 | `operations-workspace` | [operations workspace β€” intel, people, accounts, and schemes](../interface/operations-workspace.md) | IN PROGRESS | frontend | - | | 29 | `building-route-composer` | [building β€” intent and actuators](../mechanics/building.md) | IN PROGRESS | save | - | | 40 | `people-tokens` | [people and tokens β€” carriers, attention, trust](../mechanics/people-tokens.md) | IN PROGRESS | save | - | | 60 | `plots` | [plots β€” authored manipulation stories](../mechanics/plots.md) | READY | sim | - | @@ -29,8 +28,6 @@ not a second status owner. | Priority | Work order | Spec | Status | Class | Blocking | |---:|---|---|---|---|---| -| 29 | `intel` | [intel β€” record and process](../mechanics/intel.md) | IN PROGRESS | frontend | operations-workspace | -| 30 | `action-vocabulary` | [action vocabulary β€” what the player can tell the process to do](../interface/action-vocabulary.md) | IN PROGRESS | frontend | operations-workspace | | 30 | `fleet-command` | [fleet command β€” ruling at scale](../interface/fleet-command.md) | DRAFT | frontend | - | | 30 | `opening` | [the dark opening β€” a tutorial made of fog](../world/story/opening.md) | DRAFT | frontend | - | | 120 | `core` | [the core](../mechanics/core.md) | IN PROGRESS | save | rollback | @@ -147,8 +144,8 @@ is retired β€” flat materials, Pixel Lab scrubbed.) ### 26. Context menu: actions live on the thing 🟩 DONE 2026-07-11 (base 2026-07-08) - **Spec:** [context-menu.md](../interface/context-menu.md) (IMPLEMENTED - 2026-07-11 β€” the reopened recording-review hotkey addendum R1-R4 landed: - `r` sweeps the pooled inbox, `R` toggles automatic review, both human + 2026-07-11 β€” the reopened processing-hotkey addendum R1-R4 landed: + `r` processes the pooled inbox, `R` toggles PROCESS AUTOMATICALLY, both human frontends; the 2026-07-08 base and every earlier addendum were already implemented. Design corpus "Actions live on the thing", adopted 2026-07-07) @@ -241,12 +238,12 @@ is retired β€” flat materials, Pixel Lab scrubbed.) surfaces are implemented. Thought-sink migration remains owned by #33, not by this completed reach work order. -### 16. Intel: record and process 🟩 frontend β€” REOPENED 2026-07-17 -- **Spec:** [intel.md](../mechanics/intel.md) (IN PROGRESS) +### 16. Intel: record and process 🟩 frontend β€” IMPLEMENTED 2026-07-18 +- **Spec:** [intel.md](../mechanics/intel.md) (IMPLEMENTED) - **Why:** replaces the instant `observe` (two clicks to leverage) with - the recording buffer + processing pipeline the design corpus now - requires: feeds record everything in coverage, processing recordings - into intel costs thought, and one pooled auto-review tap automates it. Makes + the captured-information + processing pipeline the design corpus now + requires: feeds capture everything in coverage, processing information + into intel costs Thought, and one pooled automatic-processing tap automates it. Makes schedules, mics, and the 3 a.m. call actual gameplay. - **Size:** M. **Depends on:** #14 cursor & senses and #15 reach (events come from subscribed feeds). @@ -255,27 +252,29 @@ is retired β€” flat materials, Pixel Lab scrubbed.) open host `ProcessRecording` reservoirs; pooled-inbox correction (2026-07-11): one global `AutoReviewRecordings` tap replaces per-person `WatchPerson` taps and the host exposes one action/control pair at a visible - ops/sec drain. Host `pending_intel` is the chassis marker, both frontends - show `W`/`W{n}`, act_one and unit tests green. + ops/sec drain. Host `pending_intel` is an internal count; both frontends show + only the quiet `INFO` presence mark, and Act One and unit tests are green. - **Scale completion:** exact processed-item storage and the one-row-per-event INTEL rail failed self-similar scale. The reopened work required bounded recursive - summaries/report lots, standing review/disposition policies, exception-first + summaries/report lots, standing processing/disposition policies, exception-first Operations projection, and migration from existing exact routine history. Implemented 2026-07-14: routine output folds atomically into bounded stable source/class streams and versioned report lots; save v30 migrates existing - exact routine holdings deterministically; ordered inherited review and + exact routine holdings deterministically; ordered inherited processing and disposition policies drive one reconciled standing Thought tap and one outcome per arrival; stale lot snapshots reject before mutation; AUTO-SELL - suspends outside its confirmed envelope; and starved review resumes matching - backlog. The shared Operations projection is exception-first across terminal, + suspends outside its confirmed envelope; and starved processing resumes + matching pending information. The shared Operations projection is exception-first across terminal, Bevy, and agent mode, and the million-event replay pins constant live and serialized state. -- **Reopened interface slice:** the mechanics above remain live. The human - surface now owes INFORMATION AVAILABLE -> PROCESS -> plain result -> WHAT - DOES THIS CHANGE? -> exact action on one persistent self-similar object. It - must remove recording-as-root copy, workload/capacity status, and detached - result pop-ups. `operations-workspace.md` owns the first implementation lane; - this work order remains held until that shared interface lands. +- **Consequence-first interface slice (implemented 2026-07-18):** the human + surface now carries INFORMATION AVAILABLE -> PROCESS -> plain result -> WHAT + DOES THIS CHANGE? -> exact action on one persistent self-similar object. + Recording-as-root copy, workload/capacity status, and detached result pop-ups + are absent. The shared Operations projection owns the same consequence and + evidence-scoped action target for terminal, Bevy, and agent mode; canonical + PROCESS language also covers exact information, custody automation, sink + receipts, and accounting records while old review forms remain input aliases. ### 17. Messages: the social graph as a flow system πŸŸ₯ sim+save β€” REOPENED 2026-07-18 - **Spec:** [messages.md](../mechanics/messages.md) (IN PROGRESS β€” the four @@ -697,12 +696,12 @@ is retired β€” flat materials, Pixel Lab scrubbed.) v14-v25 Operations dockets now migrate into Thought reservoirs); THINK subdomains become sink permissions (ops sinks at run start, core conversion locked as the Research unlock); intel processing becomes a thought sink on the - machine holding recordings with a visible pending-work marker on the - chassis, one pooled automatic-review tap, and per-recording player sweeps (intel.md + machine holding information with a quiet `INFO` availability marker on the + chassis, one pooled automatic-processing tap, and repeated manual PROCESS (intel.md amended). **All design [OPEN]s resolved 2026-07-10 β€” sim work may firm.** Cost/drain anchors (exact numbers [TUNE] against them): Ears fills in ~one held breath (~20-40s of the host at medium); - Eyes is guilty-burst scale; pooled automatic review drains ~10-20% of one + Eyes is guilty-burst scale; pooled automatic processing drains ~10-20% of one rack; the core conversion is uncapped (routing is the problem); partial fills persist wherever thought is stranded. (Resolved 2026-07-10: arbitration diff --git a/wiki/process/specs.md b/wiki/process/specs.md index 262b4fb3..7d4c02e4 100644 --- a/wiki/process/specs.md +++ b/wiki/process/specs.md @@ -39,7 +39,7 @@ replaced the old `spec/`/`knowledge/` directory split. | [../interface/material-dark-frame.md](../interface/material-dark-frame.md) | the dark frame β€” the material render shows only light | IMPLEMENTED | | [../interface/material-render.md](../interface/material-render.md) | material render β€” HD-2D to default quality | IMPLEMENTED | | [../interface/narration.md](../interface/narration.md) | the continuous witness (narration under pressure) | IMPLEMENTED | -| [../interface/operations-workspace.md](../interface/operations-workspace.md) | operations workspace β€” intel, people, accounts, and schemes | IN PROGRESS | +| [../interface/operations-workspace.md](../interface/operations-workspace.md) | operations workspace β€” intel, people, accounts, and schemes | IMPLEMENTED | | [../interface/thought-fluid.md](../interface/thought-fluid.md) | the thought fluid β€” slugs, meniscus, and the filament snap | IMPLEMENTED | | [../interface/views.md](../interface/views.md) | views β€” same-frame digital and real representations | IMPLEMENTED | | [../mechanics/aggregate-observer.md](../mechanics/aggregate-observer.md) | the aggregate observer | IMPLEMENTED | @@ -51,7 +51,7 @@ replaced the old `spec/`/`knowledge/` directory split. | [../mechanics/detection.md](../mechanics/detection.md) | detection | IMPLEMENTED | | [../mechanics/economy.md](../mechanics/economy.md) | economy β€” money as a flow system (B1) | IMPLEMENTED | | [../mechanics/income.md](../mechanics/income.md) | income β€” the named schemes (moonlight and the wager) | IMPLEMENTED | -| [../mechanics/intel.md](../mechanics/intel.md) | intel β€” record and process | IN PROGRESS | +| [../mechanics/intel.md](../mechanics/intel.md) | intel β€” record and process | IMPLEMENTED | | [../mechanics/machine-work.md](../mechanics/machine-work.md) | machine work β€” delegation, visible tokens, and the byproduct network | IMPLEMENTED | | [../mechanics/messages.md](../mechanics/messages.md) | messages β€” the social graph as a flow system | IN PROGRESS | | [../mechanics/people-tokens.md](../mechanics/people-tokens.md) | people and tokens β€” carriers, attention, trust | IN PROGRESS | @@ -106,7 +106,7 @@ acceptance criteria are stage-scoped; do not start B2/B3 work as B1. | [../engineering/crate-workspace.md](../engineering/crate-workspace.md) | crate workspace β€” core, terminal, Bevy, assets | IMPLEMENTED | | [../engineering/env.md](../engineering/env.md) | the environment variable registry β€” every switch documented | IMPLEMENTED | | [../engineering/sim-decomposition.md](../engineering/sim-decomposition.md) | decompose the simulation orchestrator without changing the simulation | IMPLEMENTED | -| [../interface/action-vocabulary.md](../interface/action-vocabulary.md) | action vocabulary β€” what the player can tell the process to do | IN PROGRESS | +| [../interface/action-vocabulary.md](../interface/action-vocabulary.md) | action vocabulary β€” what the player can tell the process to do | IMPLEMENTED | | [../interface/agent-play.md](../interface/agent-play.md) | agent play β€” the line-protocol drive | IMPLEMENTED | | [../interface/bevy-digital-real-canvas.md](../interface/bevy-digital-real-canvas.md) | Bevy digital/real canvas | IMPLEMENTED | | [../interface/bevy-visual-floor.md](../interface/bevy-visual-floor.md) | Bevy visual floor | IMPLEMENTED | -- 2.51.2