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>
This commit is contained in:
2026-09-02 17:00:46 +02:00
co-authored by Claude Opus 5
parent a45415b23a
commit 338644b409
41 changed files with 1183 additions and 615 deletions
+3 -3
View File
@@ -12,8 +12,8 @@ tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --o
tea pr --login schweitz --repo jpmschweitzer/settled-reach --comments -o simple <PR_NUMBER>
# Post a comment on a PR (or issue) — use @filepath for long comments
tooling/tea-comment <NUMBER> @/tmp/review.md
tooling/tea-comment <NUMBER> "short inline comment"
reach pr comment <NUMBER> @/tmp/review.md
reach pr comment <NUMBER> "short inline comment"
# Approve a PR
tea pr approve --login schweitz --repo jpmschweitzer/settled-reach <PR_NUMBER>
@@ -26,7 +26,7 @@ tea issue list --login schweitz --repo jpmschweitzer/settled-reach --state open
- **All flags must be explicit** — omitting `--login` or `--repo` triggers interactive prompts that crash in Claude Code (no TTY). **One exception: `tea pr create` must OMIT `--repo`** — see Pull requests below.
- **Use `--output simple`** for machine-readable output (no table borders)
- **For comments, use `tooling/tea-comment <number> @/tmp/file.md`** for long comments (write to file first, then pass `@filepath`). Short inline strings also work: `tooling/tea-comment <number> "body"`. The `@filepath` form avoids `$()` subshells which break permission matching.
- **For comments, use `reach pr comment <number> @/tmp/file.md`** for long comments (write to file first, then pass `@filepath`). Short inline strings also work: `reach pr comment <number> "body"`. The `@filepath` form avoids `$()` subshells which break permission matching.
- **`tea pr reject` does not work on your own PRs** — use `tea comment` instead
- **Run `tea` from the main checkout, never a linked worktree** — its go-git can't read a worktree's `.git` *file* and errors with "local/remote repository required". `tea pr close`/`comment` take explicit `--login`/`--repo` so cwd barely matters for them, but `tea pr create` resolves the repo from the **local checkout's remote** (see below) — that is why it must run from the main repo.
- **Never delete protected branches:** `main`, `maintenance`, `server`, `client`, `copy`, `audio`, `visual`, `ci` are protected on Gitea. Do not use `tea pr clean`, `git push --delete`, or `git branch -D` on these branches.
-3
View File
@@ -35,8 +35,6 @@
"Bash(reach)",
"Bash(reach *)",
"Bash(tea *)",
"Bash(tooling/tea-comment *)",
"Bash(tooling/worktree-setup:*)",
"Bash(cargo test *)",
"Bash(cargo test)",
"Bash(cargo build *)",
@@ -50,7 +48,6 @@
"Bash(tests/run-*)",
"Bash(godot4:*)",
"Bash(gdformat:*)",
"Bash(tooling/pr-watchlist-diff:*)",
"Bash(chmod *)",
"Bash(ls *)",
"Bash(find *)",
+1 -1
View File
@@ -99,7 +99,7 @@ Use the project subsystem as scope. Examples:
The pre-push clerk reviews each commit for D-record consistency. For a pure bulk
content commit — e.g. shipping thousands of generated planetary description files
— that review is moot and just burns agents on noise. Add a `Clerk-Skip:` **trailer
line** to the commit message and `tooling/clerk-review` auto-approves that commit
line** to the commit message and `reach dev clerk` auto-approves that commit
without spawning an agent. Use it only for content/data dumps, never for commits
that touch `governance/`, code, or ticket-bearing work.
+2 -2
View File
@@ -26,7 +26,7 @@ so the page is a **snapshot** — this skill regenerates and redeploys it.
run from the MAIN checkout, not a worktree):
```bash
tooling/pql-board-html <scratchpad>/pql-board.html
reach pr board-html --output <scratchpad>/pql-board.html
```
The script pulls `pql ticket list --full`, batch-fetches blocker edges for
@@ -51,7 +51,7 @@ so the page is a **snapshot** — this skill regenerates and redeploys it.
with `force` only if intentionally replacing.
- If the canonical artifact was deleted and a new URL gets minted, **update the
URL in this skill file** in the same turn and commit it.
- The generator is `tooling/pql-board-html` (python, pql-native JSON only).
- The generator is `reach pr board-html` (python, pql-native JSON only).
Known scope limits vs clide: no decisions view, no kanban columns, no live
editing. Dep edges cover non-terminal tickets only — if pql grows
`ticket list --with-blockers`, simplify the script (candidate upstream FR
+5 -5
View File
@@ -217,14 +217,14 @@ versus `origin/main`. This list covers generator code AND the data files that fe
The stamped generator sources come from the shared registry
`tooling/generator_sources.py` (T-1067) — the same module the stamp writer and
`tooling/check-systems-db-stamp` use, so the lists can no longer drift (PR #136
review T7). `tooling/pr-watchlist-diff` wraps the comparison — its header comment
documents the non-stamped watch items it also checks (the surviving one-time
`reach check systems-db-stamp` use, so the lists can no longer drift (PR #136
review T7). `reach pr watchlist-diff` wraps the comparison — it reads the watched
set from that registry and adds the non-stamped items (the surviving one-time
planet-gen importers, the schema DDL whose SHA is stamped separately, and the
wiki data directories that feed the generators):
```bash
tooling/pr-watchlist-diff origin/main HEAD
reach pr watchlist-diff origin/main HEAD
```
**If output is empty:** skip this step entirely.
@@ -358,7 +358,7 @@ If comments exist and contain a review verdict (look for "CHANGES REQUESTED" or
6. Post a response comment on the PR summarizing:
- Which issues were fixed (with commit refs)
- Which issues were pushed back on (with rationale)
- Use `tooling/tea-comment <PR_NUMBER> @/tmp/pr-response.md`
- Use `reach pr comment <PR_NUMBER> @/tmp/pr-response.md`
If no review comments exist, or the review is APPROVED, skip this step.
+5 -5
View File
@@ -148,7 +148,7 @@ assumed — or via `git show`.**
Topic branches from `/whats-next` may have a worktree at
`<repo_root>/.worktrees/<branch-name>` (the kanban convention, D-221 — see
`tooling/worktree-setup`):
`reach dev worktree`):
```bash
REPO_ROOT="$(git rev-parse --show-toplevel)"
@@ -264,13 +264,13 @@ After presenting results to the user, post the review as a PR comment.
Note: `tea pr reject` does not work on your own PRs. Use `tea comment` instead.
Post using the `tea-comment` wrapper (handles temp files and cleanup).
Post using `reach pr comment` (handles temp files and cleanup).
**Two rules:**
1. **Use the Write tool** for the file content (no permission prompt, no
heredoc parsing issues with markdown tables/pipes). Then call
`tooling/tea-comment` in a separate short Bash call.
2. **Run `tooling/tea-comment` in the FOREGROUND, never with
`reach pr comment` in a separate short Bash call.
2. **Run `reach pr comment` in the FOREGROUND, never with
`run_in_background`.** The background execution path silently fails —
the comment never reaches Gitea and the team never sees the review
(Sprint 38 lost an entire review round this way).
@@ -280,7 +280,7 @@ Post using the `tea-comment` wrapper (handles temp files and cleanup).
Write({ file_path: "/tmp/pr-review-<NUMBER>.md", content: "..." })
# Step 2: Post via short Bash call (foreground)
tooling/tea-comment <PR_NUMBER> @/tmp/pr-review-<NUMBER>.md
reach pr comment <PR_NUMBER> @/tmp/pr-review-<NUMBER>.md
```
Do NOT use `cat << 'EOF'` heredocs for review content — they create
+1 -1
View File
@@ -222,7 +222,7 @@ file access), symlinks the `.venv` (so `make test-tooling`/`regen-db` and python
tooling resolve `.venv/bin/python`), and prints the in-worktree reminders:
```bash
tooling/worktree-setup <branch-name> # run from the main checkout
reach dev worktree <branch-name> # run from the main checkout
```
Report the worktree path so the user can open a terminal there.