diff --git a/governance/questions/architecture.md b/governance/questions/architecture.md index 97cb6b378..18f47b34d 100644 --- a/governance/questions/architecture.md +++ b/governance/questions/architecture.md @@ -514,6 +514,24 @@ Technical foundation questions: engine, protocols, data structures, performance, - **But the PATH problem is the actual requirement, and it is separate from the framework.** A `[project.scripts]` entrypoint lands in `.venv/bin/`, which is on PATH only when the venv is activated — and non-interactive shells (agents, git hooks) never activate it. That is the *same* split `VENV_PY` already papers over in the Makefile (`test -x .venv/bin/python || python3`). It is also exactly the failure recorded for `tea`: an absolute path breaks the `Bash(tea *)` rule and prompts every time, and the fix was a bare name on PATH. **So the deliverable is "one bare command reliably on PATH", not "a CLI framework"** — via `uv tool install` / `pipx` into `~/.local/bin`, or a symlink. Choose the framework second; a Typer app behind an absolute venv path solves nothing. - **It does not help friction (2), and may worsen (3).** Typer + Click are two more venv dependencies. And a single entrypoint that imports every subcommand eagerly pays all 123 modules' import cost on every invocation — including four times per push. Lazy subcommand registration is then mandatory, not an optimisation; measure it before and after. - **Net:** this looks like the answer for the check/gate family and the day-to-day scripts. It leaves the numpy/scipy/PIL planet-gen path untouched, which is the part a Rust port would have had to prove numerical equivalence for. Price this first. + +- **Amendment 2026-08-20 (b) — the shape Jeroen wants: one door, domain-split behind it, and failures that teach.** *"it would involve moving all python into a separate dir with proper domain split so one door answers all options we have with help and instructions/help when there is an error: a new prompt not an error code."* Three requirements, and the third is the demanding one. + 1. **A real package with a domain split.** `tooling/` is currently **85 top-level entries** — 37 loose `.py`, ~36 extensionless executables, and 11 directories of which only 6 hold anything (`planet-gen` 30, `garment-fit` 23, `economy-db` 17, `db` 9, `pql-migrate` 5, `wiki` 1). Four naming conventions coexist: `assign-astro-ids.py` (hyphen + extension), `canvas_sources.py` (underscore), `check-canvas-version` (no extension), `blender_*.py` (prefix-as-namespace). + **The domains are already there, encoded as filename prefixes** — `blender` ×14, `atlas` ×8, `generate` ×7, `check` ×7, `visual` ×3, `validate` ×3, `test` ×3, then `godot`/`garment`/`pql`/`install` ×2. So the split is **discoverable, not invented**: those prefixes are the subcommand groups (`sr atlas verify`, `sr check canvas-version`, `sr blender process-bodies`). This is the strongest argument that the consolidation is mechanical enough to be safe. + 2. **One door, with help at every level.** A single entrypoint whose `--help` enumerates the domains, and each domain's `--help` enumerates its verbs. Today there is no way to ask "what tooling exists" except `ls`, which is exactly how the `/d2-diagram` skill was mis-reported as missing on 2026-08-20 — a listing that only a directory read can answer is a listing that goes stale in someone's head. + 3. **A failure returns the next command, not a status.** This is the requirement with real teeth. Jeroen: *"I have this in pql as well: errors become instructions."* The repo already does it in places worth copying — `check-canvas-version` fails with *"Run `make regen-db`"*, and `check-dataflow-graph` names the path that stopped resolving and says whether to fix the diagram or the path. The rule generalises: **every non-zero exit prints the command that would fix it.** + **Measured against pql (2026-08-20), the principle is established there but applied unevenly**, which sets a more precise bar than "be like pql": + + | case | pql output | instruction? | + |---|---|---| + | `pql ticket frobnicate` | full usage + command list | **yes** | + | `pql ticket status T-1246 nonsense` | `invalid status "nonsense"` | no — and the valid set is 6 closed values the program knows | + | `pql ticket new` (no args) | `accepts 2 arg(s), received 0` | no — does not name which 2 | + | `pql ticket show T-99999` | `ticket T-99999 not found` | no — no "try `pql ticket list`" | + + So **unknown-subcommand is solved and invalid-value is not** — and invalid-value is the more common failure, precisely because the valid set is closed and enumerable. The bar for this CLI: **whenever the accepted set is known, print it.** Logged upstream to `pql/feature-request.md` rather than worked around here. +- **Constraint the above must not break — exit codes stay.** *"a new prompt not an error code"* cannot mean dropping the code. Four of these run in the pre-push hook, which fails the push **only** by non-zero exit; a tool that explains itself and exits 0 silently disables its own gate. That failure mode was observed first-hand on 2026-08-20 in clide, where `unsupported image format`, `no such file`, and unknown-subsystem all returned exit 0, making every error indistinguishable from success to anything checking `$?`. **So: exit code AND actionable message, never either/or.** +- **And it must not become literally interactive.** If "a new prompt" means asking the user a question, that must be TTY-gated and suppressible (`--no-input`). Agents and git hooks have no TTY, and this repo already has that scar written down: `tea`'s interactive prompts *"crash in Claude Code (no TTY)"*, which is why every `tea` call is required to pass all flags explicitly. A helpful prompt that hangs a hook is worse than a terse exit code. - **Raised by:** Jeroen, 2026-08-20: *"those python files are a pain. they throw permission prompts all over the place and the venv dependencies are annoying... We should ticket a Q record to retool that to rust probably. maybe make it into an actual cli of the quality level of pql. one can dream"* - **Cross-reference:** [D-223](../decisions/architecture.md#d-223) and `.claude/rules/asset-pipeline.md` (the stamp contract a rewrite must preserve), [D-262](../decisions/architecture.md#d-262) (`check-dataflow-graph`, the most recent addition to the per-push Python set), `.claude/rules/ticket-cli.md` (`pql` as the quality bar being referenced).