# Summary: hxprobe toolchain modernization (uv, ruff, pytest) Plan: [docs/plans/2026-07-02-09-57-hxprobe-toolchain-modernization.md](../plans/2026-07-02-09-57-hxprobe-toolchain-modernization.md) ## What was built Modernized `hxprobe`'s Python toolchain per the user's confirmed choices (uv, ruff, pytest; mypy skipped). No behavior change to the probe/CLI itself — this is purely tooling. - `hxprobe/pyproject.toml`: added `[dependency-groups] dev = ["pytest>=8.0", "ruff>=0.8"]` (PEP 735), `[tool.pytest.ini_options]` (testpaths, a registered `integration` marker), `[tool.ruff]` (`target-version = "py311"`, `line-length = 100`) - `hxprobe/.python-version`: new, pins `3.14` - `hxprobe/uv.lock`: new, 18 packages resolved and pinned (`httpx`, `httpcore`, `h2`, `certifi`, `pytest`, `ruff`, and their transitive deps) - `hxprobe/tests/test_integration.py`: added `pytestmark = pytest.mark.integration`, replacing the `test_[!i]*.py` filename-glob convention with a real pytest marker - Ran `ruff check --fix` (one fix: removed unused `import sys` in `cli.py`, inherited from the original `latprobe/cli.py`) and `ruff format .` (6 files reformatted — collapsed the hand-aligned `=`/dict-key columns to single-space; no semantic changes) - `hxprobe/README.md`: new, standalone quick-start - `Makefile`: `hx-deps`/`hx-run`/`hx-test`/`hx-test-integration` now shell out to `uv sync`/`uv run` instead of manual venv+pip; added `hx-lint`/ `hx-fmt`; `hx-check` now bundles lint + hermetic tests (mirrors `go-check`'s fmt+vet+test pattern) - `docs/usage/hxprobe.md`: Setup and Makefile-targets sections updated - `.gitignore`: added `.pytest_cache/`, `.ruff_cache/` ## Key design decisions - **`[dependency-groups]` (PEP 735) over `[tool.uv.dev-dependencies]`** — the standardized, current uv-recommended way to declare dev-only deps, keeps them out of the installable package's `dependencies` list. - **Runner swap only, no test rewrite.** `unittest.TestCase` classes, `unittest.skipUnless` decorators, and `if __name__ == "__main__": unittest.main()` guards are untouched — pytest is a superset runner for unittest-style tests. Only the marker-based selection mechanism changed. - **`hx-check` now includes lint**, not just tests — matches how `go-check: go-fmt go-vet go-test` already bundles static checks with tests in this repo, rather than treating lint as a separate, easy-to-skip step. - **Verified the `ruff format` diff was purely cosmetic** before accepting it: reviewed the actual diff (whitespace/alignment only, no reordering or logic changes), then confirmed with `ast.parse` on every file post-format and a full pytest run afterward (37 tests: 28 hermetic + 9 integration, all passing) — did not run the suite pre-format, so this confirms the post-format state is correct rather than a strict before/after diff. ## Deviations from the plan None. Implemented exactly as planned; the `import sys` removal and the ~6-file reformatting were both explicitly anticipated in the plan text ("Lint fixes" section) rather than being surprises. ## Verification - `cd hxprobe && uv sync` — creates `.venv`, installs from `uv.lock` (`httpx[http2]`, `pytest`, `ruff` + transitive deps) - `make hx-run ARGS="-v http://github.com"` — unchanged output (HTTP/2, 1 redirect, IP/TLS/cert) - `make hx-lint` — `ruff check .` clean (`All checks passed!`) - `make hx-test` — `pytest tests -m "not integration"`: 28 passed, 9 deselected (matches the pre-toolchain-change hermetic test count exactly) - `make hx-test-integration` — `pytest tests -m integration`: 9 passed, 28 deselected - `grep -rn "latprobe" hxprobe/` — zero matches (toolchain change didn't reintroduce coupling) - `git diff --stat python/` — empty (hxprobe-only change, `latprobe` untouched)