1e8ef793d2
Closes the dead-PAT-spins-idle-forever gap. Without this probe, a
rotated / revoked Forgejo PAT lets every dispatcher loop forever:
each work item's claim returns labels-fetch-failed (a "soft"
outcome that counts as a cycle success with zero dispatches), so
the consecutive_failures counter resets every iteration and the
cycle-failure-budget escape hatch never trips. Operators see
timed-out heartbeats but no SystemExit and no log alert.
_validate_pat_or_die() probes GET /user at run_outer_loop startup:
- 200: log INFO with the resolved login (auditable bot identity
at process start), return.
- 401 / 403: raise SystemExit(2) — matches the existing
cycle-failure-budget exit code so supervisor restart semantics
are uniform.
- Other (transient 5xx, network flap, malformed body): log
WARNING and return; the cycle-failure-budget covers persistent
cases.
Skippable via DISPATCHER_SKIP_PAT_VALIDATION=1 for tests / bisect.
The skip is logged loudly so a missing safety net in production
telemetry is obvious.
6 new tests cover the 5 response classes + the env-skip path.
Three existing run_outer_loop tests stub the validator (they test
loop semantics, not PAT validation, which has its own dedicated
tests).
Refs: docs/development/final-working-harvest-plan.md (G5).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>