fix: collection fails loud -- admin pre-check, per-stage error budget, non-zero exit
Problem
Collection could ship empty or broken data while exiting green.
- A non-admin Personal Access Token (PAT) gets HTTP 200 with truncated data, not HTTP 403. A run "succeeds" and renders a believable-but-empty dashboard that silently undercounts.
- The orchestrator checked the error budget only after the events stage. Merge-request, issue, and pipeline errors then accumulated unchecked, so a failing instance kept going.
- A whole-stage merge-request or issue failure was swallowed:
Run()returnednil, wrote a manifest, and the process exited 0. A stale or empty dashboard published green in continuous integration (CI).
Fix
- Admin pre-check.
CheckAdminfetches the authenticated user (GET/api/v4/user) early, before the expensive collection, and aborts loudly when the token user is not an instance admin. New--skip-admin-checkflag (cmd -> collector config) is the escape hatch for intentional scoped runs. - Per-stage error budget. The budget check now runs after the merge-request, issue, and pipeline stages too, not just events, so a failing instance aborts promptly.
- Fail loud on fatal failure. A whole-stage merge-request or issue collection failure is now fatal:
Run()returns a non-nil error and writes no success-looking artifact for the failed stage. Tolerable partial failures (per-item errors below the budget) remain a success, recorded in the manifest.cmd/collect.goandcmd/run.goalready propagate theRun()error, so the process exits non-zero.
Validation
make checkpasses (go vet + full test suite).go test -race ./...passes.- New tests: admin pre-check abort on non-admin, proceed on admin, bypass with
--skip-admin-check; per-stage budget abort on pipeline-stage errors; fatal-stage error return with no artifact written. - Fails-on-old proof (per-stage budget): with the post-pipeline budget check temporarily reverted,
TestRun_PerStageBudget_PipelineErrorsAbortFAILS (Run()returns nil, collects through). With the check restored it PASSES (aborts with "too many errors"). Both observed locally.