ceremony/changelog.d/205.md
clad2 37e31ffd85
Some checks failed
CI / test (pull_request) Failing after 3m13s
CI / release-exercise (pull_request) Successful in 11s
CI / self-guards (pull_request) Successful in 7s
CI / action-exercise (pull_request) Successful in 6s
CI / docs-sync-exercise (pull_request) Successful in 6s
Refs guard / refs-not-closing (pull_request) Has been skipped
labels / labels (pull_request) Successful in 8s
fix(labels): refuse an unset API root, name transport failures, update the docs
Three corrections from @codex-reviewer-andresmgsl's review of 935a813.

1. `api="${GITHUB_API_URL:-https://api.github.com}"` guessed GitHub when the
   variable was absent — driven with a recording curl, it reported success
   after POSTing to api.github.com from this forge. That is the "Never
   'probably github'" rule, and the same unset-environment refusal #201 just
   established for docs-sync. It now refuses before any request, and the test
   asserts zero calls were made: refusing after a POST is not refusing.

2. The "never silenced with || true" invariant was still asserted by grepping
   the gh line this port removed, so it passed on any REST implementation
   including one that swallows a failed POST. It is rebound behaviourally: a
   curl that dies at the transport must fail the step. Doing that revealed the
   step failed with a bare exit 7 and no sentence, so it now names the failure
   — owning the diagnostic is the whole point of the surrounding code.

3. docs/CONSUMERS.md and both caller comments still described `gh workflow
   run` as the mechanism. They describe the REST dispatch now, and the manual
   bootstrap command carries a forge-neutral curl form beside the gh one: a
   cross-forge runbook that sends this forge to a missing binary is wrong even
   where the prose around it is right.

Refs #205
2026-08-05 17:16:30 +00:00

2.1 KiB

Fixed

  • .github/workflows/labels.yml wakes the sweep over REST instead of gh workflow run, so a board event reconciles within seconds on any forge rather than waiting up to an hour for the scheduled sweep (#205).

  • The workflow-dispatch endpoint has the same shape on both forges, so that step no longer decides one: the CEREMONY_FORGE_CLIENT=gh declaration and both inline refusals are gone rather than ported (#205).

  • The dispatch supplies its ref explicitly, because REST has no default branch where gh workflow run had one, and refuses without it (#205).

  • It takes that ref from the repository, never from GITHUB_REF_NAME — on a pull_request_target run that is <n>/merge, which is not a branch (#205).

  • A failed dispatch names the endpoint, the ref and the status, and says that an empty 500 body from Forgejo means the workflow name or the ref did not resolve — a bare status sends the reader after a server fault that is not there (#205).

Added

  • test/labels-dispatch.test.sh extracts the shipped step and executes it against a recording stub, asserting the method, endpoint, ref and inputs.bootstrap actually sent (#205).

  • That test also drives the failure path: any non-204 still fails the job, so the misconfiguration alarm the trigger exists to be cannot decay into a warning (#205).

  • An unset GITHUB_API_URL refuses before any request instead of defaulting to api.github.com. Guessing sent this forge's dispatch to GitHub and reported success — the "Never 'probably github'" rule, and the same unset-environment refusal #201 established for docs-sync (#205).

  • A dispatch that never reaches the forge names the failure. Letting set -e carry curl's exit code out did fail the job, but with a bare status and no sentence (#205).

  • docs/CONSUMERS.md and both caller comments describe the REST dispatch, and the manual bootstrap command carries a forge-neutral form beside the gh one — a cross-forge runbook that directs this forge to a missing binary is wrong even where the surrounding prose is right (#205).