Merge remote-tracking branch 'origin/atlas-companion-app'

This commit is contained in:
2026-07-17 09:32:07 +02:00
19 changed files with 2260 additions and 165 deletions
+47 -26
View File
@@ -94,7 +94,11 @@ fn serve_atlas_requests(
let reader = city_reader.as_ref().map(|r| &r.0);
let params_reader = body_params_reader.as_ref().map(|r| &r.0);
let pending: Vec<_> = requests.0.drain(..).collect();
for req in pending {
// D-254 §2: 1:1, in-order request->response — the connection id rides
// alongside the request untouched by handle_atlas_request (which has no
// notion of connections) and is re-attached to the response so the
// bridge's send_atlas_responses routes it back to only that connection.
for (conn_id, req) in pending {
let resp = match resolver.as_ref() {
Some(r) => handle_atlas_request(
&req,
@@ -116,7 +120,7 @@ fn serve_atlas_requests(
region_grid: None,
},
};
responses.0.push(resp);
responses.0.push((conn_id, resp));
}
}
@@ -133,7 +137,7 @@ fn serve_star_map_requests(
return;
}
let pending: Vec<_> = requests.0.drain(..).collect();
for req in pending {
for (conn_id, req) in pending {
let resp = match path.as_ref() {
Some(p) => handle_star_map_request(&req, &p.0),
None => crate::atlas::atlas_data_proxy::StarMapResponse {
@@ -143,7 +147,7 @@ fn serve_star_map_requests(
data: None,
},
};
responses.0.push(resp);
responses.0.push((conn_id, resp));
}
}
@@ -159,8 +163,10 @@ fn serve_city_names_requests(
}
let reader = city_reader.as_ref().map(|r| &r.0);
let pending: Vec<_> = requests.0.drain(..).collect();
for req in pending {
responses.0.push(handle_city_names_request(&req, reader));
for (conn_id, req) in pending {
responses
.0
.push((conn_id, handle_city_names_request(&req, reader)));
}
}
@@ -760,6 +766,7 @@ mod tests {
use super::*;
use crate::atlas::gen_queue::{GenPriority, GenWorkItem};
use crate::atlas::road_graph::{RoadEdge, RoadNode, RoadNodeKind};
use crate::bridge::ConnectionId;
use crate::seed::SeedChain;
use crate::simulation::generator::{
ArrangementPattern, AttractorType, FoundingOrientation, MaintenanceAuthority,
@@ -834,10 +841,13 @@ mod tests {
use crate::atlas::layer_proxy::AtlasLayerRequest;
let mut world = World::new();
world.insert_resource(AtlasRequestBuffer(vec![AtlasLayerRequest {
body_id: "GJ1c".to_string(),
up_to: CascadeLayer::Topography,
}]));
world.insert_resource(AtlasRequestBuffer(vec![(
ConnectionId(0),
AtlasLayerRequest {
body_id: "GJ1c".to_string(),
up_to: CascadeLayer::Topography,
},
)]));
world.insert_resource(AtlasResponseBuffer::default());
world.insert_resource(BodyWorldStateCache::new(CACHE_CAPACITY));
world.insert_resource(GenerationQueue::with_threads(1));
@@ -849,9 +859,13 @@ mod tests {
let responses = world.resource::<AtlasResponseBuffer>();
assert_eq!(responses.0.len(), 1, "request should produce one response");
assert_eq!(responses.0[0].body_id, "GJ1c");
assert_eq!(responses.0[0].0, ConnectionId(0), "connection id preserved");
assert_eq!(responses.0[0].1.body_id, "GJ1c");
// No resolver wired → Error status (exercises the drain + push path).
assert!(matches!(responses.0[0].status, AtlasLayerStatus::Error(_)));
assert!(matches!(
responses.0[0].1.status,
AtlasLayerStatus::Error(_)
));
// The request buffer was drained.
assert!(world.resource::<AtlasRequestBuffer>().0.is_empty());
}
@@ -869,9 +883,10 @@ mod tests {
std::fs::write(&path, r#"{"_meta": {}, "nodes": [], "edges": []}"#).unwrap();
let mut world = World::new();
world.insert_resource(StarMapRequestBuffer(vec![StarMapRequest {
star_map: true,
}]));
world.insert_resource(StarMapRequestBuffer(vec![(
ConnectionId(0),
StarMapRequest { star_map: true },
)]));
world.insert_resource(StarMapResponseBuffer::default());
world.insert_resource(StarMapDataPath(path.clone()));
@@ -881,7 +896,8 @@ mod tests {
let responses = world.resource::<StarMapResponseBuffer>();
assert_eq!(responses.0.len(), 1);
assert_eq!(responses.0[0].status, StarMapStatus::Ready);
assert_eq!(responses.0[0].0, ConnectionId(0), "connection id preserved");
assert_eq!(responses.0[0].1.status, StarMapStatus::Ready);
assert!(world.resource::<StarMapRequestBuffer>().0.is_empty());
let _ = std::fs::remove_file(&path);
@@ -894,9 +910,10 @@ mod tests {
use crate::atlas::atlas_data_proxy::{StarMapRequest, StarMapStatus};
let mut world = World::new();
world.insert_resource(StarMapRequestBuffer(vec![StarMapRequest {
star_map: true,
}]));
world.insert_resource(StarMapRequestBuffer(vec![(
ConnectionId(0),
StarMapRequest { star_map: true },
)]));
world.insert_resource(StarMapResponseBuffer::default());
// No StarMapDataPath resource.
@@ -906,7 +923,7 @@ mod tests {
let responses = world.resource::<StarMapResponseBuffer>();
assert_eq!(responses.0.len(), 1);
assert!(matches!(responses.0[0].status, StarMapStatus::Error(_)));
assert!(matches!(responses.0[0].1.status, StarMapStatus::Error(_)));
}
/// T-949b: without `CityContextReaderResource` wired, the serve system
@@ -917,10 +934,13 @@ mod tests {
use crate::atlas::atlas_data_proxy::{CityNamesRequest, CityNamesStatus};
let mut world = World::new();
world.insert_resource(CityNamesRequestBuffer(vec![CityNamesRequest {
city_names: true,
body_id: "GJ1c".to_string(),
}]));
world.insert_resource(CityNamesRequestBuffer(vec![(
ConnectionId(0),
CityNamesRequest {
city_names: true,
body_id: "GJ1c".to_string(),
},
)]));
world.insert_resource(CityNamesResponseBuffer::default());
// No CityContextReaderResource.
@@ -930,8 +950,9 @@ mod tests {
let responses = world.resource::<CityNamesResponseBuffer>();
assert_eq!(responses.0.len(), 1);
assert_eq!(responses.0[0].body_id, "GJ1c");
assert!(matches!(responses.0[0].status, CityNamesStatus::Error(_)));
assert_eq!(responses.0[0].0, ConnectionId(0), "connection id preserved");
assert_eq!(responses.0[0].1.body_id, "GJ1c");
assert!(matches!(responses.0[0].1.status, CityNamesStatus::Error(_)));
assert!(world.resource::<CityNamesRequestBuffer>().0.is_empty());
}