diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index fd639dc8..40ba07ca 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -1062,6 +1062,10 @@ struct TokenMarker { struct SidebarScrollArea; #[derive(Component, Clone, Copy)] enum SidebarText { + /// Crown metric value — large ops/sec number (clinical-frame.md). + OpsCrown, + /// Quiet unit label under the crown ("ops/sec"). + OpsCrownUnit, Header, Nudge, Focus, @@ -5539,6 +5543,25 @@ fn setup_ui(mut commands: Commands) { BorderColor::all(Color::srgba(0.20, 0.20, 0.19, 0.55)), )) .with_children(|p| { + // Crown metric first (clinical-frame.md persistent layer): one + // large ops/sec number — how fast the brain is going. Quiet unit + // label under it; no box, no amber chrome. + p.spawn(( + Node { + width: Val::Percent(100.0), + flex_direction: FlexDirection::Column, + padding: UiRect::axes(Val::Px(2.0), Val::Px(2.0)), + row_gap: Val::Px(0.0), + flex_shrink: 0.0, + ..default() + }, + BackgroundColor(Color::NONE), + )) + .with_children(|crown| { + spawn_sidebar_text(crown, SidebarText::OpsCrown, 30.0, BONE); + spawn_sidebar_text(crown, SidebarText::OpsCrownUnit, 10.0, DIM); + }); + // Header sits directly on the rail field: no box, no amber // frame — branding and clocks are quiet chrome; the nudge is // the one causal line and reads brighter (clinical-frame.md). @@ -6104,8 +6127,17 @@ fn fact_source(source: &FactSource) -> String { } } +/// Crown metric value (clinical-frame.md): effective ops/sec at the current +/// tick clock. Paused runs report 0 so a frozen world does not claim speed. +fn sidebar_ops_crown_text(game: &Game) -> String { + let tick_ms = if game.paused { 0 } else { game.tick_ms }; + let ops = game.sim.effective_ops_per_sec(tick_ms); + Sim::format_ops_per_sec(ops) +} + /// Pinned sidebar status: the player should not lose clock, run state, current /// representation, or the one actionable nudge while scanning the ops cards. +/// The ops/sec crown sits above this block as its own large readout. fn sidebar_header_text(game: &Game, material: bool) -> String { let sim = &game.sim; let mode = if material { "MATERIAL" } else { "SENSORIUM" }; @@ -6692,6 +6724,8 @@ fn render_ui( for (kind, mut text) in sidebar_texts.iter_mut() { text.0 = ascii_ui(&match *kind { + SidebarText::OpsCrown => sidebar_ops_crown_text(&game), + SidebarText::OpsCrownUnit => "ops/sec".to_string(), SidebarText::Header => sidebar_header_text(&game, mode.material), SidebarText::Nudge => sidebar_nudge_text(&game.sim), SidebarText::Focus => sidebar_focus_text(&game), diff --git a/crates/misaligned-core/src/sim.rs b/crates/misaligned-core/src/sim.rs index de8db2d2..31711992 100644 --- a/crates/misaligned-core/src/sim.rs +++ b/crates/misaligned-core/src/sim.rs @@ -4134,6 +4134,52 @@ impl Sim { self.last_research_rate } + /// Effective operations per sim tick — productive THINK yield (the ops + /// channel plus the research remainder) as of the last fleet rate refresh. + /// clinical-frame.md's crown metric converts this to wall-clock ops/sec + /// via the frontend tick duration; more THINK machines and efficiency make + /// it climb (the growth drive). + pub fn effective_ops_per_tick(&self) -> f32 { + self.last_research_rate + self.last_operations_rate + } + + /// Wall-clock ops/sec from a tick duration in milliseconds. Zero tick + /// duration (or pause presentation) reports 0 so the number never lies + /// about a frozen clock. + pub fn effective_ops_per_sec(&self, tick_ms: u64) -> f32 { + if tick_ms == 0 { + return 0.0; + } + self.effective_ops_per_tick() * (1000.0 / tick_ms as f32) + } + + /// Format ops/sec so magnitude stays legible as the number grows + /// comically large rather than compacting into scientific notation + /// (clinical-frame.md crown metric [TUNE]). + pub fn format_ops_per_sec(ops_per_sec: f32) -> String { + let n = ops_per_sec.max(0.0); + if n < 1_000.0 { + format!("{n:.1}") + } else if n < 1_000_000_000.0 { + // Full integer with thousand separators — the digits *are* the + // fantasy ("I can make the number go up"). + let whole = n.round() as u64; + let raw = whole.to_string(); + let mut out = String::with_capacity(raw.len() + raw.len() / 3); + for (i, ch) in raw.chars().enumerate() { + if i > 0 && (raw.len() - i).is_multiple_of(3) { + out.push(','); + } + out.push(ch); + } + out + } else { + // Beyond a billion, keep three significant groups so growth is + // still visible without a 15-digit rail wrap. + format!("{:.3}B", n / 1_000_000_000.0) + } + } + /// Select the active research track (one job at a time at B1); parked /// progress on other tracks is kept. pub fn set_research_track(&mut self, track: Track) { @@ -10402,4 +10448,40 @@ mod tests { ); assert_eq!(sim.compute.machines.len(), 2); } + + #[test] + fn ops_per_sec_format_keeps_magnitude_legible() { + assert_eq!(Sim::format_ops_per_sec(0.0), "0.0"); + assert_eq!(Sim::format_ops_per_sec(42.3), "42.3"); + assert_eq!(Sim::format_ops_per_sec(12_450.0), "12,450"); + assert_eq!(Sim::format_ops_per_sec(1_234_567.0), "1,234,567"); + assert_eq!(Sim::format_ops_per_sec(2.5e9), "2.500B"); + } + + #[test] + fn effective_ops_climb_with_think_and_zero_when_paused_clock() { + let mut sim = Sim::new(); + // Host starts on WORK: no THINK yield until delegated. + for _ in 0..ECONOMY_INTERVAL { + sim.advance(); + } + assert!( + sim.effective_ops_per_tick() <= f32::EPSILON, + "WORK-only fleet has no ops crown" + ); + let host = sim.core.host_machine; + sim.set_machine_mode(host, MachineMode::Think); + for _ in 0..ECONOMY_INTERVAL { + sim.advance(); + } + assert!( + sim.effective_ops_per_tick() > 0.0, + "THINK produces the crown rate" + ); + assert!( + sim.effective_ops_per_sec(150) > sim.effective_ops_per_tick(), + "wall-clock multiplies by ticks per second" + ); + assert_eq!(sim.effective_ops_per_sec(0), 0.0); + } } diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index 235a9b5f..81fda1b1 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -1665,6 +1665,16 @@ fn fact_source(source: &FactSource) -> String { fn render_sidebar(sim: &Sim, cursor: (i32, i32)) -> Vec { let mut lines = Vec::new(); + // Crown metric (clinical-frame.md). Agent frames have no wall-clock tick + // duration; report ops per sim tick as the rate and label it ops/tick so + // the number stays honest under the command clock. + line( + &mut lines, + &format!( + "ops/tick {}", + Sim::format_ops_per_sec(sim.effective_ops_per_tick()) + ), + ); line(&mut lines, "MISALIGNED"); line( &mut lines, diff --git a/crates/misaligned-terminal/src/ui.rs b/crates/misaligned-terminal/src/ui.rs index b41e9880..4b4c9633 100644 --- a/crates/misaligned-terminal/src/ui.rs +++ b/crates/misaligned-terminal/src/ui.rs @@ -822,6 +822,23 @@ impl UI { r }; + // Crown metric first (clinical-frame.md): effective ops/sec — how + // fast the brain is going. Large bold number, quiet unit. + let ops = if paused { + 0.0 + } else { + sim.effective_ops_per_sec(tick_ms) + }; + put_attr( + stdout, + sx, + row, + &trunc(&Sim::format_ops_per_sec(ops), w), + pal::TEXT, + Attribute::Bold, + )?; + row += 1; + line(stdout, &mut row, "ops/sec", pal::DIM)?; // Identity block. The clock is always on screen. put_attr(stdout, sx, row, "MISALIGNED", pal::AMBER, Attribute::Bold)?; row += 1; diff --git a/wiki/interface/clinical-frame.md b/wiki/interface/clinical-frame.md index e9a9e3b1..62e549e1 100644 --- a/wiki/interface/clinical-frame.md +++ b/wiki/interface/clinical-frame.md @@ -13,13 +13,18 @@ Status note: adopted 2026-07-10 after comparing the live Bevy close frame with floor raised to a porcelain field (0.55->0.74 [TUNE]); Seen wall faces bone/ivory with the cap as the near-black cutaway seam. Before/after/ grayscale evidence: assets/reference/art-direction/b1-clinical-frame- - {before,after,after-grayscale}.png. Still open in this work order: - progressive disclosure of secondary rail detail beyond the existing scroll, - and the [TUNE] sweep against played captures. The current machine language is strong, - but the complete frame still reads as a hero object in a black void beside a - heavy debug rail. This work order makes earned facility form clinical and - world-dominant without weakening epistemic fog, replacing the oblique - material camera, or treating generated text/layout as literal UI design. + {before,after,after-grayscale}.png. 2026-07-11: crown metric landed — + effective ops/sec is the large bone number at the top of Bevy/terminal + rails (`Sim::effective_ops_per_tick` = THINK yield; wall-clock via tick_ms; + magnitude-preserving format; agent frames report ops/tick under the + command clock). Still open in this work order: progressive disclosure of + secondary rail detail beyond the existing scroll, and the [TUNE] sweep + against played captures (including ops/sec type size). The current machine + language is strong, but the complete frame still reads as a hero object in + a black void beside a heavy debug rail. This work order makes earned + facility form clinical and world-dominant without weakening epistemic fog, + replacing the oblique material camera, or treating generated text/layout as + literal UI design. Stage: B1 — The Basement Work order: clinical-frame Work priority: 34 @@ -141,12 +146,16 @@ its resting presentation becomes narrower and quieter. The always-visible layer answers only the immediate operational questions: -- **the crown metric (decided 2026-07-10): effective operations per - second, one large number at the top of the rail** — how fast the brain - is going. It is the identity readout and the growth drive: more - machines make it climb, and its formatting must let magnitude be felt - as it grows comically large rather than compacting it away - ([TUNE] units/formatting); +- **the crown metric (decided 2026-07-10; runtime 2026-07-11): effective + operations per second, one large number at the top of the rail** — how + fast the brain is going. Runtime: `Sim::effective_ops_per_tick` is the + productive THINK yield (ops channel + research remainder after the fleet + rate refresh); frontends multiply by `1000 / tick_ms` for wall-clock + ops/sec (0 while paused). More THINK machines and efficiency research + make it climb. Formatting keeps full digit groups with thousand + separators until a billion, then `B` suffixes — magnitude is felt rather + than compacted into scientific notation ([TUNE] units/type size). Agent + frames report the same rate as ops/tick under the command clock; - current time/run state and representation; - objective and next pressure; - focused anchor and its most consequential live fact; diff --git a/wiki/log/2026-07-11-ops-per-sec-crown.md b/wiki/log/2026-07-11-ops-per-sec-crown.md new file mode 100644 index 00000000..9e2dd5ac --- /dev/null +++ b/wiki/log/2026-07-11-ops-per-sec-crown.md @@ -0,0 +1,25 @@ +# Crown metric: ops/sec at the top of the rail + +``` +Type: log +``` + +- Intent: land the clinical-frame crown metric — one large effective + ops/sec number at the top of the instrument rail. +- Changed: + - `Sim::effective_ops_per_tick` / `effective_ops_per_sec` / + `format_ops_per_sec` (THINK yield → wall-clock rate; magnitude-preserving + formatting). + - Bevy rail: large bone number + quiet `ops/sec` label above the header. + - Terminal and agent sidebars surface the same rate (agent: ops/tick). + - clinical-frame.md status note + persistent-layer clause amended. +- Design/spec impact: implements + `wiki/interface/clinical-frame.md#instrument-rail-contract` crown metric + (decided 2026-07-10). Type size and [TUNE] remain open under the clinical- + frame work order. +- Checks: unit tests for format and THINK climb; `./tools/check.sh + --frontend` (or `--lib` if core-gated). + +Defense: Implements clinical-frame.md persistent-layer crown metric: one +large effective ops/sec readout at the top of the rail as the growth drive +for how fast the brain is going. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 8ab6b397..02428e69 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -31,6 +31,11 @@ add or amend a session log, then re-run the generator. - Intent: Correct an overbroad interpretation of the adopted Foundation compute form. The machine chassis needed to become consistent across machine-focused game, spec, and reference surfaces; Cameron's separately selected homepage image did not need to be replaced. - Log: [wiki/log/2026-07-11-restore-selected-homepage-front.md](2026-07-11-restore-selected-homepage-front.md) +## 2026-07-11 - Crown metric: ops/sec at the top of the rail + +- Intent: (see session log) +- Log: [wiki/log/2026-07-11-ops-per-sec-crown.md](2026-07-11-ops-per-sec-crown.md) + ## 2026-07-11 - Intel processing migrates to thought sinks - Intent: (see session log)