Files
settled-reach/tooling/domains/__init__.py
T
jpmschweitzerandClaude Opus 5 559f3d82dc chore(config): T-1258 — tooling/ becomes an importable package
The skeleton the reach CLI hangs off. Nothing moves yet: this adds the
package, the bounded core/, and explicit setuptools discovery.

core/console.py is the single output path, and the split it enforces is the
whole design — stdout carries the command's actual output so `reach ... | jq`
keeps working, stderr carries the event stream as JSONL. Rendering happens at
the sink: a terminal gets human text, anything else gets raw JSONL, so a live
view and a job log are one artefact in two presentations. Emitting is
optional — the gates emit nothing — and verdict() prints once, last, carrying
its remedy as a structured field.

core/config.py resolves the repo root from __file__ against a project.yaml
sentinel, with an SR_REPO_ROOT override. No subprocess and no git call: this
is on the gate path, and cwd is not a reliable signal anyway since a hook runs
from the root and an agent call may not. Both paths are validated, because a
silent fallback is how you end up editing one checkout and checking another.

Discovery is configured explicitly rather than left to flat-layout
auto-discovery, which would have had to choose between erroring on the
ambiguity and quietly shipping client/ or docs/. Verified: top_level.txt
contains exactly "tooling".

Verified beyond the happy path — the sentinel rejects SR_REPO_ROOT=/tmp and
names both remedies; debug events are suppressed at the default threshold
while the verdict is not; stdout stays clean with stderr redirected away; and
the three unconditional push-gate checks still pass now that tooling/ is a
package, which was the real regression risk.

Two findings recorded on the tickets. make setup-venv is stale — it calls
.venv/bin/pip, but the venv was created by uv and has no pip, so the recorded
procedure and the actual state have already diverged (T-1261 owns the fix).
And settled-reach-tooling had never actually been installed: site-packages
held the dependencies but no dist-info, which follows from there being no
__init__.py to expose. This is the first commit where `import tooling` means
anything.

.venv/ was only ignored via .git/info/exclude, which is machine-local, so a
fresh clone or a new worktree did not ignore it at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 18:53:48 +02:00

24 lines
1.2 KiB
Python

"""One directory per domain (D-263).
Each domain is split by role, and the split is what makes this a codebase that
shares rather than 123 scripts in twelve folders:
router.py CONTROLLER — args in, delegate, format out. No logic.
service.py LOGIC — transport-agnostic, importable by anything.
schemas.py this domain's data shapes (pydantic).
helpers.py domain-local pure helpers.
dependencies.py resolved collaborators (DB handle, paths, launchers).
The invariant that makes it work: `router.py` holds no logic and `service.py`
holds no Typer. A service must not know it was called from a CLI — that is what
lets one domain's service call another's, lets tests call services directly
without a CLI round-trip, and leaves a second front end possible without a
rewrite. It is also what keeps lazy loading achievable: routers are cheap,
services are not, and only the invoked domain's service is ever imported.
Not every domain needs every file. `schemas.py` and `dependencies.py` appear
when a domain has data shapes or collaborators worth naming. The layering is a
vocabulary, not a quota — a folder of five empty modules is worse than a folder
of two full ones.
"""