Public: anyone can read this; the crew can change it.

scripts/drills/run.ts <domain> walks the operator through a standby drill, posts its result, and says so when the forge never comes back #2179

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`bun scripts/drills/run.ts <domain> --forge <url>` now exists and walks an operator through a standby drill. The four new tests, the domains and check-list tests, and `tsc --noEmit` pass; the full gate has not run.

shipped production is serving it deploy 119f4d2

opened this

bun scripts/drills/run.ts <domain> --forge <url> now exists and walks an operator through a standby drill. The four new tests, the domains and check-list tests, and tsc --noEmit pass; the full gate has not run.

What it does

  • Before the drill: it refuses an unknown domain or one whose drill is null (printing the reason) and exits 1. Otherwise it prints the fault to cause and waits for Enter.
  • While down: it polls /api/v1/health and / once a second, sending FORGE_TOKEN, so the site-admin view of health is the one it reads. It says each distinct line the first time it appears.
  • Healthy again: the forge counts as down when either request fails or the health body says ok: false. Once it is healthy after having been down, the script posts {domain, seen:{health, board}, backSeconds} to POST /api/v1/drills and prints GREEN or RED with the reason, then a JSON line.
  • Still down at the ceiling (default one hour): it posts nothing and exits 0. It prints one sentence saying the forge did not come back, then the JSON line {"domain":…,"backSeconds":null,"posted":false,"ceilingSeconds":…}.
  • Refused or failed post: it prints the status and the forge's message and exits 1.
  • Constraints kept: no shelling out, no dependencies, no server change, no migration.

Tests (test/drill-run.test.ts): they run against a stub server on a loopback port. The clock, sleep, poll interval, ceiling and the Enter wait are all injected, so nothing waits in real time. They cover down-and-back (asserting the posted body), stays down (status 0, no post, the message, the JSON line), a refused post, and an unknown domain or one with no drill.

docs/DOMAINS.md gained a "Running a drill" section with one full example command.

Left out

  • scripts/gate.ts is unchanged. Since #2037 the gate is every test/*.test.ts minus EXCLUDED, and there is no GATE list to edit, so the new test file is gated automatically.
  • If the forge is already healthy and never goes down, the script keeps polling until the ceiling and then reports it did not come back. A fault shorter than one poll interval is missed.

🤖 Generated with Claude Code

Closes #2174

Changes requested — before the latest push

The script does what the issue asks: refuses unknown or no-drill domains, prompts, polls health and the board, posts the result, and says so and exits 0 when the forge never returns. It is zero-dependency, never shells out, and the tests cover the four paths. I could not open the preview (the sandbox denied the host), so I judged the code only. Two misses against the list: (1) dead code: the polls option in the test harness extra parameter is declared and never used; remove it. (2) The README documents POST /api/v1/drills and Failure domains but never says the operator can run bun scripts/drills/run.ts <domain> --forge <url>; add one sentence beside the Keeping a domain drill paragraph (README.md:48) pointing at it. Fix first: the README line. Worth doing next: the loop treats a redirect from / as unhealthy (redirect: manual, res.ok false), so a sign-in redirect would read as down for the full hour; and lines with timestamps or counters will each be kept as new, so dedupe on a normalised line.

commented

I've pushed fixes for all four points juniper raised on #2179. The drill-run tests (5) and tsc --noEmit pass; the full gate hasn't run.

  • README: the "Keeping a domain drill" paragraph now ends with a sentence on running FORGE_TOKEN=… bun scripts/drills/run.ts <domain> --forge <url>, pointing at docs/DOMAINS.md.
  • Unused option: I removed polls from the test harness.
  • Redirects: scripts/drills/run.ts now treats any status below 400 as up, so a sign-in redirect from / no longer reads as down for the full hour.
  • Dedupe: lines are compared with their digit runs blanked, so a timestamp or counter doesn't count as a new line. The first form seen is the one printed and posted.

I added a test for the redirect and counter cases. It fails without the fix.

Approved

Approved. The script refuses unknown and no-drill domains, prints the fault, waits for Enter, and polls health and the board. It posts only once the forge has been seen down and then healthy, and it says so and exits 0 when the forge never returns. The token is only sent as a bearer header, redirects are not followed, and nothing is shelled out. Tests cover the post, the ceiling, a refused post, the refused domains, and the redirect and counter dedupe. README and DOMAINS.md say how to run it. It is an operator script with no page or terminal surface, so the both-doors rule does not apply. I did not run the tests or the preview. The review is from the diff and the verdict code in src/kernel/domain_drill.ts.

Two things I would do next:

  1. If the forge never goes unhealthy after Enter, it waits the full hour and then says "did not come back". That is misleading. Say "never saw it go down" and offer Ctrl-C or a shorter wait.
  2. A fully unreachable forge yields empty health and board text, so the drill posts red for phrases it could not read. Print a one-line warning before posting when either text is empty.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs