chore(tools): every tool lives with its reader - #778
Merged
Merged
Conversation
`tools/` held 77 top-level scripts and classified them in a column of `docs/reference/tools.md`. A creator opening the directory faced six sevenths of it that was not for them, and the classification was data in a table rather than structure on disk. Four homes, each named for its reader: - `tools/creator/` (7 scripts + `skin/`) — exactly what a `/new-delve` page file INVOKES. A tool the page only cites as the source of a constant is not a creator tool: `check-patrol-types.py` and `derive-client-langs.py` are named in `init.md` only as the carriers of the Mojang manifest URL, and each regenerates a committed table, so both live under maintenance. - `tools/ci/` (49 scripts + `data/`) — one file per gate a workflow runs, plus `gallery_domain.py` / `gallery_units.py`, which only those gates import. - `tools/planner/` (4) — `planner-state.sh` with its `SessionStart` and `UserPromptSubmit` hook binding, `worktree-new.sh`, `worktree-reclaim.py`, `next-numbered-doc.py`. - `tools/maintenance/` (17 + the two Java dumpers) — the regenerators a Minecraft pin bump calls, and `site-plan-scalars.py`, spec-0059's instrument. `tools/lib/`, `tools/tests/` and the `spike-*` rigs keep their homes: a library has no reader of its own. Nothing is removed. Every one of the 77 has a reader that names it — a workflow, the page, a `sites` list in `.github/pins.toml`, a crate source comment pointing at the table it regenerates, or a spec naming it as its instrument. Re-pointed in the same change: 1174 path references across 287 files, `.github/workflows/*`, `.github/ci-reach.toml` (4 globs), `.github/pins.toml` `sites` lists, `.github/actions/*`, `.claude/settings.json`'s hook command, the `/new-delve` page, `tools/tests`, the crates' provenance notes, and CLAUDE.md's repository-layout block. Every moved script's own repo-root resolution moves with it: 53 `parent.parent` -> `parents[2]`, 15 `parent / "lib"` -> `parents[1] / "lib"`, 8 `parent` -> `parents[1]` where the insert feeds `from lib import ...`, 11 shell `dirname/..` -> `../..`. `docs/reference/tools.md` section 6 is one table per directory, so a row naming a file no directory holds is visible by reading the tree beside the page. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
…can cannot see Five classes of reference a literal-path rewrite does not reach, each found by running the gate rather than by grepping: - A path spelled as a REGEX. `check-structure-emitters.py` looked for `tools/fmt-workspaces\.sh` and reported, correctly, that nothing establishes `cargo fmt` for the prefab packages. - A path a TEST BUILDS rather than names. Ten fixtures assemble a throwaway tree and copy a script into it; the copy has to land where the script's own root resolution expects it, so `tools/ci/`, `tools/creator/` and `tools/planner/` are created in the fake trees too. - A path this repository must NOT move. `check-publishable-d5908698.sh` is a frozen instrument, named by that revision, and at that revision the script lived at `tools/check-publishable.sh` and resolved its root one directory up. Its bytes are restored and its clone is laid out the way d590869 laid it out; running frozen bytes against today's layout would be judging that revision on a tree it was never written for. - A LEDGER ROW. A `{"kind": "tool"}` carrier in `docs/playtest-findings.json` names its script relative to `tools/`, so the row now carries the home of the reader the tool is for. - A path inside a `note` in a gallery stage document, which is gallery SOURCE: `gallery/baseline` is retaken over `74c61b5abd14` with a force-rebuilt instrument. manifests.json and warnings.json are unchanged and the review delta is 0 added / 0 removed / 0 changed over 3797 emitted paths — the move emits byte-identical output. `gallery/README.md` and `test_gallery_domain.py` reach `gallery_domain` through `tools/ci` now; the latter's denominator is the python tools of all five homes, enumerated from the directories, because `TOOLS.glob("*.py")` matches nothing at the top level any more and a zero there would have been a silent pass. `init.md` named `check-patrol-types.py` and `derive-client-langs.py` under `$DELVEWRIGHT_ENGINE/`, where the rewrite's own lookbehind could not see them. Both are maintenance tools: the page cites them as the carriers of the Mojang manifest URL and invokes neither. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
`prefab-procedure-friction-log.md` and `skill-drill-friction-log.md` name their instrument by revision and quote terminal sessions a person ran. Rewriting a transcript changes what the record says happened, so both are restored to the bytes they carried at 74c61b5. The other three notes under `docs/notes/` name their tools in the present tense — what enforces a rule, what asserts a property — and keep the re-point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
`tools/check-seating-agrees.py` moved here and changed there; git followed the rename and the change landed at `tools/ci/check-seating-agrees.py`. Three conflicts, each resolved toward what the other side is authority for: - `docs/reference/compiler.md` and the `check-seating-agrees.py` row of `docs/reference/tools.md` — origin/main's sentence, re-pointed to the new home. This side is authority for the path only. - `gallery/baseline/` — reset to origin/main's four documents wholesale. It is a generated artifact and is regenerated in the next commit, after this merge commit exists, against a force-rebuilt instrument. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
Regenerated after the merge commit exists, against an instrument force-rebuilt from the merged tree (`delvec 1.5.0, dsl 0.28.0, mc 1.21.11`, built from `crates/delvec/tests/remedy_reachability.rs` at the newest of 803 tracked compiler sources). header.json and delta.json move; manifests.json and warnings.json are unchanged. The review delta against `9e101878b7aa` is 0 added, 0 removed, 0 changed over 3797 emitted paths, 0 warning rows at a different count and 0 manifest values differing — this branch moves no emission relative to main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
One commit landed since the last merge of `9e101878`: the firework round (spec-0068, `dsl_version` 0.29.0, `DW0899`). `git merge-tree --write-tree` against this head named exactly two conflicting paths before the merge was started, and the merge produced exactly those two: `gallery/baseline/delta.json` and `gallery/baseline/header.json`. Everything else auto-merged — `crates/delvec/src/compiler/emit.rs`, `crates/dsl/src/stages.rs`, `crates/dsl/src/validate.rs`, `docs/playtest-findings.json`, `docs/reference/compiler.md`, `docs/specs/README.md`, `versions.toml`. `gallery/baseline/` is generated, so all four of its documents are reset to origin/main's wholesale rather than three-way merged. It is regenerated in the next commit, after this merge commit exists, against a force-rebuilt instrument. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
The firework round wrote `tools/check-gallery-coverage.py` and `tools/check-skill-page.py` while this branch was moving both into `tools/ci/`. They are the only two paths the merge brought in that the move had invalidated: a scan of the whole merged tree for every one of the 81 old paths returns 16 occurrences, and the other 14 are the deliberate ones — two dated friction logs, the frozen `d5908698` instrument, the comments naming that revision's layout, and one dated reproduction note in the findings ledger. Nothing the round ADDED names a `tools/` path otherwise: `compiler/firework.rs`, `dsl/src/firework.rs`, `dsl/src/color.rs`, both `v29_firework.rs` and `gallery/probes/a-rocket-under-a-roof/probe.json` mention none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
Regenerated after the merge commit exists, against an instrument force-rebuilt with `cargo build -p delvec --bin delvec` at exit 0 (`delvec 1.5.0, dsl 0.29.0, mc 1.21.11`, newest of 808 tracked compiler sources). 8 builds, 3798 emitted paths — one more than before the merge, which is the firework round's `valley-site.en:validation/firework-gate.json`. Every changed row attributed: - `manifests.json` and `warnings.json` are BYTE-IDENTICAL to origin/main's. The 77 rows the firework round moved and the one it added are all carried through unchanged: none of them is this branch's. This branch moves no emission at all. - `header.json` differs from main in exactly one field, `gallery_source_sha256`. That is this branch's, and it has one cause: the `note` of `gallery/overlays/valley-site/overlay.json` names `tools/ci/check-gallery-stageable.py`, and a `note` in a stage document is gallery SOURCE. `gallery/README.md` is this branch's other gallery edit and the digest excludes it by name, so it contributes nothing. - `delta.json` is re-based `9e101878b7aa` -> `3598d8f86732` and its lists empty: the 1 added and 77 changed paths it carried were the firework round's own, measured against the older base. Against `3598d8f86732` the review delta is 0 added, 0 removed, 0 changed over 3798 emitted paths, 0 warning rows at a different count and 0 manifest values differing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
stellarfeline
marked this pull request as draft
September 16, 2026 06:55
stellarfeline
marked this pull request as ready for review
September 16, 2026 10:14
Six merges landed since `3598d8f8`: spec-0058 (`delvec detail`), spec-0070 (`DW0900`), the CRLF work, `delvec prefab`/`playtest-server.sh` taking either kind of artifact, the 1.6.0 version name, and the page re-pin to a release tag (ADR-0029). `git merge-tree --write-tree` named eleven conflicting paths before the merge was started and the merge produced exactly those eleven. Nine of them are the same shape: origin/main is the authority for the content and this branch is the authority for the path alone, proved rather than assumed — this side's version of six of them (`versions.toml`, `skill-page-objects/action.yml`, `pins.toml`, `ci.yml`, `skill-workflow.md`, `spec-0063`) is byte-equal to the merge base once the home directories are stripped out, so each takes origin/main's file with the path mapping applied and nothing else. Three carried more than a path, and each was resolved as origin/main's file plus exactly what this branch adds to it, named: - `tools/ci/check-skill-page.py` — 7 literal paths, 3 `REPO / "tools" / …` joins, and `REPO` resolving two directories up instead of one. - `tools/creator/playtest-server.sh` — 8 literal paths and 3 `dirname "$0"` roots. origin/main's restructure of the script (either kind of artifact, and the staging gate moving with it) is taken whole. - `docs/reference/tools.md` — origin/main's 100 section-6 rows, re-pointed and re-grouped into this branch's one-table-per-home structure. Its row set is this branch's 98 plus the two tools the round added, and nothing else. `gallery/baseline/` is generated: all four documents reset to origin/main's wholesale, regenerated in the next commit. The two tools origin/main added land in the home of their reader in this same commit, because they arrive at `tools/` root and nothing else would put them anywhere: `check-eol-attributes.py` and `gallery-prefabs.py` are both run by a CI job, so both go to `tools/ci/`, each with its own repo-root resolution moved one level and `gallery-prefabs.py`'s `lib` import re-pointed; 7 references to them across 6 files move with them. The eol population is unchanged by any of this, measured on both trees rather than argued: origin/main at `7bc14feb` reports 128 of 1520 tracked files run through their first line (128 by shebang, 58 by the executable bit), and this merged tree reports the same 128 of 1520, 128 and 58, every one pinned `eol=lf` and 128 materialised with LF. `.gitattributes` matches by extension with no leading slash, so a pattern reaches a file at any depth. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
The page re-pin (ADR-0029) points `[engine].ref` at `delvec--v1.6.0`, which is unborn, so `check-skill-page.py` materialises THIS tree and rule 21 holds every `$DELVEWRIGHT_ENGINE/<path>` the page names against it. It reds on this branch the moment the merge lands, which is the whole point of the rule. What it found, and what each repair is: - `REFIMG` was the bare basename `refimg.py` and rule 15 resolved it as `engine / "tools" / REFIMG`. Against the older pin that was true of the engine it named; against this tree it is not. It is now the path relative to `tools/`, carrying the home of the reader the tool is for. - The config the probe writes is `delvewright.local.toml` at the engine ROOT, which `refimg.py` resolves as `parents[2]` since the move. The gate wrote it at `refimg.parent.parent`, one directory short, so every provider probe would have run unconfigured. - `container_names` globbed `engine/tools/*.sh`, which matches nothing now that no script sits at the root of `tools/`. It reads the tree recursively; the `^NAME="…"` lines it is after are unaffected by which directory they are in. Rule 21 then binds 38 of 42 named paths on BOTH arms — the tree the page ships from and the tree the pin names — 34 of the 38 present, 4 named as build output this tree's own `.gitignore` covers with git judging, 1 never a tree entry (`.git`) and 3 written with a placeholder segment. The twelve the page names under `tools/` are all present at their new homes. The rest of the merge's live references move with them: 36 literal paths and 2 `Path` joins across 11 files — ADR-0029, spec-0058, spec-0070, `compiler.md`, the page's `tools-by-symptom.md` and `fetch-delvec.py`, and five test modules, of which `test_check_skill_page.py` and `test_playtest_server_takes_either_kind.py` would otherwise fail outright because they read the real index. A whole-tree scan for all 83 old paths leaves 14, every one deliberate: two dated friction logs, the frozen `d5908698` instrument, the comments naming that revision's layout, and one dated reproduction note in the findings ledger. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
Regenerated after the merge commit exists, against an instrument force-rebuilt with `cargo build -p delvec --bin delvec` at exit 0 (`delvec 1.6.0, dsl 0.29.0, mc 1.21.11`, newest of 810 tracked compiler sources), over pieces written by `tools/ci/gallery-prefabs.py` — the step spec-0058 put in place of the generator's own manifest. 8 builds, 3799 emitted paths. Every changed row attributed: - `manifests.json` and `warnings.json` are BYTE-IDENTICAL to origin/main's. Everything spec-0058, spec-0070 and the firework round moved in them is carried through unchanged; this branch moves no emission at all. - `header.json` differs from main in exactly one field, `gallery_source_sha256`. That is this branch's, with one cause: the `note` of `gallery/overlays/valley-site/overlay.json` names `tools/ci/check-gallery-stageable.py`, and a `note` in a stage document is gallery SOURCE. `gallery/README.md` is this branch's other gallery edit and the digest excludes it by name. - `delta.json` differs from main in exactly one line, `base_commit`, re-based `33e3dbe3e74f` -> `7bc14febcd4c`. Its path lists are unchanged. Against `7bc14febcd4c` the review delta is 0 added, 0 removed, 0 changed over 3799 emitted paths, 0 warning rows at a different count, 0 manifest values differing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
ADR-0029 gave `check-pins.py` an import of `release_tags` from `tools/lib`, resolved as `<its parent>/lib`. From `tools/ci/` that is `tools/ci/lib`, which does not exist, and the gate died with `ModuleNotFoundError` before it read a single pin — found by running it rather than by reading it. It is the last of this shape in the tree: no script under `tools/ci`, `tools/creator`, `tools/planner` or `tools/maintenance` still inserts `<its parent>/lib` on `sys.path`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tools/held 77 loose scripts at its top level and a table indocs/reference/tools.mdsaid who each one was for. The classification is now the directory a tool lives in, and the top level holds no loose file.The homes
tools/creator//new-delvepage runs, plusskin/tools/ci/tools/planner/planner-state.sh(its hook binding moves with it),worktree-new.sh,worktree-reclaim.py,next-numbered-doc.pytools/maintenance/tools/lib/,tools/tests/,tools/spike-*/7 + 49 + 4 + 17 = 77.
check-patrol-types.pyandderive-client-langs.pyare maintenance: the page cites the Mojang manifest URL constant each carries and never invokes them.Nothing is removed
Every one of the 77 has a reader that names it, checked against workflows, the page,
.github/pins.toml'ssites, crate comments pointing at the table a script regenerates, and specs that name a script as their instrument.next-numbered-doc.pyimplements the numbering rule and belongs to the planner;site-plan-scalars.pyis spec-0059's own instrument.What a pure path rewrite cannot reach
Five classes came out of running the gates, not out of
git grep: a path written as a regex (which redscheck-structure-emitters), a fake tree a test builds rather than names (10 fixtures), a frozen instrument that must not move, the{"kind": "tool"}carriers indocs/playtest-findings.json, and paths inside gallery stage documents, which are gallery source and so move the baseline.Old-path references in this repository: 1117 across 284 files at
74c61b5a, 14 across 5 files here, over 1485 tracked files. All 14 are deliberate — dated friction logs that name their instrument by revision, the frozencheck-publishable-d5908698.sh, two comments describing that frozen layout, and one reproduction record.The
delvecsubcommand list, reportedblock-appearance.py,staging-gate.pyandcheck-storybook-version.pyare subcommands: each reads only what the binary already holds.i18n-translate.pyandrefimg.pystay scripts (live third-party endpoints and per-provider keys; the compiler does no network I/O).refscore.pystays (its backends are Python ML packages).playtest-server.shstays (container lifecycle, port mutex, rcon).skin/stays Python (its tests assert byte-identical golden PNGs fromskinpy-extended).Initwalked end to endOn a scratch
HOME, dev mode, I0 through I8: python3 3.14.7, git, java; I1b exits 4 with noenv.sh;cargo build --release -p delvecon toolchain 1.97.1;delvec 1.5.0, dsl 0.28.0, mc 1.21.11; the client jar downloads and its sha1 verifies;DELVEWRIGHT_PREFABSresolves 74 entries; all 9 lines of I8 answer.docker compose versionis the one line this machine cannot answer, for want of the Compose plugin.Gates (tree merged with
3598d8f8)fmt2 workspaces clean;clippy --workspace --all-targets -D warningsexit 0;cargo test --workspace --no-fail-fast3564 passed, 0 failed over 264 result lines;pytest tools/tests1355 passed, 1 skipped;check-dw-codes363 codes, all covered; gallery coverage 36 refusal probes, 28 ledgers, 0 zero-bindings, baseline verified, stageable 8 of 8, render 70 of 70, whole-map render 3 bases and 230 scenes;check-required-contexts16 of 16;check-ci-reach15 jobs, 14 groups, 60 globs over 1492 files, 3 events;check-pins41 pins against 44 entries;check-skill-pagegreen against engine70eea629;check-doc-dupes163 documents;check-source-dupes500 Rust files;check-json-canonical438 of 439;check-effect-roots218 files;check-generator-preservation1024 planted keys;check-unsanctioned-identifiersOK.The baseline over
3598d8f8moves one field,header.json'sgallery_source_sha256, because a stage document'snotenames a gate and that note is gallery source.manifests.jsonandwarnings.jsonare byte-identical tomain's, and the delta is 0 added, 0 removed, 0 changed: this branch moves no emitted byte.The layout survives the merge: creator 25, ci 50, planner 4, maintenance 19, lib 20, tests 84, and nothing loose at the top.
8 ADRs and 22 specs carry path re-points only: reversing the new paths gives back
74c61b5a's bytes exactly, so no decision text moved.🤖 Generated with Claude Code
https://claude.ai/code/session_01Vx4gBbZLG8Ecy9qzufa14L