Files
http-latency-prober/docs/summaries/2026-07-02-14-05-hxprobe-run-summary-footer.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

106 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# hxprobe: end-of-run summary footer — summary
Plan: `docs/plans/2026-07-02-14-05-hxprobe-run-summary-footer.md`.
Trigger: a follow-up to
`docs/explanations/2026-07-02-13-25-hxprobe-worst-exit-code-and-render-loop.md`
— does a single worst-code exit even make sense across multiple URLs with
different possible errors? The answer landed on: keep the scalar exit code
(it's a documented cross-implementation contract with `latprobe`/Go — see
`hxprobe/USAGE.md`'s Exit codes table, asserted by 13 existing tests), and
instead add the missing visibility as an end-of-run summary footer.
## What changed
All in `hxprobe/hxprobe/cli.py` unless noted, matching the plan exactly (no
deviations):
1. **`_EXIT_LABELS`** (new, next to `_PHASE_EXIT`): inverse mapping from exit
code → short label (`ok`, `dns`, `connect`, `timeout`, `tls`, `http`), used
to render the footer's `→ exit N (label)` line.
2. **Accumulation loop refactor**: previously computed a single running
`worst` directly inside the per-URL loop via two different idioms
(`if c > worst: worst = c` for network failures, `max(worst, EXIT_HTTP)`
for `--fail`). Now each URL first gets its own `code` (`EXIT_OK` folded up
via `max()` across its failed samples and, if `--fail`, its ≥400 successes),
appended to a new `url_codes: list[int]` (index-aligned with `urls`), and
*then* folded into `worst = max(worst, code)`. Unifies both idioms into one.
3. **`_print_run_summary(urls, url_codes, worst, out)`** (new helper, next to
`_print_failure_summary`): writes a separator line, an
`N URLs — X ok[, Y failed]` header, one `✗ {label:<8}: {count}` line per
non-OK class present (first-seen order, same dedup style as
`_summarize_failures`), and the closing `→ exit N (label)` line.
4. **Call site**: `elif len(urls) > 1: _print_run_summary(urls, url_codes,
worst, stdout)` — added after the per-URL loop, in the `else` branch of the
existing `if ns.json_out:` check (so it's text-mode-only), right before
`return worst`. JSON path (`json.dumps(json_items, ...)`) is completely
untouched — still a bare array, no top-level summary object, preserving the
documented "same shape as `latprobe`'s JSON" contract.
## Design decisions (confirmed with user before implementing)
- **Exit code stays a scalar** (worst/highest severity across URLs) — not
count-of-failed-URLs, not binary 0/1. Both alternatives were presented and
rejected because they'd break the documented 06 table, Go/`latprobe`
parity, and the 13 existing exit-code tests.
- **Summary is a text footer, multi-URL only** (`len(urls) > 1`) — not always
shown, and not also duplicated into JSON as a top-level object (which would
turn the JSON array into an object and break the documented array-shape
parity). Single-URL text output is untouched; JSON output is untouched.
## Tests
`hxprobe/tests/test_cli.py`: new `TestCLIRunSummary` class, 3 tests, reusing
the existing `_OKHandler`/`_start_server`/`_free_port`/`_invoke` harness:
- `test_multi_url_mixed_shows_summary` — one OK URL + one connection-refused
URL: asserts `EXIT_CONNECT`, and the footer strings (`"Summary: 2 URLs"`,
`"1 ok"`, `"1 failed"`, `"connect : 1"`, `"→ exit 3"`).
- `test_multi_url_all_ok_summary` — two OK URLs: asserts `EXIT_OK`,
`"Summary: 2 URLs — 2 ok"`, and no `"✗"` anywhere in output.
- `test_single_url_has_no_summary` — one OK URL: asserts `"Summary:"` is
absent (locks the multi-URL-only rule).
All 33 pre-existing tests pass unedited (33 + 3 new = 36 total).
## Verification
- `hxprobe/.venv/bin/python -m pytest tests/test_cli.py tests/test_probe.py -q`
→ **36 passed**.
- `hxprobe/.venv/bin/ruff check hxprobe/ tests/` → **all checks passed**.
- Manual smoke tests, all matching the plan's expected behavior exactly:
- `hxprobe https://example.com https://example.org` → footer
`Summary: 2 URLs — 2 ok` / `→ exit 0 (ok)`.
- `hxprobe https://example.com http://no.such.host.invalid` → footer
`Summary: 2 URLs — 1 ok, 1 failed` / `✗ dns : 1` / `→ exit 2 (dns)`;
process exit code confirmed `2` via `echo $?`.
- `hxprobe https://example.com` (single URL) → **no** footer, output
byte-for-byte the same shape as before this change.
- `hxprobe --json https://example.com https://example.org` → still a bare
JSON array, no summary object.
- Also captured a 3-URL mixed run (`example.com` ok, DNS failure, TLS
failure against `self-signed.badssl.com`) to confirm severity ordering in
the footer: DNS (2) and TLS (5) both counted, exit reported as `5 (tls)`
— the higher-severity class correctly wins the scalar while the footer
still shows the DNS failure that the scalar alone would hide.
## Docs updated (per CLAUDE.md conventions)
- `hxprobe/USAGE.md`: new "Multi-URL summary footer" section with a real
3-URL mixed-outcome capture; refreshed the pre-existing "Multiple URLs" and
`-f configs/all-ok.txt` / `-f configs/dns-failure.txt` examples, which were
captured before this feature existed and were now stale (missing the
footer) — replaced with fresh live captures; added a sentence to the Exit
codes section pointing at the new section.
- `docs/usage/hxprobe.md`: one-line addition to the exit-codes bullet
pointing at `hxprobe/USAGE.md`'s new section.
- `docs/explanations/2026-07-02-13-25-hxprobe-worst-exit-code-and-render-loop.md`:
appended an "Update (2026-07-02)" paragraph pointing forward to this work,
per the plan's "optional — pointer instead of a new file" option.
- `CHANGELOG.md`: new entry at the top.
- This file.
No deviations from the approved plan.