From c0db2670f8065951f0d6f14090965a7f8b7d5843 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Tue, 1 Sep 2026 16:07:45 +0000 Subject: [PATCH] fix(ship): PR/MR create aborts on a missing or empty scanned body file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the gh and glab send blocks now guard [ -s "$PR_BODY_FILE" ] and the prose restates that the variable comes from the scan block — bash blocks run in separate shells, and an unset/empty path would previously send an empty body (gh) or cat's error output (glab) instead of the scanned bytes. Codex/factory ship goldens regenerated. Co-Authored-By: Claude Fable 5 --- ship/sections/pr-body.md | 9 +++++++-- ship/sections/pr-body.md.tmpl | 9 +++++++-- test/fixtures/golden/codex-ship-SKILL.md | 9 +++++++-- test/fixtures/golden/factory-ship-SKILL.md | 9 +++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/ship/sections/pr-body.md b/ship/sections/pr-body.md index c3e516415..f699e833d 100644 --- a/ship/sections/pr-body.md +++ b/ship/sections/pr-body.md @@ -186,11 +186,14 @@ printf '%s' "v$NEW_VERSION : " | ~/.claude/skills/gstack/bin/gsta HIGH blocks (exit 3, no skip). MEDIUM → AskUserQuestion (PII subset offers `--auto-redact`). Same scan runs before the `gh pr edit --body` path (Step 17). -**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent): +**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent). +`$PR_BODY_FILE` comes from the scan block above — restate it in this shell if +blocks ran separately, and never proceed with an empty file: ```bash # PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } gh pr create --base --title "v$NEW_VERSION : " --body-file "$PR_BODY_FILE" rm -f "$PR_BODY_FILE" ``` @@ -201,7 +204,9 @@ rm -f "$PR_BODY_FILE" # MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) # Send the SCANNED file's bytes — scan-at-sink means never re-render the body -# from a fresh heredoc (that reopens the scan-vs-send gap). +# from a fresh heredoc (that reopens the scan-vs-send gap). $PR_BODY_FILE comes +# from the scan block above; never proceed with an empty file. +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } glab mr create -b -t "v$NEW_VERSION : " -d "$(cat "$PR_BODY_FILE")" rm -f "$PR_BODY_FILE" ``` diff --git a/ship/sections/pr-body.md.tmpl b/ship/sections/pr-body.md.tmpl index ba42495c8..313714c3c 100644 --- a/ship/sections/pr-body.md.tmpl +++ b/ship/sections/pr-body.md.tmpl @@ -184,11 +184,14 @@ printf '%s' "v$NEW_VERSION : " | ~/.claude/skills/gstack/bin/gsta HIGH blocks (exit 3, no skip). MEDIUM → AskUserQuestion (PII subset offers `--auto-redact`). Same scan runs before the `gh pr edit --body` path (Step 17). -**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent): +**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent). +`$PR_BODY_FILE` comes from the scan block above — restate it in this shell if +blocks ran separately, and never proceed with an empty file: ```bash # PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } gh pr create --base --title "v$NEW_VERSION : " --body-file "$PR_BODY_FILE" rm -f "$PR_BODY_FILE" ``` @@ -199,7 +202,9 @@ rm -f "$PR_BODY_FILE" # MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) # Send the SCANNED file's bytes — scan-at-sink means never re-render the body -# from a fresh heredoc (that reopens the scan-vs-send gap). +# from a fresh heredoc (that reopens the scan-vs-send gap). $PR_BODY_FILE comes +# from the scan block above; never proceed with an empty file. +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } glab mr create -b -t "v$NEW_VERSION : " -d "$(cat "$PR_BODY_FILE")" rm -f "$PR_BODY_FILE" ``` diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index 19551d0af..588261067 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -2468,11 +2468,14 @@ printf '%s' "v$NEW_VERSION : " | $GSTACK_ROOT/bin/gstack-redact - HIGH blocks (exit 3, no skip). MEDIUM → AskUserQuestion (PII subset offers `--auto-redact`). Same scan runs before the `gh pr edit --body` path (Step 17). -**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent): +**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent). +`$PR_BODY_FILE` comes from the scan block above — restate it in this shell if +blocks ran separately, and never proceed with an empty file: ```bash # PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } gh pr create --base --title "v$NEW_VERSION : " --body-file "$PR_BODY_FILE" rm -f "$PR_BODY_FILE" ``` @@ -2483,7 +2486,9 @@ rm -f "$PR_BODY_FILE" # MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) # Send the SCANNED file's bytes — scan-at-sink means never re-render the body -# from a fresh heredoc (that reopens the scan-vs-send gap). +# from a fresh heredoc (that reopens the scan-vs-send gap). $PR_BODY_FILE comes +# from the scan block above; never proceed with an empty file. +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } glab mr create -b -t "v$NEW_VERSION : " -d "$(cat "$PR_BODY_FILE")" rm -f "$PR_BODY_FILE" ``` diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index 0758e4321..7aeb57466 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -2903,11 +2903,14 @@ printf '%s' "v$NEW_VERSION : " | $GSTACK_ROOT/bin/gstack-redact - HIGH blocks (exit 3, no skip). MEDIUM → AskUserQuestion (PII subset offers `--auto-redact`). Same scan runs before the `gh pr edit --body` path (Step 17). -**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent): +**If GitHub:** create from the SCANNED file (exact bytes scanned = bytes sent). +`$PR_BODY_FILE` comes from the scan block above — restate it in this shell if +blocks ran separately, and never proceed with an empty file: ```bash # PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } gh pr create --base --title "v$NEW_VERSION : " --body-file "$PR_BODY_FILE" rm -f "$PR_BODY_FILE" ``` @@ -2918,7 +2921,9 @@ rm -f "$PR_BODY_FILE" # MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions. # (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.) # Send the SCANNED file's bytes — scan-at-sink means never re-render the body -# from a fresh heredoc (that reopens the scan-vs-send gap). +# from a fresh heredoc (that reopens the scan-vs-send gap). $PR_BODY_FILE comes +# from the scan block above; never proceed with an empty file. +[ -s "$PR_BODY_FILE" ] || { echo "ERROR: scanned body file missing/empty — re-run the scan block." >&2; exit 1; } glab mr create -b -t "v$NEW_VERSION : " -d "$(cat "$PR_BODY_FILE")" rm -f "$PR_BODY_FILE" ```