Red test first: a raw TCP listener that never speaks HTTP must read down
under an http probe (up under tcp), while a real HTTP server reads up. This
test caught a real hang — the backgrounded listener inherited the test
runner's stdout pipe and held it open; fixed by redirecting its output and
killing both listeners in teardown.
scripts/homepage-status.py: probe() now dispatches on method. http does an
urlopen (any HTTP status = up; no connection = down); tcp connects.
The checker is now complete: tcp + http + wip + atomic write + generated_at.
Remaining slices: services.json schema, the pages + theme + toggle, the
Caddyfile (validate + two hashes), the git-driven deploy.
Full TDD (Q36): red test first, then the minimal implementation.
- tests/homepage_checker.bats: seam = homepage-status.py <services.json>
<out.json>. Asserts an open port is up, a closed port is down, a wip
service is wip (not probed), and the output carries generated_at.
- scripts/homepage-status.py: reads the config, probes each backend (tcp,
5 s timeout), skips wip, writes status.json atomically (temp + rename).
Remaining slices: http probe method, services.json schema, the pages +
theme + toggle, the Caddyfile (validate + two hashes), the git-driven deploy.