Problem
SHIPIT_TOKEN + launchpad/scripts/report.sh currently make a ship appear on Mission Control purely because the script POSTed an event. It's decoupled from whether the learner's GitHub Pages deploy actually succeeded or is reachable — the board shows a ship, but it proves nothing about the real deployment. Pedagogically this is a seam: the CI/CD 3 secret reads as classroom telemetry rather than something tied to the learner's real deploy.
Goal
Make the board reflect the real deployment: a ship shows an active / LIVE (green) status only when the learner's actual Pages site responds 200. This ties the token + report to the real deploy artifact and makes "who's actually live" visible on the shared board.
The hook already exists
The pinned event contract in CLAUDE.md already reserves an optional siteUrl field on POST /api/event ("Board accepts … plus optional version, siteUrl"). report.sh just doesn't send it yet. This is completing an intended seam, not a rearchitecture.
Design (lean)
launchpad/scripts/report.sh — derive the learner's Pages URL from env GitHub already sets (GITHUB_REPOSITORY_OWNER + repo name → https://<owner>.github.io/<repo>/) and include it as siteUrl in the POST body. Do this inside the script so the learner's taught env: surface stays the pinned two lines (BOARD_URL + SHIPIT_TOKEN) — no lesson-surface change. Mind project-pages path + trailing slash.
board/ — on each event with siteUrl, store it on the roster entry. Add a liveness sweep: verify on arrival + re-check every ~30s via GET → 200 = live. Broadcast a live boolean on the roster (existing WS pattern). Render a green pulse / "LIVE" indicator on live ships in orbit; dim/neutral when not (yet) reachable.
- First-deploy lag — a fresh Pages deploy can 404 for ~1 min after the report lands. That's exactly why the periodic re-check beats a one-shot verify: the ship flips green when the site actually comes up.
- Rate/timeout — ~60 forks; short-timeout
GET/HEAD, small concurrency; treat non-200/timeout as "not live yet," never as an error.
Contract / discipline notes
- Keep
report.sh's curl without -f (pinned — the 401 "unauthorized" lesson depends on it).
- Do not change the taught two-line
env: surface (BOARD_URL + SHIPIT_TOKEN).
siteUrl is already documented as optional-accepted; formalize its shape + the new live semantics in CLAUDE.md when you add them.
- Write a short spec in
docs/specs/ first (repo convention), then build board + report.sh, test on a fork, then hand back to update the bootcamp slides.
Out of scope
Slide updates. The bootcamp slides live in a separate repo (~/repo/slides-devops-bootcamp, deck slides/2026/ci-cd3/) which quotes the board contract verbatim and is not auto-updated by changes here — update it by hand in a follow-up once this ships.
Problem
SHIPIT_TOKEN+launchpad/scripts/report.shcurrently make a ship appear on Mission Control purely because the script POSTed an event. It's decoupled from whether the learner's GitHub Pages deploy actually succeeded or is reachable — the board shows a ship, but it proves nothing about the real deployment. Pedagogically this is a seam: the CI/CD 3 secret reads as classroom telemetry rather than something tied to the learner's real deploy.Goal
Make the board reflect the real deployment: a ship shows an active / LIVE (green) status only when the learner's actual Pages site responds
200. This ties the token + report to the real deploy artifact and makes "who's actually live" visible on the shared board.The hook already exists
The pinned event contract in
CLAUDE.mdalready reserves an optionalsiteUrlfield onPOST /api/event("Board accepts … plus optionalversion,siteUrl").report.shjust doesn't send it yet. This is completing an intended seam, not a rearchitecture.Design (lean)
launchpad/scripts/report.sh— derive the learner's Pages URL from env GitHub already sets (GITHUB_REPOSITORY_OWNER+ repo name →https://<owner>.github.io/<repo>/) and include it assiteUrlin the POST body. Do this inside the script so the learner's taughtenv:surface stays the pinned two lines (BOARD_URL+SHIPIT_TOKEN) — no lesson-surface change. Mind project-pages path + trailing slash.board/— on each event withsiteUrl, store it on the roster entry. Add a liveness sweep: verify on arrival + re-check every ~30s viaGET→200= live. Broadcast aliveboolean on the roster (existing WS pattern). Render a green pulse / "LIVE" indicator on live ships in orbit; dim/neutral when not (yet) reachable.GET/HEAD, small concurrency; treat non-200/timeout as "not live yet," never as an error.Contract / discipline notes
report.sh'scurlwithout-f(pinned — the 401 "unauthorized" lesson depends on it).env:surface (BOARD_URL+SHIPIT_TOKEN).siteUrlis already documented as optional-accepted; formalize its shape + the newlivesemantics inCLAUDE.mdwhen you add them.docs/specs/first (repo convention), then build board +report.sh, test on a fork, then hand back to update the bootcamp slides.Out of scope
Slide updates. The bootcamp slides live in a separate repo (
~/repo/slides-devops-bootcamp, deckslides/2026/ci-cd3/) which quotes the board contract verbatim and is not auto-updated by changes here — update it by hand in a follow-up once this ships.