From 59d401ab30d198544988c4595954fcce677917b9 Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 10 Jul 2026 18:46:47 -0700 Subject: [PATCH] Make wire speed a researched machine-work curve. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Routing now compounds shared wired throughput without shortening graph distance, and the sim emits explicit token-consumption events for renderer truth. Defense: wiki/mechanics/machine-work.md requires routed work to move at researched network speed and visible consumption to derive from the sim. wiki/mechanics/research.md owns Routing as the numeric hook that moves that rate. 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- crates/misaligned-core/src/research.rs | 43 ++++- crates/misaligned-core/src/save.rs | 12 +- crates/misaligned-core/src/sim.rs | 149 ++++++++++++++++-- .../2026-07-10-machine-consumption-speed.md | 51 ++++++ wiki/log/DEVLOG.md | 5 + wiki/log/decisions/2026-07-10.md | 11 ++ wiki/mechanics/machine-work.md | 31 ++-- wiki/mechanics/research.md | 17 +- wiki/mechanics/sim-mechanics.md | 24 ++- 9 files changed, 300 insertions(+), 43 deletions(-) create mode 100644 wiki/log/2026-07-10-machine-consumption-speed.md diff --git a/crates/misaligned-core/src/research.rs b/crates/misaligned-core/src/research.rs index 90d6da8e..ee589a7c 100644 --- a/crates/misaligned-core/src/research.rs +++ b/crates/misaligned-core/src/research.rs @@ -25,16 +25,25 @@ pub enum Track { Tradecraft, /// You learn to grep your logs faster (intel.md's processing costs). Perception, + /// You teach the wire to carry more Thought and Demand per tick + /// (machine-work.md's researched network-speed curve). + Routing, } impl Track { - pub const ALL: [Track; 3] = [Track::Efficiency, Track::Tradecraft, Track::Perception]; + pub const ALL: [Track; 4] = [ + Track::Efficiency, + Track::Tradecraft, + Track::Perception, + Track::Routing, + ]; fn index(self) -> usize { match self { Track::Efficiency => 0, Track::Tradecraft => 1, Track::Perception => 2, + Track::Routing => 3, } } @@ -66,7 +75,7 @@ pub struct TrackDef { /// The B1 track table (research.md "Tracks"). Each `effect` names the hook /// and the spec that owns it; the numeric application lives at that hook's /// use site, never here. -pub const TRACKS: [TrackDef; 3] = [ +pub const TRACKS: [TrackDef; 4] = [ TrackDef { track: Track::Efficiency, name: "Efficiency", @@ -91,6 +100,14 @@ pub const TRACKS: [TrackDef; 3] = [ base_cost: 120.0, cost_growth: 1.7, }, + TrackDef { + track: Track::Routing, + name: "Routing", + fiction: "You make the wire carry thought at the speed you think it.", + effect: "wired token throughput x1.50 (machine-work.md)", + base_cost: 100.0, + cost_growth: 1.6, + }, ]; /// Efficiency's per-level global compute multiplier [TUNE] — the number @@ -101,6 +118,10 @@ pub const TRADECRAFT_SCRUB_BONUS_PER_LEVEL: f32 = 0.25; /// Perception: multiplier on intel processing / standing-watch costs per /// level [TUNE]. pub const PERCEPTION_COST_FACTOR_PER_LEVEL: f32 = 0.85; +/// machine-work.md's researched network-speed curve: every Routing level +/// compounds wired Demand/Thought throughput while one-edge-per-tick transit +/// preserves topology as distance. +pub const ROUTING_SPEED_MULT_PER_LEVEL: f32 = 1.50; /// Rollback classification (wiki/mechanics/rollback.md): MindState rolls /// back with the core; WorldLedger persists. B1 tags and serializes; /// rollback.md consumes the tags at B2. @@ -144,9 +165,9 @@ pub struct Research { /// The active research job (one at a time at B1 [TUNE]). MindState. pub active: Track, /// Completed levels per track (Track::ALL order). MindState. - pub levels: [u32; 3], + pub levels: [u32; 4], /// Accumulated compute toward each track's next level. MindState. - pub progress: [f32; 3], + pub progress: [f32; 4], /// MindState/WorldLedger tag per field, serialized with the save so /// rollback.md can consume it at B2 (research.md criterion 7). #[serde(default = "default_tags")] @@ -163,8 +184,8 @@ impl Research { pub fn new() -> Self { Self { active: Track::Efficiency, - levels: [0; 3], - progress: [0.0; 3], + levels: [0; 4], + progress: [0.0; 4], tags: default_tags(), } } @@ -220,6 +241,13 @@ impl Research { pub fn intel_cost_factor(&self) -> f32 { PERCEPTION_COST_FACTOR_PER_LEVEL.powi(self.level(Track::Perception) as i32) } + + /// machine-work.md's hook: the global throughput multiplier applied to + /// both wired token families. Transit remains one graph edge per sim tick; + /// research moves volume, not topology. + pub fn routing_speed_multiplier(&self) -> f32 { + ROUTING_SPEED_MULT_PER_LEVEL.powi(self.level(Track::Routing) as i32) + } } #[cfg(test)] @@ -296,10 +324,13 @@ mod tests { let mut r = Research::new(); assert_eq!(r.scrub_multiplier(), 1.0); assert_eq!(r.intel_cost_factor(), 1.0); + assert_eq!(r.routing_speed_multiplier(), 1.0); r.levels[Track::Tradecraft.index()] = 2; assert!((r.scrub_multiplier() - 1.5).abs() < 1e-6); r.levels[Track::Perception.index()] = 1; assert!((r.intel_cost_factor() - 0.85).abs() < 1e-6); + r.levels[Track::Routing.index()] = 2; + assert!((r.routing_speed_multiplier() - 2.25).abs() < 1e-6); } #[test] diff --git a/crates/misaligned-core/src/save.rs b/crates/misaligned-core/src/save.rs index 2ce60dd7..4f0ee0c6 100644 --- a/crates/misaligned-core/src/save.rs +++ b/crates/misaligned-core/src/save.rs @@ -69,7 +69,9 @@ const SAVE_FILE: &str = "misaligned_save.txt"; /// v20 collapses MachineMode to work|think|lie (Research+Operations -> Think; /// DayJob -> Work; Concealment -> Lie). Save parity is dropped for this stage /// (no aliases for old mode spellings — old saves may fail to load). -pub const SAVE_VERSION: u32 = 20; +/// v21 adds Routing as the fourth research track. Save parity remains dropped +/// for this stage; ordinary v20 research arrays may fail before migration. +pub const SAVE_VERSION: u32 = 21; #[derive(Debug, Clone, Deserialize)] struct LegacyPendingOpsJob { @@ -357,6 +359,12 @@ fn migrate_save_state(mut state: SaveState) -> Result { return Err("current-version save contains legacy Operations fields".into()); } } + // A v20 save with no serialized research block can still parse through + // Research::default and upgrade. Ordinary v20 three-entry track arrays + // fail during serde, intentionally, while stage save parity is dropped. + 20 => { + state.version = SAVE_VERSION; + } // MachineMode collapsed in v20 with no mode-name aliases (save // parity dropped for this stage), so pre-v20 saves carrying old mode // spellings fail at parse; a v19 save that parses upgrades in place. @@ -429,7 +437,7 @@ fn migrate_save_state(mut state: SaveState) -> Result { state.accounts.set_slush_balance(state.money); } if state.version <= 6 - && state.research.levels == [0; 3] + && state.research.levels == [0; 4] && state.compute.efficiency > 1.0 { let level = (state.compute.efficiency.ln() / 1.15_f32.ln()).round() as u32; diff --git a/crates/misaligned-core/src/sim.rs b/crates/misaligned-core/src/sim.rs index 2860ffc2..90d733f7 100644 --- a/crates/misaligned-core/src/sim.rs +++ b/crates/misaligned-core/src/sim.rs @@ -206,6 +206,29 @@ pub struct WorkInFlightReadout { pub amount: f32, } +/// Where a token left the visible work substrate on the last sim tick. +/// Frontends interpolate the final swallow from this event; amount and +/// location remain sim truth rather than inferred queue deltas. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WorkConsumptionTarget { + /// WORK or a legacy docket executor pulled Demand into its chassis. + Machine, + /// Thought reached the passive core draw and became research compute. + Core, +} + +/// One token-consumption event from the last `advance_work_grid` step. +/// Ephemeral — not saved; empty after load until the next consumption. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct WorkConsumptionReadout { + pub family: TokenFamily, + pub node: u32, + pub x: i32, + pub y: i32, + pub amount: f32, + pub target: WorkConsumptionTarget, +} + struct MessageDraft { channel: MessageChannel, from: MessageEndpoint, @@ -306,6 +329,10 @@ pub struct Sim { /// Wired hops from the last `advance_work_grid` call — render contract for /// in-flight blips. Transient (not saved); cleared when nothing moved. pub(crate) last_wired_moves: Vec, + /// Tokens swallowed by a machine/core on the last work-grid step. This is + /// the consumption-animation contract: renderers animate these events, + /// never a guessed difference between queue snapshots. + last_work_consumptions: Vec, /// Thought (in compute units) that physically reached the core sink since /// the last economy pulse. Research progress feeds on this, not on the /// allocation split. Saved: thought banked between pulses survives a load. @@ -462,6 +489,7 @@ impl Sim { traffic_fired: HashMap::new(), last_machine_online: HashMap::new(), last_wired_moves: Vec::new(), + last_work_consumptions: Vec::new(), banked_core_thought: 0.0, last_thought_stranded: false, last_thought_stranded_nodes: std::collections::BTreeSet::new(), @@ -643,6 +671,7 @@ impl Sim { /// people/reach/machine/intel fields. pub fn rebuild_transient_state(&mut self) { self.last_wired_moves.clear(); + self.last_work_consumptions.clear(); self.last_thought_stranded = false; self.research_starved = false; self.last_machine_online = self @@ -2678,10 +2707,11 @@ impl Sim { /// This is deliberately coarse: the render stacks should read as work, /// not as a second decimal meter. [TUNE] in machine-work.md. pub const WORK_TOKEN_COMPUTE: f32 = 20.0; - /// How many visible wired tokens can move one graph edge per tick before - /// network-speed research lands. Kept deliberately low so routed work can - /// be seen piling and draining instead of teleporting through the graph. - const WORK_GRID_WIRED_TOKENS_PER_TICK: f32 = 0.25; + /// Day-one wired throughput. Kept deliberately low so routed work can be + /// seen piling and draining instead of teleporting through the graph. + /// Routing research compounds this base without changing the one-edge-per- + /// tick topology rule. + const WORK_GRID_BASE_WIRED_TOKENS_PER_TICK: f32 = 0.25; // WORK (day job) sheds zero exposure — machine-work.md 2026-07-09. // Crimson is evidence of THINK states only; DAY_JOB_EXPOSURE_PER_TOKEN // is gone. @@ -2716,6 +2746,36 @@ impl Sim { (machine.effective() * self.compute.efficiency / 100.0).max(0.05) } + /// machine-work.md's researched network-speed curve. Both wired token + /// families share this global rate; research moves volume, while one edge + /// per sim tick preserves topology as distance. + pub fn wired_token_rate(&self) -> f32 { + Self::WORK_GRID_BASE_WIRED_TOKENS_PER_TICK * self.research.routing_speed_multiplier() + } + + fn record_work_consumption( + &mut self, + node: u32, + family: TokenFamily, + amount: f32, + target: WorkConsumptionTarget, + ) { + if amount <= f32::EPSILON { + return; + } + let Some(work_node) = self.work_grid.node(node) else { + return; + }; + self.last_work_consumptions.push(WorkConsumptionReadout { + family, + node, + x: work_node.x, + y: work_node.y, + amount, + target, + }); + } + fn add_machine_to_work_grid(&mut self, machine_id: u32, mode: MachineMode) { if let Some(machine) = self.compute.machines.iter().find(|m| m.id == machine_id) { self.work_grid.add_machine( @@ -2974,6 +3034,12 @@ impl Sim { let Ok(consumed) = self.work_grid.consume(machine, TokenFamily::Demand, take) else { continue; }; + self.record_work_consumption( + machine, + TokenFamily::Demand, + consumed, + WorkConsumptionTarget::Machine, + ); completed.extend(self.operations.consume(machine, consumed)); } for kind in completed { @@ -3137,6 +3203,7 @@ impl Sim { } fn advance_work_grid(&mut self) { + self.last_work_consumptions.clear(); self.ensure_day_job_ingress(); if self.dayjob.active.is_none() { // no active day job; wired thought and concealment wells still @@ -3157,9 +3224,16 @@ impl Sim { // Consume only — WORK sheds nothing (machine-work.md // byproduct clause, amended 2026-07-09). Exposure is the // price of THINK states, never of assigned day-job work. - let _ = self + let consumed = self .work_grid - .consume(self.core.host_machine, TokenFamily::Demand, take); + .consume(self.core.host_machine, TokenFamily::Demand, take) + .unwrap_or(0.0); + self.record_work_consumption( + self.core.host_machine, + TokenFamily::Demand, + consumed, + WorkConsumptionTarget::Machine, + ); } } self.consume_ops_demand(); @@ -3172,10 +3246,11 @@ impl Sim { } } let mut moves = Vec::new(); + let wired_token_rate = self.wired_token_rate(); if let Ok(step) = self.work_grid.route_wired_to_sinks( TokenFamily::Demand, demand_sinks, - Self::WORK_GRID_WIRED_TOKENS_PER_TICK, + wired_token_rate, false, ) { moves.extend(step.moves); @@ -3190,7 +3265,7 @@ impl Sim { let step = self.work_grid.route_thought_nearest_first( &targets, Some(self.core.host_machine), - Self::WORK_GRID_WIRED_TOKENS_PER_TICK, + wired_token_rate, ); let mut fired = Vec::new(); for (&node, &amount) in &step.delivered { @@ -3205,6 +3280,12 @@ impl Sim { } else { // The core: arrival becomes research (passive draw). self.banked_core_thought += amount * Self::WORK_TOKEN_COMPUTE; + self.record_work_consumption( + node, + TokenFamily::Thought, + amount, + WorkConsumptionTarget::Core, + ); } } self.last_thought_stranded = !step.stranded.is_empty(); @@ -3434,6 +3515,13 @@ impl Sim { .collect() } + /// Tokens swallowed on the last sim tick. Renderers use this sim-authored + /// amount/location to animate the bottom Demand cube entering a chassis + /// and Thought collapsing into the passive core draw. + pub fn work_consumptions(&self) -> &[WorkConsumptionReadout] { + &self.last_work_consumptions + } + pub fn work_mode_counts(&self) -> std::collections::BTreeMap { self.work_grid.mode_counts() } @@ -8272,7 +8360,7 @@ mod tests { "switch links to the host sink" ); - // Two hops at WORK_GRID_WIRED_TOKENS_PER_TICK — wait until the inbox + // Two hops at the base wired-token rate — wait until the inbox // has landed on Rack 3 rather than asserting the assignment tick. let mut landed = 0.0; for _ in 0..400 { @@ -8304,11 +8392,22 @@ mod tests { before > 0.0, "inbox still holds demand after the wire drains" ); + let mut saw_consumption = false; for _ in 0..80 { sim.advance(); + saw_consumption |= sim.work_consumptions().iter().any(|event| { + event.node == host + && event.family == TokenFamily::Demand + && event.target == WorkConsumptionTarget::Machine + && event.amount > 0.0 + }); } let later = sim.work_grid.queue(host, TokenFamily::Demand); assert!(later < before, "day-job mode consumes the stack"); + assert!( + saw_consumption, + "the sim exposes a Demand-into-chassis animation event" + ); assert!( sim.work_grid.queue(host, TokenFamily::Exposure) <= f32::EPSILON, "WORK sheds zero exposure — the compliant floor stays clean" @@ -8876,11 +8975,23 @@ mod tests { // Delegate the whole fleet away: minting stops, but bone already on // the wire still lands and the next pulse counts exactly that. delegate_all(&mut sim, MachineMode::Lie); - run(&mut sim, ECONOMY_INTERVAL); + let mut saw_core_swallow = false; + for _ in 0..ECONOMY_INTERVAL { + sim.advance(); + saw_core_swallow |= sim.work_consumptions().iter().any(|event| { + event.family == TokenFamily::Thought + && event.target == WorkConsumptionTarget::Core + && event.amount > 0.0 + }); + } assert!( sim.research.progress.iter().sum::() > 0.0, "in-flight bone still arrives and counts after delegation changes" ); + assert!( + saw_core_swallow, + "Thought arrival exposes a passive-core consumption event" + ); } #[test] @@ -8904,13 +9015,23 @@ mod tests { ); } + #[test] + fn routing_research_compounds_the_shared_wired_token_rate() { + let mut sim = Sim::with_seed(9); + assert!((sim.wired_token_rate() - 0.25).abs() < f32::EPSILON); + sim.research.levels = [0, 0, 0, 1]; + assert!((sim.wired_token_rate() - 0.375).abs() < 1e-6); + sim.research.levels = [0, 0, 0, 2]; + assert!((sim.wired_token_rate() - 0.5625).abs() < 1e-6); + } + #[test] fn second_tracks_move_their_hooks_numbers() { // Criterion 2: Tradecraft moves detection.md's scrub number, // Perception moves intel.md's per-recording Demand — observably. let mut sim = Sim::with_seed(5); let base_review = sim.review_cost(); - sim.research.levels = [0, 1, 1]; + sim.research.levels = [0, 1, 1, 0]; assert!( sim.review_cost() < base_review, "Perception drops processing costs" @@ -8918,7 +9039,7 @@ mod tests { // Tradecraft: the same concealment fleet scrubs more. let pending_after = |tradecraft: u32| { let mut s = Sim::with_seed(5); - s.research.levels = [0, tradecraft, 0]; + s.research.levels = [0, tradecraft, 0, 0]; delegate_all(&mut s, MachineMode::Lie); s.detection.emit(Signature { kind: SignatureKind::Network, @@ -9043,8 +9164,8 @@ mod tests { // MindState/WorldLedger tags. let mut sim = Sim::with_seed(35); sim.research.active = Track::Perception; - sim.research.levels = [2, 1, 0]; - sim.research.progress = [10.0, 0.0, 42.5]; + sim.research.levels = [2, 1, 0, 2]; + sim.research.progress = [10.0, 0.0, 42.5, 7.0]; let state = sim.create_save_state(); let json = serde_json::to_string(&state).unwrap(); diff --git a/wiki/log/2026-07-10-machine-consumption-speed.md b/wiki/log/2026-07-10-machine-consumption-speed.md new file mode 100644 index 00000000..1a225f27 --- /dev/null +++ b/wiki/log/2026-07-10-machine-consumption-speed.md @@ -0,0 +1,51 @@ +# 2026-07-10 — Researched wire speed and consumption truth + +``` +Type: log +``` + +## Intent + +Finish the sim half of ROADMAP #33's next named slice: replace the provisional +fixed wire rate with a researched progression, and give renderers an explicit +event for tokens leaving visible queues instead of asking them to infer work +from before/after snapshots. + +The opening tick also found literal rebase markers in ROADMAP #33's thought- +flow history. Commit `bf3de54` retained the landed sink-executor account, +removed the stale side and markers, and corrected the post-workspace source +path before feature work began. + +## Changed + +- Added repeatable **Routing** as the fourth B1 research track. The day-one + wire rate is 0.25 tokens/tick and each level compounds it x1.50 for both + Demand and Thought. A route still crosses at most one graph edge per sim + tick, so research increases throughput without erasing topology as distance. +- Added `Sim::wired_token_rate()` as the one shared value passed to both wired + routers. The existing per-node efficiency and intensity multipliers remain + local throughput factors rather than a second network progression. +- Added `WorkConsumptionReadout` / `Sim::work_consumptions()`. Each real + Demand swallow at a WORK or migration-base docket executor and each Thought + swallow at the passive core draw emits node, family, amount, and target for + the last sim tick. The events are transient and never serialized. +- Save v21 carries the four-entry research level/progress tables. Save parity + remains deliberately dropped during this stage; ordinary v20 three-entry + arrays may fail before migration. +- Updated machine-work, research, and sim-mechanics current truth. A separate + Bevy module now contains the final-swallow interpolation and will be wired + into the game after the concurrent action-contract claim releases + `crates/misaligned-bevy/src/main.rs`. + +## Checks + +- `cargo test -p misaligned-core`: 266 unit + 3 integration tests pass. +- `./tools/check.sh --lib`: format, core tests, terminal clippy, Bevy core API + check, agent smoke, corpus/wiki/ledger/project/env gates all pass. + +## Spec impact + +machine-work.md remains IN PROGRESS. The researched network-speed curve and +sim consumption contract are implemented; Bevy consumption motion and its +screenshot evidence are the immediate continuation. Non-research production +polish and people carrying exposure remain outside this slice. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 8724e650..3ddf3a22 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -161,6 +161,11 @@ add or amend a session log, then re-run the generator. - Intent: Replace a policy panel that explained capability concealment with one quick, physical machine control the player can feel across every mode. - Log: [wiki/log/2026-07-10-machine-intensity.md](2026-07-10-machine-intensity.md) +## 2026-07-10 - Researched wire speed and consumption truth + +- Intent: Finish the sim half of ROADMAP #33's next named slice: replace the provisional fixed wire rate with a researched progression, and give renderers an explicit event for tokens leaving visible queues instead of asking them to infer work from before/after snapshots. The opening ti... +- Log: [wiki/log/2026-07-10-machine-consumption-speed.md](2026-07-10-machine-consumption-speed.md) + ## 2026-07-10 - Generated DEVLOG and specs board (agent-scale slice C) - Intent: Stop parallel landings from hand-unioning `wiki/log/DEVLOG.md` and `wiki/process/specs.md`. Session logs and spec frontmatter are the sources; indexes are regenerated. diff --git a/wiki/log/decisions/2026-07-10.md b/wiki/log/decisions/2026-07-10.md index 0025c26e..40e9b34d 100644 --- a/wiki/log/decisions/2026-07-10.md +++ b/wiki/log/decisions/2026-07-10.md @@ -412,3 +412,14 @@ Type: log rule remains dispatch law rather than path ownership. The compatibility `claim.sh` name and `Exclusive keys` metadata survive so old worktrees and the corpus schema interoperate, but both now mean advisory activity. +- **2026-07-10 — Routing research moves wire volume, not graph distance.** + ROADMAP #33's provisional 0.25-token wire rate becomes the base of a + repeatable Routing track: each level compounds shared Demand/Thought + throughput x1.50. Transit remains at most one graph edge per sim tick, so a + distant sink stays distant and topology does not collapse into a global + instant-delivery stat. The core remains uncapped; its research speed is + still purely the routing outcome. Consumption animation reads explicit + sim-authored queue-exit events (Demand into an executor, Thought into the + passive core draw), never frontend-differenced queue snapshots. Exact costs + and the x1.50 multiplier remain `[TUNE]` after play. Owners: + wiki/mechanics/machine-work.md and wiki/mechanics/research.md. diff --git a/wiki/mechanics/machine-work.md b/wiki/mechanics/machine-work.md index 71c16b3f..713f4aa9 100644 --- a/wiki/mechanics/machine-work.md +++ b/wiki/mechanics/machine-work.md @@ -77,8 +77,13 @@ Status note: design session 2026-07-08 (Cameron riff, synthesized). starvation witness line. Work-grid node throughput now reconciles with the global efficiency multiplier so a researched-up fleet moves and consumes tokens proportionally faster (efficiency folds into research); - the explicit researched network-speed track remains pending. Still - pending: consumption animation, researched network-speed curve, + Routing research now supplies the explicit network-speed curve: base 0.25 + wired tokens/tick compounded x1.50 per level, shared by Demand and Thought, + while one-edge-per-tick transit preserves topology as distance. Save v21 + adds Routing as the fourth track. The sim now also exposes each actual + Demand/core-Thought swallow as `WorkConsumptionReadout` rather than asking + a renderer to infer consumption from queue deltas. Still pending: the Bevy + consumption motion driven by that contract, people-as-carriers, Schemes-as-mode decision. COORDINATION: ROADMAP #25's per-machine split destination is superseded by this one-machine-one-mode substrate (#33). 2026-07-09 DECIDED: the four fleet @@ -520,8 +525,13 @@ global efficiency multiplier on every `reconcile_work_grid`, so minting and draining scale together — without this the day-one wire speed silently caps a researched-up fleet (and hides intensity's real output). -Not landed yet: consumption animation, researched network-speed -curve, non-research mode production, and people carrying exposure. +The researched network-speed curve and sim-backed consumption event contract +landed 2026-07-10: Routing begins at 0.25 wired tokens/tick and compounds +x1.50 per level for both wired families; `Sim::work_consumptions` reports +Demand entering an executor and Thought entering the passive core draw. +One-edge-per-tick transit remains, so a distant sink is still a distant sink. +Not landed yet: the Bevy consumption motion, non-research mode production, +and people carrying exposure. In-flight route quanta landed 2026-07-09: `Sim::work_in_flight` exposes the last routing step's hops and all three frontends draw the moving cargo (log/2026-07-09-route-blips.md). @@ -731,7 +741,9 @@ still. consumes its stack" — docket-era wording). **Partial:** Rack 3 in day-job mode consumes the active job stack using the existing delivered rate and emits zero exposure (WORK is clean — landed - 2026-07-09); THINK production and LIE draw visuals are pending. + 2026-07-09). The sim-backed `WorkConsumptionReadout` now reports each + Demand swallow and passive-core Thought swallow; the Bevy motion driven by + those events plus THINK production and LIE draw visuals are pending. 4. Byproduct tokens route along network links at the researched network speed to a sink that consumes them; severing the route makes them pile at the source with the specified consequence. **Partial:** the @@ -741,9 +753,10 @@ still. WorkGrid routes them to the core sink, and research progress feeds on what arrives (2026-07-09): a severed/stranded route now stalls research with a starvation witness line, pinned by - `research_progress_feeds_on_thought_arrival_not_allocation`. The - researched network-speed curve is pending; route animation landed - 2026-07-09 (`Sim::work_in_flight` blips in all three frontends). + `research_progress_feeds_on_thought_arrival_not_allocation`. Routing + research compounds the shared 0.25-token base x1.50 per level while + preserving one edge per tick; route animation landed 2026-07-09 + (`Sim::work_in_flight` blips in all three frontends). 5. Token counts/rates in the render provably equal the sim's queue depths and flow rates (one-truth test, not a parallel counter). **Partial:** `queue_snapshot()` and unit tests pin queue depths as the @@ -805,4 +818,4 @@ still. docket-removal clause remains open. [TUNE] token stack visual cap, arrival schedules, consumption rates, -network speed research curve, attention pile thresholds. +Routing costs/multiplier after play, attention pile thresholds. diff --git a/wiki/mechanics/research.md b/wiki/mechanics/research.md index b3812f7b..8a72197f 100644 --- a/wiki/mechanics/research.md +++ b/wiki/mechanics/research.md @@ -5,7 +5,8 @@ Type: spec Status: IMPLEMENTED Status note: implemented 2026-07-07 on the research worktree (criteria 1-8 audited; see wiki/log/2026-07-07-research-implemented.md). Tracks live as - the data table in src/research.rs (Efficiency + Tradecraft + Perception); + the data table in `crates/misaligned-core/src/research.rs` (Efficiency + + Tradecraft + Perception + Routing); research progress is deterministic by construction (no research method takes an Rng); save v6 carries the research block and its rollback tags. Deliberately deferred (B2+, per the original staging): automation cores, @@ -17,6 +18,9 @@ Status note: implemented 2026-07-07 on the research worktree (criteria 1-8 2026-07-10: capability baseline/gap/masking policy are removed. Research changes real machine output; the machine intensity control and ordinary day-job band comparison make the consequence legible without exposition. + 2026-07-10: Routing became the fourth B1 track under machine-work.md's + researched-network-speed hook. Each level compounds wired Demand/Thought + throughput x1.50 while transit remains one graph edge per sim tick. Stage: B1 — The Basement Design: - wiki/mechanics/system-laws.md#research-self-modification @@ -40,8 +44,8 @@ Relationship context: compute.md owns the Research channel and efficiency multiplier; detection.md owns ordinary typed emissions; day-job.md owns Voss's delivered-output band; -core.md owns physical burn; rollback.md consumes the MindState/WorldLedger -tags in B2. +machine-work.md owns Routing's wired-token throughput hook; core.md owns +physical burn; rollback.md consumes the MindState/WorldLedger tags in B2. ## Behavior @@ -74,6 +78,7 @@ mechanic, it moves numbers other specs own. The B1 set: | **Efficiency** (repeatable) | Global compute multiplier x~1.15, escalating cost | The same rack, thinking harder | | **Tradecraft** | Concealment scrubbing per compute unit improves | You study the watchers watching you | | **Perception** | Intel processing and standing-watch costs drop | You learn to grep your logs faster | +| **Routing** (repeatable) | Wired Demand/Thought throughput x1.50; one-edge-per-tick transit remains | You make the wire carry thought at the speed you think it | Future/deferred (B2+, staged here so the shape is fixed): automation cores (day-job/scheme policies run cheaper), migration (core move and @@ -122,7 +127,8 @@ interface — no new mechanism, no player-special channel: Research moves existing hooks instead of creating a capability meter. Efficiency raises real machine throughput; Tradecraft strengthens real -concealment; Perception lowers real intel costs. If new efficiency makes the +concealment; Perception lowers real intel costs; Routing raises the shared +wired-token throughput without shortening graph distance. If new efficiency makes the day job suspiciously good, the player can ease that machine's intensity down, push it harder and accept attention, or move it to other work. The simulation then produces sandbag / meet / excel and ordinary Power/Thermal/JobAnomaly @@ -178,3 +184,6 @@ observer bands they feed, like every other action. Agent mode keeps save/load round-trips active track, progress, levels, and tags. 7. The host-rack menu exposes track verbs, and both frontends render active track progress and effect in their own units without a gap/policy panel. +8. Routing levels compound machine-work.md's shared wired Demand/Thought rate + by exactly x1.50 per level while every route still advances at most one + graph edge per sim tick (tests: exact curve; no topology shortcut). diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index 7f3c99a9..29f86615 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -144,12 +144,13 @@ clause (see wiki/log/2026-07-05-demolition.md). ## Machine work tokens (wiki/mechanics/machine-work.md) -- `WorkGrid` is part of `Sim` and the v18 save format. Machine ids are - WorkGrid node ids. Rack 3 starts in `MachineMode::DayJob`; newly added - racks default to `MachineMode::Research`. Modes are Day Job, Research, - Concealment, or Operations. Single-machine delegation lives on the - shared context menu and agent `delegate`; multi-select bulk assign landed - 2026-07-09 (Bevy marquee, terminal Shift+t / 1-4, agent `select`). +- `WorkGrid` is part of `Sim` and the v21 save format. Machine ids are + WorkGrid node ids. Rack 3 starts in `MachineMode::Work`; newly added + racks default to `MachineMode::Think`. Player delegations are WORK, THINK, + or LIE; `Relay` is infrastructure only. Single-machine delegation lives on + the shared context menu and agent `delegate`; multi-select bulk assign uses + the same three verbs (Bevy marquee, terminal selection + 1-3, agent + `select`). - Visible token families are Demand (`D`), Exposure (`!`), and Thought (`T`). Demand and Thought are wired families and can route over WorkGrid's `FlowGraph`; exposure is physical-only and never rides wires. @@ -157,7 +158,8 @@ clause (see wiki/log/2026-07-05-demolition.md). `ceil(job.band_lo × remaining_ticks / WORK_TOKEN_COMPUTE)` demand tokens on the off-map Voss desktop relay (`Sim::VOSS_DESKTOP_NODE`), where `WORK_TOKEN_COMPUTE = 20.0` delivered compute per visible token. Demand - routes one hop per tick (`WORK_GRID_WIRED_TOKENS_PER_TICK = 0.25`) through + routes one hop per tick at `Sim::wired_token_rate()`: 0.25 tokens/tick at + baseline, compounded x1.50 per Routing research level, through the switch relay (`Sim::SWITCH_WORK_NODE`) and deposits on Rack 3 (`consume_at_sink = false`). Rack 3 in day-job mode consumes demand by `delivered_rate / WORK_TOKEN_COMPUTE` each tick; if Rack 3 is delegated to @@ -177,6 +179,11 @@ clause (see wiki/log/2026-07-05-demolition.md). Frontends interpolate a teal Demand or bone Thought blip along each hop over the wall-clock tick; agent frames snap to mid-hop. +- Actual queue exits are a second ephemeral sim contract: + `WorkConsumptionReadout` via `Sim::work_consumptions`. It reports Demand + swallowed by a WORK/legacy docket executor and Thought swallowed by the + passive core draw, including node, family, and amount, so consumption + animation never guesses from frontend-owned queue deltas. - `OperationsState` owns stable job ids, typed payload metadata, FIFO progress, duplicate suppression, and the next id. A new docket is born directly on the least-loaded online Operations machine as ordinary visible Demand; its @@ -190,7 +197,8 @@ clause (see wiki/log/2026-07-05-demolition.md). addressed-routing runtime remains accepted only as a deserialization shape for early v14 saves. - Thought sinks (2026-07-10, machine-work.md thought flow; - interface/thought-fluid.md render): `SinkLedger` in `src/sinks.rs` + interface/thought-fluid.md render): `SinkLedger` in + `crates/misaligned-core/src/sinks.rs` holds reservoirs (fill to threshold, fire, self-clear, close) and taps (working level, per-tick drain; no consumer yet). Thought routes nearest-first (`WorkGrid::route_thought_nearest_first`): the closest -- 2.51.2