Step 2 was doing `curl -sI .../mercure?topic=ping` to verify the hub was
reachable. Over HTTP/2, that HEAD against the SSE endpoint apparently
leaves a connection state on Caddy/Mercure that causes the next subscribe
from the same source to receive zero bytes — making step 6's round-trip
fail every time. Took a careful bisect to find: minimal script worked,
adding step 2 broke it 100%.
The hub-reachable check is redundant anyway: step 5's full publish→
subscribe round-trip is a stronger proof of life. Renumbered to 5 steps,
removed the also-not-using set-uo-pipefail commentary too.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs after every deploy. Six checks against pictureframe.edholm.me:
1. Frontend reachable (302/200 expected).
2. Mercure hub reachable (200 expected).
3. All pictureframe-* containers Up/healthy.
4. No CRITICAL / Fatal / 5xx in last 5 min of php/worker/nginx logs.
5. Authenticated /api/devices round-trip via testbot.
6. Mercure publish→subscribe round-trip via no-op PATCH.
Catches the class of bug that just bit us today: nginx caching a stale
PHP container IP after `docker compose up -d`, and a silently-dropped
composer dep crash-looping the worker. Neither shows up in unit tests
because they're infra-level.
Per the new "post-deploy smoke check" rule: if a unit test doesn't
cover a change, run this script (or an equivalent cURL) before
declaring the deploy done.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>