The star-map family was the last unported part of the tree, and it never had a ticket. Two of its scripts become `reach atlas map` verbs, nested under atlas like planet (D-243: the Reach map is the ladder's top rung): - `reach atlas map data [--check]` regenerates client/data/star_map_data.json. The regenerated file differs by one line: `_meta.note`, which named the old script's path. - `reach atlas map svg` renders the concentric SVG (+ PNG), byte-identical to the old script's output on the same data. make check-star-map and star-map-data stay as one-line delegates, because pre-pr-client and pre-pr-validate depend on check-star-map. generate-star-map.py, its seed, sculpt-star-map.py and tune-star-map-topology.py are archived, not ported. The generator rewrites docs/design/star-map.json unconditionally from an S-NNN-keyed seed, so re-running it would erase the GJ migration and every hand edit since; sculpt and tune only understand S-NNN edges. .claude/rules/diagrams.md was telling agents to "edit the generator and re-run it". It now distinguishes the live concentric render, the seven frozen S-keyed sector .d2 files (T-1294), and the two SVGs that never had a generator in the repo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
180 lines
13 KiB
Markdown
180 lines
13 KiB
Markdown
# The domain map (T-1271, D-263)
|
|
|
|
Every Python file and every executable in `tooling/`, assigned to a domain
|
|
before anything moves. This is the artefact the per-domain port tickets are
|
|
written from — without it their boundaries would be guesses, renegotiated
|
|
halfway through the move.
|
|
|
|
**Status:** the map was written before anything moved; the ✅ rows below record
|
|
which domains have since been ported, and by which ticket.
|
|
|
|
## What the survey changed
|
|
|
|
Two corrections to the T-1250 description, both found by counting rather than
|
|
reading:
|
|
|
|
- **Three Rust crates, not one.** `econ-sim`, `line-previewer` and `test-client`
|
|
are all Cargo projects with zero `.py` files. None is renamed and none moves;
|
|
a hyphen only matters for something Python must import.
|
|
- **The "28 singleton prefixes" were an artefact of my own measurement.**
|
|
Splitting filenames on the first token scattered coherent families:
|
|
`sculpt-star-map`, `tune-star-map-topology` and `generate-star-map*` are one
|
|
group, not three orphans. Counting families instead of prefixes, the genuinely
|
|
ambiguous set is small and is listed under *Judgment calls* below.
|
|
|
|
And two found while reading the tree:
|
|
|
|
- **`garment-fit/` is mostly a Blender payload directory.** 22 of its 23 files
|
|
are `blender_author_*.py`, leaving one real module. So the Blender carve-out
|
|
is **35 files**, not the 13 visible at top level — the T-1250 description was
|
|
right about 35 and an intermediate survey of mine was wrong, because it
|
|
counted only the top level. The consequence is not cosmetic: `character`
|
|
is a much smaller domain than the directory sizes imply, and the carve-out is
|
|
much larger.
|
|
- **`tooling/db/` is misnamed.** It holds the audio/image/Trellis connectors and
|
|
`wiki_sync.py` — the actual database work is in `economy-db/`. Naming a domain
|
|
`db` after that directory would carry the misnomer forward, so its contents
|
|
split between `assets` and `wiki` instead.
|
|
|
|
## Half the executables are bash
|
|
|
|
Found 2026-08-31, after this map was first written and while starting the first
|
|
port. **17 of the 33 extensionless executables are bash**, ~900 lines. This map
|
|
originally assigned them as though they were Python files to be moved; they are
|
|
rewrites.
|
|
|
|
Decided: **rewrite all of them in Python** (D-263). Wrapping would achieve one
|
|
door while leaving half the surface outside the contract, so `reach --help`
|
|
would list verbs that behave differently from the ones beside them — worse than
|
|
two doors, because the inconsistency only shows up at a failure.
|
|
|
|
| shape | scripts | cost |
|
|
|---|---|---|
|
|
| thin wrappers | `atlas-systems-done` 9, `atlas-names` 17, `generate-brands` 23, `atlas` 24, `generate-corporations` 23, `blender` 28 | near-free; the router calls what the script called |
|
|
| logic | `check-fact-ids` 89, `validate-ron` 137, `godot-parse-sweep` 64, `godot-cold-parse` 96, `pr-watchlist-diff` 37, `atlas-update-field` 59, `atlas-commit-and-sync` 60, `tea-comment` 41 | real rewrite; gains the most — testable, failures that teach |
|
|
| environment | `install-godot` 108, `install-rust` 33, `worktree-setup` 49 | gains least, riskiest — port the *decision* logic, keep the external calls behind `core/process` |
|
|
|
|
A **bash** source turns a port from mechanical into a rewrite that needs its own
|
|
parity evidence. Each per-domain ticket must say which of its sources are bash.
|
|
|
|
## Revised 2026-09-02: domains mirror the implant apps
|
|
|
|
The first version of this map invented a taxonomy. It should have read one off
|
|
the game, and D-263 now says so: **where the game presents something to the
|
|
player, the CLI uses that name and that shape.**
|
|
|
|
Two corrections follow, and the first was a contradiction of an existing record
|
|
rather than a matter of taste:
|
|
|
|
- **`atlas` absorbs `starmap` and `planet`.** D-191: *"Atlas is the star map
|
|
extended downward, not a separate app — `implant/map` at different zoom
|
|
levels"*, four rungs Reach map → system → planetary → regional. This map had
|
|
them as three peer domains, presenting as unrelated what the game presents as
|
|
one descent. Generation now **nests by rung**; authoring and inspection verbs
|
|
stay flat on `atlas`, because they act on the whole thing.
|
|
- **`db` becomes `ledger`.** Named for the UI component that aggregates
|
|
economics — markets, wealth, transactions — the economic counterpart to what
|
|
the Atlas offers for topography. `db` named a storage layer nobody looks at.
|
|
|
|
Domains that mirror nothing — `check`, `validate`, `godot`, `visual`, `jobs`,
|
|
`dev` — are unaffected. No app exists for a lint gate and none should be
|
|
invented.
|
|
|
|
## Domains
|
|
|
|
| domain | what it is | sources |
|
|
|---|---|---|
|
|
| `check` | repo consistency gates the push hook runs | `check-client-version` ✅, `check-canvas-version`, `check-systems-db-stamp`, `check-fact-ids`, `check-dataflow-graph.py` |
|
|
| `validate` | content and schema validation | `validate-content`, `validate-checklist`, `validate-ron` |
|
|
| `atlas` | **the whole spatial ladder** (D-191). Flat verbs for authoring and inspection; nested groups per rung for generation | flat: `atlas` (Rust binary), `atlas-check`, `atlas-names`, `atlas-commit-and-sync`, `atlas-systems-done`, `atlas-update-field`, `atlas-verify`, `atlas-flatness` · `atlas map`: ✅ ported (T-1293) — `reach atlas map data [--check]` (client JSON; diff was only the self-naming note line) and `reach atlas map svg` (byte-identical to the old script). The generator + seed + sculpt + tune were S-keyed bootstrap and would overwrite `star-map.json`: archived, not ported · `atlas planet`: ✅ ported (T-1288) from `planet-gen/` (30) — ten verbs, each restating its module's options for real `--help`; `test_planet_router.py` fails if a router option drifts from the module parser |
|
|
| ~~`starmap`~~ | **folded into `atlas map`** — the top rung of the same ladder | — |
|
|
| ~~`planet`~~ | **folded into `atlas planet`** — the third rung of the same ladder | — |
|
|
| `ledger` | the economics pipeline, named for the UI component that will aggregate it | ✅ ported (T-1289). `economy-db/` → `domains/ledger/` (`economy_import/` kept by name; the entrypoint became `service.py`), `schema_version.py` with it. `reach ledger import`; `make regen-db` survives as a one-line delegate, `make economy-db` retired. `generated_brands.toml` byte-identical across the move |
|
|
| `wiki` | wiki sync and content maintenance | ✅ ported (T-1290): `reach wiki stats`, `reach wiki gttr-hook` (both output-identical to the originals). `wiki_sync.py` moved whole, but its renderer and importer are NOT verbs — re-rendering deletes ~10,700 lines of committed pages (T-1292). The seven one-shots (`assign-astro-ids`, `migrate-s-to-gj`, `patch-core-sector`, `fill-missing-globes`, `generate-stubs`/`find-stubs`, `backfill_cultural_corridor`) and the destructive `process-wiki-system-changes` went to `archive/wiki-bootstrap/` |
|
|
| `assets` | connectors to the tower-of-joy generators | ✅ ported (T-1290): `reach assets {audio,image,trellis} …` + `synth-ui`. The four audio bash wrappers and `trellis-batch.sh` retired; connectors call each other instead of spawning each other; `tooling/db/` is gone. Synth WAVs byte-identical, ffmpeg pipeline decode-identical; network paths pinned by `test_assets.py` against a fake Gradio. Unreachable reads as OFF (VRAM, D-17), never "restart it" |
|
|
| `character` | bodies, garments, GLB handling | ✅ ported (T-1290): `reach character {logo,strip-glb,qa,qa-analyze}` — logo PNG, stripped GLB and QA report byte-identical; `run-garment-qa` (bash) rewritten with its decisions pinned by `test_character.py`. **Map correction:** six of the ten files assigned here (`convert_outfit`, `inspect_glb`, `check_hair_symmetry`, `check_icosphere`, `render_quaternius_test`, `test_quaternius_raw`) import `bpy` — they joined the carve-out as `blender_*` payloads. `setup_clothing_metadata` and `wipe-bodies.sh` archived; `segment_reference_distribution.md` moved to `docs/assets/visual/` |
|
|
| `visual` | screenshot and render comparison | `visual-diff`, `visual-thumbnail`, `visual-blank-check` |
|
|
| `godot` | Godot parse and cold-start checks | ✅ ported (T-1283); the two bash originals were left beside the port and retired in T-1290 |
|
|
| `generate` | content generators not owned elsewhere | ✅ ported (T-1286). `generate-brands` + `generate-corporations` collapsed into `core.process.cargo_binary` — they were the same 24 lines of bash a third time |
|
|
| `dev` | developer environment and workflow | ✅ ported (T-1286). The three environment scripts split decision from performing — `godot_plan`/`worktree_plan` are pure and pinned by `test_environment.py` |
|
|
| `pr` | the PR/review loop | ✅ ported (T-1286). `watchlist-diff` now reads the watched set from `generator_sources.py` instead of restating it |
|
|
| `blender` | **carve-out** — payloads run by Blender | ✅ done (T-1273). 35 payloads in `tooling/scripts/blender/` (41 after T-1290 found six more among the `character` files), excluded from package scope and from importability; the bash wrapper's install-resolution and path-absolutising became `domains/blender/service.py`, pinned by `test_blender.py` |
|
|
|
|
## Judgment calls, with reasons
|
|
|
|
Each of these sets a precedent, so the reasoning matters more than the answer.
|
|
|
|
**Registries stay module-level data, not commands.** `canvas_sources.py` and
|
|
`generator_sources.py` are lists of paths consumed by gates — nothing types them.
|
|
They move beside the domain that reads them (`check` and `db` respectively) as
|
|
plain modules, not verbs. Making them commands would put something in
|
|
`reach --help` that answers no question a person has.
|
|
|
|
**`schema_version.py` belongs to `ledger` (named `db` when this map was
|
|
drawn), and `check` reads it.** It is consumed by the economics importer *and*
|
|
by the stamp gate. Shared, but not equally owned: the importer defines the
|
|
version, the gate reads it. It goes where it is defined. *As ported (T-1289)
|
|
the gate never imports the module at all — it reads the version back out of
|
|
the `meta` table and checks it is semver — so the cross-domain import this
|
|
ruling allowed for turned out not to be needed.*
|
|
|
|
**`test_*.py` files do NOT become a domain.** They are gate tests run by
|
|
`make test-tooling`, not commands anyone types. `reach test …` would imply a
|
|
test runner that does not exist. They stay standalone scripts.
|
|
|
|
**`pql-migrate/` is provenance, not tooling.** One-shot scripts from a completed
|
|
migration, already documented as such in `.claude/rules/project-structure.md`.
|
|
They are not live tools and must not become verbs. Move to `tooling/archive/`,
|
|
excluded from package discovery — deleting them would destroy migration
|
|
provenance, and keeping them importable would imply they still run.
|
|
|
|
**`pr` is a domain the epic did not list.** `tea-comment` and `pr-watchlist-diff`
|
|
are the PR/review loop, which is neither `dev` (environment setup) nor anything
|
|
else on the original list. Folding them into `dev` would make `dev` the drawer
|
|
everything ambiguous goes into — which is how `core/` rots, and the same
|
|
argument applies here.
|
|
|
|
**`atlas` is overloaded, and the port must not merge the three uses.** The word
|
|
appears in three unrelated places: the top-level `atlas-*` executables (the map
|
|
data surface), `planet-gen/atlas_*.py` (`atlas_cohesion_audit`,
|
|
`atlas_common`, `atlas_quality_analysis` — quality analysis of generated
|
|
terrain), and `economy-db/atlas.py` (the atlas index tables in `systems.db`).
|
|
These are three concerns sharing a noun, not one domain in three places. Each
|
|
stays with its owner — `atlas`, `atlas planet` and `ledger` respectively — and
|
|
the port should resist the pull to collect them, which would produce a domain
|
|
whose only common thread is a word. *Held through both ports (T-1288,
|
|
T-1289): `domains/atlas/`, `domains/atlas/planet/atlas_*.py` and
|
|
`domains/ledger/economy_import/atlas.py` are still three separate files.*
|
|
|
|
**`economy-db/errors.py` predates `core/errors.py` and is not the same thing.**
|
|
Domain-local error types are fine; what must not happen is a silent merge, or a
|
|
second `ReachError` with different semantics. *Reconciled in T-1289:
|
|
`ImportAborted` stays, as internal control flow only — a step raises it to
|
|
request a rollback. It never reaches a caller: `ledger/service.py` rolls back
|
|
and converts it to a `ReachError` carrying the remedy.*
|
|
|
|
**`character` rather than `garment`.** D-263's sketch says `garment`, but the
|
|
files cover bodies, hair, GLB utilities and Quaternius imports as well as
|
|
clothing. Naming it for one of its five concerns would leave the other four
|
|
looking misfiled.
|
|
|
|
## Not moving
|
|
|
|
| what | why |
|
|
|---|---|
|
|
| `econ-sim/`, `line-previewer/`, `test-client/` | Rust crates. Excluded from package discovery; hyphens are harmless. |
|
|
| `scripts/blender/` (after T-1273) | Run under Blender's bundled Python; cannot import `tooling.core`. Excluded from the conformance scope for the same reason. |
|
|
| `archive/` (was `pql-migrate/`) | Completed-migration provenance. |
|
|
| `test_*.py` | Gate tests, not commands. |
|
|
|
|
## Naming, applied on the way in
|
|
|
|
- **Modules** `snake_case`: `check-dataflow-graph.py` → `dataflow_graph.py`.
|
|
- **Verbs** `kebab-case`: `reach check dataflow-graph`.
|
|
- **No prefix-as-namespace.** The domain directory supplies what the `blender_`,
|
|
`atlas-` and `check-` prefixes were doing by hand. `atlas-verify` becomes
|
|
`reach atlas verify`, not `reach atlas atlas-verify`.
|
|
- **Layering is a vocabulary, not a quota.** A domain with only a router and a
|
|
service gets exactly those two files. Empty `schemas.py` and `dependencies.py`
|
|
are worse than absent ones — they suggest a shape the domain does not have.
|