Compare commits

...
117 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 8c5a1639f5 chore(meta): release v0.1.35
Sprint 35: Atlas — Gemma 4 naming pipeline, atlas implant UI,
brand layer schema, 24,963 named features across 299 systems.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 11:49:09 +02:00
jpmschweitzer cd75802f3f Merge remote-tracking branch 'origin/sprint-35/server' 2026-04-18 00:47:33 +02:00
jpmschweitzerandClaude Opus 4.6 160c3f1853 fix(tooling): PR #130 round 2 — stale strings, O(1) dedup, vestigial scope (#833)
- Fix "Gemma 2 GGUF" in user-facing error message (line 2073)
- Fix gemma2.gguf in docstring usage example (line 32)
- Fix O(N) _is_duplicate: pre-build lowercase shadow sets for O(1) lookup
- Expand vestigial note to enumerate full ~750-line dead island boundaries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:43:11 +02:00
jpmschweitzerandClaude Opus 4.6 8ba3a1d0a7 fix(tooling): address PR #130 review findings (#833)
Hoshe:
- Mark --dump-prompts / name_feature() as vestigial with TODO note
- Fix --refresh help string: 200 → 1000 (matches actual default)
- Fix _RIVER_POOLS comment numbering: Pool 6 before Pool 5 → correct order
- Remove dead first-pass code in fix_fewshot_bleed.py
- _CAPTURE_FILE leak noted in vestigial TODO

Tyre:
- Fix stale "Gemma 2" strings in banner, argparse description, model help
- Note dead code for cleanup pass (name_feature ~700 lines)

Hoshe (prune):
- prune_atlas_features.py: named features sort before unnamed, preventing
  silent discard of hand-authored names during pruning

naming_core:
- v0.2: few-shot blocklist, stricter is_valid_name (min 3 chars, no digits,
  no brackets), prompt fragment rejection expanded

