668772075cbddc62b2bb7cff12ae1faa356309db
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
668772075c |
refactor(tooling): T-1288 — planet-gen becomes reach atlas planet
The 30-file tree moves under atlas as its third rung (D-243), ten verbs fronting it. Each verb restates its module's options so `--help` describes something; tooling/test_planet_router.py hands every declared option to the module's own argparse and fails on drift, and now runs in make test-tooling. The 2026-09-02 half of this move had converted the top-level imports and the repo roots. Finishing it found what the half-move left: - Lazy in-function imports, and all of sol_data/, still named siblings bare. They resolved only through sys.path.insert hacks, so under reach the first globe render in generate, batch or sol-import would have raised ModuleNotFoundError. Qualified; the hacks are gone. - 247 print() calls and a stdout progress writer that fired once per 8 KB block. Report verbs (audit, quality) write through console.out, progress through console.event, and download progress is throttled to 10% steps so a job log is not tens of thousands of lines. - Every error exit raises ReachError with a fix. Two checks that could not fail: - batch --verify-determinism printed a warning and exited 0 on a mismatch. - import-provinces exited 0 with errors > 0. Both now raise. The 271-body bake is only safe to re-run because the first one holds. sol-import --body is action="append" in the module but the router took one value, so --body GJ0d --body GJ0e kept one. Now repeatable, and _flags repeats list options. test_conformance walked one level, so a nested group was reported as a verb missing @command and its ten verbs were never checked. It recurses now; proven by stripping @command from `planet quality` and watching it fail. Stray PNGs from the 2026-09-03 runaway router-test run are parked in .cache/t1288-stray-pngs/, not committed. Their reliefmaps differ from HEAD while the heightmap regenerated byte-identical — filed as T-1291. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
201dabd19b |
refactor(tooling): T-1273 — the Blender carve-out, and a guard that keeps it carved
35 payloads move to tooling/scripts/blender/ and stay outside package scope. They run under Blender's bundled Python, which cannot see the repo venv, so they physically cannot import tooling.core — holding them to the D-263 contract would either fail the gate forever or force the contract to be weakened for everyone, and the second is how a gate stops meaning anything. Count verified by import rather than filename: 33 import bpy/bmesh directly, and the two that do not are still payloads per their own usage lines. garment-fit/make_logo.py is the one genuine non-payload and stays for T-1290. The bash wrapper is retired rather than kept. Keeping it would have put the install-resolution logic in two places, which is the duplication T-1286 had just finished collapsing three copies of. domains/blender/service.py owns the decisions — resolve_blender (native beats flatpak, ordering preserved), resolve_payload, absolutise — and only run_payload performs. test_blender.py pins all of them without launching Blender, which matters here more than usual: the thing being launched is a 200 MB GUI application that writes GLBs. `reach blender run` takes a registered payload name OR a path to any script, because the wrapper served both — the spikes and the glb-gen skill hand it one-off scripts of their own. An unknown name enumerates all 35 and exits 2. The exclusion now defends itself. check_carve_out_stays_carved fails if `scripts` is added to PACKAGE_ROOTS, if the payload directory empties (an empty exclusion proves nothing), or if an __init__.py appears there (which would make the payloads importable — the coupling the carve-out exists to prevent). All three arms mutation-proved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
338644b409 |
refactor(tooling): T-1286 — generate, pr and dev become reach domains
Twelve scripts retired, three domains registered. `reach` now covers nine. generate: `generate-brands` and `generate-corporations` were the second and third copies of the same 24-line build-if-missing-then-exec bash `tooling/atlas` carried, so they collapsed into `core.process.cargo_binary` rather than being ported. `import_economics` shelled out to the first of those, so it now calls that helper — `generated_brands.toml` comes back byte-identical, and the stamp registry swaps the retired wrapper for `core/process.py`. pr: `watchlist-diff` derives its watched set from `generator_sources.py` instead of restating it, so it cannot drift from the stamp check. dev: the environment scripts split decision from performing, per D-263's guarded-exec rule. `godot_plan()` and `worktree_plan()` decide what would happen; `install_godot()`, `install_rust()` and `setup_worktree()` do it. `tooling/test_environment.py` pins the version pin, both override precedences, the already-current skip, the platform refusal and both worktree refusals — none of them performed. `make setup` now installs reach first, since the targets that install rust and godot are reach verbs. Two live bugs found while porting: - The clerk read its decision index from `decisions/README.md`, a path that stopped existing when the DQR tree moved to `governance/`. Every clerk agent has been grepping blind; its prompt pointed at the same dead directory. - The conformance exec-check matched any `x.system()` regardless of receiver, so `platform.system()` read as `os.system()`. Narrowed and re-proved against a real mutant. `process.run` gains `input=`, `timeout=` and a `ProcessTimeout` subclass so a killed run stays distinguishable from a verdict. The pre-push hook no longer merges the clerk's stderr into its stdout — under streaming the last merged line is a JSONL event, which would read as an unrecognised verdict and block. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
6daaa2235f |
docs(governance): D-263 — domains mirror the implant apps, and atlas is one ladder
reach's domain names should not be a fresh taxonomy. Where the game already presents something to the player, the CLI takes that name and that shape: what you browse in-game is what you generate and inspect from the terminal. That splits domains in two. atlas, ledger and wiki mirror implant apps and follow their structure. check, validate, godot, visual, jobs and dev mirror nothing — no app exists for a lint gate, and inventing a player-facing framing for one would be worse than having none. The first consequence corrects a contradiction rather than a preference. D-191 already says "Atlas is the star map extended downward, not a separate app — implant/map at different zoom levels", four rungs from Reach map to regional. The domain map had atlas, starmap and planet as peers, which would have presented as three unrelated things 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 rather than a rung. The second is a rename with the same reasoning: db becomes ledger, after the UI component that will aggregate economics — markets, wealth, transactions, the economic counterpart to what the Atlas offers for topography. db named a storage layer nobody looks at. One caution recorded because the words collide. D-191's MVP criterion 7 says "Atlas is read-only (no verbs execute from map)". That governs the app. The atlas tooling writes — it commits proposals, mutates fields, syncs the wiki — and a later reader must not take the app's constraint as licence to delete the authoring verbs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e359cfa841 |
docs(governance): D-263 — half the tooling is bash, and it gets rewritten
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> |
||
|
|
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> |