Files
http-latency-prober/docs/summaries/2026-07-02-09-32-hxprobe-standalone-project.md
Jan Novak f487a4b1bd docs: hxprobe plans, summaries, explanations, usage, and changelog
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>
2026-07-02 13:22:59 +02:00

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 from python/hxprobe/probe.py, with Options, Phase, Result, VerboseDetail, CertInfo dataclasses and _parse_cert/_parse_cert_date helpers now defined locally (copied from latprobe/probe.py) instead of imported; all the httpx-instrumentation logic (_Trace, _TimingStream, _TimingBackend, _TimingTransport, measure()) is unchanged
  • hxprobe/hxprobe/aggregate.py, duration.py — verbatim copies of latprobe's; their imports were already package-relative (from .probe import Result), so copying required zero edits
  • hxprobe/hxprobe/cli.py — rewritten as a full standalone CLI. Previously a 27-line wrapper delegating to latprobe.cli.run() via an injected measure_fn; now has its own exit codes, argparse, and text/JSON rendering (copied from the shared latprobe/cli.py, then stripped of the measure_fn/prog/description/protocol_flags parameterization that only existed to let two packages share one run())
  • hxprobe/tests/{test_probe,test_cli,test_integration}.py — moved from python/tests/test_hx_*.py / test_integration_hx.py, hx-prefix dropped, imports repointed from latprobe.* to hxprobe.*
  • python/latprobe/{cli.py,probe.py} — reverted via git checkout -- to their exact pre-hxprobe committed state (confirmed zero diff afterward)
  • Makefilepy-deps/PY_VENV*/shared hx-run/hx-test-integration removed from the Python section; new standalone hx-deps/hx-run/ hx-test/hx-test-integration/hx-check/hx-clean targets under HX_DIR/HX_VENV*; umbrella test/check/clean now run all three (go-*/py-*/hx-*)
  • docs/usage/py-hxprobe.mddocs/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.py and the three test files carry real bug fixes found during the original implementation (the mark_dns present-on-failure bug, verbose detail not populated on the failure path, Content-Length needed once the test fixtures switched to HTTP/1.1 keep-alive). Rewriting from scratch would have risked reintroducing them.
  • aggregate.py/duration.py needed zero import changes — their existing relative imports (from .probe import ...) already resolve correctly once copied into a new package with its own probe.py. Not every file needed the same treatment as probe.py/cli.py.
  • cli.py's starting point was the current shared latprobe/cli.py, not a from-scratch rewrite — it already contained 100% of the needed logic (including the --no-http2/--no-follow-redirects flags 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_flags params) that existed solely to let two packages share one run().
  • Reverting latprobe via git checkout -- rather than hand-editing — confirmed first via git log/git diff --stat that cli.py/probe.py had no changes besides the hxprobe-sharing scaffolding since the last commit, making this a safe, exact, zero-risk revert.
  • Comments referencing latprobe by 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-contained
  • git diff --stat python/latprobe/ — empty (exact revert to last commit)
  • make hx-deps — creates hxprobe/.venv, installs httpx[http2] from hxprobe/pyproject.toml
  • make 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, own PYTHONPATH=hxprobe)
  • make hx-test-integration — live HTTP/2 + redirect tests still pass
  • make py-testlatprobe's own suite passes with zero setup (no py-deps/venv needed), confirming the revert didn't leave residue
  • make check (top-level) — Go + latprobe + hxprobe all green in one gate
  • python -m latprobe --help output confirmed unchanged from before the whole hxprobe feature existed (no leftover --no-http2 etc.)