feat(simulation): feature-name pipeline wired + legacy window_granularity u32 retired (T-1169, T-1159)
One commit for two tickets whose changes share the bridge/plugin plumbing files. T-1169 connects the three dormant feature-name pieces: atlas_feature_names populated at regen (17,891 rows — 15,190 mountain, 2,701 river — via populate_atlas_feature_names mirroring the city-names importer; systems.db regenerated, stamp fresh), attach_feature_names wired into the cascade's Topography block with name pools threaded DB-free through AnalyzeBody (D-225 pattern) and assignments stored on Layer1Output/BodyWorldState for future consumers, and a FeatureNamesRequest/Response read proxy as the bridge's 7th tagged envelope (D-236 pattern, both SimBridge impls). Client label DRAW is deliberately NOT here — implementation proved both river and mountain labels need a wire-carried position (the pool is position-free; course polylines aren't correlated with the named attractors by construction) — deferred to T-1195's single design pass. cascade_layer1 golden re-pinned (additive feature_names field). T-1159 retires the legacy u32 granularity field fully shadowed by window_granularity_v2: AtlasLayerRequest.window_granularity, DistrictWindowLayer.granularity echo, the u32::MAX sentinel, and resolve_window_granularity are gone server-side; client encode paths and the caller-less atlas_window_cache legacy key component dropped; msgpack fixtures regenerated; the T-1150 aliasing regression test now drives through the surviving enum field. The district_window carrier itself survives byte-compatible per D-255(c). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,8 @@ use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::atlas::atlas_data_proxy::{
|
||||
handle_city_names_request, handle_star_map_request, StarMapDataPath,
|
||||
handle_city_names_request, handle_feature_names_request, handle_star_map_request,
|
||||
StarMapDataPath,
|
||||
};
|
||||
use crate::atlas::attractor_matching::CityPlacement;
|
||||
use crate::atlas::body_params_reader::BodyParamsReaderResource;
|
||||
@@ -52,7 +53,8 @@ use crate::atlas::trait_swerve::{
|
||||
};
|
||||
use crate::bridge::{
|
||||
AtlasRequestBuffer, AtlasResponseBuffer, BrowseRequestBuffer, BrowseResponseBuffer,
|
||||
CityNamesRequestBuffer, CityNamesResponseBuffer, StarMapRequestBuffer, StarMapResponseBuffer,
|
||||
CityNamesRequestBuffer, CityNamesResponseBuffer, FeatureNamesRequestBuffer,
|
||||
FeatureNamesResponseBuffer, StarMapRequestBuffer, StarMapResponseBuffer,
|
||||
StepCanvasRequestBuffer, StepCanvasResponseBuffer,
|
||||
};
|
||||
use crate::seed::{SeedChain, SeedDomain};
|
||||
@@ -83,6 +85,10 @@ impl Plugin for GenerationPlugin {
|
||||
Update,
|
||||
serve_city_names_requests.in_set(TickPhase::PreInput),
|
||||
)
|
||||
.add_systems(
|
||||
Update,
|
||||
serve_feature_names_requests.in_set(TickPhase::PreInput),
|
||||
)
|
||||
.add_systems(Update, serve_browse_requests.in_set(TickPhase::PreInput))
|
||||
.add_systems(
|
||||
Update,
|
||||
@@ -201,6 +207,26 @@ fn serve_city_names_requests(
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain inbound feature-names requests and serve each through the proxy
|
||||
/// (T-1169): D-236 Sol check, then the names-only `atlas_feature_names` read.
|
||||
/// Mirrors [`serve_city_names_requests`] exactly.
|
||||
fn serve_feature_names_requests(
|
||||
mut requests: ResMut<FeatureNamesRequestBuffer>,
|
||||
mut responses: ResMut<FeatureNamesResponseBuffer>,
|
||||
city_reader: Option<Res<CityContextReaderResource>>,
|
||||
) {
|
||||
if requests.0.is_empty() {
|
||||
return;
|
||||
}
|
||||
let reader = city_reader.as_ref().map(|r| &r.0);
|
||||
let pending: Vec<_> = requests.0.drain(..).collect();
|
||||
for (conn_id, req) in pending {
|
||||
responses
|
||||
.0
|
||||
.push((conn_id, handle_feature_names_request(&req, reader)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain inbound data-browser requests and serve each through the proxy
|
||||
/// (D-254 §4, T-1131): one of the six v1 registry-tier entity kinds, dispatched
|
||||
/// to `BrowseReader` by `(kind, query)`.
|
||||
@@ -1043,6 +1069,8 @@ mod tests {
|
||||
cities: vec![],
|
||||
dominant_faction: None,
|
||||
body_params: None, // T-1023: no DB params in this unit test
|
||||
river_names: vec![],
|
||||
mountain_names: vec![],
|
||||
},
|
||||
GenPriority::Immediate,
|
||||
);
|
||||
@@ -1079,7 +1107,6 @@ mod tests {
|
||||
up_to: CascadeLayer::Topography,
|
||||
window_center: None,
|
||||
window_n: 0,
|
||||
window_granularity: 0,
|
||||
window_granularity_v2: None,
|
||||
window_min_wl_m: 0,
|
||||
},
|
||||
@@ -1193,6 +1220,36 @@ mod tests {
|
||||
assert!(world.resource::<CityNamesRequestBuffer>().0.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serve_feature_names_without_reader_is_error() {
|
||||
use crate::atlas::atlas_data_proxy::{FeatureNamesRequest, FeatureNamesStatus};
|
||||
|
||||
let mut world = World::new();
|
||||
world.insert_resource(FeatureNamesRequestBuffer(vec![(
|
||||
ConnectionId(0),
|
||||
FeatureNamesRequest {
|
||||
feature_names: true,
|
||||
body_id: "GJ1c".to_string(),
|
||||
},
|
||||
)]));
|
||||
world.insert_resource(FeatureNamesResponseBuffer::default());
|
||||
// No CityContextReaderResource.
|
||||
|
||||
let mut sched = Schedule::default();
|
||||
sched.add_systems(serve_feature_names_requests);
|
||||
sched.run(&mut world);
|
||||
|
||||
let responses = world.resource::<FeatureNamesResponseBuffer>();
|
||||
assert_eq!(responses.0.len(), 1);
|
||||
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,
|
||||
FeatureNamesStatus::Error(_)
|
||||
));
|
||||
assert!(world.resource::<FeatureNamesRequestBuffer>().0.is_empty());
|
||||
}
|
||||
|
||||
fn sample_read_set() -> CityEconomicReadSet {
|
||||
use crate::simulation::generator::SettlementClass;
|
||||
CityEconomicReadSet {
|
||||
|
||||
Reference in New Issue
Block a user