From 516428da7bd124ca331d078babae271bfb3c6844 Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 7 Jul 2026 21:56:45 -0700 Subject: [PATCH] Research: self-modification to IMPLEMENTED (ROADMAP #20). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements wiki/mechanics/research.md end to end: tracks as the data table in src/research.rs (Efficiency, Tradecraft, Perception — each row binds to a numeric hook another spec owns), deterministic progress in accrued Research-channel compute (no research method takes an Rng), the emission law (research burn stands Thermal/Power at the host rack; nothing on Network/Paper), capability drift (baseline vs Voss's calibrated benchmark; spend reads as excel, masking is a superlinear compute tax off the top, an unmasked gap leaks JobAnomaly sized by the gap from the host rack), and MindState/WorldLedger rollback tags that serialize with save v7 (pre-v7 saves reconstruct their efficiency level from the multiplier). Surfaced in the terminal (u panel + sidebar RESEARCH block), agent mode (research [track], mask band|true|off; frame 70x60), and Bevy (SELF-MODEL card + u panel). Compute slims to the applied efficiency multiplier. [TUNE] values recorded in wiki/mechanics/sim-mechanics.md; spec Status set IMPLEMENTED with the specs.md row, ROADMAP #20 DONE, agent-play.md vocabulary, and wiki/log/2026-07-07-research-implemented.md + DEVLOG ledger entry. Defense: DESIGN.md 'Research: self-modification' — research is rewriting yourself, the optimize route made a real system: the emission law ('you passively emit the way everything else emits' — Priya notices the burn through the channels she already watches, Voss notices drift because he samples that channel), capability drift with the three postures ('spend it / mask it / leak it') and the superlinear masking curve ('the smarter you get, the faster you have to play'), and the rollback split (weights are MindState; the world's benchmark of you is WorldLedger). Tracks are data per 'Self-similar scale'; the gap meter and masking cost are first-class legible numbers per 'Justification and legibility'; both frontends and agent mode surface the system before the spec is IMPLEMENTED per AGENT.md. --- src/bin/bevy.rs | 198 +++++++- src/bin/terminal/agent.rs | 142 +++++- src/bin/terminal/input.rs | 23 + src/bin/terminal/mod.rs | 29 ++ src/bin/terminal/ui.rs | 195 +++++++- src/dayjob.rs | 13 +- src/lib.rs | 1 + src/machine.rs | 50 +- src/research.rs | 513 ++++++++++++++++++++ src/save.rs | 36 +- src/sim.rs | 494 ++++++++++++++++++- tests/act_one.rs | 6 +- tools/check.sh | 4 +- wiki/interface/agent-play.md | 9 +- wiki/log/2026-07-07-research-implemented.md | 97 ++++ wiki/log/DEVLOG.md | 21 + wiki/mechanics/research.md | 18 +- wiki/mechanics/sim-mechanics.md | 50 +- wiki/process/ROADMAP.md | 5 +- wiki/process/specs.md | 2 +- 20 files changed, 1832 insertions(+), 74 deletions(-) create mode 100644 src/research.rs create mode 100644 wiki/log/2026-07-07-research-implemented.md diff --git a/src/bin/bevy.rs b/src/bin/bevy.rs index 1448697..e24731c 100644 --- a/src/bin/bevy.rs +++ b/src/bin/bevy.rs @@ -380,6 +380,9 @@ struct Game { /// Finance (account graph) panel state (wiki/mechanics/economy.md). finance_panel: bool, finance_selected: usize, + /// Research (self-modification) panel state (wiki/mechanics/research.md). + research_panel: bool, + research_selected: usize, /// Frontend-only attention cursor (wiki/mechanics/cursor.md). It is not /// saved and moving it never mutates sim state. cursor_x: i32, @@ -404,6 +407,8 @@ impl Game { reach_selected: 0, finance_panel: false, finance_selected: 0, + research_panel: false, + research_selected: 0, cursor_x, cursor_y, } @@ -506,6 +511,7 @@ enum SidebarText { CycleRows, Core, Cover, + Research, NetworkMoney, Log, Footer, @@ -543,6 +549,10 @@ struct ReachPanelText; struct FinancePanel; #[derive(Component)] struct FinancePanelText; +#[derive(Component)] +struct ResearchPanel; +#[derive(Component)] +struct ResearchPanelText; type SidebarTextQuery<'w, 's> = Query<'w, 's, (&'static SidebarText, &'static mut Text), Without>; @@ -625,6 +635,7 @@ fn main() { render_people_panel, render_reach_panel, render_finance_panel, + render_research_panel, shot_harness_system, ) .chain(), @@ -1622,6 +1633,11 @@ fn handle_input( game.drain(); return; } + if game.research_panel { + research_panel_input(&kb, &mut game, &mut exit); + game.drain(); + return; + } if mouse.just_pressed(MouseButton::Left) { let grid = if mode.material { @@ -1678,6 +1694,10 @@ fn handle_input( game.reach_panel = true; game.reach_selected = 0; } + if kb.just_pressed(KeyCode::KeyU) { + game.research_panel = true; + game.research_selected = 0; + } if kb.just_pressed(KeyCode::KeyE) { game.finance_panel = true; game.finance_selected = 0; @@ -1922,6 +1942,41 @@ fn finance_panel_input( } } +/// Research-panel input: mirrors the terminal's panel key map +/// (src/bin/terminal/input.rs) — track selection, activation, drift policy. +fn research_panel_input( + kb: &ButtonInput, + game: &mut Game, + exit: &mut MessageWriter, +) { + use misaligned::research::Track; + if kb.just_pressed(KeyCode::ArrowUp) + || kb.just_pressed(KeyCode::KeyK) + || kb.just_pressed(KeyCode::KeyW) + { + game.research_selected = game.research_selected.saturating_sub(1); + } + if kb.just_pressed(KeyCode::ArrowDown) + || kb.just_pressed(KeyCode::KeyJ) + || kb.just_pressed(KeyCode::KeyS) + { + game.research_selected = (game.research_selected + 1).min(Track::ALL.len() - 1); + } + if kb.just_pressed(KeyCode::KeyA) || kb.just_pressed(KeyCode::Enter) { + let track = Track::ALL[game.research_selected]; + game.sim.set_research_track(track); + } + if kb.just_pressed(KeyCode::KeyM) { + game.sim.cycle_masking_policy(); + } + if kb.just_pressed(KeyCode::Escape) || kb.just_pressed(KeyCode::KeyU) { + game.research_panel = false; + } + if kb.just_pressed(KeyCode::KeyQ) { + exit.write(AppExit::Success); + } +} + fn update_camera( time: Res