From 16b7fe0bb52248fe0c874f4eb0f89f70684beab7 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 4 Apr 2026 23:50:11 +0200 Subject: [PATCH] =?UTF-8?q?fix(simulation):=20address=20PR=20#108=20review?= =?UTF-8?q?=20=E2=80=94=20LEFT=20JOIN,=20JSON=20output,=20atmosphere=20def?= =?UTF-8?q?ault?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review fixes: - corridor-status: INNER JOIN → LEFT JOIN so systems without gate records are included in counts instead of silently excluded - corridor-status: output as JSON (serde_json) matching all other atlas commands, instead of plain-text ASCII table - generate_body_matrix: emit atmosphere "standard" instead of "breathable" to match committed-system conventions - Doc header: add corridor-status usage example - CHANGELOG: note stale habitable_planet_count in pre-fix systems Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 4 ++- server/src/bin/atlas.rs | 63 ++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa98b353b..eb0726d3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ Format based on [Keep a Changelog](https://keepachangelog.com/). - `corridor-status` subcommand for atlas CLI — shows remaining unfinished systems grouped by geographic sector and hop distance (#744) ### Fixed -- `habitable_planet_count` filter now accepts both "breathable" and "standard" atmosphere values — previously all committed systems reported 0 habitable planets (#762) +- `habitable_planet_count` filter now accepts both "breathable" and "standard" atmosphere values — previously all committed systems reported 0 habitable planets (#762). Systems committed before this fix may have stale `habitable_planet_count = 0`; re-commit to update. +- `corridor-status` uses LEFT JOIN so systems without gate records are included in counts +- `generate_body_matrix` now emits `atmosphere: "standard"` (was "breathable") to match committed-system conventions ## [v0.1.29] — 2026-04-03 diff --git a/server/src/bin/atlas.rs b/server/src/bin/atlas.rs index 6157e3110..f346ef3b5 100644 --- a/server/src/bin/atlas.rs +++ b/server/src/bin/atlas.rs @@ -10,6 +10,7 @@ //! tooling/atlas show-body "GJ 15Ab" //! tooling/atlas add-body --system "GJ 15A" --type planet --orbit 1 --id "GJ 15Ab" //! tooling/atlas stats +//! tooling/atlas corridor-status # remaining systems by corridor/hop //! tooling/atlas populate # bulk classifier pass //! //! # Direct: @@ -911,7 +912,7 @@ fn generate_body_matrix( surface_gravity: Some(0.9), orbital_period_days: Some(365.0), rotation_period_hours: Some(24.0), - atmosphere: Some("breathable".into()), + atmosphere: Some("standard".into()), biome_summary: Some("temperate".into()), hydrosphere: None, economic_role: None, @@ -943,7 +944,7 @@ fn generate_body_matrix( surface_gravity: Some(0.85), orbital_period_days: Some(400.0), rotation_period_hours: Some(26.0), - atmosphere: Some("breathable".into()), + atmosphere: Some("standard".into()), biome_summary: Some("temperate".into()), hydrosphere: None, economic_role: None, @@ -1999,26 +2000,28 @@ fn format_population(pop: i64) -> String { fn cmd_corridor_status(conn: &Connection) { // Query unfinished systems grouped by geographic_sector and hop_distance_from_gateway. // "Unfinished" = no rows in bodies for this system_id. + // LEFT JOIN so systems with no gate record are still counted (hop = NULL → "?"). let mut stmt = conn .prepare( "SELECT s.geographic_sector, g.hop_distance_from_gateway, COUNT(*) AS remaining FROM star_systems s - JOIN system_gates g ON s.system_id = g.system_id + LEFT JOIN system_gates g ON s.system_id = g.system_id WHERE s.system_id NOT IN (SELECT DISTINCT system_id FROM bodies) GROUP BY s.geographic_sector, g.hop_distance_from_gateway ORDER BY s.geographic_sector, g.hop_distance_from_gateway", ) .unwrap(); - struct Row { + #[derive(Serialize)] + struct CorridorRow { sector: Option, hop: Option, remaining: i64, } - let rows: Vec = stmt + let rows: Vec = stmt .query_map([], |row| { - Ok(Row { + Ok(CorridorRow { sector: row.get(0)?, hop: row.get(1)?, remaining: row.get(2)?, @@ -2029,31 +2032,39 @@ fn cmd_corridor_status(conn: &Connection) { .collect(); if rows.is_empty() { - println!("All systems have bodies authored."); + #[derive(Serialize)] + struct EmptyResult { + total: i64, + message: &'static str, + corridors: Vec<()>, + } + println!( + "{}", + serde_json::to_string_pretty(&EmptyResult { + total: 0, + message: "All systems have bodies authored.", + corridors: vec![], + }) + .unwrap() + ); return; } - // Plain text table: corridor | hop | remaining let total: i64 = rows.iter().map(|r| r.remaining).sum(); - println!("{:<30} {:>4} {:>9}", "Corridor", "Hop", "Remaining"); - println!("{}", "-".repeat(48)); - let mut last_sector = String::new(); - for row in &rows { - let sector = row.sector.as_deref().unwrap_or("(unknown)"); - let hop = row - .hop - .map(|h| h.to_string()) - .unwrap_or_else(|| "?".to_string()); - if sector != last_sector { - if !last_sector.is_empty() { - println!(); - } - last_sector = sector.to_string(); - } - println!("{:<30} {:>4} {:>9}", sector, hop, row.remaining); + + #[derive(Serialize)] + struct CorridorResult { + total: i64, + corridors: Vec, } - println!("{}", "-".repeat(48)); - println!("{:<30} {:>4} {:>9}", "TOTAL", "", total); + println!( + "{}", + serde_json::to_string_pretty(&CorridorResult { + total, + corridors: rows, + }) + .unwrap() + ); } // ---------------------------------------------------------------------------