Files
settled-reach/tooling/DOMAINS.md
T
jpmschweitzerandClaude Opus 5 91a57b8304 docs(config): T-1271 — the domain map, before anything moves
Every Python file and executable in tooling/ assigned to one of 15 domains,
with the ambiguous cases carrying their reasoning. The per-domain port tickets
are written from this rather than guessed, so their boundaries do not have to
be renegotiated halfway through a 160-file move.

Three things counting turned up that reading would not have.

The Blender carve-out is 35 files, not the 13 visible at top level — 22 more
are inside garment-fit/, which turns out to be a payload directory wearing a
domain's name. The epic said 35 and an earlier survey of mine said 14; the
epic was right. That is not cosmetic: `character` is a far smaller domain than
directory sizes imply, and a port ticket written from the listing would have
been wrong about both it and the carve-out.

The "28 singleton prefixes" were an artefact of splitting filenames on the
first token, which scattered coherent families — sculpt-star-map,
tune-star-map-topology and generate-star-map* are one group counted as three
orphans. Counting families instead, the genuinely ambiguous set is small
enough to enumerate with reasons.

And tooling/db/ is misnamed: it holds the audio/image/Trellis connectors and
wiki_sync, while the actual database work is in economy-db/. Naming a domain
after that directory would have carried the misnomer forward.

Judgment calls settled with reasons, since each sets a precedent. Registries
stay data rather than becoming verbs nobody would type. Gate tests do not
become a `test` domain implying a runner that does not exist. pql-migrate is
provenance — archived, not deleted and not importable. `pr` is a domain the
epic omitted, kept out of `dev` so dev does not become the drawer everything
ambiguous goes into. And `atlas` is overloaded across three unrelated places —
map data, terrain quality analysis, and systems.db index tables — which stay
with their owners rather than being collected into a domain whose only common
thread is a noun.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 15:26:55 +02:00

130 lines
8.2 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:** map only. Nothing here has moved yet except `check client-version`,
which shipped in T-1262 as the reference implementation.
## 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.
## 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 Atlas map data surface | `atlas`, `atlas-check`, `atlas-names`, `atlas-commit-and-sync`, `atlas-systems-done`, `atlas-update-field`, `atlas-verify`, `atlas-flatness` |
| `starmap` | the star map and its renders | `generate-star-map.py`, `generate-star-map-data.py`, `generate-star-map-svg.py`, `sculpt-star-map.py`, `tune-star-map-topology.py`, `star-map-seed.json` |
| `planet` | planetary generation and its guards | `planet-gen/` (30 files) |
| `db` | the economics DB pipeline | `economy-db/` (17 files), `schema_version.py` |
| `wiki` | wiki sync and content maintenance | `wiki/`, `db/wiki_sync.py`, `db/populate_gttr_hook.py`, `db/backfill_cultural_corridor.py`, `assign-astro-ids.py`, `fill-missing-globes.py`, `migrate-s-to-gj.py`, `patch-core-sector.py`, `process-wiki-system-changes` |
| `assets` | connectors to the tower-of-joy generators | `db/audio_*.py`, `db/audio-*`, `db/image_connector.py`, `db/trellis_connector.py`, `db/common.py`, `trellis-batch.sh`, `synth_ui_sounds.py` |
| `character` | bodies, garments, GLB handling | `garment-fit/make_logo.py`, `garment-qa/analyze_captures.py`, `convert_outfit.py`, `glb_strip_utility_nodes.py`, `inspect_glb.py`, `check_hair_symmetry.py`, `check_icosphere.py`, `render_quaternius_test.py`, `setup_clothing_metadata.py`**note this is far smaller than `garment-fit/`'s file count suggests; 22 of its 23 files are Blender payloads and belong to the carve-out** |
| `visual` | screenshot and render comparison | `visual-diff`, `visual-thumbnail`, `visual-blank-check` |
| `godot` | Godot parse and cold-start checks | `godot-parse-sweep`, `godot-cold-parse` |
| `generate` | content generators not owned elsewhere | `generate-brands`, `generate-corporations`, `generate-character-manifest`, `generate_corp_stubs.py` |
| `dev` | developer environment and workflow | `install-rust`, `install-godot`, `worktree-setup`, `perf-baseline`, `clerk-review` |
| `pr` | the PR/review loop | `tea-comment`, `pr-watchlist-diff`, `pql-board-html` |
| `blender` | **carve-out** — payloads run by Blender | **35** `blender_*.py` (13 top-level + 22 in `garment-fit/`), `blender` wrapper → `tooling/scripts/blender/` |
## 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 `db`, and `check` imports 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, and the cross-domain import is legitimate — that is what a service
layer is for.
**`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`, `planet` and `db` respectively — and the port
should resist the pull to collect them, which would produce a domain whose only
common thread is a word.
**`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. Reconcile explicitly when `db` is
ported.
**`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.