From c63a55067e203607eff81dbe60e2bb8ca029785f Mon Sep 17 00:00:00 2001 From: cluade-reviewer-andresmgsl Date: Tue, 4 Aug 2026 11:42:28 +0000 Subject: [PATCH] fix(exercise): pin the rehearsal to the backend its stub speaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release-exercise stubs `gh` to answer the one API fact the ceremony path consults. Since #191 facts.sh selects a backend, and on this Forgejo runner it selected the forgejo one — which speaks curl and walked straight past the stub to the live instance, read the fixture's SHA against the real repository, found no merged release-labeled PR behind it and refused. The exercise rehearses the WIRING — facts → decide → notes through the real $GITHUB_OUTPUT plumbing. Which backend answers is lib/forge.sh's own contract and is covered in test/forge*.test.sh. So the facts step now pins CEREMONY_FORGE=github, the backend its stub is shaped for, and the stub returns the array shape the new label read expects. Refs #191 Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release-exercise.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-exercise.yml b/.github/workflows/release-exercise.yml index 90201c4..aa83b37 100644 --- a/.github/workflows/release-exercise.yml +++ b/.github/workflows/release-exercise.yml @@ -94,12 +94,25 @@ jobs: # consumes the tool end to end instead of hand-writing its output. # Same shape as test/release-chain.test.sh. The gh stub answers the # one API fact the ceremony path consults (the merged - # release-labeled PR) so nothing here talks to GitHub. + # release-labeled PR) so nothing here talks to a forge. + # + # The stub is gh-shaped, so the facts step below pins + # CEREMONY_FORGE=github: since #191 facts.sh selects a backend, and + # on a Forgejo runner it would otherwise pick the forgejo backend, + # which speaks curl and would walk straight past this stub to the + # real instance — reading the exercise's fixture SHA against the + # live repository and refusing it. The exercise rehearses the + # WIRING; which backend answers is lib/forge.sh's own contract, + # covered in test/forge*.test.sh. run: | mkdir -p "$RUNNER_TEMP/stub" cat > "$RUNNER_TEMP/stub/gh" <<'EOF' #!/usr/bin/env bash - if [ "$1" = api ]; then echo true; exit 0; fi + # The label read is GET commits/{sha}/pulls — a JSON array (#191). + if [ "$1" = api ]; then + echo '[{"merged_at":"2026-01-01T00:00:00Z","labels":[{"name":"release"}]}]' + exit 0 + fi echo "gh stub: unexpected call: gh $*" >&2 exit 97 EOF @@ -136,6 +149,9 @@ jobs: # back to the merge commit's first parent (#1 constraint 10). EVENT_BEFORE: "" VERSION_SOURCE: file + # The stub above is gh-shaped; pin the backend that uses it. + CEREMONY_FORGE: github + GITHUB_REPOSITORY: fixture/fixture # release.yml's step verbatim — same invocation, same # $GITHUB_OUTPUT plumbing — cwd'd at the fixture instead of the # workspace (the one thing a replay cannot inherit).