Stop the shell asserting things that are not true

The footer was rebuilt on a real ledger two commits ago. The rest of the shell
was never audited the same way, and a multi-agent pass over it found the same
class of defect everywhere else:

- A sidebar card reading "Buzz · lumbridgecode / connected · signed identity"
  in the success colour. lumbridge-buzz is not a dependency of this binary.
- A saved host "amd-server", and a WORKTREES section with five entries and a
  working selector, backed by a lumbridge-git crate that does not exist.
- A first-run workspace of six panes announcing "Codex · runtime / metal ·
  Tailscale SSH", "Claude Code · UI / MacBook Air · local" and a Pi pane on a
  saved host. Every one of them was a /bin/sh, and the machine names were this
  developer's.
- A declared "Pi · spark-1 · laguna-s-2.1" usage profile with no probe of any
  kind behind it. Declaring a profile promises the gap is real; that one could
  never be filled.
- FOOTER_CENTER = "Codex · ChatGPT subscription · 62% window remaining",
  rendered by the Floem shell. Decision 0013 names that exact form as the thing
  that must never be shown.
- The header's PTY count painted green unconditionally, so "0/5 LIVE PTYS" read
  as success. runtime_rows already had the right rule three hundred lines away.
- A browser panel describing itself as "An isolated system-web-engine surface"
  on the chooser screen where you pick it. There is no web engine in this build.

First run is now three real local shells, and a pane claims a harness when one
has actually been launched into it. The seed mapping stays for when that is
possible.

Also removes the only unsafe block in the shell: a test set LUMBRIDGE_*_PROBE
through the environment, which needs unsafe under edition 2024 and silently
disabled both probes for every other test in the binary. Replaced with
UsageFeedOptions passed to start_with.

