Three things stood between "cloned the repo" and "measured something",
and all three were mine.
.env.example told the operator to run `iris login`. There is no such
command — Iris authenticates through GitHub's device flow, three requests
deep, and doing it by hand with curl and jq is the fiddliest step in
getting started. src/login.mjs does it: begin, print the code to approve,
poll at GitHub's own interval (widened on slow_down), print the token on
stdout and nothing else, so `IRIS_TOKEN=$(node src/login.mjs)` works. It
writes the token nowhere — where a credential lives is the operator's
decision, and one this script silently dropped into a file would be one
nobody remembered was there.
A refused token now stops the campaign instead of consuming it. These are
GitHub user tokens and they can expire before a multi-day run finishes;
without this, the remaining items would each be submitted, refused, and
written to the ledger as failures in about a minute, and recovering would
mean re-running the whole corpus. Nothing is ledgered for an auth
failure, so a fresh token resumes at the exact point the old one stopped
being accepted. The run exits non-zero and says which command to run.
And the README now has a getting-started path that starts with ten URLs
rather than two thousand: install, `npm test` to prove the harness works
without a deployment at all, log in, then a handful of documents whose
per-page cost and latency are what size everything after them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>