The corridor over-represented southern-African heritage (afrikaans on 15
systems; arab=2, persian/turkic=0) as an artifact of the earlier
name-balancing overcorrecting. Convert five genuinely-thin afrikaans
systems — whose distinctive threads are heritage-agnostic — into
Arab/Persian/Turkic founders so the cultural cascade is built on a
balanced set. Load-bearing mystery systems (Eerste Wacht / Helderoog /
Brandpunt etc.) are left untouched.
Droëland (GJ 914A) -> Marib (arab)
Stilwater (GJ 508A) -> Sawad (arab)
Koeberg (GJ 1245B) -> Akhgar (persian)
Skuilplek (GJ 722) -> Siginak (turkic)
Carnarvon (GJ 680) -> Golestan (persian; Mostert dynasty -> Farahani)
Result: afrikaans 15->10; arab 0->2, persian 0->2, turkic 0->1.
Full narrative retouch (not just names): gttr.md + index.md prose,
body/station proper_names, cultural_specialization, gttr_hook,
atlas_city_names, and the four brand-corps named after the converted
systems (corp IDs kept stable; only display names + products renamed).
Cross-references in neighbour systems, the catalog, the aggregate
drifter guides, and the atlas proposals are updated to match.
arab/persian/turkic added to _CULTURAL_HERITAGE so the values validate;
the full canonical 47-value migration remains #1016.
Also fixes a pre-existing canon bug: Sawad (GJ 508A) no longer claims
GJ 914A is "unsettled" — it is Marib, a three-century settlement.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconciles the ~30 inconsistent heritage proposals from the 6-sector #1016
content pass into one canonical cultural_specialization heritage vocabulary
(47 values). Key reconciliations: norse_compact->nordic (un-fuses people from
faction), spanish_iberian+spanish_hispanic->spanish, brazilian_portuguese+
lusophone_frontier->brazilian, italian_northern->italian, afrikaans_cape->
afrikaans, french_provencal+french_canadian->french. No compound values; one
token per system (blends take dominant heritage or the cosmopolitan activity
value).
Maintainer decisions (2026-06-01): keep ALL values distinct (no lumping —
welsh/afro_brazilian/cape_malay/xhosa/luxembourgish/konkan all retained);
keep empty-but-complete slots (yoruba/hausa/hungarian/persian/turkic). Fills
the Middle-East gap the pass exposed: arab/persian/turkic added even at near-
zero current usage so the canon is complete.
Logs the southern-African overrepresentation (~25/300, afrikaans=15) as a DLC
content-rewrite rebalancing task (#1019) rather than lumping the taxonomy.
Migration note included: 4 already-shipped hero cultural values use old suffix
forms (afrikaans_cape, french_provencal, italian_northern, norse_compact) and
will be renamed in the culture-write pass when _CULTURAL_HERITAGE is replaced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 6-sector content pass (core pilot + deep_frontier/north/east/south/west,
~260 systems read from both index.md and gttr.md) authored economic_
specialization + dominant_faction for the systems whose lore makes those
identities distinct. Conservative pin bar: corridor-typical systems left NULL
for the heuristic/derivation fallback.
Totals now: economic 170 (27 hero + 143), faction 76 (27 hero + 49),
cultural still 27 (DEFERRED — the culture pass needs a canonical heritage
vocabulary first; the agents surfaced ~30 real heritages from the names plus a
genuine Middle-East/Arabic gap, to be reconciled into one taxonomy before
writing cultural_specialization).
regen-db green, stamp fresh, all CI guardrails pass. Soft warnings are the
expected D-177 MonopolySource review list, the known Arbour estate/breadbasket
question, and sparse-corp_presence W-FAC-03 advisories — none blocking.
Notable pins: Haodu financial_hub/syndic_dominant, Matamba legal_archive,
Inhambane/Sonnwend/etc breadbasket, the terroir cluster, the west_reach
Compact zone, Aurelius governance_center/veil_institute. FLAGs left NULL
pending human calls (ISPI=veil_institute?, Gate-Corp-as-faction).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
generate_infobox() now renders economic_specialization (Specialization) and
cultural_specialization (Cultural Register) as read-only infobox rows when
authored (NULL = omitted, falls to heuristic). dominant_faction already
showed via Governance. Makes the authored generator-input values visible on
the wiki face so the #1016 content pass output renders. Verified: Ran shows
'breadbasket'/'agrarian'; unauthored systems omit the rows.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records that the two are a deliberate parallel representation, not a
duplicate: economic_base_primary is uncomputable GTTR prose flavor rendered
to the wiki infobox; economic_specialization is the higher-fidelity enum the
D-233 generator consumes. Notes they must stay mutually consistent (#1016
authors the enum from the same lore; W-SES-03 flags divergence), that
unification was considered and rejected (each carries info the other can't),
and clarifies the DB-canonical / index.md-projection data flow (only the
prose sections are authored in-place). Surfaced when the content-pass review
questioned the redundancy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
make regen-db with the D-237 authored layer live: 27-row
specialization_vocabulary, economic_specialization + cultural_specialization
on 27 hero systems, dominant_faction on the authored set. Meta stamp fresh
(check-systems-db OK). Unauthored systems remain NULL pending the #1014
fallback and #1016 content pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #1015 V-SES-03 edit replaced the vocabulary validation loop body and
dropped the trailing vocab_rows.append(), so specialization_vocabulary was
inserted with 0 rows even though per-system UPSERTs (which read the dict
directly via valid_spec_ids) still succeeded. regen-db reported
'vocab 0 | economic 27 | ...'. Restored the append at the end of the loop.
Verified: regen-db now writes 27 vocab rows + 27/27 economic/cultural;
spot checks financial_hub=NonPhysical/Specialist, Ran=breadbasket.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the V-SES / V-FAC guardrail suite to import_system_specialization():
Always-on hard errors (abort the import transaction): V-SES-01 economic
value in vocabulary; V-SES-03 production_ubiquity_override >= commodity
catalog concentration (HUB values with empty override exempt — they
intentionally project lower); V-SES-04 cultural value in the combined
activity+heritage vocabulary; V-SES-05 faction in 8-value vocab; V-SES-06
vocab commodity FK; plus unknown system_id.
Completeness gates — V-SES-02 (every inhabited system resolves a non-null
economic value) and V-FAC-01 (every inhabited named system has authored
faction) — are HARD only under --strict-specialization (default off). Their
preconditions are the #1014 heuristic fallback (blocked by #982) and the
#1016 content pass; until those land they print as warnings so regen-db
stays green.
Soft warnings (always print): W-SES-01 MonopolySource D-177 review list,
W-SES-02 single-value concentration, W-SES-08 estate_farming + large pop,
W-FAC-01 compact + TRACTUS currency, W-FAC-02 compact + MonopolySource
(terroir/marble exempt), W-FAC-03 syndic_dominant w/o corp HQ, W-FAC-04
compact_sympathetic + MARK currency. Coverage report always prints
economic/cultural/faction counts + BulkClass/ProductionUbiquity dists.
Cultural vocabulary is _CULTURAL_ACTIVITY | _CULTURAL_HERITAGE module
constants — #1016 adds heritage values there in one place.
Validated on a copy of the live DB: default exits 0 (gates as warnings, real
W-SES-08 hit on Arbour); strict exits 1 on V-SES-02 (Sol, Struve) and rolls
back cleanly; dry-run exits 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the D-237 authored specialization layer into import_economics.py:
- import_system_specialization(): reads specialization_vocabulary.toml
(FK-validated against commodities; repopulates specialization_vocabulary)
and system_specialization.toml (UPSERTs economic_specialization +
cultural_specialization onto system_economy, dominant_faction onto
system_factions for authored systems only). Hard errors on bad commodity
FK / projected enum / unknown system_id abort the transaction; prints a
coverage report + missing-row warnings.
- Called as step 4b in main() (after commodities so the FK resolves, before
currency zones). economic/cultural columns are importer-owned and cleared
to NULL first for idempotency; dominant_faction only overwritten for
authored systems (never globally cleared — shared with other derivation).
- specialization_vocabulary added to MIGRATION_SQL (after commodities for FK)
so the migration path on existing DBs creates the table, not just fresh
systems-schema.sql builds — this is what #1011 missed. Also cleared before
commodities in the FK-safe clear block.
- Both source TOMLs added to IMPORT_ECONOMICS_SOURCES and mirrored in
check-systems-db-stamp GENERATOR_SOURCES so editing them flips the stamp.
Validated: full non-dry-run import on a copy of the live systems.db exits 0;
27 vocab rows, 27/27/27 economic/cultural/faction set, no missing rows;
spot checks Ran=breadbasket/agrarian, Vuurkloof=independent,
financial_hub=NonPhysical/Specialist. Dry-run also exits 0.
V-SES CI guardrail suite remains #1015; code note flags that V-SES-03
(equal-or-higher) must not hard-fail HUB specializations.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per maintainer call — 3 was too tight for the parallel Phase 4 work in
flight; 5 better matches how many tickets are genuinely active at once.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes ticket #1010. The D-237 record and D-233 re-amendment landed
earlier; this adds the three downstream amendments:
- D-199: read-set gains economic_specialization + cultural_specialization;
dominant_faction now authored-sourced where present.
- D-214: dominant_faction is an authored 8-value vocabulary for named
systems (heuristic fallback otherwise); lattice_commission is not a
faction value (Commission is a regulator). Archetype mapping unchanged
but now reads a trustworthy faction for the systems the heuristic got
wrong (e.g. Groombridge → Syndic/Corporate, not Commission).
- D-232: template draw reads authored cultural_specialization to select/
bias the pool when founding heritage diverges from the corridor baseline
(Phase-4 correctness, not flavor); NULL = existing corridor algorithm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The D-233/D-237 built-world fill model is implicitly a surface model
(roofed-coverage fraction, operations surface, scatter-vs-concentrate on
open ground), but bodies.settlement_pattern already carries enclosed
morphologies (underground_concentrated, cave, domed, underground_complex)
that nothing in the chain reads — not in the D-199 read-set, not in
city_context_reader, not in skeleton_gen. Engine z-level primitives exist
(D-110, D-106, UndergroundComplex) but no morphology switch connects them
at the built-world layer, so a body like Vuurkloof (GJ 35) would generate
as a surface town against its underground-concentrated lore.
Q-108 schedules the surface-vs-enclosed morphology debate before the
Phase 4 content pass authors built form for enclosed-habitat bodies.
Tracked by ticket #1018. Surfaced via Vuurkloof during the
system-economic-specialization workshop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the D-237 authored specialization layer (and D-233 re-amendment) under
[Unreleased].
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Running notes for a later workshop-start pass: read-only participant agents
can't self-write output files (lead-as-scribe relay needed); SI has no
round-1 task; create+assign tasks before spawning; TaskCreate is one-per-call;
decision claim is not idempotent (caused a stray duplicate ID); the optional
scout-critic idea and its guardrails; and background always-present teammates
can be slow to consume shutdown_request at wrap-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three-round design workshop (Miri, Burnelli-Sheldon, Paula; documented by
Qatux, ticketed by SI) that produced D-237. Includes per-agent round
outputs, round notes, the independent scout critique, and the final
workshop-outcomes.md with the consolidated schema, 27-value economic
vocabulary, cultural + faction vocabularies, deterministic-varied fallback
spec, must-pin table, and CI guardrails.
Clerk-Skip: workshop discussion docs, no D-record surface (D-237 filed separately)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add D-237: each inhabited system carries three authored, static (t=0),
deterministic per-system identity fields sourced from
wiki/economics/system_specialization.toml — economic_specialization
(27-value vocabulary, scale encoded in the value), cultural_specialization
(unified activity + heritage vocabulary), and dominant_faction (populate
the existing system_factions column, 8 values, lattice_commission dropped).
Authored lore wins; a deterministic-varied seed-hashed weighted draw is the
fallback for unnamed systems so they don't read identically.
Re-amend D-233 to source dominant_bulk_class x dominant_production_ubiquity
from this authored layer (heuristic becomes fallback). Groombridge encodes
as a financial_hub Specialist district with the GSH clearing house as a
D-222/D-232 landmark rather than a composite vocabulary value.
Add the specialization-layer d2 diagram (3 fields -> D-233/D-232/D-214
consumers). Produced by the system-economic-specialization workshop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- settings.json: add Read(repo/**), Read(/tmp/**), Grep, Glob to the
allowlist. Teammates inherit settings.json (not settings.local.json),
which had no Read rule — so every teammate file read escalated to the
lead as a per-file prompt. This closes that gap.
- Add the system-economic-specialization workshop brief (lore-authored
per-system dominant-commodity field + within-system weighted variation;
Q5 covers adding a small identity field set in the same 300-system pass).
Note: agent memory-strip (6c93b698f) + this read-allow reach teammates
only after a Claude Code restart (settings/agent-def snapshot is taken at
lead startup).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address PR #145 review. Convert prosperity from f32 to integer basis
points (matching the existing prosperity_bps, D-010 integer-only),
removing both float-determinism bugs by construction:
- New server/src/bps.rs: log10_floor (integer order-of-magnitude) +
bps_to_f32 edge helper, with boundary tests.
- city_context_reader: prosperity_baseline_bps (u32, 0-10000). role base
+ pop bonus (400*log10_floor, cap 1200) + symmetric noise via integer
modulo (fixes the always-negative bug) + clamp [1000,9500]. No floats.
- CityGenerationContext.prosperity_baseline -> prosperity_baseline_bps;
updated the two test context builders. Not serialized — no wire break.
- district_mix population_tier now uses log10_floor (same determinism
bug class as the comment claimed to avoid).
- Tests in bps + assert positive noise is achievable (the case the old
test hid).
cargo check/clippy --all-targets -D warnings clean; 1291 lib tests pass;
fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Only Qatux (the librarian — cross-session recall is its job) keeps
project memory. Removed memory: project from the 20 ephemeral
implementer/reviewer/design agents that are spawned per-task and die:
they have no curation discipline and already use decisions/ + briefings/
as shared memory, so an uncurated per-agent store only invited rot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layer 2 clean half. GenerateSkeleton now builds a CityGenerationContext
from a body's real economic read-set instead of stub defaults.
- New CityContextReader (server/src/atlas/city_context_reader.rs): reads
the 6-field D-199 set (economic_role, prosperity_baseline, population,
dominant_faction, founding_age_years, settlement_class) via one JOIN;
prosperity_baseline derived per D-197.
- GenWorkItem::GenerateSkeleton carries the resolved context; run_work_item
builds the real context instead of DistrictWorldState::default().
- Left at defaults (deferred, documented): dominant_bulk_class /
dominant_production_ubiquity (#982, design-blocked), trait_selection
(#1005), morphology_zone + Layer-3 fields (attractor placement / D-204 /
D-214).
16 new tests; cargo check/clippy --all-targets -D warnings clean; 1279
lib tests pass; fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- pr-review §7a: after a PR merges, recommend tearing down the worktree
and deleting the merged topic branch (local + origin) by default —
state the action, let the user decline; never touch protected branches;
git branch -d as the unmerged-work safety net.
- whats-next §3c: document the worktree lifecycle — created at activation,
removed by pr-review §7a at merge; prune stale worktrees before creating.
Closes the gap that left empty worktrees parked at main's HEAD.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Update D-216 amendment text to match the implemented decision:
events-first uses event_type='colonial_charter' (9 systems, 11 bodies,
5 diverging from wave) — not the stale founding/first_settlement/
colonization scaffolding vocabulary.
- Add ORDER BY sort_order ASC to the colonial_charter subquery for a
deterministic pick if a system ever has two charter rows.
- Add explicit ELSE NULL to the wave-fallback CASE so an unexpected
settlement_wave leaves a trace instead of silently nulling.
Data unchanged: 269/273 set, 4 Sol NULL; stamp fresh.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add D-230 skeleton: DistrictSkeleton field to DistrictWorldState;
cascade Default to DistrictSkeleton + contained enums/structs. Box the
GenCompletion::SkeletonGenerated state to avoid large_enum_variant.
- Derive PartialEq on FloorExtent/FloorHeightProfile/DistrictWorldState/
CityGenerationContext (+ minimal cascade) for downstream assert_eq tests.
- Add 4 unit tests for floor_at_voxel_z / voxel_range_for_floor (uniform,
basement, variable heights, boundary) — the Q-104 deliverable.
- Drop unused smallvec direct dep (stays transitive via bevy_ecs).
- Key districts insert by skeleton.district_id, sharpen TODO(#957).
clippy --all-targets -D warnings clean; 1263 lib tests pass; fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Define the type-definition layer the Phase-4 fill-seam tickets depend on
(D-229/D-230/D-231/D-232/D-233), compiling with stubs/defaults; behavior
logic lands in #982-985/#998.
- New types in generator.rs: BuildingPropertyTag, FloorExtent +
FloorHeightProfile (floor_at_voxel_z/voxel_range_for_floor, resolves
Q-104), BuildingEntryClass, ConstructionEra, ZoneTypeId, MorphologyZone,
BulkClass(5), ProductionUbiquity, DoorSpec, InteriorDescriptor,
DistrictWorldState.
- Rename spatial AccessTier -> ZoneAccessTier to free the name for the new
per-building BuildingEntryClass.
- CityGenerationContext: +morphology_zone, +trait_selection,
+dominant_bulk_class, +dominant_production_ubiquity.
- BodyWorldState: +districts (DistrictWorldState w/ block_tags).
- GenCompletion::SkeletonGenerated carries body_id + DistrictWorldState;
plugin handler inserts into BodyWorldState.districts.
- Add smallvec as a direct dep (DoorSpec list stays Vec for now, TODO).
cargo check --all-targets / clippy clean; 1259 lib tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Anchors the events-first / wave-fallback COALESCE that #1000 will write into import_economics.py MIGRATION_SQL. Founding-edge values from systems-framework-final-miri.md: wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40, origin=NULL (Sol excluded per D-236). historical_events is currently empty so events-first is forward-compatible scaffolding; wave-fallback is the practical default for all 273 inhabited bodies today.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Formalises what was previously implicit in D-223's naming exemption and GJ-0's wiki frontmatter into a single canonical scope rule. (a) Phase-4+ generation pipelines exclude Sol bodies (settlement_wave='origin' gate); (b) Atlas renders Sol at system level only -- no zoom; (c) deeper Sol treatment is reserved for a future DLC. Cross-refs D-145 (DLC precedent), D-191 (Atlas Phase-3), D-223.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
From the Si refinement of the Phase-4 fill-seam tickets. D-097: the mandatory-check gate keys on ComplexityTier, not WorldTier (wording fix). D-233: bulk_class is the 8->5 built-form projection (the 8 cargo-types stay on commodities); a settlement's dominant commodity is derived from its production chains, not an authored role->commodity table. D-234: streets are two-layer — MST arterials (Civ6-style, the guarantee-audit graph) + +/-45deg grid local streets (Civ4-style); Voronoi rejected (breaks +/-45 + the axis-aligned footprint fast-path). Ticket-level refinements (foundational types task, era-gating fix, catalog resequence) live in the ticket DB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Stage-2 workshop brief and the consolidated three-scan coverage map (per-step decided-vs-open across the 4-step built-world pipeline) that became round 2's foundation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas_gen_open opens the real atlas app via HudGroups, navigates to GJ71c's
regional screen, and enables the Layer-1 overlays — exercising the production
opener + the live request→cascade→render pipeline against a --test-mode server
(SR_LIVE=1). Capture with: tests/run-visual --screenshot atlas_gen_open.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Generation overlays map positions from Layer1Output.grid_w/grid_h onto the
displayed texture (not the markers.json grid), fixing the off-by-2 scale.
- AtlasViewer loads ImplantPending by path instead of referencing the new
class_name, so a stale global-class cache (a session that hasn't re-imported
after the class was added) can't fail to parse AtlasViewer and break the
atlas from opening.
- Rivers and mouths use the reliefmap's own water colour (sampled median ocean
blue) so river lines blend into surface water instead of reading as a
distinct-coloured line flowing onto the sea.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two Layer-1 generation fixes surfaced by the per-layer atlas viewer:
- Layer1Output now carries grid_w/grid_h (the downsampled working-grid the
positions live in). The client maps overlays from these, so the scale is
correct for any source heightmap resolution rather than assuming the texture
size — fixes overlays projecting at half scale into a corner.
- Drainage basin boundaries are traced as ordered, non-self-crossing contours
via Moore-neighbour tracing instead of an angle-from-centroid sort. The sort
produced star-shaped, self-crossing polygons for concave basins that rendered
as straight chords across the map.
Golden (cascade_layer1.json) and the cross-language atlas_response_ready
fixture regenerated. 100 atlas lib tests + the new tracer test pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ad-hoc capture scenario that overlays the ImplantPending "generating" indicator
on the booted scene for visual sign-off — `tests/run-visual --screenshot
implant_pending`. No golden committed; this is an inspection scenario, not a
regression gate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
visual_capture.gd runs via `godot -s`, where the `class_name` registry isn't
populated — so the bare `Protocol.decode_snapshot()` reference failed to
compile, breaking ALL --screenshot/--movie/golden captures (not just the
replay scenarios that use it). Instantiate the script and call the static
decoder on the instance (then free), matching the file's existing -s-mode
load() workaround for VisualScenarios.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A reusable implant-layer busy indicator (Araminta's spec): an animated
bracket sweep `[ >>>>···· ]` with a caption, themed entirely via ImplantTheme.
The Atlas shows it centered over the canvas while the Layer-1 proxy is Pending
and hides it on Ready — so cache hits never flash it and serverless mode never
shows it.
Layer separation (per direction): ImplantPending belongs to the diegetic
implant UI only. The global, non-diegetic UI layer must use its own busy
indicator with its own visuals — sharing the sweep logic is fine, resting on
this theme/these glyphs is not. Documented in the component header.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
show_body() now requests the body's Layer-1 cascade output via
SimBridge.request_atlas_layers(); the response feeds set_generation_layer1().
The proxy returns Pending on a cache miss and generates in the background
(D-225), so the viewer re-requests every 0.5s (20-retry ceiling) until Ready,
guarding against stale responses by body_id. Serverless/test mode is a no-op
(overlays stay empty). Connected in _ready, torn down in _exit_tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Formatting-only cleanup of the #969/#960-A codec + bridge scripts to match
gdformat output (the pre-push gdformat check is advisory; these landed
un-formatted). No behavior change — 70/70 protocol tests green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Render the proxied Layer1Output (D-225) as toggleable Atlas overlays. The
viewer stores the decoded Layer1Output via set_generation_layer1() and the
marker overlay draws three new layers gated by their visibility flags:
RVR river_cells as dots, confluences as small circles, mouths as
double-ring sea-terminus markers
BAS drainage-basin boundaries as thin closed polylines + faint fill
ATR geographic attractors — shape by attractor_type (Araminta's 7-shape
vocabulary), color by sub_biome, size by strength; <0.15 culled
Layer-1 positions are [row, col] in the 512x256 working grid, which matches
the viewer's grid_to_canvas transform, so they project directly onto the
heightmap. OVERLAY_DEFS gains gen_l1_rivers/basins/attractors (toggle group)
so AtlasOverlayBar auto-exposes them as toggle buttons.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Client transport half of the layer-stream protocol.
- SimBridge.request_atlas_layers(body_id) sends an AtlasLayerRequest frame
(live mode only; no-op in test mode); responses arrive via a new
atlas_layers_received signal.
- receive_bytes now decodes each frame ONCE via Protocol.decode_inbound and
branches by shape (snapshot vs atlas response) — avoids double-decoding the
20 Hz snapshot path. decode_snapshot is split into decode_raw +
_decode_snapshot_from_raw (public decode_snapshot unchanged, so the 70 protocol
tests stay the regression guard); decode_inbound returns {kind, value}.
70/70 protocol tests pass, including the new decode_inbound classifier test.
(Pre-existing client-suite failures in server-dependent e2e/roundtrip + unrelated
audio/fog/dialogue suites are unchanged — verified identical at baseline.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Client half of the layer-stream protocol (codec only; transport wiring next).
- protocol.gd: encode_atlas_layer_request (bare {body_id, up_to} map so the
server demux routes it to the proxy, not the PlayerInput array) and
decode_atlas_layer_response (-> {body_id, status, error, layer1}; returns null
for non-atlas frames, e.g. a snapshot, so receive_bytes can disambiguate).
- gen_fixtures.rs: cross-language fixtures (atlas_response_ready/pending/
not_found) from real rmp_serde output, matching the test_protocol.gd pattern.
- test_protocol.gd: 5 tests decode the fixtures + verify a snapshot is not
mistaken for a response + the request encodes to the right shape. 68/68 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the server-side layer-stream loop. serve_atlas_requests (PreInput) drains
the AtlasRequestBuffer and runs each through handle_atlas_request (cache hit ->
Ready; miss -> resolve via BodySourceResolver + enqueue an Immediate AnalyzeBody
-> Pending), buffering AtlasLayerResponses. send_atlas_responses (PostSnapshot)
flushes them to the client. main.rs wires BodySourceResolverResource (base root
= systems.db's 3rd ancestor; mod roots layer on later). Misses flow through the
#968 background tier and a re-request hits the now-warm cache.
Full path now live server-side: client request -> receive() demux -> serve ->
proxy -> (cache | queue+cascade) -> response -> client. The client half (send
request, decode response, render overlays) is #960.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>