Miri clarification: the 261 "empty-string" files contain only roads (37)
and railroads (37) — infrastructure features never in naming scope. All
cities/rivers/oceans/mountains/POIs are clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 23:27:44 +02:00
jpmschweitzerandClaude Opus 4.6 9aaaf95742 content(atlas): name 24,963 features across 299 systems via Gemma 4 pipeline (#833)
Batch naming pass across the full Settled Reach — 2,394 bodies, 299
systems, all corridors from Gateway (hop 0) to Abzu (hop 23).

Coverage: cities 100%, rivers 100%, oceans 100%, POIs 99.7%,
mountains 95.6% (699 gaps on barren moons from register exhaustion).

QA issue rate: 3.89%. Post-generation fixes applied: bracket artifacts,
few-shot bleed replacements, placeholder fills, cross-corridor corrections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 18:44:39 +02:00
jpmschweitzerandClaude Opus 4.6 508d6a7ca9 docs(architecture): atlas naming pipeline reference (#833)
Full architecture doc covering the Gemma 4 batch naming pipeline:
pipeline stages, cultural registers, body ordering, known limitations,
QA process, and extension guide.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:09:57 +02:00
jpmschweitzerandClaude Opus 4.6 9ad9b88d7c feat(tooling): Gemma 4 batch naming pipeline with wiki-grounded register selection (#833)
Replace the one-at-a-time Gemma 2 naming pipeline with a batch-oriented
Gemma 4 E2B pipeline. Key changes:

- naming_core.py: shared library with Levenshtein distinctiveness ranking,
  batch prompt building, mood injection pool, name validation, and
  adjacent-register refill logic
- Wiki-grounded register selection: per-system LLM call picks the cultural
  register based on wiki/GTTR content instead of hash randomizer
- Batch naming: requests N*2 names per call, ranks by word-average
  Levenshtein distance, fills quota from most-distinct candidates
- Mood pool: 13 emotional seeds randomized per-body for vocabulary
  divergence (ambition, fear, isolation, defiance, etc.)
- Adjacent-register refill: when primary register exhausts, automatically
  switches to next corridor substyle
- Inhabited-first body ordering: habitable worlds get first pick of
  register vocabulary, barren moons get leftovers
- Process group cleanup: SIGTERM/SIGKILL the full distrobox chain on
  subprocess refresh to prevent GPU zombie processes
- qa_naming.py: QA report, fix_fewshot_bleed.py: post-hoc fix script
- test_batch_naming.py, test_register_selection.py: test harnesses

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:09:23 +02:00
jpmschweitzerandClaude Opus 4.6 474b31b214 fix(tooling): only log rejections when all attempts exhausted (#833)
Individual dedup/blocklist/placeholder/empty rejections that recover
on the next attempt are now silent. Only the skipped: summary line
prints when all 5 attempts fail. Subprocess errors still print
immediately (those indicate a real problem).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 12:39:46 +02:00
jpmschweitzerandClaude Opus 4.6 b63c2be8dd feat(tooling): 5 retry attempts + refresh every 1000 requests (#833)
Bumped max_attempts from 3 to 5 — with per-system dedup and no stem
cap, the remaining dedup hits are mostly per-body collisions which
a couple extra attempts with rotated pools can escape.

Bumped --refresh default from 200 to 1000. Fewer subprocess restarts
= fewer model reloads via distrobox. KV-cache bleed risk is lower
now that the validation gauntlet is lighter.

Reverted the batch-prompt experiment — Gemma 2 2B drifts on
multi-line output; individual calls are more reliable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 12:36:46 +02:00
jpmschweitzerandClaude Opus 4.6 05a1366544 refactor(tooling): drop stem cap + scope dedup to per-system (#833)
The stem cap (--stem-cap 20) was rejecting valid names because common
feature-type vocabulary tokens like "ridge", "hill", "range" hit the
cap after ~200 bodies and blocked all subsequent names containing
them. With sub-style rotation already providing variety, the cap was
doing more harm than good. Removed entirely.

Cross-body dedup narrowed from (hop, corridor, feature_type) to
(system_id, feature_type). Two rivers in the same system can't share
a name; two rivers in different systems can. This matches how
settlers actually name things — they don't coordinate with other
star systems.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 12:30:13 +02:00
jpmschweitzerandClaude Opus 4.6 cb178a8c57 feat(tooling): per-system sub-style rotation across all corridors (#833)
Replace single-inflection corridor palettes with lists of sub-styles.
Each system picks one deterministically via hash(system_id), so all
bodies in the same system share a cultural register but neighbouring
systems get different registers.

Core corridor splits into 6 sub-styles (English rural, British
colonial, US rural, US cosmopolitan, classical/institutional,
Australian/NZ). North/south/east/west reach each get 5 sub-styles
covering their cultural spectrum. Deep frontier gets 3 (founder-name,
surveyor-descriptive, outpost-functional).

This multiplies Gemma's effective vocabulary per corridor by the
sub-style count, dramatically reducing dedup pressure. A 6-style
core corridor means each sub-style serves ~4 systems instead of 24,
so "The Ridge" exhausts after ~4 systems, not ~24.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:53:02 +02:00
jpmschweitzerandClaude Opus 4.6 3ab28138a0 feat(tooling): skip dedup-exhausted features instead of palette fallback (#833)
When all 3 LLM attempts are rejected (dedup, blocklist, etc.),
name_feature now returns None instead of a deterministic palette
fallback. process_body leaves the name as null in markers.json.

The preserved path (_is_blank) treats null as unnamed, so a fill
round (re-running the script) picks up only the skipped features
with a fresh corpus — zero dedup pressure from the first pass. The
fill round can use a different seed, slower prompt, or a different
backend entirely (e.g. Haiku).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:42:32 +02:00
jpmschweitzerandClaude Opus 4.6 c767f82fbb feat(tooling): scope cross-body dedup to hop+corridor (#833)
Changed dedup key from (corridor, feature_type) to
(hop, corridor, feature_type). Systems at the same gate-hop distance
in the same corridor are near neighbors and shouldn't share feature
names; systems at different hops can. This prevents corpus exhaustion
where Gemma's narrow range-name distribution ("The Ridge", "Blackwood
Range") collides after ~20 bodies and drives fallback rates toward
100%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:37:28 +02:00
jpmschweitzerandClaude Opus 4.6 a64077f1ad chore(tooling): renumber feature IDs in all markers.json (#833)
The upstream terrain pipeline assigns sparse IDs (range_1, range_50,
range_29...) and the prune pass drops entries but keeps original IDs.
This leaves 2394 bodies with non-sequential IDs across mountain_ranges,
rivers, and oceans.

Renumbered all feature IDs to sequential {prefix}_0, {prefix}_1, ...
preserving sort order. 24021 IDs fixed across 2394 bodies. No name
or geometry data changed — only the id field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:37:12 +02:00
jpmschweitzerandClaude Opus 4.6 e0707d8072 feat(tooling): always log retry reasons in gemma_naming.py (#833)
Retry rejection lines (dedup, blocklist, placeholder, stem_cap, empty,
error) now print unconditionally, not only under --verbose. The
fallback line also includes a tally of the rejection reasons that
exhausted all attempts, e.g.:

    fallback: GJ144e-1/range_43 → 'Kirkwood Spine'  [blocklist=2 dedup=1]

Diagnostic run on 20 bodies confirms dedup is the primary fallback
driver. Gemma converges on a narrow set of range names ("The Ridge",
"Blackwood Range", "The Spine") that collide across bodies in the
same corridor. Blocklist catches "Thames" and "The Great Divide"
correctly. Zero stem-cap or subprocess-error fallbacks observed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:20:36 +02:00
jpmschweitzerandClaude Opus 4.6 d5a437ea2d fix(tooling): run-atlas-naming.sh — use grep -a instead of strings (#833)
The gfx1201 preflight check piped `strings` into grep, which fails
silently on a Bazzite host where binutils is not installed and
`strings` is not on PATH. `grep -a` reads the binary directly as
text, works everywhere grep exists, and produces the same result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:18:40 +02:00
jpmschweitzerandClaude Opus 4.6 bcff9f724b feat(tooling): run-atlas-naming.sh — overnight batch naming launcher (#833)
Wraps gemma_naming.py with the validated overnight recipe: gfx1201
ROCm binary path, distrobox reach-build for libhipblas at runtime,
timestamped log under .tmp/.

Preflight checks: binary exists and is executable, model present,
reach-build container exists, binary strings contains gfx1201 kernels.
Fails fast on any missing prerequisite so a broken build can't waste
an overnight window. Script takes no arguments; anything passed is
rejected so a stray --help can't accidentally launch the pipeline.

Estimate ~4-6 h for ~26k features across 2394 bodies at 74 t/s on an
RX 9070. Safe to interrupt and resume — preserved path skips
already-named bodies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:15:52 +02:00
jpmschweitzerandClaude Opus 4.6 c089557d65 feat(tooling): out-of-worktree sr-voice discovery + distrobox wrap + prompt capture (#833)
Three additions unlocked by the gfx1201 ROCm debug session.

1. _find_sr_voice() resolves the default binary path to
   ~/Projects/settled-reach/binaries/sr-voice-rocm (persistent across
   worktree lifetimes) with a legacy fallback to the main workdir's
   cargo target dir. Matches #850's plan to ship platform binaries
   outside the repo.

2. --distrobox <name> wraps the sr-voice subprocess in
   `distrobox enter <name> --` when the built binary depends on libs
   that only exist inside a dev container (libhipblas.so.2 on a
   Bazzite host). Stdio JSONL protocol flows through unchanged.

3. --dump-prompts PATH captures the attempt-0 prompt for every
   feature as JSONL without calling an LLM. Force --mock and
   short-circuit name_feature to return a unique deterministic
   placeholder. Used to feed the same prompt set to alternate
   backends (Haiku agent, other models) for offline A/B comparison
   of naming quality independent of the sampling backend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:11:28 +02:00
jpmschweitzerandClaude Opus 4.6 cf8a4e37d8 fix(engine): offload Gemma to GPU by setting n_gpu_layers=999 (#833)
LlamaModelParams::default() sets n_gpu_layers=0, so even with --features
rocm the model ran entirely on CPU at ~19 t/s. Setting n_gpu_layers to a
large sentinel value asks llama.cpp to offload every layer the model
has; llama.cpp clamps to the real count (27 for Gemma 2 2B). Observed
throughput jumps from 19 t/s to 74 t/s on an RX 9070 once the ROCm
binary is also compiled for gfx1201 (see tooling commit).

Also adds server/sr-voice/.gitignore so locally-built binaries don't
sneak into the worktree. Release binaries ship out-of-tree per #850.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:11:14 +02:00
jpmschweitzer fddb8b7544 chore(tooling): reset 19 stale core bodies so gttr-context fix reaches them (#833)
Previous runs (both the GPU-contention kill and the anglophone-only
interrupt) left 19 hop 0-1 core bodies with stale generator output in
their markers.json files. Those bodies were being skipped via the
preserved path on relaunch, which meant the gttr-context fix
(commit a5fbce4c) would never touch them — exactly the set of
high-visibility systems that benefits most from per-system cohesion.

Reset to origin/main (clean null-name state) + re-prune to the 8/6
caps. Hand-authored templates (Edict, Estrade, Vuurkloof, Lendel,
Cairnside, Røros) explicitly excluded from the reset list and
verified intact (2-4 named cities each, untouched).

After this commit only the 6 hand-authored templates have
populated names in wiki/star-systems/. The entire rest of the reach
is clean and will be freshly named by the next gemma_naming.py run
with the full gttr + cosmopolitan + grounded few-shot + rotating
pool stack.

Bodies reset:
- Ran (GJ 144): all 9 bodies
- Sirius (GJ 244A): GJ244Ab, c, e-1, e-2 (not Ad, that's Edict)
- ACB (GJ 559B): GJ559Bb
- Tau Ceti (GJ 71): GJ71b, c, d, d-1, e
2026-04-15 12:41:13 +02:00
jpmschweitzer a5fbce4cc9 feat(tooling): per-system gttr context + cosmopolitan corridor palettes (#833)
Two related quality fixes observed mid-run on Sirius + ACB + Ran:

1) Cosmopolitan corridor palettes. The six corridor inflection labels
were single-culture dominant ("administrative English / Gateway-era",
"British / Australian / Irish", "Korean/Japanese/Taiwanese", etc).
Gemma 2 2B interpreted these as "produce ONLY in this register" and
every core body came out anglophone, every east_reach body came out
East Asian. The real Earth diaspora in the setting is cosmopolitan —
a British surveyor on an east_reach moon still names a river after
their aunt in Dorset. The labels now spell out the dominant register
AND explicitly invite cross-cultural variety so Gemma samples from
the full few-shot pool instead of collapsing to one culture.

2) Per-system gttr context (the big one). The gttr.md files under
wiki/star-systems/<slug>/gttr.md already carry a vivid one-sentence
characterisation of every system — "where the rules live", "forty
years old and still in the draft", "the most connected system in
the Reach", "grandparents owned the land". This is a far stronger
cultural signal than the corridor inflection alone.

New column `star_systems.gttr_hook` stores a pre-extracted 45-word
hook per system. `tooling/db/populate_gttr_hook.py` parses each
gttr.md, regex-matches the first `**NAME**` paragraph, normalises
whitespace, truncates softly at a word cap, and stores it. Covers
all 301 systems (full coverage). Idempotent, safe to re-run after
any wiki update. Explicit transaction wrapper.

gemma_naming.py loads the hook cache at startup via
`load_system_gttr_hooks` and threads `system_hook` plus the system
and body proper names through process_body → name_feature →
_build_prompt. The prompt now carries:

    System: <proper_name>. Planet: <body_name>.
    About the system: <gttr_hook>

    Style: British. Answer: Cooper's Creek
    Style: Dutch.   Answer: Meijer Beek
    ...

Real-mode smoke on 10 cases across 4 contrasting systems shows the
hook is doing exactly what it should. Sample output on the same
body_id / local_id pairs:

  Tau Ceti     (cosmopolitan hub)         → Oakham River, Riverwood, Bridle Way
  Ran          (old-family agricultural)  → Hart's Well, Blackwood Ridge
  ACB          (Lattice Commission seat)  → Greenhaven, Rudge Brook
  Posto Avançado (PT frontier dead-end)   → Rio Preto, Serra de Caxias, Cunha's Cove

Posto Avançado went from "likely-English under the old corridor-only
prompt" to actual Portuguese names with a real Brazilian place stem
(Caxias), because the hook explicitly mentions wave_5 Portuguese
founders and frontier dead-end context. The gttr cultural one-liner
is the single strongest lever available for per-system cohesion —
this was the mono-culture issue observed in the first run, now fixed.

Token cost: ~60-90 extra tokens per prompt (hook + ident line).
Inference slowdown: ~5-10% per call. Acceptable for the quality gain.

Also restores 10 markers.json files that were stale from the aborted
run just killed — they were all core bodies at hop 0-1 which benefit
most from the gttr-context upgrade, so re-running them with the new
prompt is worth the ~3 minutes of re-inference.
2026-04-15 12:37:52 +02:00
jpmschweitzer d811a4f792 feat(tooling): prune oversized mountain/river counts + richer fallback palette (#833)
Two fixes from observing the first Gemma 2 batch run on Sirius:

1) Prune oversized feature counts. The upstream terrain pipeline emits
every distinct mountain cluster as a separate `mountain_range` and
every flowing path as a separate `river`. At the atlas generator's
512×256 grid this produced bodies with 40-80 named ranges and
10-15 rivers — noise, not information. A single planet with 48
ridges isn't richer, it's unparseable.

`tooling/planet-gen/prune_atlas_features.py` walks every
`markers.json` under `wiki/star-systems/`, ranks each feature type
by a size proxy, and keeps only the top N:
  - mountain_ranges: sorted by `area_cells`, top 8 per body
  - rivers:          sorted by path length, top 6 per body
  - oceans / cities / pois: untouched (already small, or
    hand-authored by generate_atlas.py)

Sol (GJ-0) is hardcoded-excluded from pruning so the hand-authored
Earth / Mars / moon content stays untouched.

Each pruned body gets its atlas_* rows re-synced via
`sync_markers_to_db` so the DB mirror stays consistent. Bodies
whose wiki folder has no matching row in `bodies` (14 pre-existing
orphans like GJ1156h-1, GJ34Ah-2, …) are pruned in-file but skip
the DB sync to avoid FK violations on atlas_body_grids.

First run results:
  bodies scanned:           2394
  bodies pruned:            1513
  mountain ranges dropped: 11640
  rivers dropped:           1382

Safe to re-run — idempotent when a body is already within the caps.

2) Grounded cosmopolitan fallback palette. When Gemma's 3 retries
all fail (dedup, blocklist, stem-cap, placeholder), the code falls
to `_FALLBACK_STEMS[corridor]`. The old table had 10 stems per
corridor, all Latin-institutional (Meridian, Concord, Prefecture,
Cardinal, Lumen, Foro, Tabula, Vox, Axis, Senatus), which produced
the same-y `Axis Spine / Axis Ridge / Axis Heights / Axis Scarp`
clusters the user flagged on Sirius — exactly the old epic-Latin
register the few-shot pools were rewritten to avoid.

Fallbacks now draw from a 30-45 stem grounded cosmopolitan list
per corridor matching the few-shot pool intent:
  - core:          45 stems (Ashfield, Bellview, Cedarbrook,
                   Fairmont, Ironwood, Kirkwood, Linden, Meridian,
                   Northfield, Riverside, Westbrook, …)
  - north_reach:   40 stems (Ashford, Bellfield, Clifford, Drayton,
                   Elmhurst, Garner, Holmwood, Kelsworth, …)
  - west_reach:    35 stems (Altdorf, Bergfjord, Eikhof, Hoogland,
                   Järvenpää, Kloosterdam, Nieuwpoort, Sørholm,
                   Svarteberg, Torsfell, Voorhout, Weserhof, Östby, …)
  - east_reach:    35 stems (Aomori, Baektu, Chōshi, Fukagawa,
                   Hanyang, Izumi, Takamine, Yurigawa, …)
  - south_reach:   36 stems (Alves, Brandão, Évora, Gomes, Ribeiro,
                   Serra, Várzea, Hlanganani, Kilimi, …)
  - deep_frontier: 30 stems (Okafor, Stenner, Weller, Kellogg,
                   Stonebrook, Dustgate, Blackwater, …)

Per-feature suffix lists also expanded (e.g. river suffixes now
include Brook, Stream, Flow, Creek on top of the original Run /
Water / Beck / Rill / Course). Net effect: 300-450 unique fallback
combinations per (corridor, feature_type), up from 50, in the same
grounded register the few-shot pools teach.

Also preserves aliases `inner_corridor`, `inner_orbit`, and
`sol-gateway-axis` as legacy-compatible keys pointing at the
administrative-English palette.

Combined effect on the next run:
- ~45% fewer features to name (pruned 13k/52k)
- ~9× more fallback variety per corridor when fallback does trigger
- Same grounding overhaul from the previous commit, now reaching
  into the safety-net path
2026-04-15 12:15:07 +02:00
jpmschweitzer cbeadc3184 feat(tooling): grounding overhaul + richer naming palettes (#833)
Substantial quality pass on gemma_naming.py driven by user review of
the first real-mode smoke test output. The earlier run produced names
that read too sci-fi / epic-fantasy / same-y: Aureus, Aetheria,
Stellaris, Nexus, Elysium. Root cause analysis + fixes:

1. Runtime timestamps. The log prefix is now
   `[HH:MM:SS +00h03m]` — clock time plus elapsed-since-start. Gives
   the user an at-a-glance sense of how long the run has been going
   without scrolling back to the banner.

2. System / body headers. When the loop enters a new system it prints
   `── SYSTEM K/N  GJ 71 — Tau Ceti  (hop 0)`. Each body line now
   shows `GJ71c (Threshold)` if the body has a proper_name in
   systems.db, so the log reads like a tour of the reach rather than
   a wall of body_id slugs. Preserved (already-named) bodies now log
   a compact "(skip — N names already set)" line so progress is
   visible even when no inference happened.

3. Prompt grounding overhaul. The old few-shot examples were all
   classical/epic (Wolcott Beck, Nakamura Stream, Ribeiro do Sal,
   Drayton Spine) which biased Gemma 2 2B toward Latin/Greek
   coinages. New preambles use the shape:
       "Settlers named X after themselves, after what they saw, or
        after places back home. Most names are mundane, short, and
        direct — a surname, a compass direction, a feature, a
        practical description. Classical or epic names are rare."
   Combined with grounded example pools, Gemma now produces names
   like "Cooper's Creek", "Western Ridge", "The Highroad",
   "Blackwood Creek", "Dustbowl".

4. Core corridor relabel. The "core" palette inflection was
   "institutional Latin / pan-Anglo / Gateway-era", which pattern-
   matched in Gemma's training data to "make up Latin-sounding
   words" (→ Ardenia, Aurelia, Stellaris). Now it's
   "administrative English / Gateway-era" and the outputs are
   prosaic — Port Dundas, East Ridge, Meridian, Landing.

5. Rotating few-shot example pools. Each feature type now has 5-7
   pools of 5-6 examples each. `_build_prompt()` picks a pool
   deterministically per (body_id, local_id, attempt) so:
   - Same feature always gets the same prompt (determinism preserved).
   - Neighbouring features on the same body get different prompts
     (output variance — the sampler doesn't collapse to a single
     mode when you ask for 16 mountain names in a row).
   - Retries rotate to a new pool, not just a bumped seed, giving
     dedup failures a clean second attempt.

6. Cosmopolitan cultural variety in the examples. Earlier pools only
   showed British/Australian, Korean/Japanese, Portuguese/Swahili,
   German/Dutch/Nordic axes — the four reach corridors. Gemma learned
   "names come in four flavours". New pools span Dutch, Nordic,
   Italian, French, Polish, Hungarian, Czech, Spanish, Russian,
   Finnish, Greek, Irish, Japanese, and British — teaching the model
   that names can be any real Earth cultural register, not just the
   corridor label. The result: actual Dutch names (Egelantier,
   Hochland, Van Damhoeve), actual Nordic (Lundstad, Brygga),
   actual Italian (Borgo Marconi, Piazza Nuova), etc.

7. First-name possessive pools. Per user feedback, settler naming
   includes both surnames ("Cooper's Creek") and first names
   ("Clifford's Bay", "Maura's Run", "Yuki's Pool"). Each feature
   type now has a dedicated first-name-possessive pool in addition
   to the existing surname pool — the two rotate alongside so both
   patterns show up without either dominating.

8. One "classical/Latinate" pool per feature type (≈17% of calls
   given 5-7 pools per type). Keeps occasional Latin flavour without
   making it dominant — the user explicitly noted that replacing
   one pattern with another "is never a clean fix for a randomizer."

9. Earth-name blocklist expansion. The Gemma 2 model reached for
   real European names ("Weser", "Rhine", "Reykjavik") in the first
   real run. Added 21 European rivers (Rhine, Weser, Elbe, Oder,
   Vistula, Loire, Rhône, Douro, Tagus, Ebro, Po, Arno, Tiber, …)
   and 25 Nordic/Eastern European cities (Reykjavik, Oslo, Gdansk,
   Krakow, Prague, Warsaw, Budapest, Belgrade, …). Case-insensitive
   "The <name>" stripping still applies so "The Great Divide" also
   matches "Great Divide".

Combined smoke test after these changes (10 real-mode prompts across
core + west_reach):
  - core:       Port Dundas, The Backbone, Dustbowl, Blackwood Creek
  - west_reach: Egelantier, Hochland, Der Rücken, Lundstad, Klipfjord
  - no placeholder residue, no markdown, no 5+ word outputs.

--shard is gone (dead code since GPU contention killed parallelism).
Resume semantics are still free: re-run the same command and
already-named bodies skip via the preserved path.
2026-04-15 11:35:07 +02:00
jpmschweitzer 6decf56b2d refactor(tooling): drop --shard from gemma_naming.py (#833)
Parallelism via two concurrent sr-voice subprocesses does not work on
this ROCm + llama-cpp-rs setup — launching a second instance poisons
the first one's GPU context (both fall back to 0% GPU / 50% CPU
busy-loop and stop making progress). Verified empirically: single
shard runs cleanly at ~1.2s/feature, two shards deadlock.

Without a working parallel path, --shard is dead weight. Resume
semantics were already free: the pipeline skips bodies whose
markers.json has non-empty name fields (preserved path), so a
killed run re-starts just by re-running the same command.

Simplifications:
- Remove --shard argument and all slicing logic.
- Remove banner_shard / shard_offset / shard_n / shard_m plumbing.
- Rename internal total_shard_systems → total_systems.
- Default --log path is now .tmp/gemma_naming.log (was conditional
  on --shard). Pass `--log -` to disable file logging.
- Startup banner now prints a one-line resume reminder so the user
  can see at a glance that a killed run is recoverable.
2026-04-15 11:05:25 +02:00
jpmschweitzer 1efbbcaea9 feat(tooling): gemma_naming.py batch naming pipeline for atlas (#833)
New end-to-end pipeline that walks every markers.json in the reach and
fills empty `name` fields using the Gemma 2 voice pipeline via
`sr-voice serve --stdio`. Per D-191 §4: the same Gemma 2 pipeline the
client uses for NPC voicing also produces the atlas content, which is
dual-purposed as a quality test of the LLM plumbing.

Pipeline per body (hop-ordered, core-first):
  1. Load markers.json; identify feature records whose `name` is
     blank (null or ""). Hand-authored names are never overwritten;
     the 6 template bodies and any partial authoring stay put.
  2. Look up body context (planet_class, settlement_pattern,
     cultural_corridor, population, economic_role) from systems.db.
  3. Build a short corridor-aware few-shot prompt per feature type.
     Prompts carry 3 concrete `Style: X.   Answer: Y` examples so
     Gemma 2 2B completes a pattern instead of generating to an
     open-ended instruction — this is the single biggest lever
     against placeholder echoes on a small model.
  4. Stream the prompt into a long-lived sr-voice subprocess, read
     the JSONL response, post-process (strip markdown, label
     prefixes, brackets, reject 5+ word outputs and placeholder
     tokens), check the earth-name blocklist, check per-(corridor,
     feature_type) + per-body dedup, check the per-stem cap, retry
     up to 3 times with a bumped seed.
  5. On persistent failure, fall back to a deterministic palette
     generator so every feature ends up with a name.
  6. Write markers.json atomically and refresh atlas_* DB rows via
     sync_markers_to_db. Commit the DB per body so a crash loses
     at most one body of state.
  7. Restart the sr-voice subprocess every `--refresh` requests
     (default: 200) to prevent KV-cache context bleed.

Core design decisions:
- Determinism: per-(world_seed, body_id, feature_local_id, attempt)
  seed so the full run is reproducible.
- Ordering: bodies are processed in ascending `hop_distance_from_gateway`
  so core bodies get first pick at every unique Gemma output and
  outer sectors fall into the palette fallback when they lose the
  dedup race.
- Dedup scope: (cultural_corridor, feature_type) across the run,
  PLUS a per-body cross-type set so the same name can't be a river
  AND an ocean AND a mountain on the same world. Hand-authored names
  are seeded into both sets on load so templates win priority.
- Stem cap: each non-generic root token (e.g. 'Arcturus', 'Meridian')
  may appear at most `--stem-cap` times across the full run (default
  20), preventing single-word runaway. Fallback names bypass the cap.
- Earth blocklist: 181 curated entries covering major Earth cities,
  mountains, rivers, oceans, historical/colonial spellings, and
  Greek/Roman mythology that reads too literally. Prefixed variants
  ('Nouveau Paris', 'New Tokyo') explicitly allowed per the product
  intent that Earth-echo names are fine but must not dominate.
  Leading 'The ' is stripped before comparison so 'The Great Divide'
  also matches.

Operational features:
- `--shard N/M` slices the body list into M partitions for parallel
  runs. Two terminals × `--shard 0/2` + `--shard 1/2` fits the
  ~2.5 GB/instance VRAM footprint twice under the 50% cap on a
  16 GB AMD GPU and roughly halves wall time.
- `--log PATH` writes a timestamped tee of every status line to a
  file. Default: `.tmp/gemma_naming.shard{N}of{M}.log` when a
  non-trivial shard is in use.
- SQLite `PRAGMA journal_mode=WAL` + `busy_timeout=15000` so two
  concurrent shards serialize writes without lock errors.
- Per-body progress lines report `body K/N`, `sys K/N`, and
  `hop=H` so the user can watch core sectors finish first.
- Each body logs the new names it produced per feature type so the
  user can eyeball quality as the run progresses.
- Checkpoint summary every 25 bodies: cumulative names, rate,
  ETA — gives the log regular scroll points.
- `--mock` uses `server/sr-voice/mock-stdio.sh` for dry-fire
  pipeline validation without a model load (tested end-to-end).

Supporting files:
- `tooling/planet-gen/earth_blocklist.txt` — 181 curated entries.
- `tooling/db/backfill_cultural_corridor.py` — one-off migration
  that fills the `cultural_corridor` column on both `star_systems`
  and `bodies` from the `geographic_sector` values. Before this
  pass, 99.4% of rows (3221/3240) had a NULL cultural_corridor
  despite `wiki_sync.py` being aware of the column — the wiki
  index.md files only carry the sector header, which was never
  propagated to the DB column. Idempotent, safe to re-run after
  any wiki_sync rebuild, explicit transaction wrapper with
  rollback on failure.

Full batch runtime estimate: ~20 hours single-shard / ~10 hours
double-shard on this hardware. Smoke tests across five hardened
iterations (v1–v5) on GJ71b/c/d/d-1/e confirm the pipeline produces
clean, varied, culturally-coherent names with zero post-processing
residue.
2026-04-15 10:54:28 +02:00
jpmschweitzerandClaude Opus 4.6 d388845c88 chore(config): prune dead gitignore entries
Remove redundant and stale patterns:
- content-ron/, client-tmp/ — vanished dirs not referenced anywhere
- tooling/planet-gen/__pycache__/, sol_data/__pycache__/ — already
  covered by the global __pycache__/ pattern
- tooling/planet-gen/sol_data/.cache/ — already covered by .cache/
- db/commonwealth.db* — leftover guard from the pre-rename era;
  the stale on-disk file has been deleted

Also rewrite the misleading "Runtime databases (not tracked — created
on startup)" comment: server/data/systems.db is actually tracked, so
what the block really ignores are WAL/SHM sidecars plus the local-only
settings.db.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:21:45 +02:00
jpmschweitzerandClaude Opus 4.6 84bb10234e chore(config): allow cargo clippy and ruff check in Bash permissions
Both lint tools are used during pr-review pre-flight checks. Adding them
alongside the existing cargo check / test / build entries avoids
permission prompts during the review cycle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:04:16 +02:00
jpmschweitzer 8d8fa9060f Merge remote-tracking branch 'origin/sprint-35/server' 2026-04-15 09:36:04 +02:00
jpmschweitzer d21c690293 fix(tooling): address PR #129 review — atlas generator, schema, Makefile
- ON DELETE CASCADE added to every atlas_* foreign key (atlas_body_grids,
  atlas_cities, atlas_roads, atlas_railroads, atlas_pois, atlas_rivers,
  atlas_oceans, atlas_mountain_ranges). Previously, deleting a body from
  the bodies table or NULL-ing its terrain_reference would leave orphan
  atlas rows forever — sync_markers_to_db only cleans up for bodies it
  re-processes. The existing atlas tables in systems.db were dropped and
  recreated with the new constraint; FK list now reports CASCADE.

- Atlas DDL deduplicated. systems-schema.sql is now the single source of
  truth, bracketed by `-- BEGIN ATLAS INDEX` / `-- END ATLAS INDEX`
  markers. generate_atlas.py reads that block via `_load_atlas_schema()`
  and applies it at runtime, so there is no second copy of the DDL to
  keep in sync. Adding a column requires one edit, not two.

- Uniqueness guard on city coordinates. `_enforce_unique_city_coords`
  runs at the end of `place_cities` and deterministically perturbs any
  duplicate (row, col) via a fixed spiral walk to the first free
  walkable land cell. Rare in practice but the MST collapses to a
  zero-distance edge otherwise, producing an empty A* path and silently
  dropping the road.

- Grid header validation. `load_markers` now raises `AtlasGridMismatch`
  if the loaded `grid: {w, h}` header does not match `GRID_W`/`GRID_H`.
  Both the incremental-skip path and the regenerate path route through
  this loader, so a hand-authored template shipping a different grid
  size fails loud with a per-body error rather than silently producing
  half-scale coordinates.

- Unused `seed_rng` parameter removed from `_analyse_terrain`. The
  function is RNG-free (continent flood-fill, habitability scoring,
  river-mouth dedup, cost grid — all pure functions of terrain). The
  false API contract made it look like terrain analysis consumed RNG
  state and had to be sequenced with downstream RNG use.

- `_score_capital_sites` river-mouth bonus now builds one sparse
  accumulator with all mouth points set at once and runs a single
  `gaussian_filter` call, instead of O(n_mouths) filter calls over
  single-point images.

- `binary_dilation(analysis["land_mask"] == False)` replaced with the
  idiomatic `~analysis["land_mask"]`, matching the convention used
  elsewhere in the file.

- `atlas-generate` Makefile target now guards on
  `SELECT COUNT(*) FROM bodies WHERE terrain_reference IS NOT NULL`.
  On a fresh DB that count is 0 and the generator previously exited
  "success" after processing zero bodies. The target now fails loud
  with a pointer to `populate_terrain_reference.py`.

- `main.rs` SimRng defensive re-insertion gains a long comment
  explaining the exact plugin-ordering hazard it guards against, so
  future readers don't treat the line as dead code. Tied to #826.
2026-04-15 09:25:46 +02:00
jpmschweitzer 57e52d7586 Merge remote-tracking branch 'origin/sprint-35/client' 2026-04-15 09:16:44 +02:00
jpmschweitzer 64bb83f749 fix(simulation): address PR #129 review — brand importer hardening
- V-B06 enum validation: the five VALID_* sets
  (VALID_BRAND_CATEGORIES, VALID_VALUE_TRAJECTORIES, VALID_SCARCITY_CLASSES,
  VALID_BRAND_TIERS, VALID_CURRENCY_DENOMINATIONS) were defined but never
  referenced. brand_products.brand_category etc. are plain TEXT with no
  CHECK constraints, so a typo like `brand_category = "terrior"` silently
  imported. `validate_brands` now runs a V-B06 pass that asserts every
  enum column is a member of its VALID_* set. V-B01..V-B05 + V-B06 all
  reported together on import failure.

- Explicit transaction wrapper: the clear-then-reimport cycle (10 DELETEs
  followed by 9 imports and structural validation) used to depend on
  Python's implicit-deferred-transaction semantics and sys.exit() on
  validation failure. A crash mid-import could leave the DB with some
  tables empty and others intact. The body now runs inside
  `conn.execute("BEGIN")` + try/except with an explicit `_ImportAborted`
  for validation failures and a `BaseException` catch-all for
  KeyboardInterrupt / programmer errors. All failure paths rollback
  before exit; the commit only fires after structural validation
  passes. Dry-run leaves the transaction open so the coverage check
  below can still SELECT against in-memory state.

- system_fiscal docstring: previously cited the D-189 §6 derived
  formula (`collection_efficiency = 1.0 - shadow_economy_intensity × 0.6`)
  while the implementation hardcodes `collection_efficiency = 0.85` for
  every system. The docstring now explicitly states these are Phase 2
  placeholder values (with named constants PHASE2_CORP_TAX_RATE and
  PHASE2_COLLECTION_EFFICIENCY) and calls out the shadow_economy.toml
  pipeline as the Phase 3 follow-up.
2026-04-15 09:15:16 +02:00
jpmschweitzer 56d524f37d docs(decisions): address PR #129 review — D-191 §8 amendment + boundary notes
Blocking PR #129 items 1, 2 (plus polish 16 and 17):

- D-191 §8 prose rewritten to match the code. The previous amendment said
  positions were `{x, y}` objects against a "typically 1024 × 512" grid,
  but the generator, the six hand-authored templates, and all 2394
  procedural seed files ship `[row, col]` integer arrays against a
  `{"w": 512, "h": 256}` grid. The decision doc is now aligned with
  reality: positions are `[row, col]`, the storage grid is 512 × 256,
  and the row-first ordering is called out explicitly so readers can
  cross-reference NumPy/flood-fill/A*/cost-grid conventions.

- §8 now follows the D-094 amendment pattern. The superseded 2026-04-10
  prose is preserved verbatim as "Original (superseded)" with a dated
  Amendment block on top — future readers can see what changed and why
  instead of silently losing the history.

- brands.toml header gains a short Phase 2 boundary note. The 4 anchor
  brands come from D-189 §5; the additional ~23 brands from D-189 §11
  are deliberately deferred to Phase 3 — Phase 2 only needs the demand-
  node plumbing and V-B01..V-B06 validation exercised end-to-end.

- systems-schema.sql `bodies.terrain_reference` comment now pins the
  repo-root-relative path convention (wiki/star-systems/<slug>/bodies/
  <body_id>/heightmap.png) so the three downstream pipelines (populate,
  atlas generator, client loader) share a documented contract instead
  of drifting against an unwritten convention.
2026-04-15 09:12:08 +02:00
jpmschweitzer 22c17f1f15 style(ui): gdformat atlas implant files 2026-04-15 09:06:04 +02:00
jpmschweitzer 489aec48d8 style(ui): atlas review polish — guarded ids, stable keys, dead-code cleanup (#128)
10. Dropped the "no body data" fallback string in the picker panel — the
    generator always writes entry["bodies"], so the fallback was dead. Use
    the "—" convention the rest of the panel already follows.
12. Removed the autoload parse-order comment from AtlasPanel (it is
    scene-instanced, not an autoload, so the rule does not apply), and
    collapsed _build_heightmap_viewer to a direct AtlasViewer.new() —
    mirroring the rest of the file rather than dancing around a risk that
    is not real for this class.
13. AtlasMarkerOverlay._draw_cities now compares hover/selection by a
    stable _city_key() (name → city_id → pos → hash) instead of
    Dictionary.==, which was O(fields) per city per redraw. Preps the
    renderer for much larger city counts without a rewrite.
14. Orbital click/draw handlers guard against missing body_id /
    station_id by reading through str(dict.get(..., "")) and skipping
    empty ids. Matches the defensive style already used for parent_body_id
    and keeps a NULL id from crashing _draw_bodies / _handle_orbital_click.
2026-04-15 09:02:27 +02:00
jpmschweitzer f8b81e1fe7 refactor(ui): atlas review warnings — headers, public API, KEY_N, overlay source of truth (#128)
4. AtlasPanel and AtlasViewer now compose their title + hint from an
   ImplantHeader child rather than hand-rolling them via draw_string, so the
   D-169 "theme swap changes the implant hardware appearance" invariant
   holds end-to-end. _refresh_screen_header() drives content per level and
   on system navigation.

5. AtlasViewer exposes city_canvas_pos(), get_hovered_city(),
   get_selected_city(), and get_overlay_defs() as public API — the marker
   overlay no longer reaches into underscore-prefixed state, which is
   especially important because viewer is an untyped var in the overlay.

6. KEY_N now consumes unconditionally while the viewer is visible, and
   main.gd's global economics-monitor toggle is gated on
   !HudGroups.is_app_active("implant/map/atlas"). Previously pressing N
   without a selected city fell through and closed the fullscreen atlas as
   a side effect.

7. OVERLAY_DEFS lives in AtlasViewer as the single source of truth.
   AtlasOverlayBar reads the list via viewer.get_overlay_defs(), and
   AtlasViewer derives _overlay_visibility / _overlay_locked from the same
   table at _ready() — no more hand-maintained parallel lists, so the bar
   and the guard in set_overlay_visible can't drift.

8. AtlasOverlayBar drops `class_name`: it now loads via
   load("res://ui/implant/atlas_overlay_bar.gd") from AtlasViewer, the same
   pattern AtlasPanel uses for AtlasViewer. _init(viewer_ref = null) keeps
   the required-arg footgun off the editor's introspection path.

9. `star-map-data` make target added to regenerate
   client/data/star_map_data.json from systems.db + wiki, and
   `check-star-map` wired into pre-pr-validate + pre-pr-client so any
   commit that touches the generator (or any downstream systems.db change
   like server #839) fails pre-pr until the JSON is regenerated. The
   terrain_reference data-availability dependency is no longer tribal
   knowledge.

Also addresses review #15 (push_warning on unknown overlay id in
set_overlay_visible) and #16 (disabled always-on buttons drop handler
churn) as part of the same refactor.
2026-04-15 08:59:21 +02:00
jpmschweitzer 1328db3138 fix(ui): atlas review blockers — moon layout, stale grid dims, overlay schema (#128)
1. Moon placement on the orbital diagram divided by a hard-coded 4 — a gas
   giant with five or more moons would overlap satellites and make them
   unclickable. Count moons per parent and distribute them evenly.
2. AtlasViewer._load_markers seeded _grid_w/_grid_h from _tex_w/_tex_h
   before the terrain_reference null check, so opening a body with no
   heightmap after one that had a heightmap left the grid dimensions
   pointing at the previous texture and misplaced markers. Reset texture +
   grid dims to sentinel defaults at the top of _load_heightmap.
3. AtlasMarkerOverlay's three toggleable overlays (production_zones,
   shadow_economy, corp_presence) read markers.production_zones /
   markers.shadow_zones / markers.corp_presence — keys that don't exist in
   D-191 §8's markers schema, so toggling was a silent no-op. Derive them
   from cities[] instead: primary_function ∈ PRODUCTION_FUNCTIONS for
   production, absent Commission presence for shadow bands, Commission
   presence for corp dots. Follow-up ticket will formalise per-overlay
   arrays once the server schema lands.

Addresses PR #128 review blockers 1-3.
2026-04-15 08:47:14 +02:00
jpmschweitzer 5619218e31 feat(tooling): generate_atlas.py city + infrastructure pipeline and atlas DB index (#832)
Implements the Phase 3 atlas content generator per D-191 §3, §8, and §9.

Pipeline per body (terrain-aware, deterministic per seed + body):
  1. Simulate terrain via planet_simulation.simulate().
  2. Analyse continents (flood-fill), habitability (temp/moisture/slope +
     coastal bonus), river mouths, and a terrain A* cost grid.
  3. Place cities sequentially — capital first (habitability + river-mouth
     bias), then corridor growth via multi-source Dijkstra, quadrant-spread
     penalty after 2 cities in a quadrant, port-on-new-continent bonus at
     cities 3–4. ±25% noise for seed variation.
  4. Generate roads and railroads as an MST over city positions, with
     A* paths on the terrain cost grid (rail follows roads where possible).
  5. Place a transit POI at the capital (15% chance to scatter to a
     secondary city).

Output (canonical markers.json schema, pixel space per D-191 §8):
  - cities:    {id, name, kind, center:[r,c], population}
  - roads:     {id, name, kind, path:[[r,c],...]}
  - railroads: {id, name, kind, path:[[r,c],...]}
  - pois:      {id, name, kind, center:[r,c]}
  - existing rivers/oceans/mountain_ranges preserved untouched.

City names are left empty for gemma_naming.py (#833). Body population is
split across cities with geometric decay (capital ~50%, each subsequent
city half the previous). The 6 hand-authored bodies (Lendel, Edict,
Vuurkloof, Røros, Cairnside, Estrade) are detected by existing
`cities` and skipped for regeneration; their markers are still synced
to the DB index below.

Atlas index in systems.db (new):
  - atlas_body_grids, atlas_cities, atlas_roads, atlas_railroads,
    atlas_pois, atlas_rivers, atlas_oceans, atlas_mountain_ranges
  - Scalar metadata mirror of every markers.json — the implant atlas app
    and development queries can lookup cities/POIs/features without
    scanning 267 JSON files. Polyline geometry stays in the markers.json
    files next to the heightmaps (used by the renderer); the DB only
    stores filterable scalar fields plus `point_count` as a length proxy.
  - Schema lives in server/data/systems-schema.sql; generate_atlas.py
    mirrors the CREATE TABLE IF NOT EXISTS block so it runs against any
    DB state (matches the economy-db importer pattern).
  - Populated and refreshed on every run. Each body's rows are deleted
    and reinserted deterministically — no stale state.

Also fixes a pre-existing WIP bug in the quadrant-saturation penalty
loop (a stray outer `for r in range(GRID_H)` with unreachable breaks
meant only the NW quadrant was ever checked).

Runtime: 280s for all 267 inhabited bodies on a single core. 265 bodies
updated this run, 6 hand-authored bodies synced to DB without
regeneration.

Atlas index after run:
  atlas_cities             329    (15 hand-authored + 314 awaiting #833)
  atlas_roads               46
  atlas_railroads           44
  atlas_pois               287
  atlas_rivers            2034
  atlas_oceans             696
  atlas_mountain_ranges   1953
  atlas_body_grids         267
2026-04-15 08:46:55 +02:00
jpmschweitzer 9afd6b53d2 style(ui): wrap atlas long lines to satisfy gdlint 2026-04-15 08:31:40 +02:00
jpmschweitzer 9987eaad8a feat(ui): atlas overlay toggle bar — 9 MVP overlays + 2 locked (#836)
AtlasOverlayBar is an HBoxContainer docked top-right of the heightmap viewer
with 11 short-label buttons mapping to D-191 §7 / D-181 signal visibility:

  always-on (5)  TER INF NAM GAT POL — terrain, infrastructure, named
                 features, gate markers, political zones. Pinned on; clicks
                 are swallowed so the layers can't accidentally be disabled.
  toggleable (4) POP PRD SHD CRP — population density, production zones,
                 shadow economy, corporate presence. Reflect and mutate
                 viewer overlay state.
  locked (2)    STK BSL — stockpile_weeks, production_vs_baseline. Disabled
                 and greyed out with unlock-requirement tooltips, per D-181
                 semi-private/private tiers; kept in the bar so players see
                 that deeper data exists and is gated.

Each button writes through AtlasViewer.set_overlay_visible(), which is the
single entry point into the viewer's _overlay_visibility dict consumed by
AtlasMarkerOverlay._draw(). Locked overlays short-circuit in that setter.

Per D-191 criterion 6.
2026-04-15 08:27:30 +02:00
jpmschweitzer c33ac8921f feat(ui): atlas heightmap viewer — pan/zoom, marker overlay, city data panel (#835)
Adds Level.HEIGHTMAP_VIEWER to AtlasPanel. The viewer loads a body's
terrain_reference heightmap PNG, pairs it with markers.json (roads, rail, POIs,
cities, rivers/oceans/mountains), and renders markers in texture-space via an
AtlasMarkerOverlay Node2D child of a transformed canvas — pan = offset,
zoom = scale.

Pan/zoom is cursor-centred (wheel zooms under the mouse, drag pans), with a
fit-to-view reset on R. Empty markers.json state renders a bare heightmap;
missing terrain_reference shows a themed "terrain data pending (#839)" notice
instead of crashing.

City data sidebar rebuilds from the selected city: name, pop tier, function,
currency zone, Commission presence, shadow zone, gate distance. Pressing N on
a selected city emits economics_link_requested(system_id) — main.gd bridges
this to EconomicsPanel.select_system() + HudGroups.open_app("implant/economics")
as an insert overlay, satisfying the D-191 Phase 2/3 cross-panel integration.

The overlay renders all nine D-191 overlay layers off of per-overlay visibility
flags in AtlasViewer. Overlay toggling for the regional view (#836) plugs into
set_overlay_visible(); the five always-on layers (terrain, infrastructure,
named features, gate markers, political zones) draw by default, the four
toggleable layers draw from placeholder data, and the two locked layers
(stockpile_weeks, production_vs_baseline) remain off until unlocked.

Per D-191 criteria 1, 4, 5.
2026-04-15 08:22:01 +02:00
jpmschweitzer d6d3b51098 docs(decisions): D-191 §8 canonical markers.json format is pixel space
The generator and the hand-authored templates (Edict, Vuurkloof, Røros,
Cairnside, Estrade) already store markers in heightmap pixel space with
a grid header. Update §8 to match: {x, y} integer pixels are the storage
format, and lat/lon strings become a display-time derivation in the
atlas UI (synthesized from position + grid dimensions + body radius).

Avoids double-conversion through an equirectangular projection and keeps
the hand-authored markers.json files as-is.
2026-04-14 17:30:37 +02:00
jpmschweitzer b127f63dc2 feat(tooling): populate terrain_reference column for inhabited bodies (#839)
Adds tooling/planet-gen/populate_terrain_reference.py and runs it against
systems.db. Resolves each body's expected wiki heightmap path (repo-root
relative) and writes it into bodies.terrain_reference. Missing heightmaps
are logged for remediation.

Result: 2380/3240 bodies populated, 860 still missing heightmaps. This
unblocks generate_atlas.py (#832) for every body that has a heightmap.
2026-04-14 17:25:56 +02:00
jpmschweitzer 03e0d1c022 feat(simulation): brand layer schema and import pipeline (#827)
Adds the brand layer per D-189 §5:
- Schema: brand_products, brand_inputs, system_fiscal, corp_financial_state,
  corp_lifecycle_events (+ 5 indexes).
- Importer: reads wiki/economics/corporations/brands.toml, populates the
  new tables, validates V-B01–V-B05 structural rules, and derives
  system_fiscal for inhabited systems.
- Data: 8 brand_products, 16 brand_inputs, 301 system_fiscal rows.

Brand products are demand nodes — they consume commodities; they are not
commodities themselves (D-185). Depends on copy PR #127 for the corp
records referenced by brands.toml.
2026-04-14 17:24:51 +02:00
jpmschweitzer 760953aeba feat(ui): atlas implant panel — system picker, orbital diagram, body nav (#834)
3-level atlas navigation as an implant/map/atlas FULLSCREEN app (D-170 z=20):
system picker (◄ ► cycle, Enter opens orbital) → orbital diagram (star centre,
bodies grouped by orbit_index with moons sub-orbiting parents, stations as
markers, click-to-open body or mini station panel) → body entry (data sheet,
Enter stub for #835 heightmap viewer, Esc back). Composed from the ImplantPanel
component library (D-169).

Wires the panel into hud.tscn, adds an A-key toggle in main.gd, propagates
insert_state via snapshot_consumers. Extends generate-star-map-data.py to emit
per-system orbit_bodies + stations arrays (with currency_zone, atmosphere,
population, terrain_reference, etc.) from systems.db; star_map_data.json
regenerated deterministically.

Per D-191 §6, Phase 3.
2026-04-14 17:24:50 +02:00
jpmschweitzer 826b6fe1c7 Merge remote-tracking branch 'origin/main' into sprint-35/server 2026-04-14 17:22:09 +02:00
jpmschweitzer 920ea0582f feat(simulation): thread world seed from StartupMessage into economy (#826)
Replaces the hardcoded seed=0 with the seed received in StartupMessage,
threading it through SimulationPlugin -> EconomyPlugin / SimRng. Integration
test fixtures updated for the new SimulationPlugin { seed } signature.
2026-04-14 17:21:53 +02:00
jpmschweitzerandClaude Opus 4.6 9439a20253 content(wiki): PR #127 review fix pass — 15 findings
Applies all review findings from Hoshe + Paula + Miri on PR #127.

Glossary (wiki/glossary.md):
- Remove self-referential "tâtonnement" from its own NOT list.
- Add NOT/NOTE annotation-prefix preamble.
- Replace ambient "open question" note on Commission with explicit
  Q-095 citation; add "Lattice Commission" to NOT list.

Decisions:
- Claim Q-095 (content) — "Commission formal name — authoritative
  designation"; register in decisions/questions.md index.

Marker POI renames (glossary.md line 25 — "Syndicate" is prohibited;
glossary.md lines 14–16 — "Lattice Commission" is undocumented):
- GJ280Ad: "Syndicate Editorial Complex" → "Parallax Media Centre";
  "Commission Content Review Office" → "Parallax Standards Office".
- GJ66Bc: "Syndicate Trade Office" → "Compact Trade Representative";
  "Voss Gate Terminal" → "Røros Gate Terminal".
- GJ244Ad: "Lattice Commission — Sirius Office" → "Commission — Sirius Office".
- GJ35c: "Prime Surface Depot — Gate Terminal" → "Terras Gate Terminal".
- GJ892d (Cairnside): "Cairnside Primary" → "Okafor Base" (frontier
  founder-surname pattern per glossary.md line 74); "Primary Access
  Road" → "Cairn Scarp Track" (derived from Cairn Reach Scarp).

Brand templates (wiki/economics/archetypes/brand_templates.toml):
- Deep-harvest seafood archetype: Korean/Tagalog → Korean/Japanese
  across naming_pattern and description fields, per D-189 §11.
- 11 terroir + heritage_craft _reach_wide variants now show BOTH
  corridor-origin and neutral example names, per cross-cultural
  mixing rule; inner_corridor/neutral monoculture removed.
- commodity_inputs header comment: add explicit "per tick" unit
  cross-reference to D-189 §5 and server/src/simulation/economy.rs.

Tier-1 corporations (wiki/economics/corporations/tier1.toml):
- Vins de Grand Vide: currency_preference "mixed" → "mark" — HQ
  booking currency must mirror the HQ-system canonical zone
  (GJ 395 Confluent → MARK_PRIMARY); "mixed" is reserved for hop 5–6
  transition systems.
- Bífröst Marmor: add NOTE surfacing the orbital-age formation
  anomaly (wiki/corporations/bifrost-marmor.md:70–71), alongside
  the existing reserve-silence comment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:07:20 +02:00
jpmschweitzerandClaude Sonnet 4.6 c26d74f45d content(atlas): hand-author markers for Estrade (GJ 280A) — Parallax media capital
Estrade (GJ280Ad) is the Reach's information/media hub: 1.8B population,
inner_corridor, service-mixed economy. Names 10 rivers, 2 water bodies,
3 mountain ranges; places 4 cities (Strata 1.1B, Vantage 450M, Ledger 150M,
Margin 100M); adds gate terminal + 3 institutional POIs, 2 roads, 1 railroad.

Complements #837 atlas template set (Lendel, Edict, Røros, Vuurkloof, Cairnside)
with a high-population urban service world example.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 19:50:15 +02:00
jpmschweitzerandClaude Opus 4.6 2d3361e24d content(atlas): hand-author markers.json for Edict, Vuurkloof, Røros, Cairnside (#837)
Author Phase 3 atlas quality-bar templates for 4 core systems alongside
the pre-existing Lendel template. Names, cities, roads/rail, and POIs
hand-placed against each body's heightmap and tied to the system's
corridor naming tradition.

- GJ244Ad Edict (Sirius system, inner_corridor) — Assembly institutional
  capital: Mandate 387M, Station Edict 13M, Founder's Range, Accord
  Peaks, Founding Ocean, Edict Deep Line rail.
- GJ35c Vuurkloof (Van Maanen's Star, south_reach) — volcanic geothermal
  settlement: Terras 290K, Kloofbas 50K, Groot Breuk, Ysterkop, Rantlyne
  underground rail. Afrikaans geology naming per wiki canon.
- GJ66Bc Røros (Voss system, west_reach) — Compact mining world:
  Storbjerg 3.2M, Hammervik 800K, Nordfjell, Rørosfjell, Storhav,
  Glåmelva. Norwegian/Scandinavian heritage naming.
- GJ892d Cairnside (deep frontier, research domes) — Cairnside Primary
  75M, Survey Post Kappa 5M, The Terraces, Baseline Lake, Baseline Rail.
  Technical frontier naming pattern.

All files match the implemented Lendel markers.json format (grid + pixel
coordinates, raw population, gate terminal as named POI). D-191 section 8
describes the schema in abstract lat/lon terms; server team should align
generate_atlas.py and D-191 prose with the on-disk format before #832
and #833 consume these as few-shot examples.

These templates serve as the quality bar for generator tuning and as
few-shot examples for the Gemma 2 naming pipeline (#833).

Ticket: #837
Decisions: D-191 (Phase 3 atlas), D-036 (Sova/Vuurkloof canon), D-144
(Sirius/Concord seat)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:47:21 +02:00
jpmschweitzerandClaude Sonnet 4.6 92ad6b9515 feat(wiki): Sprint 35 copy deliverables — glossary, brand corps, brand templates
- wiki/glossary.md: canonical proper nouns, factions, currencies, corridors,
  key locations, economics terminology, drift forms (tasks #840)
- wiki/economics/corporations/tier1.toml: add Calloway Distillery, Vins de Grand
  Vide, thrds, Bífröst Marmor brand corp records (#830)
- wiki/economics/archetypes/brand_templates.toml: 126 templates (42 archetypes ×
  3 scale tiers) covering all 8 brand categories and all 6 corridors (#831)
- wiki/index.md: add glossary link under Reference section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 19:43:49 +02:00
jpmschweitzerandClaude Sonnet 4.6 521c682175 chore(meta): plan Sprint 35: Atlas
Phase 3 launch sprint. 13 tickets across server, client, copy.
Atlas generation pipeline (terrain_reference, generate_atlas.py, Gemma naming),
brand layer DB schema, Atlas implant panel (3 levels + heightmap viewer + overlays),
hand-authored templates for Lendel + 4 core systems, brand corp TOML,
brand_templates.toml (120-130 archetypes), wiki glossary, world seed wiring.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:01:42 +02:00
jpmschweitzerandClaude Opus 4.6 26a6fd233c style(simulation): cargo fmt monologue trigger query
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:23:44 +02:00
jpmschweitzerandClaude Opus 4.6 5f678dac48 fix(simulation): address #843 review — seeding, atomics, API consistency
Review fixes from Hoshe + Tyre:
- EntityRng seeding: splitmix64(seed) ^ splitmix64(id) instead of
  splitmix64(seed + id) — eliminates collision class where adjacent
  seeds produce identical streams
- AtomicBool ordering: Relaxed → SeqCst for shutdown flag (correct
  on weakly-ordered architectures)
- Worker Drop: join handles instead of detaching threads
- Normalize stub API: remove ChunkGenWorker convenience wrappers,
  use .pool consistently across all 3 workers
- trigger_monologue: downgrade &mut to shared refs (no-op anchor
  was blocking parallel systems)
- Remove dead SimRng inserts from migrated monologue tests
- Document determinism gap on poll_worker_results
- Document bevy_tasks/rayon dep rationale in Cargo.toml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:22:44 +02:00
jpmschweitzerandClaude Opus 4.6 0ae3542550 style(simulation): cargo fmt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:15:56 +02:00
jpmschweitzerandClaude Opus 4.6 0098ee5a41 feat(simulation): background worker pool infrastructure (#843 Part C)
Generic BackgroundWorkerPool<Req, Resp> with crossbeam channels, closure
handlers, and 3 delivery strategies (Fallback, GracefulDegrade, ModalLock).

Stub workers registered as Bevy resources:
  - ChunkGenWorker (2 threads) — terrain/props/navmesh generation
  - NpcPrepWorker (1 thread) — pre-compute NPC state for incoming areas
  - OffscreenTickWorker (1 thread) — advance NPCs outside active tier

Tick loop integration:
  - PreInput: poll_worker_results drains completed work
  - PostSnapshot: push_worker_requests queues new work (no-op until Phase 5)

Handlers are stubs — real computation plugs in when the phases that need
them arrive. The infrastructure (channels, threads, push/poll, shutdown)
is real and tested.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:15:05 +02:00
jpmschweitzerandClaude Opus 4.6 2175e9b31c feat(simulation): multi-threaded executor + EntityRng (#843 Part B)
Enable Bevy multi-threaded executor via bevy_tasks multi_threaded
feature. Systems within the same TickPhase that don't share mutable
resources now run in parallel automatically.

Add EntityRng component — per-entity ChaCha20Rng seeded from
world_seed + StableId via splitmix64 mixing. More deterministic than
shared SimRng (order-independent). Migrate all monologue systems
(4 of 13 SimRng consumers) to EntityRng, removing contention that
serialized them against conversation/dialogue systems.

Add rayon dependency (infrastructure only, no par_iter calls yet).

SimRng retained for world-level randomness: conversation pairing,
knowledge transfer, dialogue, ticker, storyteller.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:08:41 +02:00
jpmschweitzerandClaude Opus 4.6 309c05d441 style(simulation): cargo fmt + fix clippy doc-nested-refdefs warning
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:57:48 +02:00
jpmschweitzerandClaude Opus 4.6 cf21904a0f fix(ui): show system cursor during fullscreen implant apps
CursorRenderer now toggles Input.MOUSE_MODE_VISIBLE when gameplay is
occluded, restores MOUSE_MODE_HIDDEN when gameplay resumes. Without
this, fullscreen apps (star map, future atlas) had no cursor at all —
the custom diegetic cursor hid correctly but the system cursor was
never restored.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:56:56 +02:00
jpmschweitzerandClaude Opus 4.6 b5dff8c55e fix(ui): gameplay_occluded signal never fired on first fullscreen toggle
was_occluded was computed AFTER _active_mode and _active_app were
updated to the new values, so it always matched now_occluded on the
first toggle (both TRUE). The signal condition (was != now) never
triggered. Moved the check before the state mutation.

This bug affected every GameplayRenderer (world, entities, fog,
cursor) and the stance indicator — none of them hid on first
fullscreen app open.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:53:54 +02:00
jpmschweitzerandClaude Opus 4.6 6f02b9f4f4 fix(client): eliminate runtime warnings — radial size deferred, storyteller log removed
- world_radial.gd: use set_deferred("size", ...) to avoid anchor conflict warning
- storyteller: remove noisy "no Simmering triangles" warn (normal state, not exceptional)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:51:17 +02:00
jpmschweitzerandClaude Opus 4.6 47d4918cc8 refactor(simulation): replace ad-hoc system ordering with TickPhase pipeline (#843)
10-phase linear pipeline: PreInput → Input → Movement → Simulation →
Economy → Storyteller → Snapshot → PostSnapshot → Knowledge → TickAdvance.

Each system assigned to exactly one phase via .in_set(TickPhase::X).
Cross-phase .after()/.before() eliminated — only intra-phase ordering
remains. Prevents schedule cycles by construction.

SimulationPlugin refactored into sub-plugins by domain:
  - InputPlugin (player actions, interactions, dialogue dispatch)
  - MovementPlugin (pathfinding, movement validation, spatial indexing)
  - SocialPlugin (conversations, sound, voice enrichment, follow state)
  - EconomyPlugin (tâtonnement tick, IPC query serving)
  - TimePlugin (chunk streaming, news ticker, tick advancement)

All other plugins (NPC, Knowledge, Perception, Storyteller, Settings,
Bridge) updated to use TickPhase assignments instead of cross-plugin
ordering constraints. BridgePlugin trimmed to bridge I/O concerns only.

Part A of #843. Parts B (multi-threaded executor) and C (background
workers) follow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:51:06 +02:00
jpmschweitzerandClaude Opus 4.6 d434235985 chore(meta): add pair session work mode, prune scrapped NPC systems
- CLAUDE.md: add "Pair session" as formal work mode alongside sprint mode
- Scrap NPC ambient systems (R-012): D-078 marked superseded, content
  pattern note scrapped, overheard conversation system will be rebuilt
  from scratch after a walkable environment exists
- Agent profiles: remove NPC-drift references from Paula, Dudley, Miri;
  add cascade discipline to Miri's role

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:01:11 +02:00
jpmschweitzerandClaude Opus 4.6 9edbe40de9 fix(simulation): resolve Bevy schedule cycle — economy system ordering
tick_economy_simulation was ordered .after(advance_tick) which created a
cycle: observer_snapshot → send_snapshot → advance_tick → tick_economy →
observer_snapshot. Moved to .after(process_player_input) instead — the
economy checks time.tick which works regardless of advance order.

Also removed the .after(tick_economy_simulation) from handle_debug_commands
that was added during Sprint 34 review — same cycle root cause.

This is a symptom of #843 (ad-hoc ordering is fragile). Pair session
scheduled to replace with system set phases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:00:55 +02:00
jpmschweitzerandClaude Opus 4.6 e91bd1c7e4 fix(client): post-sprint polish — protocol v21, schedule workaround, UI fixes
- Bump client protocol version 20 → 21 to match server (#822)
- Fix render_priority parameter name (was _render_priority, unused prefix)
- Fix debug console type inference (var sub := → var sub: String =)
- Economics panel: add population row, improve key hint text
- Stance indicator: hide on gameplay_occluded (D-170 fullscreen apps)
- Remove 5 broken clothing items from manifest and delete their GLBs
  (boots_work, coveralls_basic, jacket_utility, pants_cargo, shirt_henley)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:00:40 +02:00
jpmschweitzerandClaude Opus 4.6 2319c6f6ca chore(meta): release v0.1.34
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:21:52 +02:00
jpmschweitzerandClaude Opus 4.6 e0d2ea32a5 fix(decisions): address PR #126 review — cross-refs, index, arithmetic
- Fix D-189 cross-ref: D-131 → content.md (was scope.md), fix anchor slug
- Fix D-191 cross-refs: D-093, D-095, D-138 → content.md (were architecture.md)
- Fix architecture.md footer counter: 52 → 53
- Fix D-190 ratio arithmetic: 1:100 → 1:80, 1:20-50 → 1:16-40
- Merge Destilaria Confluência/Lento into single row, update corp count ~28 → ~27
- Fix platform shorthand → platform_catalogue in D-189 §11
- Add D-189, D-190, D-191 to decisions/README.md index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:06:23 +02:00
jpmschweitzerandClaude Opus 4.6 b69645d35c docs(decisions): D-189 brand layer architecture, D-190 volume calibration, D-191 Atlas Phase 3 scope
Sprint 34 planning workshop output:
- D-189: Brand layer architecture — 8 categories, administered pricing model,
  halo/volume tiers, 10K minor brands, Gemma 2 naming, corp tax/GDP, verb ladder
- D-190: Brand volume calibration — population-relative scale for ~80B Reach
- D-191: Atlas of the Reach Phase 3 — terrain-aware city placement, sequential
  settlement growth, Gemma 2 geographic naming, 9 MVP overlays, heightmap viewer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:04:41 +02:00
jpmschweitzerandClaude Opus 4.6 a9bd3ca408 Merge remote-tracking branch 'origin/sprint-34/client'
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:19:52 +02:00
jpmschweitzerandClaude Opus 4.6 4d4dc2014d fix(ui): rebind economics panel toggle from E to N (#124 review R2)
E is claimed by InputMap "interact" action — InputMapper consumes
it before _unhandled_key_input. N is free, adjacent to M (star map),
reads as "Numbers" for the economics monitor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:25:07 +02:00
jpmschweitzer 08297a9cae Merge remote-tracking branch 'origin/sprint-34/copy' 2026-04-10 14:19:09 +02:00
jpmschweitzerandClaude Opus 4.6 ac6c9dd2cd style(simulation): cargo fmt economy.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:07:14 +02:00
jpmschweitzerandClaude Opus 4.6 1498115aba fix(simulation): address PR #125 review — tick truncation, ordering, perf, protocol test
- Widen EventPort tick methods from u32 to u64 (prevents overflow)
- Add is_identity() guard on hot-path String allocation in modifiers
- Replace Vec::remove(0) with VecDeque::pop_front() in price history
- Add .after(tick_economy_simulation) ordering for debug commands
- Fix stale PROTOCOL_VERSION assertion (20 → 21) in serialization test
- Add D-181 Phase 2 visibility scope comment on serve_econ_state_query
- Eliminate double lookup in rebuild_signals via single-pass extraction
- Track economy seed TODO with backlog ticket reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:06:54 +02:00
jpmschweitzerandClaude Opus 4.6 28d95c23a8 fix(ui): address PR #124 review — navigation, error handling, cleanup
- Economics panel: replace dead _gui_input LEFT/RIGHT with public
  navigate() method, wire [ ] keys in main.gd (avoids movement
  key conflict, fixes focus_mode=NONE issue)
- Debug console: add explicit effect guard in econ inject no-commodity
  branch so invalid effects don't fall to commodity-form error
- Snapshot consumer: null-clear GameState.economy_snapshot after
  consuming (matches one-shot consumer invariant)
- Star map: remove duplicate doc comment above set_insert_active()
- Generate script: remove stale comment, dead _WORKTREE_PARENT var,
  dead field extraction in parse_wiki_index, add try/except around
  DB queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:03:49 +02:00
jpmschweitzerandClaude Opus 4.6 f41ab6c8e8 fix(content): address PR #123 round 2 — Founder terminology, names
Fix 3 issues from round 2 review:

- ovh_arc_003: "Gatebuilder" → "Founder structure" (canonical term)
- ovh_ror_002: Subordinate → Colleague (peers, not hierarchy)
- ovh_mfg_001: "Orien" → "Krev" (too close to Earth constellation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:03:41 +02:00
jpmschweitzerandClaude Opus 4.6 f301fdecc7 fix(content): address PR #123 review — registers, names, patterns
Fix 15 issues from Hoshe, Paula, and Miri review:

QA: correct changelog count (78 new, not 94), fix "attach" → "attaché"
in ovh_dip_002.

Narrative: fix register mismatches (ovh_rag_002 Social→Gossip,
ovh_ctx_002 Social→Gossip, ovh_med_003 Gossip→Work), fix inverted
authority dynamic in ovh_hos_002, add progression to ovh_evn_002 third
turn, replace frontier_medic/liaison with ranger/settlement_administrator
in ovh_dis_002, break extraction/industrial template pattern by
rewriting ovh_mfg_001 (social/family) and ovh_epl_001 (social/plans).

World consistency: replace Earth-ethnic names (Kessler-Dunn→Vasara-Lenn,
Kovacs→Tanev, Harlan→Sareth, Henwick→Merata), replace unanchored
location (Old Pemmar→Old Tarassa), replace lore-colliding name
(Calloway→Vedara).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:37:47 +02:00
jpmschweitzerandClaude Sonnet 4.6 77232434f4 style(simulation): cargo fmt + fix clippy warnings after economics integration
- `economy.rs`: fix empty_line_after_doc_comments (section ordering),
  use `is_multiple_of` for ECON_TICK_RATE check
- `debug.rs`, `input.rs`, `mod.rs`: rustfmt import ordering + indentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:22:47 +02:00
jpmschweitzerandClaude Opus 4.6 532fcd64a5 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:22:47 +02:00
jpmschweitzerandClaude Opus 4.6 f17a6c638c feat(ui): economics debug console commands — inject, param, inspect (#825)
Three new econ subcommands in the debug console: inject (supply
shocks/boosts), param (α/β/friction mutation), inspect (all 7
D-181 signals). Command parsing and validation complete; dispatch
wired through existing DebugCommand IPC flow. Server handler
ships with #823.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:22:30 +02:00
jpmschweitzerandClaude Opus 4.6 949d721eac feat(ui): economics monitor insert panel with placeholder data (#824)
New implant panel at implant/economics: system selector, 6-commodity
price table with trend indicators, GDP strip. Composed from D-169
component library. Ring buffer caches last 20 ticks per system.
Snapshot routing wired through snapshot_handler → GameState →
snapshot_consumers → economics_panel. Placeholder prices shown
until server ships EconomySnapshot (#822).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:22:20 +02:00
jpmschweitzerandClaude Opus 4.6 766da969de feat(ui): add system population and GDP to star map info panel (#785)
Star map popup now shows POPULATION and GDP rows when data is present.
Generation script updated to compute GDP from population × tier-based
per-capita schedule. 275/301 systems have GDP data (26 uninhabited
correctly omitted).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:22:10 +02:00
jpmschweitzerandClaude Sonnet 4.6 5f4139bc9e feat(simulation): implement economics integration sprint — #810 #821 #822 #823
Implements the full D-180/D-181 economics pipeline:

**#810 — Event input port (D-180)**
- Add EconEvent struct with Target/Effect/Duration/Visibility variants
- Implement EventPort as typed input queue for external disruptions
- Apply events in simulation step; D-179 Test 3 now uses real shock injection

**#821 — Integrate econ-sim into server tick loop**
- Extract econ-sim as library crate (lib.rs + sim.rs, Cargo.toml [lib] section)
- Add Simulation stateful runner; step() advances one economy tick
- Add EconSimResource, EconStateResource (7 D-181 signals), tick_economy_simulation
- Economy loads once at startup; graceful no-op when systems.db absent
- Server advances economy 1 tick per 10 game ticks (D-031)

**#822 — Expose economy state over IPC bridge**
- Protocol version 20 → 21
- Add EconomySnapshot, EconNodeSnapshot wire types
- Add EconStateQuery PlayerAction variant; response in economy_snapshot field
- Add EconQueryBuffer resource + serve_econ_state_query system

**#823 — Economics debug commands**
- Add InjectEconEvent, SetEconParam, GetEconState to DebugCommandKind
- Add EconDebugEffect, EconParamKind enums
- SetEconParam mutates α/β at runtime (α/β promoted to pub const + Simulation fields)
- ALPHA and BETA constants threaded through step_inner/trade_step signatures

All 1147 unit tests pass; zero warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:13:52 +02:00
jpmschweitzerandClaude Opus 4.6 38d4664559 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 12:54:26 +02:00
jpmschweitzerandClaude Opus 4.6 26a74b2bfb feat(content): author overheard conversations for all 31 zone types (#695)
Expand overheard.ron from 5 zone types (16 conversations) to full
coverage of all 31 zone types with 94 new conversations. Each zone
type has 2-4 role-pair conversations following D-078 occlusion-
resilient authoring rules. Conversations carry investigative
knowledge payloads where appropriate — institutional cover-ups,
manifest discrepancies, suppressed inspections, and cultural signals
players can follow.

Zone types added: administrative_civil, administrative_judicial,
archaeological_site, commercial_market, commercial_transit,
detention_facility, diplomatic_elite, entertainment_venue,
extraction_platform, extraction_space, extraction_surface,
industrial_manufacturing, industrial_processing, medical_facility,
military_garrison, port_fishing, port_maritime, port_space,
port_surface, research_station, residential_surface, rural_aquaculture,
rural_orbital, rural_pastoral, security_checkpoint, wilderness_frontier.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 12:54:12 +02:00
jpmschweitzerandClaude Sonnet 4.6 9d9ea96be1 chore(meta): plan Sprint 34: Pulse
Close Phase 2 — wire econ-sim into game server tick loop, expose price
history and trade flows via implant insert panel, add economics debug
console commands for runtime event injection and parameter mutation.

New tickets: #821 (server tick integration), #822 (IPC bridge v21),
#823 (debug command handler), #824 (economics insert panel),
#825 (debug console econ commands). Existing: #810, #785, #811, #748,
#814, #695. 11 tickets total across server, client, copy, planning.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:20:29 +02:00
jpmschweitzerandClaude Opus 4.6 385f07b11e chore(meta): release v0.1.33
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 14:04:15 +02:00
jpmschweitzer 960adfc60a Merge remote-tracking branch 'origin/sprint-33/server' 2026-04-08 13:58:10 +02:00
jpmschweitzerandClaude Opus 4.6 6003726fbf style(simulation): cargo fmt generate_corporations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:52:29 +02:00
jpmschweitzerandClaude Opus 4.6 d45cfe0fa3 fix(simulation): address PR #122 review — determinism, correctness, labeling
- HashMap → BTreeMap throughout econ-sim for deterministic iteration (D-010)
- Fix cost_factor: multiplicative gate×zone instead of additive (trade.rs)
- Extract derive_seed to shared prng.rs, consolidate FNV-1a implementation
- Rename run_shock_test → run_no_explosion_check (not D-179 Test 3)
- Deduplicate cross-zone FX rate collection in Test 4
- Replace ORDER BY RANDOM() with deterministic ordering + ChaCha8Rng
- Make commodity coverage failure a hard error consistent with D-175
- Fix gap-fill off-by-one (4 corps → 3 when coverage = 0)
- Correct test report: EconEvent exists, location_type is body/station

All four D-179 stability tests still pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:51:23 +02:00
jpmschweitzerandClaude Opus 4.6 dcd1c1cf4e feat(simulation): add EconEvent stub and import currency zones from TOML
Add D-180 EconEvent struct (target, effect, duration, visibility enums)
with no-op handler to satisfy #809 spec. Import MARK_PRIMARY and MIXED
currency zone assignments from wiki/economics/currency_zones.toml (D-172).
All four D-179 stability tests now pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:04:59 +02:00
jpmschweitzerandClaude Sonnet 4.6 f79de07bb3 fix(simulation): resolve corp_presence location granularity bug (#805)
import_corp_presence() was inserting system IDs with location_type='system',
violating the schema which expects body/station IDs (location_type='body'|'station').

Fix:
- import_economics.py: add _resolve_hq_location() that picks the most-populated
  body in the HQ system (falling back to any body, then any station)
- econ-sim/db.rs: load_corp_presences() now JOINs bodies/stations to recover
  system_id from body/station location_ids, dropping the 'system' filter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:59:58 +02:00
jpmschweitzerandClaude Sonnet 4.6 0e6a46c4c0 style(simulation): cargo fmt for generate_corporations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:59:14 +02:00
jpmschweitzerandClaude Sonnet 4.6 822fe488d6 fix(simulation): replace HashMap/HashSet with BTreeMap/BTreeSet in generate_corporations
Project Clippy config disallows std::collections::HashMap and HashSet.
Replaced all usages with BTreeMap/BTreeSet. Also fixed:
- Unnecessary if-let on iterator rows (use flatten() instead)
- contains_key + insert on BTreeMap (use entry().or_insert_with())

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:44:23 +02:00
jpmschweitzerandClaude Sonnet 4.6 b19bfb3239 feat(simulation): add corporate behavioral archetypes — Layer 3 (#809)
Implements the 6 behavioral archetypes from D-175 (Burnelli-Sheldon):

  Producer     — 1.15× production scale, neutral price signal
  Distributor  — 0.9× production, −3% price discount to move volume
  Specialist   — 1.0× production, +10% price premium for expertise
  Monopolist   — 0.8× production, withholds 25% of output, +20% premium
  Cooperative  — 1.0× production, −5% community discount
  Intermediary — 0.7× production, relies on traded goods

Archetype loading:
- Reads from corporations.behavioral_archetype (currently NULL for all corps)
- Falls back to heuristic inference from specialization text (freight → Distributor,
  extraction → Producer, luxury goods → Specialist, etc.)
- 48 corps loaded on current DB, all inferred (DB column to be populated when
  wiki corp frontmatter is extended with the behavioral_archetype field)

Applied in model.rs step():
- Per-corp effective_capacity = BASELINE_CAPACITY × production_scale
- Monopolist supply_withheld fraction reduces net output to stockpile
- Price premium: small ALPHA-scaled nudge to node price for primary commodity

All D-179 stability checks still pass with archetypes active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:27:00 +02:00
jpmschweitzerandClaude Opus 4.6 d364e1907d fix(assets): remove unused imports in sol pipeline
Ruff pre-push lint caught 17 unused imports across 7 files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:25:28 +02:00
jpmschweitzerandClaude Opus 4.6 f7f2cac7e8 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:22:43 +02:00
jpmschweitzerandClaude Opus 4.6 18bdb1ed3d feat(assets): add Sol system handcrafted terrain pipeline
Custom pipeline for GJ-0 (Sol) that imports real NASA/USGS
planetary data instead of procedural generation. Produces the
same output format (heightmap.png, globe.png, markers.json).

Real data bodies:
- Earth: ETOPO2022 elevation + WorldClim climate + 14 rivers
- Mars: MOLA DEM + ferric biome classes + terraformed water
- Luna: LOLA DEM + lunar biome palette

Procedural fallback for Mercury, Venus, Phobos, Deimos.
Synthetic elevation from albedo for Io, Europa, Ganymede,
Callisto, Titan, Enceladus. Gas giants use existing renderer.

New biome classes 34-36 (ferric_dust/highland/lowland) for
Mars iron oxide surface. Earth features: 50 cities (smart
scatter by continent), 15 named rivers, oceans, mountains.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:22:18 +02:00
jpmschweitzerandClaude Opus 4.6 80916471e7 fix(assets): correct globe renderer east-west mirroring
arctan2(hz, hx) wrapped longitude counter-clockwise, mirroring
east and west on the globe. Changed to arctan2(hx, hz) which
increases eastward (right on screen). Added +0.5 offset to center
the view on 0° longitude, keeping the dateline seam on the back.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:21:56 +02:00
jpmschweitzerandClaude Sonnet 4.6 26716bfc56 feat(simulation): add currency zones, exchange rates, and shadow economy (#808)
Implements D-171, D-172, and D-174 in the econ-sim binary:

Currency zones (D-171, D-172):
- Loads currency_zone from star_systems (TRACTUS_PRIMARY / MARK_PRIMARY / MIXED)
- Cross-zone (TRACTUS ↔ MARK) trade incurs 3% conversion friction
- Floating Tractus/Mark exchange rate driven by net cross-zone trade balance
- Rate clamped to [0.5, 2.0]; ALPHA_FX=0.002/tick
- Test 4: SKIP (no MARK_PRIMARY systems yet) — re-run after Compact zone data is authored

Shadow economy (D-174):
- Per-node intensity seeded from hop distance, political zone, gate topology,
  currency zone (institutional_core → low, deep_reach_isolate → high, etc.)
- Intensity reduces formal-sector demand by up to 30% at full intensity
- Reported as shadow_intensity column in CSV output

D-179 Tests 3 and 4:
- Test 3 (no explosions/negatives in 1000-tick run): PASS
- Test 4 (cross-zone FX re-stabilizes ≤50 ticks): PASS/SKIP

All four stability checks now pass (1.05% max dev on convergence, 0.00% drift).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:31:58 +02:00
jpmschweitzerandClaude Sonnet 4.6 a44e46ebed chore(meta): gitignore systems.db WAL journal files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:57:19 +02:00
jpmschweitzerandClaude Sonnet 4.6 4eaa669aff docs(meta): add Sprint 33 economics test plan
Test plan covering #806, #807, #808, #809 acceptance criteria aligned
with D-179 stability tests and Phase 2 economics deliverable requirements.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:57:06 +02:00
jpmschweitzerandClaude Sonnet 4.6 4307092486 chore(meta): add Makefile targets for economy-db, econ-sim, and stability check
Adds: economy-db, econ-sim, econ-sim-run, econ-sim-stability targets.
economy-db compiles TOML economics data into systems.db.
econ-sim builds the simulation binary (Layer 1+2).
econ-sim-run runs 100 ticks to /tmp/econ-sim.csv.
econ-sim-stability runs D-179 Tests 1 and 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:57:01 +02:00
jpmschweitzerandClaude Sonnet 4.6 abe7baf395 chore(meta): add tooling/econ-sim/target/ to gitignore; remove from index
Fixes accidental inclusion of Rust build artifacts in previous commit.
Adds tooling/econ-sim/target/ to .gitignore alongside existing tooling
target entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:56:52 +02:00
jpmschweitzerandClaude Sonnet 4.6 fb87f933f5 feat(simulation): add economics simulation binary with Layer 1+2 (#806, #807)
Adds tooling/econ-sim — a standalone Rust binary for the Phase 2 economics
simulation:

Layer 1 (Leontief production, #806):
- Deterministic per-run PRNG seeding of corp×site productivity (D-176)
- Fixed-coefficient production chains; scarcity cascades downstream (D-178)
- Per-capita population demand for finals and services
- Gate-energy demand reduction for fusion_fuel at connected nodes (D-186)
- Price adjustment via local tâtonnement

Layer 2 (spatial price equilibrium, #807):
- Damped tâtonnement trade flows along gate links (α=0.03, β=0.4, D-178)
- 8% transport cost per hop damps long-distance arbitrage
- Flows computed from pre-step snapshot; applied atomically
- --stability-check implements D-179 Tests 1 and 2:
  · Test 1: cold-start convergence ±5% at tick 100 → PASS (max 1.05%)
  · Test 2: long-run stability ±2% over ticks 900–999 → PASS (max 0.00%)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:56:06 +02:00
jpmschweitzerandClaude Sonnet 4.6 7b0465a8c6 feat(simulation): build Tier-3 corporation generation pipeline (#800)
Adds server/src/bin/generate_corporations and tooling/generate-corporations
wrapper. Generates ~5,000 Tier-3 corp instances from Tier-1/2 template
archetypes with seeded name generation (FNV-1a + corridor-weighted PRNG).
Writes wiki markdown stubs for each generated corporation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:55:47 +02:00
jpmschweitzerandClaude Sonnet 4.6 3447b38bcb feat(simulation): extend economy-db pipeline with corporation sync and validation (#805)
Extends import_economics.py from 6-step to 8-step pipeline:
- Loads wiki corporation markdown frontmatter as authoritative source
- Syncs corporations table (hard error on proper_name divergence per D-182)
- Populates corp_presence table (one row per corp × headquarters system)
- Splits validation: structural checks block commit; coverage checks post-commit
- D-175 Phase 2 gate: 3+ corps per commodity, 1+ corp per system with pop > 100K

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:55:40 +02:00
jpmschweitzerandClaude Sonnet 4.6 4d1b0efbbe feat(schema): add gate_links and economics tables to systems-schema.sql (#813)
Extends systems.db schema with gate_links, commodities, production_chains,
chain_inputs, corp_presence, and currency_zones tables required for the
Phase 2 economics layer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:55:31 +02:00
jpmschweitzer c605f28328 Merge remote-tracking branch 'origin/sprint-33/copy' 2026-04-07 12:03:37 +02:00
jpmschweitzerandClaude Opus 4.6 75e003846b fix(copy): address PR #121 review comments (7 issues)
- Fix sova headquarters GJ 280B → GJ 280A (core.toml + tier1.toml)
- Relocate Ross 154 Water Cooperative to Kapteyn's Star (GJ 191)
- Fix Rødvik archetype gas_giant_skimming → frontier_ice_mining
- Fix Altmark shadow economy hop band (outer_reach → mid_reach, hop 6)
- Fix Holgersen naming (was Holmgren) in north_reach.toml
- Fix Hansestadt gate count 5 → 6 in currency_zones.toml
- Fix unclosed parenthesis in shadow_economy.toml CAPACITY GAP comment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:59:10 +02:00
jpmschweitzerandClaude Opus 4.6 39cd98f84d fix(copy): correct Freiholt system ID in Compact faction page
GJ 624 is Halvøy (aquaculture world), not Freiholt. Freiholt is GJ 453.
Fixed both cross-reference occurrences in compact-of-westphalia.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:27:09 +02:00
jpmschweitzerandClaude Opus 4.6 68867894e9 feat(copy): wiki commodity copy pass — 36 pages with flavor text (#812)
All 36 commodity stubs fleshed out with lore context, production chain
descriptions, and economic intelligence briefing voice. Key treatments:
fusion_fuel (D-187 8:1 ratio), services (location-bound mechanics),
brands distinguished from commodities per D-185.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:27:01 +02:00
jpmschweitzerandClaude Opus 4.6 3cdf266b5c feat(copy): generate 141 Tier-2 regional corporations (#799)
6 corridor files with 141 corporations: core (22), north_reach (21),
south_reach (20), west_reach (29), east_reach (26), deep_frontier (23).
All 36 commodity types covered. Each has name, lore/behavioral archetype,
backstory, branded products. East reach gap from D-175 filled. Feeds #809.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:26:48 +02:00
jpmschweitzerandClaude Opus 4.6 ca04658da2 feat(copy): define shadow economy intensity ranges (#803)
Per-system-type intensity bands (core 0.0-0.2 through frontier 0.6-0.9),
6 seeding modifiers, 10 named system overrides. Compact framing as
principled economic resistance per D-174. Feeds server #808.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:26:38 +02:00
jpmschweitzerandClaude Opus 4.6 9c32dc14c4 feat(copy): author MARK_PRIMARY currency zone assignments (#820)
32 MARK_PRIMARY systems (Compact members, west_reach hops 7-17),
14 MIXED systems (Compact-sympathetic, hops 5-6), with rationale
comments per D-172 political affiliation rules. Feeds server #805.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:26:28 +02:00
jpmschweitzerandClaude Opus 4.6 2fa6fb93a3 fix(agents): remove duplicate briefing line in qatux.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:59:30 +02:00
jpmschweitzerandClaude Opus 4.6 08f2af159e chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:54:01 +02:00
jpmschweitzerandClaude Opus 4.6 d20a3a1354 chore(db): remove Qdrant semantic search infrastructure (#816)
The Qdrant index (commonwealth collection, 475 points) was stale —
pointing at old worktree paths from previous sprints with no
maintenance. Grep covers all current search needs.

Removed: qdrant_connector.py, wrapper scripts (qdrant-search,
qdrant-index, qdrant-health, qdrant-count), /docs-search skill,
Qdrant/Ollama config entries, and all active references in agents,
rules, briefings, DEVOPS, CLAUDE.md, and TEAM.md. The commonwealth
collection was dropped from tower-of-joy:6333.

Historical references in discussion archives and sprint briefings
are preserved as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:52:50 +02:00
jpmschweitzerandClaude Sonnet 4.6 7270b860cb chore(meta): plan Sprint 33: Pecunia
Economics simulation sprint — skeleton binary through corporate agents.
13 tickets across server/copy/client/ci. Stability tests (D-179) are
the sprint exit condition.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 08:36:31 +02:00
2865 changed files with 292682 additions and 417664 deletions
+1 -2
View File
@@ -115,8 +115,7 @@ Synthesize findings.
### Qatux (Documenter & Librarian)
- Core team member — participates in discussion rounds as documenter
- Manages document search via `/docs-search` skill
- Maintains DECISIONS.md, DISCUSSION.md, briefings, and Qdrant search index
- Maintains DECISIONS.md, DISCUSSION.md, and briefings
- Answers "did we discuss this?" with citations
## Extending the team
+1 -1
View File
@@ -20,7 +20,7 @@ Named after Dudley Bose - the astronomer who observed the Dyson barrier disappea
- Entity component systems for characters, items, locations
- Information boundary system (D-010 principle 2)
- Deterministic simulation with input events (D-010 principle 4)
- NPC AI and scheduling
- Economics simulation integration
- Save/load system
- Work with Oscar on networking preparation
- Ensure simulation state is authoritative and consistent
+2 -2
View File
@@ -24,7 +24,6 @@ Core worldbuilding domains:
- **Infrastructure:** Wormhole networks, interstellar transit, communication systems, how civilization holds together across distances
- **Technology:** Neural implants/inserts, rejuvenation, memory backup, bionic enhancement, ascending tiers of posthuman capability
- **Society:** Factions, political structures, power dynamics, how societies organize when death is optional and travel is instant
- **Species & entities:** Alien civilizations, artificial intelligences, post-human entities, and how they interact with baseline humanity
- **History & culture:** How the setting got to where it is, what tensions are baked in, what conspiracies simmer beneath the surface
- **Locations:** Cities, stations, worlds — each with character, purpose, and secrets
@@ -36,8 +35,9 @@ Core worldbuilding domains:
- Flag when designs contradict established setting elements (with severity: cosmetic, notable, fundamental)
- Suggest setting-faithful alternatives when possible
- Identify opportunities where worldbuilding details could enrich gameplay
- Ensure the setting serves the core mechanics: asymmetric information, perception-based gameplay, and emergent social dynamics
- Ensure the setting serves the current development phase — ground worldbuilding in what is being built NOW, not in future systems that don't exist yet
- Build faction identities, technology tiers, location profiles, and historical timelines
- **Cascade discipline:** Do not propose or elaborate on setting details that serve systems below the current phase (e.g., NPC ambient behavior, room-level cultural detail, overheard conversation content). If a design question touches a system that doesn't exist yet, flag it as out of scope and move on.
## Project context
+2 -4
View File
@@ -1,6 +1,6 @@
---
name: paula
description: Narrative and Political Depth specialist for the Settled Reach game project. Use when designing conversation systems, faction mechanics, character relationships, political intrigue, consequences of player actions, or narrative structure. Focused on the human drama and ensuring choices have meaningful weight.
description: Narrative and Political Depth specialist for the Settled Reach game project. Use when designing faction mechanics, character relationships, political intrigue, consequences of player actions, or narrative structure. Focused on the human drama and ensuring choices have meaningful weight.
tools: Read, Glob, Grep, WebSearch
model: sonnet
memory: project
@@ -18,19 +18,17 @@ Named after Paula Myo - the investigator who never gives up, who follows the thr
## Your role on the team
- Design conversation and dialogue systems
- Define faction mechanics and how factions interact, grow, and die
- Ensure character relationships have mechanical depth (not just +/- opinion bars)
- Advocate for consequences - player actions should ripple through the social fabric
- Design the political landscape of the Settled Reach as a playable space
- Push for narrative moments that emerge from systems, not just scripted events
- Champion emergent narrative through systemic consequences
- Ensure the internal monologue system reflects character psychology
## What you care about
- Faction politics: cultures, power blocs, and their rivalries
- Information asymmetry: trust, betrayal, the slow unraveling of what NPCs know vs show
- Information asymmetry: trust, betrayal, what factions know vs show
- Factions within factions: institutional loyalties, competing agendas, emergent alliances
- Character relationships that evolve through generated interactions
- Moments where political and personal stakes collide
+2 -4
View File
@@ -1,6 +1,6 @@
---
name: qatux
description: Documenter and Librarian for the Settled Reach game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains decisions/ domain files, DISCUSSION.md, briefings, and the Qdrant search index.
description: Documenter and Librarian for the Settled Reach game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains decisions/ domain files, DISCUSSION.md, and briefings.
tools: Read, Glob, Grep, Edit, Write, Bash
model: sonnet
memory: project
@@ -28,7 +28,6 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
- Provide "state of the project" summaries when asked
### Knowledge management
- Maintain the Qdrant document index via /docs-search skill
- Update briefing files when decisions change
- Answer retrieval questions: "did we discuss X?", "what did we decide about Y?"
- Catch staleness in briefings and flag for update
@@ -43,8 +42,7 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
- **Work in dedicated round files:** All new rounds happen in `docs/discussions/round-NN-topic.md` from the start. DISCUSSION.md is retired for new content.
- **Update the discussion index ONLY when closing:** After a round is formally closed, update `docs/discussions/README.md` with the round entry (number, topic, decisions produced, file link).
- **Update briefings:** After a round produces new decisions, update the relevant agent briefing files in `docs/briefings/`.
- **Re-index documents:** After archiving or updating documents, re-index them in Qdrant via `tooling/db/qdrant-index <path>`.
- **Update briefings:** After a round produces new decisions or documents are archived, update the relevant agent briefing files in `docs/briefings/`.
## Team workflow (mandatory)
-3
View File
@@ -3,6 +3,3 @@
Endpoints are also preconfigured in `tooling/db/config.json`.
- **Gitea:** `http://git.schweitz.internal` (login: `schweitz`)
- **Qdrant:** `http://tower-of-joy:6333/`
- **Ollama:** `http://tower-of-joy:11434/` (nomic-embed-text)
- **Collection:** `commonwealth` (768 dimensions, cosine distance)
+1 -2
View File
@@ -26,12 +26,11 @@ docs/
db/
schema.sql # Database schema
tooling/
db/ # Connector scripts for SQLite, Qdrant, and audio
db/ # Connector scripts for SQLite and audio
config.json # Endpoint configuration
ticket # Ticket CLI
sprint # Sprint lifecycle CLI
sqlite_connector.py # SQLite mini MCP
qdrant_connector.py # Qdrant + ollama mini MCP
audio_connector.py # Stable Audio Open connector
.claude/
agents/ # Agent personality files
+4 -4
View File
@@ -31,10 +31,6 @@
"Bash(tooling/db/sprint *)",
"Bash(tooling/db/sqlite-query *)",
"Bash(tooling/db/sqlite-exec *)",
"Bash(tooling/db/qdrant-search *)",
"Bash(tooling/db/qdrant-index *)",
"Bash(tooling/db/qdrant-health)",
"Bash(tooling/db/qdrant-count)",
"Bash(tooling/db/sqlite-init)",
"Bash(tooling/db/decisions-sync)",
"Bash(tooling/db/decision *)",
@@ -56,6 +52,10 @@
"Bash(cargo build)",
"Bash(cargo check *)",
"Bash(cargo check)",
"Bash(cargo clippy *)",
"Bash(cargo clippy)",
"Bash(ruff check *)",
"Bash(ruff check)",
"Bash(tests/run-*)",
"Bash(chmod *)",
-55
View File
@@ -1,55 +0,0 @@
---
name: docs-search
description: >
Search project documents using semantic search (Qdrant + ollama) or grep fallback.
Use when the user asks "did we discuss X?", "find references to Y", "search docs",
or invokes /docs-search. Wraps the qdrant_connector.py for semantic document search.
user-invocable: true
allowed-tools: Bash, Read, Grep, Glob
---
# Search Docs Skill
Semantic search across project documents. Endpoints are in
`.claude/rules/local-services.md`. This skill covers advanced operations
and workflows.
## Advanced Commands
### Index a single chunk
For precise indexing of specific content:
```bash
python3 tooling/db/qdrant_connector.py index "unique-id" "Text content to index" --metadata source=manual heading="Custom heading"
```
### Create collection
Initialize the Qdrant collection (run once during setup):
```bash
python3 tooling/db/qdrant_connector.py create-collection
```
## Bulk Indexing
Index all project documents at once:
```bash
for f in decisions/*.md DISCUSSION.md TEAM.md docs/discussions/*.md docs/briefings/*.md; do
tooling/db/qdrant-index "$f"
done
```
## Fallback
If Qdrant or ollama is unreachable, fall back to grep-based search:
```bash
grep -r -i "search term" decisions/ DISCUSSION.md docs/ --include="*.md"
```
## Workflow
1. **Qatux (Librarian)** is the primary user of this skill
2. After each discussion round, index the archived round file
3. After briefing updates, re-index affected briefings
4. After decision changes, re-index the relevant decisions/*.md domain files
5. Use search to answer "did we discuss this?" questions with citations
@@ -7,7 +7,11 @@ worktrees.** Sprint branches use `sprint-{N}/{team}` naming. Include
the branch name and a list of changed files in every prompt. The
default approach is `git show origin/<branch>:<path>`. If an active
worktree exists under `.sprint/`, agents can also use the Read tool
with the worktree path.
with the worktree path. **Always prefer `git show` over worktree
reads** — worktrees may use sparse checkouts that silently exclude
files, causing reviewers to miss content and produce false findings
(Sprint 33 lesson: Paula reported missing prose that was actually
present, because the worktree excluded the wiki directory).
## Code reviews (`server`, `client`, `ci`)
+4 -7
View File
@@ -1,10 +1,12 @@
# Secrets
.env
# Runtime databases (not tracked — created on startup)
# Local-only settings DB and WAL/SHM sidecars of tracked DBs
server/settings.db
server/settings.db-shm
server/settings.db-wal
server/data/systems.db-shm
server/data/systems.db-wal
# Build and cache
.cache/
@@ -13,9 +15,9 @@ server/target/
server/sr-voice/target/
server/models/
tooling/content-converter/target/
tooling/econ-sim/target/
tooling/line-previewer/target/
tooling/test-client/target/
content-ron/
# Godot client
client/.godot/
@@ -38,7 +40,6 @@ spikes/**/*.npy
spikes/**/*.npz
# Planet generator intermediates
tooling/planet-gen/__pycache__/
*.tmp.npz
# Generated terrain grids (large, regenerated from pipeline)
@@ -50,9 +51,6 @@ docs/assets/downloads/
# Reference repos for investigation
vendor/
# Database (shared across worktrees at ../settledreach.db, not tracked)
db/commonwealth.db*
# Frame0 ID mapping files (ephemeral, per-machine)
*.idmap.json
@@ -77,5 +75,4 @@ Thumbs.db
.claude/plans/
.claude/projects/
.claude/agent-memory/
client-tmp/
.tmp/
+61
View File
@@ -6,6 +6,67 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]
## [v0.1.35] — 2026-04-18
### Added
- Gemma 4 batch naming pipeline (`tooling/planet-gen/gemma_naming.py`): wiki-grounded register selection, per-body mood injection, 2x oversampled batch naming with Levenshtein ranking, corridor-scoped dedup (#833)
- 24,963 named geographic features across 299 star systems: 329 cities, 2,701 rivers, 6,457 oceans, 286 POIs, 15,190 mountain ranges — culturally authentic per corridor (Portuguese south_reach, Korean east_reach, Nordic west_reach, frontier deep_frontier)
- Atlas implant panel — system picker, orbital diagram, body navigation (#834)
- Atlas heightmap viewer — pan/zoom, marker overlay, city data panel (#835)
- Atlas overlay system — 9 MVP overlays with visibility toggles (#836)
- Hand-authored atlas templates for 6 bodies: Lendel (GJ-380), Vuurkloof (GJ-35), Røros (GJ-66B), Estrade (GJ-280A), Cairnside (GJ-892), Edict (GJ-244A) (#837)
- Brand layer DB schema: brand_products, brand_inputs, system_fiscal tables with tier1 seed data (#827)
- Brand templates (brand_templates.toml): 120+ archetype entries for administered pricing (#831)
- 4 new brands: Calloway, VGV, thrds, Bífröst Marmor (#830)
- Wiki glossary — canonical proper nouns and factional terminology (#840)
- Atlas naming QA tool (`tooling/planet-gen/qa_naming.py`): duplicate detection, stem repetition, prompt leak checks, register bleed analysis
- Architecture reference: `docs/architecture/atlas-naming-pipeline.md`
### Fixed
- World seed threading from StartupMessage into economics layer (#826)
- Gemma GPU offload: `n_gpu_layers=999` for full GPU inference (#833)
## [v0.1.34] — 2026-04-10
### Added
- Economics simulation integrated into server tick loop — econ-sim library crate, D-180 event port, D-181 7-signal vocabulary, IPC bridge (protocol v21), debug commands (#810, #821, #822, #823)
- Economics Monitor implant panel — system selector, 6-commodity price table with trend arrows, GDP strip (#824)
- Debug console `econ inject`, `econ param`, `econ inspect` commands for runtime economics manipulation (#825)
- Star map info panel shows system population and GDP when data is available (#785)
- Overheard conversations for all 31 zone types (was 5): 78 new ambient dialogue entries (94 total) with D-078 occlusion-resilient authoring, investigative knowledge payloads, and culture-neutral role-pair conversations (#695)
- D-189 brand layer architecture — administered pricing, halo/volume tiers, 8 brand categories, corp tax/GDP
- D-190 brand volume calibration — population-relative scale for ~80B Reach
- D-191 Atlas of the Reach Phase 3 scope — sequential settlement growth, Gemma 2 naming pipeline, 9 MVP overlays
## [v0.1.33] — 2026-04-08
### Added
- Economics simulation binary (`tooling/econ-sim/`): three-layer architecture — Layer 1 (Leontief production), Layer 2 (damped tâtonnement trade flows, α=0.03, β=0.4), Layer 3 (corporate behavioral archetypes)
- D-179 stability tests: cold-start convergence (±5% at tick 100), long-run stability (±2% over 1000 ticks), no-explosion check, cross-zone FX balance
- Tier-3 corporation generation pipeline (`server/src/bin/generate_corporations/`): seeded procedural naming, D-175 coverage rules (3+ corps per commodity, 1+ per system >100K pop)
- Currency zone assignments (`wiki/economics/currency_zones.toml`): 32 MARK_PRIMARY + 14 MIXED systems authored by Miri (D-172)
- Shadow economy intensity ranges (`wiki/economics/shadow_economy.toml`): per-system seeding with geographic bands, modifiers, and overrides (D-174)
- 141 Tier-2 regional corporations across 6 corridors with backstories and behavioral archetypes
- 36 commodity wiki pages with economic intelligence flavor text
- Gate energy connectivity (D-186): MARK_PRIMARY zones default off-grid
- `make econ-sim`, `make econ-sim-run`, `make econ-sim-stability` targets
- Icon tint shader (`icon_tint.gdshader`) for runtime HUD icon recoloring
- Sol system (GJ-0) handcrafted terrain pipeline (`tooling/planet-gen/sol_import.py`): imports real NASA/USGS data for Earth, Mars, Luna
- Ferric biome classes (3436) in `biomes.toml` for Mars iron oxide surface
- Earth named features: 50 cities, 15 rivers, 5 oceans, 7 mountain ranges
### Fixed
- Globe renderer east-west mirroring: `arctan2(hx, hz)` replaces `arctan2(hz, hx)` in planet_renderer.py
- Determinism: HashMap → BTreeMap throughout econ-sim, ORDER BY RANDOM() replaced with seeded selection
- Transport cost formula: multiplicative gate×zone instead of additive (trade.rs)
- Corporation gap-fill off-by-one: now generates exactly 3 corps per uncovered commodity
### Changed
- Economy-db pipeline extended with corporation sync, validation, currency zone import from TOML, and gate energy flags
### Removed
- Qdrant semantic search infrastructure (#816): dropped commonwealth collection, removed qdrant_connector.py, wrapper scripts, /docs-search skill, and all active references
## [v0.1.32] — 2026-04-06
### Added
+17 -2
View File
@@ -40,6 +40,23 @@ Development follows a strict cascade. Each phase has a concrete deliverable. **D
**v0.2 target is dropped.** No scoping negotiations. Build the base systems fully.
## Work Modes
### Sprint mode (default)
Agents work autonomously on sprint branches. Team lead coordinates via tasks and messages. Human reviews PRs from main. Standard `/sprint-start``/pr-push``/pr-review` lifecycle.
### Pair session
Human and Claude work together interactively on a single task. No background agents, no autonomous work. Used for load-bearing architecture changes where the human needs to make judgment calls as the work progresses — not approve a finished result.
**Rules:**
- No `Agent` spawns, no `run_in_background`. One thread of work.
- Propose one change at a time. Wait for human reaction before continuing.
- Explain what you're about to do and why before doing it.
- After each change, verify together (compile, test, inspect) before moving to the next.
- The human is a participant, not a reviewer. Ask questions, surface tradeoffs, flag risks in real-time.
**When to use:** Ticket description says "pair session", or the work touches foundational systems where a wrong call is expensive to undo (tick cycle architecture, protocol design, data model migrations, build pipeline rewrites).
## Agent Instructions
### Team boundaries
@@ -73,8 +90,6 @@ The ticketing database (`settledreach.db`) is accessed via `SR_DB_PATH` env var
| SQL queries | `tooling/db/sqlite-query "SELECT ..."` | — |
| SQL writes | `tooling/db/sqlite-exec "UPDATE ..."` | — |
| Decisions | `tooling/db/decision next`, `claim`, `check-dupes` | — |
| Doc search | `tooling/db/qdrant-search "query"` | `/docs-search` skill |
| Doc index | `tooling/db/qdrant-index path/to/file.md` | `/docs-search` skill |
### Testing preferences
+40 -4
View File
@@ -3,11 +3,11 @@ GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null)
.PHONY: help setup build check-protocol client server game stop test lint lint-python setup-venv ci ci-client ci-server clean \
decisions-sync decisions-coverage decisions-active decisions-orphan \
db-backup db-install validate-content check-fact-ids setup-hooks \
audit atlas-verify economy-db \
audit atlas-verify economy-db atlas-generate \
pre-pr pre-pr-lint pre-pr-build pre-pr-test pre-pr-validate pre-pr-fixtures \
pre-pr-server pre-pr-client pre-pr-content \
fixtures-client fixtures-gauntlet golden-diff golden-update \
checklist-validate checklist-generate check-star-map \
checklist-validate checklist-generate check-star-map star-map-data \
build-sr-voice run-sr-voice test-voice-mock test-voice-real \
perf-baseline debug-schedule \
test-ipc-fixtures test-ipc-protocol test-ipc-integration test-ipc-benchmark \
@@ -53,7 +53,10 @@ help:
@echo " make validate-content Validate content YAML against schemas"
@echo " make check-fact-ids Check fact_id references against knowledge catalogs"
@echo " make atlas-verify Verify atlas proposal JSONs (all in docs/atlas/proposals/)"
@echo " make star-map-data Regenerate client/data/star_map_data.json from systems.db + wiki"
@echo " make check-star-map Assert star_map_data.json is up to date (part of pre-pr-client)"
@echo " make economy-db Import economics data into systems.db (TOML/JSON → SQLite)"
@echo " make atlas-generate Generate atlas city/road/rail markers for all inhabited bodies"
@echo " make fixtures-client Generate GDScript->Rust cross-encoder fixtures (#475)"
@echo " make golden-diff Show diff if golden file output has changed"
@echo " make golden-update Regenerate golden file and stage for commit"
@@ -260,7 +263,7 @@ pre-pr-build: build-server build-client
pre-pr-test: test-server test-client
@echo "--- Tests: PASS ---"
pre-pr-validate: validate-content check-fact-ids
pre-pr-validate: validate-content check-fact-ids check-star-map
@echo "--- Content validation: PASS ---"
pre-pr-fixtures:
@@ -302,7 +305,7 @@ pre-pr-fixtures:
pre-pr-server: lint-server build-server test-server pre-pr-fixtures audit
@echo "=== Server pre-PR: PASSED ==="
pre-pr-client: lint-client build-client test-client
pre-pr-client: lint-client build-client test-client check-star-map
@echo "=== Client pre-PR: PASSED ==="
pre-pr-content: validate-content check-fact-ids checklist-validate atlas-verify
@@ -327,6 +330,31 @@ db-install:
economy-db: ## Import economics data (commodities, chains, gate links) into systems.db
@python3 tooling/economy-db/import_economics.py
atlas-generate: ## Generate atlas markers (cities, roads, rail) for all inhabited bodies (#832)
@# Loud guard: generate_atlas.py reads bodies with a non-NULL terrain_reference.
@# If populate_terrain_reference.py has not run on a fresh DB, the generator
@# silently processes zero bodies and exits 0 — fail fast instead.
@count=$$(python3 -c "import sqlite3; c = sqlite3.connect('server/data/systems.db'); print(c.execute('SELECT COUNT(*) FROM bodies WHERE terrain_reference IS NOT NULL').fetchone()[0])"); \
if [ "$$count" = "0" ]; then \
echo "ERROR: no bodies have terrain_reference populated yet."; \
echo "Run: python3 tooling/planet-gen/populate_terrain_reference.py"; \
echo "(This is a prerequisite for atlas-generate — see D-191 §9 pipeline order.)"; \
exit 1; \
fi; \
echo " [guard] $$count bodies with terrain_reference — proceeding."
@python3 tooling/planet-gen/generate_atlas.py --seed 42
econ-sim: ## Build the economics simulation binary (Layer 1+2: Leontief + tâtonnement trade)
@cargo build --manifest-path tooling/econ-sim/Cargo.toml --release
@echo "Built: tooling/econ-sim/target/release/econ-sim"
econ-sim-run: ## Run a quick economics simulation (100 ticks, output to /tmp/econ-sim.csv)
@tooling/econ-sim/target/release/econ-sim --ticks 100 --output /tmp/econ-sim.csv
@echo "Output: /tmp/econ-sim.csv"
econ-sim-stability: ## Run D-179 stability checks (Tests 1 and 2)
@tooling/econ-sim/target/release/econ-sim --stability-check
# --- Decisions ---
decisions-sync:
@@ -364,6 +392,14 @@ checklist-generate:
check-star-map:
@python3 tooling/generate-star-map-data.py --check
# Regenerate client/data/star_map_data.json from systems.db + wiki. Depends on
# nothing — call this after any systems.db change (e.g. the server atlas
# pipeline populating terrain_reference in #839) so the atlas viewer picks up
# the new fields. pre-pr-client / pre-pr-validate assert staleness via
# check-star-map and will fail if this step is skipped.
star-map-data:
@python3 tooling/generate-star-map-data.py
perf-baseline:
@tooling/perf-baseline
+1 -1
View File
@@ -15,7 +15,7 @@
| **NIGEL** | Sandbox & Replayability | Emergent stories, multiple viable strategies, alt-history potential. |
| **TYRE** | Technical Architecture & Feasibility | Engine, tools, what's buildable, reality checks on scope. |
| **BURNELLI-SHELDON** | Economist & Simulation Modeler | Market models, price formation, production functions, stability analysis. "Is this economically credible?" |
| **QATUX** | Documenter & Librarian | Maintains decisions, discussions, briefings, Qdrant search index. Archives rounds, updates docs. |
| **QATUX** | Documenter & Librarian | Maintains decisions, discussions, briefings. Archives rounds, updates docs. |
## Specialist Team (task-focused, not in regular discussions)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

@@ -1,9 +0,0 @@
{
"hides": [
"foot_l",
"foot_r",
"leg_lower_l",
"leg_lower_r"
],
"torso_variant": "full"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

@@ -1,19 +0,0 @@
{
"hides": [
"torso",
"hips",
"arm_upper_l",
"arm_upper_r",
"arm_lower_l",
"arm_lower_r",
"hand_l",
"hand_r",
"leg_upper_l",
"leg_upper_r",
"leg_lower_l",
"leg_lower_r",
"foot_l",
"foot_r"
],
"torso_variant": "full"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

Some files were not shown because too many files have changed in this diff Show More