docs(governance): Q-124 — Typer costs the cheap option down, and moves the target
Jeroen raised Typer as the Python-CLI option. Costing it changed what the question is actually about. The repo is already most of the way there: pyproject.toml exists, `make setup-venv` already does `pip install -e ".[dev]"`, and 22 tooling files already use argparse. What is missing is a single line — there is no [project.scripts] entry at all, so no console entrypoint exists. This is consolidation, not authorship, and it resolves the largest friction (per-script permission prompts) for one allowlist entry. But the framework is the second decision, not the first. A [project.scripts] entrypoint lands in .venv/bin/, which is on PATH only when the venv is activated — and agents and git hooks never activate it. That is the same split VENV_PY already papers over in the Makefile, and precisely the failure recorded for tea: an absolute path breaks the Bash(tea *) rule and prompts every time, fixed only by a bare name on PATH. So the deliverable is "one bare command reliably on PATH" (uv tool / pipx into ~/.local/bin, or a symlink), and a Typer app behind an absolute venv path would solve nothing. Two honest costs recorded against it: Typer and Click are further venv dependencies, so it does not help the venv friction at all; and a single entrypoint importing every subcommand eagerly would pay all 123 modules' import cost on every invocation, four times per push. Lazy subcommand registration is therefore mandatory rather than an optimisation, and must be measured before and after. Net: this looks like the answer for the check/gate family and the day-to-day scripts, and it leaves the numpy/scipy/PIL planet-gen path alone — the part a Rust port would have had to prove numerical equivalence for. T-1246 updated to start here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1218,3 +1218,28 @@ the same root cause — measuring VALUES without reading the CODE that produced
|
||||
them. First correction: tectonics is derived. Second: the whole continuous/
|
||||
categorical split is an artefact of the resolution tiers. Both were available in
|
||||
a docstring the original pass grepped but never read.', NULL, '2026-08-19 22:52:46', '2026-08-19 22:52:46.636', '2026-08-19 22:52:46.636', NULL, '7fcf06ee54c5fbc71568e6b5e30760ff', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G1RWR7M1H1PC3TY2RT7AC174', 'description', 'Answer Q-124. Investigation and costing FIRST — do not open with a rewrite.
|
||||
|
||||
Price the cheap alternative before recommending Rust: a single Python dispatcher entrypoint (one command, many subcommands) would resolve the permission-prompt friction and most of the startup cost without touching the numerics. If that is enough, say so and close Q-124 with it.
|
||||
|
||||
Scope order if Rust is chosen: port the check/gate family first (check-client-version, check-canvas-version, check-systems-db-stamp, check-dataflow-graph) — small, pure, no numerics, highest prompt-friction, runs on every push. Leave planet-gen numerics (numpy/scipy/PIL) in Python behind a stable interface.
|
||||
|
||||
Hard constraint: import_economics is stamped by source SHA via tooling/generator_sources.py. Any port must keep the stamp/pre-push contract intact through the transition, not disabled during it.
|
||||
|
||||
Outcome: a recommendation with costs, then a D-record and Jeroen''s ruling. Epics only after that.', 'Answer Q-124. Investigation and costing FIRST — do not open with a rewrite.
|
||||
|
||||
Price the cheap alternative before recommending Rust: a single Python dispatcher entrypoint (one command, many subcommands) would resolve the permission-prompt friction and most of the startup cost without touching the numerics. If that is enough, say so and close Q-124 with it.
|
||||
|
||||
Scope order if Rust is chosen: port the check/gate family first (check-client-version, check-canvas-version, check-systems-db-stamp, check-dataflow-graph) — small, pure, no numerics, highest prompt-friction, runs on every push. Leave planet-gen numerics (numpy/scipy/PIL) in Python behind a stable interface.
|
||||
|
||||
Hard constraint: import_economics is stamped by source SHA via tooling/generator_sources.py. Any port must keep the stamp/pre-push contract intact through the transition, not disabled during it.
|
||||
|
||||
Outcome: a recommendation with costs, then a D-record and Jeroen''s ruling. Epics only after that.
|
||||
|
||||
2026-08-20 — Jeroen raised Typer (typer.tiangolo.com) as the Python-CLI option. Q-124 amended with the costing.
|
||||
|
||||
Start here, not with Rust. Measured state: pyproject.toml already exists and make setup-venv already does pip install -e ''.[dev]'', but there is NO [project.scripts] entry — no console entrypoint exists at all. 22 tooling files already use argparse. So this is consolidation, not authorship.
|
||||
|
||||
The real deliverable is ''one bare command reliably on PATH'', not ''a CLI framework''. A [project.scripts] entrypoint lands in .venv/bin/, which is on PATH only when activated — and agents and git hooks never activate it. That is the same split VENV_PY papers over in the Makefile, and the same failure recorded for tea (absolute path breaks the Bash(tea *) rule and prompts every time). Install via uv tool/pipx into ~/.local/bin, or symlink. A Typer app behind an absolute venv path solves nothing.
|
||||
|
||||
Watch startup cost: a single entrypoint importing every subcommand eagerly pays all 123 modules on every invocation, four times per push. Lazy subcommand registration is mandatory, not an optimisation — measure before and after.', NULL, '2026-08-20 00:00:11', '2026-08-20 00:00:11.592', '2026-08-20 00:00:11.592', NULL, '45f6dd41a5c643a730209c654bd57c76', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -1185,3 +1185,20 @@ Scope order if Rust is chosen: port the check/gate family first (check-client-ve
|
||||
Hard constraint: import_economics is stamped by source SHA via tooling/generator_sources.py. Any port must keep the stamp/pre-push contract intact through the transition, not disabled during it.
|
||||
|
||||
Outcome: a recommendation with costs, then a D-record and Jeroen''s ruling. Epics only after that.', 'backlog', 'low', NULL, 'tooling', 'Q-124', '2026-08-19 23:54:55.776', '2026-08-19 23:54:55.776', NULL, 'cfb08832c72e06f85b075a46cd3223f2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G1RWR7M1H1PC3TY2RT7AC174', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Investigate retooling Python tooling into a Rust CLI (Q-124)', 'Answer Q-124. Investigation and costing FIRST — do not open with a rewrite.
|
||||
|
||||
Price the cheap alternative before recommending Rust: a single Python dispatcher entrypoint (one command, many subcommands) would resolve the permission-prompt friction and most of the startup cost without touching the numerics. If that is enough, say so and close Q-124 with it.
|
||||
|
||||
Scope order if Rust is chosen: port the check/gate family first (check-client-version, check-canvas-version, check-systems-db-stamp, check-dataflow-graph) — small, pure, no numerics, highest prompt-friction, runs on every push. Leave planet-gen numerics (numpy/scipy/PIL) in Python behind a stable interface.
|
||||
|
||||
Hard constraint: import_economics is stamped by source SHA via tooling/generator_sources.py. Any port must keep the stamp/pre-push contract intact through the transition, not disabled during it.
|
||||
|
||||
Outcome: a recommendation with costs, then a D-record and Jeroen''s ruling. Epics only after that.
|
||||
|
||||
2026-08-20 — Jeroen raised Typer (typer.tiangolo.com) as the Python-CLI option. Q-124 amended with the costing.
|
||||
|
||||
Start here, not with Rust. Measured state: pyproject.toml already exists and make setup-venv already does pip install -e ''.[dev]'', but there is NO [project.scripts] entry — no console entrypoint exists at all. 22 tooling files already use argparse. So this is consolidation, not authorship.
|
||||
|
||||
The real deliverable is ''one bare command reliably on PATH'', not ''a CLI framework''. A [project.scripts] entrypoint lands in .venv/bin/, which is on PATH only when activated — and agents and git hooks never activate it. That is the same split VENV_PY papers over in the Makefile, and the same failure recorded for tea (absolute path breaks the Bash(tea *) rule and prompts every time). Install via uv tool/pipx into ~/.local/bin, or symlink. A Typer app behind an absolute venv path solves nothing.
|
||||
|
||||
Watch startup cost: a single entrypoint importing every subcommand eagerly pays all 123 modules on every invocation, four times per push. Lazy subcommand registration is mandatory, not an optimisation — measure before and after.', 'backlog', 'low', NULL, 'tooling', 'Q-124', '2026-08-19 23:54:55.776', '2026-08-20 00:00:11.592', NULL, 'b48a1523bdfbddb038c083b365414e9f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
|
||||
Reference in New Issue
Block a user