Plans (docs/plans/): - 2026-07-01-23-47-py-hxprobe-httpx.md — initial httpx probe design - 2026-07-02-09-32 through 14-05 — standalone project, toolchain, usage doc + Makefile, file input (-f), simplification pass, run-summary footer Summaries (docs/summaries/): one per completed feature, recording what was actually built, deviations from the plan, and verification steps Explanations (docs/explanations/): two deep-dives written during review — hxprobe concurrency model and worst-exit-code + render-loop analysis Usage (docs/usage/hxprobe.md): overview with pointer to hxprobe/USAGE.md for the full runnable reference Walkthrough (docs/py-latprobe-walkthrough.md): narrative tour of the latprobe Python package for interview / code-review context CHANGELOG.md: entries for all hxprobe features (toolchain, usage doc, file input, simplification, run-summary footer) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.7 KiB
Summary: extract hxprobe into a standalone top-level project
Plan: docs/plans/2026-07-02-09-32-hxprobe-standalone-project.md
What was built
hxprobe moved from python/hxprobe/ to a new top-level hxprobe/
directory (sibling of go/ and python/), structured as a genuinely
independent project: own pyproject.toml, own venv (hxprobe/.venv), own
tests/ directory. It imports nothing from python/latprobe — verified with
grep -rn "latprobe" hxprobe/ returning zero matches in code (a few comments
mention Go's http.DefaultClient for context, which is fine; no comment
references latprobe as a concrete path/module anymore either).
Files:
hxprobe/pyproject.toml— own manifest,httpx[http2]dependency,packages = ["hxprobe"]hxprobe/hxprobe/probe.py— moved frompython/hxprobe/probe.py, withOptions,Phase,Result,VerboseDetail,CertInfodataclasses and_parse_cert/_parse_cert_datehelpers now defined locally (copied fromlatprobe/probe.py) instead of imported; all the httpx-instrumentation logic (_Trace,_TimingStream,_TimingBackend,_TimingTransport,measure()) is unchangedhxprobe/hxprobe/aggregate.py,duration.py— verbatim copies oflatprobe's; their imports were already package-relative (from .probe import Result), so copying required zero editshxprobe/hxprobe/cli.py— rewritten as a full standalone CLI. Previously a 27-line wrapper delegating tolatprobe.cli.run()via an injectedmeasure_fn; now has its own exit codes, argparse, and text/JSON rendering (copied from the sharedlatprobe/cli.py, then stripped of themeasure_fn/prog/description/protocol_flagsparameterization that only existed to let two packages share onerun())hxprobe/tests/{test_probe,test_cli,test_integration}.py— moved frompython/tests/test_hx_*.py/test_integration_hx.py,hx-prefix dropped, imports repointed fromlatprobe.*tohxprobe.*python/latprobe/{cli.py,probe.py}— reverted viagit checkout --to their exact pre-hxprobecommitted state (confirmed zero diff afterward)Makefile—py-deps/PY_VENV*/sharedhx-run/hx-test-integrationremoved from the Python section; new standalonehx-deps/hx-run/hx-test/hx-test-integration/hx-check/hx-cleantargets underHX_DIR/HX_VENV*; umbrellatest/check/cleannow run all three (go-*/py-*/hx-*)docs/usage/py-hxprobe.md→docs/usage/hxprobe.md(renamed + rewritten for the new structure)- Old
python/hxprobe/,python/pyproject.toml,python/.venv,python/latprobe_python.egg-info/deleted
Key design decisions
- Move, don't rewrite, the already-debugged files.
probe.pyand the three test files carry real bug fixes found during the original implementation (themark_dnspresent-on-failure bug, verbose detail not populated on the failure path,Content-Lengthneeded once the test fixtures switched to HTTP/1.1 keep-alive). Rewriting from scratch would have risked reintroducing them. aggregate.py/duration.pyneeded zero import changes — their existing relative imports (from .probe import ...) already resolve correctly once copied into a new package with its ownprobe.py. Not every file needed the same treatment asprobe.py/cli.py.cli.py's starting point was the current sharedlatprobe/cli.py, not a from-scratch rewrite — it already contained 100% of the needed logic (including the--no-http2/--no-follow-redirectsflags and the verbose Protocol row/JSON keys, both added earlier specifically for hxprobe). The only work was deleting the generalization scaffolding (measure_fn,MeasureFn,prog/description/protocol_flagsparams) that existed solely to let two packages share onerun().- Reverting
latprobeviagit checkout --rather than hand-editing — confirmed first viagit log/git diff --statthatcli.py/probe.pyhad no changes besides the hxprobe-sharing scaffolding since the last commit, making this a safe, exact, zero-risk revert. - Comments referencing
latprobeby file path were reworded, not just the imports. A comment like "already used by latprobe/probe.py" becomes a dangling reference once this directory is genuinely portable to another repo. Reworded ~5 comments/docstrings to describe the technique generically (e.g., "ports the getaddrinfo → connect split" → "splits DNS and TCP connect into two timed steps") instead of naming the other project.
Deviations from the plan
None of substance. One judgment call not spelled out in the plan: the old
test_cli.py's docstring said its tests "focus on what's different... since
run() delegates almost entirely to latprobe.cli.run()" — no longer true now
that cli.py is a full standalone reimplementation. Rewrote that docstring
for accuracy rather than leaving a stale claim, without expanding the test
suite itself (that would be a larger, separate scope-creep beyond what was
asked — see the coverage note below).
Notable follow-up worth flagging
hxprobe/tests/test_cli.py has ~11 tests versus latprobe/tests/test_cli.py's
~23. That gap was fine when hxprobe's cli.py was a thin wrapper around
already-tested shared code; it's a real gap now that cli.py is an
independent ~440-line reimplementation with its own copy of every rendering
branch. Existing tests do exercise the core paths (single URL, --fail,
JSON, DNS/connect failures) so this isn't uncovered, but reaching
latprobe-level depth (multi-URL separator, sampling aggregate output, JSON
error grouping, all-failed multi-header) would be a reasonable next step if
full independent confidence in the standalone project matters. Not done here
— out of scope for a decoupling/move task.
Verification
grep -rn "latprobe" hxprobe/— zero matches in code; comment mentions reworded to be self-containedgit diff --stat python/latprobe/— empty (exact revert to last commit)make hx-deps— createshxprobe/.venv, installshttpx[http2]fromhxprobe/pyproject.tomlmake hx-run ARGS="-v http://github.com"— same output as before the move (HTTP/2, 1 redirect followed, IP/TLS/cert shown)make hx-test— all hermetic hxprobe tests pass standalone (own venv, ownPYTHONPATH=hxprobe)make hx-test-integration— live HTTP/2 + redirect tests still passmake py-test—latprobe's own suite passes with zero setup (nopy-deps/venv needed), confirming the revert didn't leave residuemake check(top-level) — Go + latprobe + hxprobe all green in one gatepython -m latprobe --helpoutput confirmed unchanged from before the whole hxprobe feature existed (no leftover--no-http2etc.)