Clippy pedantic on the spike goes 79 -> 15 against root CI's -D warnings, so
graduating it into the workspace is not gated on a warning cleanup. The four
remaining too_many_lines are the render split, which the sidebar work needs to
do anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Metal Agent
2026-08-31 22:54:24 -07:00
co-authored by Claude Opus 5
parent 219c674aea
commit 834b73e831
5 changed files with 223 additions and 201 deletions
+11 -19
View File
@@ -12,8 +12,7 @@ use floem::{
window::WindowConfig,
};
use lumbridge_spike_model::{
FOOTER_CENTER, FOOTER_RIGHT, FocusDirection, PaneId, PaneState, ShellAction, ShellModel,
SurfaceKind, WORKSPACES,
FOOTER_FIXTURE_NOTICE, FocusDirection, PaneId, PaneState, ShellAction, ShellModel, SurfaceKind,
};
const BG: Color = Color::from_rgb8(9, 12, 18);
@@ -132,22 +131,16 @@ fn render_pane_card(pane: PaneState, selected: bool, model: RwSignal<ShellModel>
}
fn sidebar() -> impl IntoView {
let worktrees = Stack::from_iter(WORKSPACES.into_iter().enumerate().map(|(index, name)| {
Stack::vertical((
Label::new(name),
Label::new(if index == 0 { "main · metal" } else { "" })
.style(|s| s.font_size(10.0).color(MUTED).margin_top(2.0)),
))
.style(move |s| {
s.width_full()
// The worktree list this shell used to render came from a five-entry
// fixture naming this developer's machines, backed by no git integration.
// The GPUI shell's copy was deleted in the same pass; this one renders the
// workspace it is actually open on.
let worktrees = Stack::vertical((Label::new("Lumbridge Code"),)).style(|s| {
s.flex_col()
.padding_horiz(8.0)
.padding_vert(7.0)
.padding_horiz(10.0)
.margin_bottom(3.0)
.color(if index == 0 { TEXT } else { MUTED })
.apply_if(index == 0, |s| s.background(PANEL_ALT).border_radius(5.0))
})
}))
.style(|s| s.flex_col().padding_horiz(8.0));
.color(TEXT)
});
Stack::vertical((
Label::new("ATTENTION · 1").style(|s| s.font_size(10.0).color(ATTENTION).padding(12.0)),
@@ -434,8 +427,7 @@ fn app_view() -> impl IntoView {
})
})
.style(|s| s.flex_grow(1.0)),
Label::new(FOOTER_CENTER).style(|s| s.flex_grow(1.0)),
Label::new(FOOTER_RIGHT),
Label::new(FOOTER_FIXTURE_NOTICE).style(|s| s.flex_grow(1.0)),
))
.style(|s| {
s.height(32.0)
+112 -91
View File
@@ -16,7 +16,7 @@ use lumbridge_runtime::{
};
use lumbridge_spike_model::{
ActionOutcome, OutputSource, PaneId as FixturePaneId, PaneStatus, ShellAction, ShellModel,
SurfaceKind, WORKSPACES,
SurfaceKind,
};
use lumbridge_storage::Store;
use lumbridge_terminal::{
@@ -28,16 +28,63 @@ use lumbridge_terminal::{
use panel_registry::{PanelId, PanelKind, PanelRegistry, SeedPane};
use usage_feed::{UsageFeed, UsageSegment};
// A colour is read as six hex digits, so `0x8b_c8ff` would be harder to check
// against a design token than `0x8bc8ff`, not easier. Scoped to the palette and
// the two terminal colour tables; every other literal keeps the lint.
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const BG: u32 = 0x090c12;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const PANEL: u32 = 0x101620;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const PANEL_ALT: u32 = 0x151d29;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const PANEL_ACTIVE: u32 = 0x182334;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const BORDER: u32 = 0x263246;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const BORDER_QUIET: u32 = 0x1c2636;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const TEXT: u32 = 0xdbe5f4;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const MUTED: u32 = 0x8290a8;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const ACCENT: u32 = 0x68b5f8;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const ATTENTION: u32 = 0xf1b96a;
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
const SUCCESS: u32 = 0x70d6a8;
const TIMING_SAMPLE_LIMIT: usize = 256;
const RUNTIME_POLL_INTERVAL: Duration = Duration::from_millis(16);
@@ -94,7 +141,6 @@ struct LumbridgeShell {
/// Which decision-shelf choice each panel has selected. Selecting one is
/// inert by design: it prepares nothing and runs nothing.
shelf_choice: BTreeMap<PanelId, usize>,
active_worktree: usize,
add_panel_chooser_open: bool,
root_focus: FocusHandle,
}
@@ -339,6 +385,34 @@ fn terminal_paint_rows(snapshot: &TerminalSnapshot) -> Vec<Vec<TerminalPaintRun>
.collect()
}
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
/// Narrows an already-clamped dimension.
///
/// Every caller clamps into `2.0..=u16::MAX` first, so this is a narrowing of a
/// value known to fit — but `as` would silently produce garbage if a caller ever
/// stopped clamping, and a NaN would become zero. This saturates instead, which
/// is why the `with_cell_size` expect below is honest rather than hopeful.
fn clamp_to_u16(value: f32) -> u16 {
if value.is_nan() {
return 1;
}
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
reason = "clamped into u16 range on the line above"
)]
{
value.clamp(0.0, f32::from(u16::MAX)) as u16
}
}
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
fn terminal_color(color: TerminalColor) -> u32 {
match color {
TerminalColor::Rgb { red, green, blue } => {
@@ -377,6 +451,10 @@ fn terminal_color(color: TerminalColor) -> u32 {
}
}
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
fn indexed_terminal_color(index: u8) -> u32 {
const ANSI: [u32; 16] = [
0x1d2430, 0xff6b6b, 0x70d6a8, 0xf1c76a, 0x68b5f8, 0xc79bf2, 0x63d5da, 0xdbe5f4, 0x6d7a91,
@@ -427,10 +505,10 @@ fn terminal_dimensions_for_window(
.floor()
.clamp(20.0, f32::from(u16::MAX));
TerminalDimensions::with_cell_size(
rows as u16,
columns as u16,
TERMINAL_CELL_WIDTH.round() as u16,
TERMINAL_CELL_HEIGHT.round() as u16,
clamp_to_u16(rows),
clamp_to_u16(columns),
clamp_to_u16(TERMINAL_CELL_WIDTH.round()),
clamp_to_u16(TERMINAL_CELL_HEIGHT.round()),
)
.expect("geometry clamps terminal dimensions above zero")
}
@@ -513,7 +591,7 @@ fn load_panel_registry() -> (Option<Store>, PanelRegistry, String) {
let Some(path) = workspace_database_path() else {
return (
None,
PanelRegistry::seeded(),
PanelRegistry::first_run(),
"layout memory-only · no data directory".to_owned(),
);
};
@@ -522,7 +600,7 @@ fn load_panel_registry() -> (Option<Store>, PanelRegistry, String) {
{
return (
None,
PanelRegistry::seeded(),
PanelRegistry::first_run(),
format!("layout memory-only · {error}"),
);
}
@@ -531,7 +609,7 @@ fn load_panel_registry() -> (Option<Store>, PanelRegistry, String) {
Err(error) => {
return (
None,
PanelRegistry::seeded(),
PanelRegistry::first_run(),
format!("layout memory-only · {error}"),
);
}
@@ -541,18 +619,18 @@ fn load_panel_registry() -> (Option<Store>, PanelRegistry, String) {
Ok(panels) => (Some(store), panels, "layout restored · SQLite".to_owned()),
Err(error) => (
Some(store),
PanelRegistry::seeded(),
PanelRegistry::first_run(),
format!("invalid layout ignored · {error}"),
),
},
Ok(None) => (
Some(store),
PanelRegistry::seeded(),
PanelRegistry::first_run(),
"layout ready · SQLite".to_owned(),
),
Err(error) => (
Some(store),
PanelRegistry::seeded(),
PanelRegistry::first_run(),
format!("layout read failed · {error}"),
),
}
@@ -642,7 +720,6 @@ impl LumbridgeShell {
usage: UsageFeed::start(),
surfaces: BTreeMap::new(),
shelf_choice: BTreeMap::new(),
active_worktree: 0,
add_panel_chooser_open: false,
root_focus,
}
@@ -655,7 +732,7 @@ impl LumbridgeShell {
let result = self
.panels
.to_json()
.map_err(|error| error.to_owned())
.map_err(|error| error.clone())
.and_then(|json| {
store
.save_workspace_snapshot(WORKSPACE_SNAPSHOT_ID, &json)
@@ -908,13 +985,6 @@ impl LumbridgeShell {
cx.notify();
}
fn select_worktree(&mut self, index: usize, window: &mut Window, cx: &mut Context<Self>) {
self.timing.mark_dispatch();
self.active_worktree = index.min(WORKSPACES.len().saturating_sub(1));
window.focus(&self.root_focus);
cx.notify();
}
fn select_pane_at(&mut self, index: usize, window: &mut Window, cx: &mut Context<Self>) {
self.timing.mark_dispatch();
if self.panels.select_attached_at(index) {
@@ -1204,7 +1274,7 @@ impl LumbridgeShell {
|| run.style.contains(TerminalCellStyle::DOTTED_UNDERLINE)
|| run.style.contains(TerminalCellStyle::DASHED_UNDERLINE)
|| run.hyperlink,
|view| view.underline(),
gpui::Styled::underline,
)
.when(run.style.contains(TerminalCellStyle::STRIKEOUT), |view| {
view.line_through()
@@ -1247,7 +1317,7 @@ impl LumbridgeShell {
"BROWSER",
vec![
"about:blank".to_owned(),
"Content process: isolated".to_owned(),
"No web engine is embedded in this build.".to_owned(),
"Choose a URL or open externally ↗".to_owned(),
],
),
@@ -1256,7 +1326,7 @@ impl LumbridgeShell {
"MARKDOWN",
vec![
"# Untitled note".to_owned(),
"".to_owned(),
String::new(),
"Local-first workspace document.".to_owned(),
],
),
@@ -1264,7 +1334,7 @@ impl LumbridgeShell {
SurfaceKind::Review,
"REVIEW",
vec![
"Working tree ready for review.".to_owned(),
"No working tree is loaded.".to_owned(),
"No approval has been requested.".to_owned(),
"0 files selected".to_owned(),
],
@@ -2069,18 +2139,10 @@ impl LumbridgeShell {
.count();
let total = self.live_terminals.len();
let local = RuntimeRow {
label: "metal",
label: "this machine",
detail: format!("{running}/{total} live PTYs"),
tone: if running == 0 { MUTED } else { SUCCESS },
};
// Remote runtimes are a Phase 1 deliverable. Until the SSH stdio
// transport exists, the only honest status for a saved host is that
// nothing is connected to it.
let remote = RuntimeRow {
label: "amd-server",
detail: "saved host · no runtime connected".to_owned(),
tone: MUTED,
};
// The usage adapter is neither a host nor an endpoint, but its health
// belongs beside them: it is the reason the footer can or cannot answer.
let adapter = RuntimeRow {
@@ -2097,7 +2159,7 @@ impl LumbridgeShell {
SUCCESS
},
};
vec![local, remote, adapter]
vec![local, adapter]
}
/// The standing of every harness, always, regardless of what is selected.
@@ -2373,41 +2435,6 @@ impl Render for LumbridgeShell {
shell.select_pane(id, window, cx);
}))
}))
.child(
div()
.px_4()
.py_2()
.text_xs()
.text_color(rgb(MUTED))
.child("WORKTREES"),
)
.children(WORKSPACES.into_iter().enumerate().map(|(index, name)| {
let active = index == self.active_worktree;
div()
.id(("worktree", index as u64))
.cursor_pointer()
.mx_2()
.mb_1()
.px_3()
.py_2()
.rounded(px(5.0))
.when(active, |view| view.bg(rgb(PANEL_ALT)).text_color(rgb(TEXT)))
.when(!active, |view| view.text_color(rgb(MUTED)))
.hover(|view| view.bg(rgb(PANEL_ACTIVE)).text_color(rgb(TEXT)))
.child(name)
.when(active, |view| {
view.child(
div()
.mt_1()
.text_xs()
.text_color(rgb(MUTED))
.child("main · metal"),
)
})
.on_click(cx.listener(move |shell, _, window, cx| {
shell.select_worktree(index, window, cx);
}))
}))
.child(
div()
.mt_3()
@@ -2460,23 +2487,7 @@ impl Render for LumbridgeShell {
shell.attach_panel(pane, window, cx);
}))
}))
.child(div().flex_1())
.child(
div()
.m_3()
.p_3()
.rounded(px(5.0))
.bg(rgb(PANEL_ALT))
.text_xs()
.text_color(rgb(MUTED))
.child("Buzz · lumbridgecode")
.child(
div()
.mt_1()
.text_color(rgb(SUCCESS))
.child("connected · signed identity"),
),
);
.child(div().flex_1());
let tabs = div()
.flex()
@@ -2499,7 +2510,7 @@ impl Render for LumbridgeShell {
.border_b_2()
.border_color(rgb(ACCENT))
.text_sm()
.child(WORKSPACES[self.active_worktree]),
.child("Lumbridge Code"),
)
.child(div().flex_1())
.child(div().px_3().text_xs().text_color(rgb(MUTED)).child(format!(
@@ -2627,15 +2638,21 @@ impl Render for LumbridgeShell {
.ml_3()
.text_sm()
.text_color(rgb(MUTED))
.child(format!("{} / main", WORKSPACES[self.active_worktree])),
.child("Lumbridge Code"),
)
.child(div().flex_1())
// The same tone rule runtime_rows applies: nothing live is
// not a success, and "0/5 LIVE PTYS" in green said it was.
.child(
div()
.mr_4()
.text_xs()
.text_color(rgb(SUCCESS))
.child(format!("metal · {runtime_summary}")),
.text_color(rgb(if running_runtime_count == 0 {
MUTED
} else {
SUCCESS
}))
.child(runtime_summary),
)
.child(
div()
@@ -2921,6 +2938,10 @@ mod tests {
}
#[test]
#[allow(
clippy::unreadable_literal,
reason = "six-digit colour hex reads whole"
)]
fn xterm_color_cube_and_grayscale_are_deterministic() {
assert_eq!(indexed_terminal_color(16), 0x000000);
assert_eq!(indexed_terminal_color(231), 0xffffff);
+32 -47
View File
@@ -36,18 +36,26 @@ impl PanelKind {
pub(crate) const fn description(self) -> &'static str {
match self {
Self::Terminal => "A real local shell with its own runtime actor",
Self::Browser => "An isolated system-web-engine surface",
// Not a web engine. There is no browser in this build; the panel
// renders a placeholder surface and says so.
Self::Browser => "A placeholder surface. No web engine is embedded yet",
Self::Markdown => "Local notes, plans, and architecture",
Self::Review => "Repository changes and approval boundaries",
}
}
/// What a newly created panel is pointed at.
///
/// Every one of these used to name a specific machine — this developer's,
/// as it happens. A panel's target is whatever it was actually launched
/// against, and a new panel has been launched against nothing but the
/// local shell.
const fn default_target(self) -> &'static str {
match self {
Self::Terminal => "metal · local runtime",
Self::Browser => "isolated system web engine",
Self::Markdown => "lumbridge-code · local document",
Self::Review => "lumbridge-code · working tree",
Self::Terminal => "local shell",
Self::Browser => "no surface attached",
Self::Markdown => "local document",
Self::Review => "working tree",
}
}
}
@@ -96,49 +104,26 @@ pub(crate) struct PanelRegistry {
impl Default for PanelRegistry {
fn default() -> Self {
Self::seeded()
Self::first_run()
}
}
impl PanelRegistry {
pub(crate) fn seeded() -> Self {
/// The workspace a first run opens with.
///
/// Three real local shells and nothing else. This used to seed six panes
/// announcing "Codex · runtime / metal · Tailscale SSH", "Claude Code · UI
/// / `MacBook` Air · local" and a Pi pane on a saved host — none of which
/// existed. Every one was a `/bin/sh`. A pane claims a harness when one has
/// actually been launched into it, and until then it is a terminal.
///
/// Three, not one: `visible_panel_count` branches at 1100 px and 2800 px,
/// so a single-panel default renders one pane on an ultrawide.
pub(crate) fn first_run() -> Self {
let seeds = [
(
PanelKind::Terminal,
"Codex · runtime",
"metal · Tailscale SSH",
SeedPane::CodexRuntime,
),
(
PanelKind::Terminal,
"Claude Code · UI",
"MacBook Air · local",
SeedPane::ClaudeUi,
),
(
PanelKind::Terminal,
"Pi · docs",
"amd-server · OpenSSH",
SeedPane::PiDocs,
),
(
PanelKind::Markdown,
"Architecture.md",
"lumbridge-code · worktree",
SeedPane::Architecture,
),
(
PanelKind::Browser,
"Preview · ACP docs",
"isolated system web engine",
SeedPane::AcpPreview,
),
(
PanelKind::Review,
"Changes · lumbridge-runtime",
"metal · worktree remote-runtime",
SeedPane::RuntimeReview,
),
(PanelKind::Terminal, "Terminal 1", "local shell", None),
(PanelKind::Terminal, "Terminal 2", "local shell", None),
(PanelKind::Terminal, "Terminal 3", "local shell", None),
];
let panels = seeds
.into_iter()
@@ -149,7 +134,7 @@ impl PanelRegistry {
title: title.to_owned(),
target: target.to_owned(),
attached: index < 5,
seed: Some(seed),
seed,
})
.collect();
Self {
@@ -335,7 +320,7 @@ mod tests {
#[test]
fn dynamic_panels_receive_monotonic_ids_and_insert_beside_selection() {
let mut registry = PanelRegistry::seeded();
let mut registry = PanelRegistry::first_run();
let browser = registry.create(PanelKind::Browser);
let terminal = registry.create(PanelKind::Terminal);
assert_eq!(browser, PanelId(7));
@@ -347,7 +332,7 @@ mod tests {
#[test]
fn identity_and_detached_state_round_trip_without_reuse() {
let mut registry = PanelRegistry::seeded();
let mut registry = PanelRegistry::first_run();
let created = registry.create(PanelKind::Markdown);
assert!(registry.detach(created));
let json = registry.to_json().unwrap();
@@ -358,7 +343,7 @@ mod tests {
#[test]
fn detach_preserves_panel_and_reattach_restores_same_identity() {
let mut registry = PanelRegistry::seeded();
let mut registry = PanelRegistry::first_run();
let id = registry.create(PanelKind::Terminal);
assert!(registry.detach(id));
assert!(registry.panel(id).is_some());
+59 -25
View File
@@ -34,9 +34,15 @@ struct DeclaredProfile {
account: &'static str,
}
/// The Codex pane maps onto the probe's own primary-window profile, so a live
/// reading lands under the pane that produced it. The rest are declarations
/// with no adapter behind them yet.
/// Only harnesses with a real adapter behind them.
///
/// A third entry declared "Pi · spark-1 · laguna-s-2.1 · self-hosted" with no
/// probe of any kind, so the strip carried a permanent empty rail for a harness
/// the user was not running. Declaring a profile is a promise that the gap is
/// real; declaring one nothing can ever fill is just a fabricated row.
///
/// The seed mapping stays: it is how a live reading lands under the pane that
/// produced it, once a harness can actually be launched into a pane.
const DECLARED: &[DeclaredProfile] = &[
DeclaredProfile {
seed: SeedPane::CodexRuntime,
@@ -58,14 +64,6 @@ const DECLARED: &[DeclaredProfile] = &[
model: "five-hour window",
account: "subscription",
},
DeclaredProfile {
seed: SeedPane::PiDocs,
id: "spark-1-local",
harness: "Pi",
provider: "spark-1",
model: "laguna-s-2.1",
account: "self-hosted",
},
];
pub(crate) struct UsageFeed {
@@ -78,8 +76,45 @@ pub(crate) struct UsageFeed {
probe_status: String,
}
/// Which probes to start.
///
/// Passed in rather than read from the environment inside the constructor:
/// a test that wanted a probe-free feed used to set a process-wide environment
/// variable, which required `unsafe` and silently disabled both probes for
/// every other test in the binary.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct UsageFeedOptions {
pub(crate) codex: bool,
pub(crate) claude: bool,
}
impl UsageFeedOptions {
/// Reads the documented opt-out switches. The only place the environment
/// is consulted, so a caller can always ask for something else.
fn from_env() -> Self {
let enabled = |name: &str| std::env::var_os(name).is_none_or(|value| value != "0");
Self {
codex: enabled("LUMBRIDGE_CODEX_PROBE"),
claude: enabled("LUMBRIDGE_CLAUDE_PROBE"),
}
}
/// Declares every profile and starts nothing.
#[cfg(test)]
pub(crate) const fn none() -> Self {
Self {
codex: false,
claude: false,
}
}
}
impl UsageFeed {
pub(crate) fn start() -> Self {
Self::start_with(UsageFeedOptions::from_env())
}
pub(crate) fn start_with(options: UsageFeedOptions) -> Self {
let mut profiles = BTreeMap::new();
let mut seeds = Vec::new();
for declared in DECLARED {
@@ -105,8 +140,8 @@ impl UsageFeed {
health: BTreeMap::new(),
probe_status: "no usage adapter running".to_owned(),
};
feed.start_codex_probe();
feed.start_claude_probe();
feed.start_codex_probe(options.codex);
feed.start_claude_probe(options.claude);
feed
}
@@ -115,8 +150,8 @@ impl UsageFeed {
/// A failure here is not an error state for the shell: the profiles stay
/// declared and render as unavailable, which is exactly what they should do
/// when no adapter can run.
fn start_codex_probe(&mut self) {
if std::env::var_os("LUMBRIDGE_CODEX_PROBE").is_some_and(|value| value == "0") {
fn start_codex_probe(&mut self, enabled: bool) {
if !enabled {
self.probe_status = "codex probe disabled".to_owned();
return;
}
@@ -143,8 +178,12 @@ impl UsageFeed {
/// This one reads files rather than launching anything, so it has no
/// harness to fail to find — a missing projects directory simply reports
/// nothing until Claude Code creates it.
fn start_claude_probe(&mut self) {
if std::env::var_os("LUMBRIDGE_CLAUDE_PROBE").is_some_and(|value| value == "0") {
fn start_claude_probe(&mut self, enabled: bool) {
if !enabled {
// Say so, rather than leaving whatever the Codex path last wrote.
// A disabled probe that reports nothing about itself is
// indistinguishable from one that failed to start.
self.probe_status = "claude probe disabled".to_owned();
return;
}
match ClaudeCodeProbe::start(ClaudeCodeProbeOptions::default()) {
@@ -415,19 +454,14 @@ pub(crate) struct UsageSegment {
#[cfg(test)]
mod tests {
use super::{DECLARED, UsageFeed};
use super::{DECLARED, UsageFeed, UsageFeedOptions};
use crate::panel_registry::SeedPane;
use lumbridge_core::UsageProvenance;
/// Never starts a probe, so the test cannot depend on an installed harness,
/// on the user's transcripts, or on a status-line bridge being present.
fn declared_only_feed() -> UsageFeed {
// SAFETY-FREE: this only sets environment variables for this process.
unsafe {
std::env::set_var("LUMBRIDGE_CODEX_PROBE", "0");
std::env::set_var("LUMBRIDGE_CLAUDE_PROBE", "0");
}
UsageFeed::start()
UsageFeed::start_with(UsageFeedOptions::none())
}
#[test]
@@ -485,7 +519,7 @@ mod tests {
let strip = feed.strip();
assert_eq!(strip.len(), DECLARED.len());
let labels: Vec<&str> = strip.iter().map(|segment| segment.label.as_str()).collect();
assert_eq!(labels, ["CODEX", "CLAUDE CODE", "PI"]);
assert_eq!(labels, ["CODEX", "CLAUDE CODE"]);
for segment in &strip {
assert!(
segment.headline.is_none() && segment.reset.is_none(),
+8 -18
View File
@@ -198,25 +198,15 @@ pub const PANES: [PaneFixture; 6] = [
},
];
pub const WORKSPACES: [&str; 5] = [
"Lumbridge Code",
"Runtime / metal",
"UI spikes",
"ACP adapters",
"Usage telemetry",
];
/// Static footer strings retained only by the Floem comparison shell.
/// The one footer string the frozen Floem shell renders.
///
/// These are layout fixtures, not usage. They are not a usage source and must
/// not be rendered as one: the GPUI shell now derives its footer from
/// `lumbridge_core::UsageLedger`, where every value carries a provenance and a
/// missing fact renders as missing. Delete these once Floem consumes the ledger
/// or the candidate is retired. See decision 0012.
pub const FOOTER_LEFT: &str = "6 panes · 3 remote · 1 needs input";
/// See [`FOOTER_LEFT`]: a layout fixture, not a usage reading.
pub const FOOTER_CENTER: &str = "Codex · ChatGPT subscription · 62% window remaining";
/// See [`FOOTER_LEFT`]: a layout fixture, not a usage reading.
pub const FOOTER_RIGHT: &str = "burn 8.4%/hr · resets in 2h 14m";
/// It replaces three that read like data — a pane census, "Codex · ChatGPT
/// subscription · 62% window remaining", and "burn 8.4%/hr · resets in 2h 14m".
/// Decision 0013 names that exact form as the thing that must never be shown,
/// and a comparison shell rendering a fabricated quota beside a real one is
/// worse than a comparison shell with no footer numbers at all. The GPUI shell
/// derives its footer from `lumbridge_core::UsageLedger`. See decision 0012.
pub const FOOTER_FIXTURE_NOTICE: &str = "layout fixture · no usage source";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PaneState {