Found on starting the first port: 17 of the 33 tooling executables are bash,
about 900 lines. Both this record and the domain map had assumed a Python tree,
so those are rewrites rather than moves — a materially larger epic than T-1250
was written for.
Decided: rewrite them, do not wrap them. Wrapping would achieve one door while
leaving half the CLI surface outside the contract — no @command, no remedy on
failure, no streaming, no testable service. reach --help would then list verbs
that behave differently from the ones beside them, which is worse than two
doors, because the inconsistency is invisible until something fails.
The cost lands unevenly and the record says where. The grep-pipeline scripts
compute verdicts and gain most from becoming services. The environment scripts
— install-godot, install-rust, worktree-setup — gain least and carry the most
regression risk, because downloading a specific Godot build or driving rustup
is awkward to exercise in a gate. For those, port the decision logic into a
testable service and keep the irreducible external calls behind core/process: a
rewrite that cannot be tested has to be trusted instead, and trusting an
installer is how a working environment becomes an unreproducible one.
The domain map gains the inventory by shape, and a rule that every per-domain
ticket states which of its sources are bash — since that is what turns a port
from mechanical into a rewrite needing its own parity evidence.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>