feat(simulation): activate background generation tier end-to-end (#968, D-206/D-225)

The D-206 queue (#924) and D-203 cache (#917) were built but never connected to
the running app — the whole background tier was inert. This closes the loop:
submit -> Rayon -> cascade -> completion -> drain -> cache.

- gen_queue.rs: GenWorkItem::AnalyzeBody now carries enqueuer-resolved inputs
  { body_id, heightmap_path, sea_level, body_seed: SeedChain } (D-225 boundary —
  run_work_item stays pure compute, no path/DB resolution). run_work_item runs
  the real cascade: load heightmap.png -> downsample to GRID_W×GRID_H working
  grid (D-202) -> run_layer1 -> BodyWorldState; load failure -> Failed.
  GenCompletion::BodyAnalyzed carries the computed BodyWorldState.
- cascade.rs: CascadeSnapshot::into_body_world_state() conversion.
- plugin.rs (new): GenerationPlugin registers GenerationQueue +
  BodyWorldStateCache and adds a PreInput drain system that inserts BodyAnalyzed
  states into the cache (off the Rayon workers — a cheap channel drain, never
  the ~45ms cascade). Wired into both the production and test app setups.

Tests run the real cascade on a tiny temp heightmap PNG (no committed fixture);
the plugin test proves the full submit->...->cache loop. The proxy (#969) is the
production submitter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 10:47:59 +02:00
co-authored by Claude Opus 4.7
parent 53263492ab
commit 8cedf670f0
5 changed files with 239 additions and 44 deletions
+2
View File
@@ -154,6 +154,7 @@ fn main() {
app.add_plugins(settled_reach_server::storyteller::StorytellerPlugin);
app.add_plugins(settled_reach_server::settings::SettingsPlugin);
app.add_plugins(settled_reach_server::bookmark::BookmarkPlugin::default());
app.add_plugins(settled_reach_server::atlas::GenerationPlugin);
// Initialize culture resolver (#679, D-128).
// systems.db is shipped read-only alongside the binary.
@@ -391,6 +392,7 @@ fn dump_schedule_graph() {
app.add_plugins(settled_reach_server::storyteller::StorytellerPlugin);
app.add_plugins(settled_reach_server::settings::SettingsPlugin);
app.add_plugins(settled_reach_server::bookmark::BookmarkPlugin::default());
app.add_plugins(settled_reach_server::atlas::GenerationPlugin);
app.insert_resource(settled_reach_server::simulation::rng::SimRng::new(0));
// Access Schedules resource directly — schedules are populated by plugins