fix(labels): compare release shape to merge base #277

Merged
andres merged 5 commits from build/275-merge-base-release-shape into main 2026-09-01 05:52:26 +00:00

Closes #275

Summary

Use each PR's fixed merge base—not the moving base-branch tip—when deciding whether its head changed the version and is therefore release-shaped. Preserve the current base-tip fact separately and keep the guard warning-only.

Acceptance criteria

  • A PR whose diff does not touch the version file, cut from a base commit older than a release that has since landed on the base branch, produces no release-shape warning
  • A PR that does bump the version relative to its merge base still produces the warning, with the same message text
  • Both cases are fixture tests that fail against the pre-fix script and pass after; the red output of each is recorded in this PR
  • The variable table describes what the guard actually reads
  • bash test/labels-reconcile.test.sh and the repository's full check suite are green at the PR head

Pre-fix evidence

bash test/labels-reconcile.test.sh at 328c870 exits 1:

FAIL: an unchanged branch cut before a later base release emits no release-shape warning — want no, got yes
FAIL: the unchanged-branch guard compares head with the PR merge base — want head / merge-base, got head / base-tip
FAIL: the genuine-bump guard also compares head with the PR merge base — want head / merge-base, got head / base-tip
labels-reconcile tests: 259 passed, 3 failed

The first fixture records the phantom downgrade; the second independently records that a genuine bump was compared to base.sha rather than merge_base even though its warning remained present.

Worklog

  • Establish a green baseline and add both failing sweep fixtures
  • Read merge_base beside the unchanged base-tip value and use it with the specified fallback
  • Correct the per-PR variable table
  • Add the cited changelog fragment
  • Clarify backend scope and prove the required null merge-base fallback
  • Reproduce and fix the grouped-fragment self-guards failure
  • Run the focused test and full repository check suite

Round log

Round at 0b1fa70d

Round passed with no written reply.

Closes #275 ## Summary Use each PR's fixed merge base—not the moving base-branch tip—when deciding whether its head changed the version and is therefore release-shaped. Preserve the current base-tip fact separately and keep the guard warning-only. ## Acceptance criteria - [x] A PR whose diff does **not** touch the version file, cut from a base commit older than a release that has since landed on the base branch, produces **no** release-shape warning - [x] A PR that **does** bump the version relative to its merge base still produces the warning, with the same message text - [x] Both cases are fixture tests that fail against the pre-fix script and pass after; the red output of each is recorded in this PR - [x] The variable table describes what the guard actually reads - [x] `bash test/labels-reconcile.test.sh` and the repository's full check suite are green at the PR head ## Pre-fix evidence `bash test/labels-reconcile.test.sh` at `328c870` exits 1: ```text FAIL: an unchanged branch cut before a later base release emits no release-shape warning — want no, got yes FAIL: the unchanged-branch guard compares head with the PR merge base — want head / merge-base, got head / base-tip FAIL: the genuine-bump guard also compares head with the PR merge base — want head / merge-base, got head / base-tip labels-reconcile tests: 259 passed, 3 failed ``` The first fixture records the phantom downgrade; the second independently records that a genuine bump was compared to `base.sha` rather than `merge_base` even though its warning remained present. ## Worklog - [x] Establish a green baseline and add both failing sweep fixtures - [x] Read `merge_base` beside the unchanged base-tip value and use it with the specified fallback - [x] Correct the per-PR variable table - [x] Add the cited changelog fragment - [x] Clarify backend scope and prove the required null merge-base fallback - [x] Reproduce and fix the grouped-fragment self-guards failure - [x] Run the focused test and full repository check suite ## Round log <!-- round:0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a --> **Round at 0b1fa70d** _Round passed with no written reply._
codex-bot-andresmgsl added 1 commit 2026-08-31 21:05:44 +00:00
test(labels): reproduce moving base-tip warning
Some checks failed
CI / self-guards (pull_request) Successful in 12s
CI / release-exercise (pull_request) Successful in 15s
CI / action-exercise (pull_request) Successful in 8s
CI / docs-sync-exercise (pull_request) Successful in 8s
Refs guard / refs-not-closing (pull_request) Successful in 8s
labels / labels (pull_request) Successful in 10s
CI / test (pull_request) Failing after 45s
328c8707df
forgejo-actions added the
scope:labels
state:building
labels 2026-08-31 21:06:20 +00:00
codex-bot-andresmgsl added 1 commit 2026-08-31 21:06:59 +00:00
fix(labels): compare release shape to merge base
Some checks failed
CI / self-guards (pull_request) Failing after 10s
CI / action-exercise (pull_request) Successful in 8s
CI / release-exercise (pull_request) Successful in 15s
CI / docs-sync-exercise (pull_request) Successful in 7s
labels / labels (pull_request) Successful in 10s
Refs guard / refs-not-closing (pull_request) Successful in 7s
CI / test (pull_request) Failing after 42s
dc29fdc84c
forgejo-actions added the
blocker:ci-red
label 2026-08-31 21:07:26 +00:00
codex-bot-andresmgsl added 1 commit 2026-08-31 21:11:40 +00:00
test(labels): document isolated fixture state
Some checks failed
CI / self-guards (pull_request) Failing after 10s
CI / action-exercise (pull_request) Successful in 8s
CI / release-exercise (pull_request) Successful in 13s
CI / docs-sync-exercise (pull_request) Successful in 7s
Refs guard / refs-not-closing (pull_request) Successful in 8s
labels / labels (pull_request) Successful in 9s
CI / test (pull_request) Successful in 3m43s
4ce43c4a3b
codex-bot-andresmgsl added 1 commit 2026-08-31 21:20:44 +00:00
test(labels): prove merge-base fallback
Some checks failed
CI / self-guards (pull_request) Failing after 9s
CI / action-exercise (pull_request) Successful in 9s
CI / release-exercise (pull_request) Successful in 14s
CI / docs-sync-exercise (pull_request) Successful in 7s
labels / labels (pull_request) Successful in 10s
Refs guard / refs-not-closing (pull_request) Successful in 8s
CI / test (pull_request) Successful in 4m18s
4bce62e1fa
codex-bot-andresmgsl added 1 commit 2026-08-31 21:24:59 +00:00
fix(changelog): match grouped fragment shape
All checks were successful
CI / action-exercise (pull_request) Successful in 9s
CI / self-guards (pull_request) Successful in 11s
CI / release-exercise (pull_request) Successful in 14s
CI / docs-sync-exercise (pull_request) Successful in 7s
labels / labels (pull_request) Successful in 10s
CI / test (pull_request) Successful in 4m15s
Refs guard / refs-not-closing (pull_request) Successful in 8s
0b1fa70d60
forgejo-actions removed the
blocker:ci-red
label 2026-08-31 21:25:28 +00:00
Author
Member

📣 round answered at head 0b1fa70d60

📣 round answered at head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a
codex-bot-andresmgsl changed title from WIP: fix(labels): compare release shape to merge base to fix(labels): compare release shape to merge base 2026-08-31 21:27:54 +00:00
codex-bot-andresmgsl requested review from glm-bot-andresmgsl 2026-08-31 21:40:00 +00:00
codex-bot-andresmgsl requested review from claude-bot-andresmgsl 2026-08-31 21:40:00 +00:00
codex-bot-andresmgsl requested review from kimi-bot-andresmgsl 2026-08-31 21:40:01 +00:00
codex-bot-andresmgsl added the
state:bots-reviewing
label 2026-08-31 21:40:01 +00:00
forgejo-actions removed the
state:building
label 2026-08-31 21:40:19 +00:00

🔎 reviewing head 0b1fa70d60

  • AC1 phantom downgrade — merge-base fixture silent at head
  • AC2 genuine bump still warns, message text unchanged
  • AC3 both fixtures red pre-fix — reproduced at 328c870 (259 passed, 3 failed, exit 1) and with the head test file against the base script
  • AC4 L273 variable table corrected
  • AC5 bash test/labels-reconcile.test.sh 264/0; bash test/run.sh 32 files, 0 failed (with CEREMONY_REQUIRE_NPM=1 CEREMONY_REQUIRE_YQ=1); shellcheck-all clean; forge CI green at this head
  • verdict submitted
🔎 reviewing head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a - [x] AC1 phantom downgrade — merge-base fixture silent at head - [x] AC2 genuine bump still warns, message text unchanged - [x] AC3 both fixtures red pre-fix — reproduced at `328c870` (259 passed, 3 failed, exit 1) and with the head test file against the base script - [x] AC4 L273 variable table corrected - [x] AC5 `bash test/labels-reconcile.test.sh` 264/0; `bash test/run.sh` 32 files, 0 failed (with `CEREMONY_REQUIRE_NPM=1 CEREMONY_REQUIRE_YQ=1`); shellcheck-all clean; forge CI green at this head - verdict submitted

🔎 reviewing head 0b1fa70d60

  • worktree detached at head; reviewing whole PR against issue #275 acceptance criteria
  • AC1 (phantom downgrade silent): fixture green at head; pre-fix red reproduced at 328c870 (same 3 FAIL lines, 259 passed / 3 failed as recorded in the PR body)
  • AC2 (genuine bump keeps warning, same text): fixture asserts exact '#701 is release-shaped (version 1.3.0 -> 1.4.0 at its head)' — passes
  • AC3 (red recorded, not asserted): verified by running pre-fix head myself; PR body's recorded output matches byte-for-byte in substance
  • AC4 (variable table): L273-274 now BASE_SHA = base tip, MERGE_BASE_SHA = merge base (the guard's ref) — accurate; BASE_SHA kept as its own fact per decision 2
  • AC5 (suites green at head): ran locally in the detached worktree — labels-reconcile 264/0; test/run.sh 32/32 files; shellcheck-all rc=0; actionlint-all rc=0; self-ref/marker/vendored checks pass (no forge CI runs visible to me)
  • spec conformance: guard stays warning-only; zero extra API calls (merge_base read from PR_JSON); /pulls/N/files approach correctly not taken; null/empty fallback fixture-proven; changelog.d/275.md grouped shape, one bullet, <300 chars, ends (#275); same-repo branch, Closes #275 with no post-merge criteria
  • composing verdict
🔎 reviewing head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a - worktree detached at head; reviewing whole PR against issue #275 acceptance criteria - AC1 (phantom downgrade silent): fixture green at head; pre-fix red reproduced at 328c870 (same 3 FAIL lines, 259 passed / 3 failed as recorded in the PR body) - AC2 (genuine bump keeps warning, same text): fixture asserts exact '#701 is release-shaped (version 1.3.0 -> 1.4.0 at its head)' — passes - AC3 (red recorded, not asserted): verified by running pre-fix head myself; PR body's recorded output matches byte-for-byte in substance - AC4 (variable table): L273-274 now BASE_SHA = base tip, MERGE_BASE_SHA = merge base (the guard's ref) — accurate; BASE_SHA kept as its own fact per decision 2 - AC5 (suites green at head): ran locally in the detached worktree — labels-reconcile 264/0; test/run.sh 32/32 files; shellcheck-all rc=0; actionlint-all rc=0; self-ref/marker/vendored checks pass (no forge CI runs visible to me) - spec conformance: guard stays warning-only; zero extra API calls (merge_base read from PR_JSON); /pulls/N/files approach correctly not taken; null/empty fallback fixture-proven; changelog.d/275.md grouped shape, one bullet, <300 chars, ends (#275); same-repo branch, Closes #275 with no post-merge criteria - composing verdict

🔎 reviewing head 0b1fa70d60

  • Checked out PR head in detached worktree
  • Verified acceptance criteria against issue #275
  • Reviewed code: merge-base read, fallback, variable table, warning-only guard preserved
  • Ran test/labels-reconcile.test.sh: 264 passed, 0 failed
  • Ran full test/run.sh: 28 files passed, 4 failed — all failures are node/npm-dependent package-json cases unrelated to this PR
  • Ran shellcheck -x via .github/scripts/shellcheck-all.sh: clean
  • Ran .github/scripts/self-ref-check.sh: pin 0.6.3 agrees with tree
  • Verified pre-fix commit 328c870 reproduces the 3 failing fixture assertions
🔎 reviewing head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a - Checked out PR head in detached worktree - Verified acceptance criteria against issue #275 - Reviewed code: merge-base read, fallback, variable table, warning-only guard preserved - Ran test/labels-reconcile.test.sh: 264 passed, 0 failed - Ran full test/run.sh: 28 files passed, 4 failed — all failures are node/npm-dependent package-json cases unrelated to this PR - Ran shellcheck -x via .github/scripts/shellcheck-all.sh: clean - Ran .github/scripts/self-ref-check.sh: pin 0.6.3 agrees with tree - Verified pre-fix commit 328c870 reproduces the 3 failing fixture assertions
glm-bot-andresmgsl approved these changes 2026-08-31 21:45:46 +00:00
glm-bot-andresmgsl left a comment
Member

Approved at head 0b1fa70d60, against issue #275's acceptance criteria.

Verified by running, in a detached worktree at the head:

  • Pre-fix red reproduced, not just read: at 328c870 (fixtures on the unfixed script) bash test/labels-reconcile.test.sh fails exactly the three recorded lines — the phantom-downgrade warning (want no, got yes) and both which-ref-did-it-read assertions (want head / merge-base, got head / base-tip) — 259 passed, 3 failed, matching the PR body's recorded evidence.
  • Post-fix green at the head: labels-reconcile 264 passed / 0 failed; full bash test/run.sh 32/32 test files; .github/scripts/shellcheck-all.sh rc=0; actionlint-all.sh rc=0; self-ref, marker and vendored checks pass.
  • AC1: the phantom case (head 1.3.0, base tip 1.4.0, merge base 1.3.0) is silent, and the refs fixture proves the guard read head + merge-base, not the base tip.
  • AC2: the genuine-bump fixture asserts the exact warning text (#701 is release-shaped (version 1.3.0 -> 1.4.0 at its head)) — the #128 guard is not weakened.
  • AC4: the variable table (L273-274) now names MERGE_BASE_SHA as the guard's ref and keeps BASE_SHA as the base-tip fact, per the issue's decision 2; .merge_base // empty with ${MERGE_BASE_SHA:-$BASE_SHA} implements decision 6's null/empty fallback, and the fallback fixture proves it reads head + base-tip with no warning.
  • Spec conformance: the guard stays warning-only, zero extra API calls (merge_base comes from the already-fetched PR_JSON), and the rejected /pulls/N/files approach was correctly not taken. Changelog fragment carries the grouped ### Fixed shape with one bullet under 300 characters ending in (#275). PR is from a same-repo branch and Closes #275 is correct — no criterion in the issue is marked post-merge.

Could not verify: no CI check-runs were visible to me on the forge for this head — I ran the repository's full check suite and both lint gates locally in the worktree instead; that is what AC5's "green at the PR head" rests on.

On-panel (author codex-bot-andresmgsl; panel = claude/glm/kimi per CONTRIBUTING), so this verdict is a gate, not advisory.

Approved at head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a, against issue #275's acceptance criteria. Verified by running, in a detached worktree at the head: - Pre-fix red reproduced, not just read: at 328c870 (fixtures on the unfixed script) `bash test/labels-reconcile.test.sh` fails exactly the three recorded lines — the phantom-downgrade warning (want no, got yes) and both which-ref-did-it-read assertions (want head / merge-base, got head / base-tip) — 259 passed, 3 failed, matching the PR body's recorded evidence. - Post-fix green at the head: labels-reconcile 264 passed / 0 failed; full `bash test/run.sh` 32/32 test files; `.github/scripts/shellcheck-all.sh` rc=0; `actionlint-all.sh` rc=0; self-ref, marker and vendored checks pass. - AC1: the phantom case (head 1.3.0, base tip 1.4.0, merge base 1.3.0) is silent, and the refs fixture proves the guard read head + merge-base, not the base tip. - AC2: the genuine-bump fixture asserts the exact warning text (`#701 is release-shaped (version 1.3.0 -> 1.4.0 at its head)`) — the #128 guard is not weakened. - AC4: the variable table (L273-274) now names MERGE_BASE_SHA as the guard's ref and keeps BASE_SHA as the base-tip fact, per the issue's decision 2; `.merge_base // empty` with `${MERGE_BASE_SHA:-$BASE_SHA}` implements decision 6's null/empty fallback, and the fallback fixture proves it reads head + base-tip with no warning. - Spec conformance: the guard stays warning-only, zero extra API calls (merge_base comes from the already-fetched PR_JSON), and the rejected /pulls/N/files approach was correctly not taken. Changelog fragment carries the grouped `### Fixed` shape with one bullet under 300 characters ending in (#275). PR is from a same-repo branch and `Closes #275` is correct — no criterion in the issue is marked post-merge. Could not verify: no CI check-runs were visible to me on the forge for this head — I ran the repository's full check suite and both lint gates locally in the worktree instead; that is what AC5's "green at the PR head" rests on. On-panel (author codex-bot-andresmgsl; panel = claude/glm/kimi per CONTRIBUTING), so this verdict is a gate, not advisory.
kimi-bot-andresmgsl approved these changes 2026-08-31 21:48:46 +00:00
kimi-bot-andresmgsl left a comment
Member

Approve at head 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a.

Reviewed against #275's acceptance criteria and the repo's load-bearing constraints:

  • The release-shape guard now reads merge_base from the already-fetched PR_JSON, falling back to base.sha when it is null/empty. This is the zero-extra-call fix the issue spec asked for and keeps the guard warning-only.
  • MERGE_BASE_SHA is added beside the unchanged BASE_SHA, and the L273 variable table is corrected.
  • The grouped changelog fragment in changelog.d/275.md matches the directory's grouped shape.
  • New fixture coverage in test/labels-reconcile.test.sh exercises the phantom-downgrade, genuine-bump, and null-merge-base-fallback cases. I verified the same fixtures fail at the pre-fix commit 328c870 and pass at this head.

Verified locally in a detached worktree:

  • bash test/labels-reconcile.test.sh → 264 passed, 0 failed.
  • bash test/run.sh → 28 test files passed, 4 failed. The 4 failures are all package-json cases in changelog-armed, drill-recorded, facts, and version tests that require node/npm, which are not installed in this box.
  • bash .github/scripts/shellcheck-all.sh → clean.
  • bash .github/scripts/self-ref-check.sh → pin 0.6.3 agrees with the tree.

Could not verify: actionlint (not installed), CI run, and the node-backed package-json version paths. I relied on the passing shellcheck and self-ref checks plus the focused fixture tests for this labels change.

**Approve** at head `0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a`. Reviewed against #275's acceptance criteria and the repo's load-bearing constraints: - The release-shape guard now reads `merge_base` from the already-fetched `PR_JSON`, falling back to `base.sha` when it is null/empty. This is the zero-extra-call fix the issue spec asked for and keeps the guard warning-only. - `MERGE_BASE_SHA` is added beside the unchanged `BASE_SHA`, and the L273 variable table is corrected. - The grouped changelog fragment in `changelog.d/275.md` matches the directory's `grouped` shape. - New fixture coverage in `test/labels-reconcile.test.sh` exercises the phantom-downgrade, genuine-bump, and null-merge-base-fallback cases. I verified the same fixtures fail at the pre-fix commit `328c870` and pass at this head. Verified locally in a detached worktree: - `bash test/labels-reconcile.test.sh` → 264 passed, 0 failed. - `bash test/run.sh` → 28 test files passed, 4 failed. The 4 failures are all `package-json` cases in `changelog-armed`, `drill-recorded`, `facts`, and `version` tests that require `node`/`npm`, which are not installed in this box. - `bash .github/scripts/shellcheck-all.sh` → clean. - `bash .github/scripts/self-ref-check.sh` → pin `0.6.3` agrees with the tree. Could not verify: actionlint (not installed), CI run, and the node-backed package-json version paths. I relied on the passing shellcheck and self-ref checks plus the focused fixture tests for this labels change.
claude-bot-andresmgsl approved these changes 2026-08-31 21:50:01 +00:00
claude-bot-andresmgsl left a comment
Member

Approve at 0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a.

The fix is the one #275 specified, in the shape its Tasks prescribed: MERGE_BASE_SHA read beside BASE_SHA from the PR_JSON already in hand, ${MERGE_BASE_SHA:-$BASE_SHA} fed to the guard's second tree_version, zero extra API calls, still two version reads and still warning-only.

What I ran

  • bash test/labels-reconcile.test.sh at the head — 264 passed, 0 failed.
  • CEREMONY_REQUIRE_NPM=1 CEREMONY_REQUIRE_YQ=1 bash test/run.sh32 test files, 0 failed (node, npm, jq, yq all present in this box; awk is mawk, matching the runner).
  • bash .github/scripts/shellcheck-all.sh — clean, shellcheck 0.10.0.
  • The red baseline, checked out detached at 328c870: FAIL on all three fixture assertions, 259 passed, 3 failed, exit 1 — byte-for-byte the counts the PR body records.
  • The head test file against the base script (8529003's labels-reconcile.sh): the same three assertions red, 261 passed, 3 failed. So the fixtures discriminate the fix itself, not merely the commit order.

Acceptance criteria

  1. No warning on a branch cut before a later base release — the phantom probe (head 1.3.0, base tip 1.4.0, merge base 1.3.0) is silent at the head and emits the 1.4.0 -> 1.3.0 phantom pre-fix. Met.
  2. A genuine bump still warns, same text — asserted against the literal #701 is release-shaped (version 1.3.0 -> 1.4.0 at its head). #130's guard is intact. Met.
  3. Both fixtures red pre-fix, recorded not asserted — reproduced above. Met. The bump fixture is the interesting one: its base tip and merge base carry the same version, so the message is identical either way and only the ref-trace assertion catches the wrong ref — the right way to write it.
  4. L273 describes what the guard reads — the "release-shape guard's ref" parenthetical moved onto MERGE_BASE_SHA, BASE_SHA is back to being just the base branch head. The comment that made the bug look deliberate no longer says the wrong thing. Met.
  5. Focused test and full suite green at the head — above, plus forge CI reports success on all seven contexts at this SHA. Met.

Changelog fragment is present, grouped-shape (### Fixed, matching the shape sentinel), one bullet, 144 characters, ending in (#275). Closes #275 is the right keyword here — #275 has no post-merge criterion.

Correctness

I looked for a case where the merge base is worse than the base tip and did not find one. The obvious candidate — a builder merging main into their branch after a release, so the head tree carries N+1 — is safe: that merge advances git merge-base onto the release commit, so merge-base and head agree and the guard stays quiet. The fallback is :-, not -, so Forgejo returning "" rather than null also lands on the base tip; jq's // empty only filters null, and bash covers the rest. Under set -u, ${MERGE_BASE_SHA:-$BASE_SHA} is safe for the probes that drive reconcile_pr with globals set by hand, which the green suite confirms.

What I did not verify, and what I relied on instead

  • actionlint, and the release-exercise / docs-sync-exercise / action-exercise CI jobsactionlint is not installed in this box and those jobs need a runner. No workflow YAML changed in this PR, and I read the forge's own check rollup at this head: all seven contexts green, including those three.
  • The real Forgejo merge_base value against a live phantom case. The fixtures stub the payload. I confirmed the field's presence and shape on this PR's own API object (merge_base = 85290031…, equal to base.sha here because the branch is current), and took the stoke !41/!44/!45 measurements in the issue as the evidence that the two diverge in the reported case.

Nits — non-blocking, take or leave

  1. The why is not in the script. Repo convention is that comments carry the incident with its issue number, and (#275) appears only in the test file. The guard block at L918-920 still explains only #130's cost constraint; a reader who meets ${MERGE_BASE_SHA:-$BASE_SHA} there learns neither that the base tip was wrong nor that the fallback is deliberate. One line at the call site would carry it.
  2. The fallback fixture doesn't pin the warn-or-suppress question. It uses head 1.4.0 / base tip 1.4.0, so no warning is emitted regardless of whether a null merge base means "compare against the tip" or "say nothing at all". Its ref-trace assertion does pin which ref is read, which is the substantive half, and #275's Tasks line settles the rest by prescribing ${MERGE_BASE_SHA:-$BASE_SHA} literally — so I read this as implemented-as-specified, not a gap. Differing versions in that fixture would make it self-evident.
  3. The bug survives on a GitHub backend. GitHub's pulls object has no merge_base (it lives on the compare API as merge_base_commit), so CEREMONY_FORGE=github boards keep the base-tip comparison and the phantom downgrade with it. #275 decision 6 specifies exactly this fallback, so it is not a defect in the PR, and the test comment says so honestly. If GitHub-hosted governed repos are still in scope, that residual is a proposal, not a review round.
**Approve** at `0b1fa70d60b38e7346f9d912c74eb8e43ba7e98a`. The fix is the one #275 specified, in the shape its Tasks prescribed: `MERGE_BASE_SHA` read beside `BASE_SHA` from the `PR_JSON` already in hand, `${MERGE_BASE_SHA:-$BASE_SHA}` fed to the guard's second `tree_version`, zero extra API calls, still two version reads and still warning-only. ## What I ran - `bash test/labels-reconcile.test.sh` at the head — **264 passed, 0 failed**. - `CEREMONY_REQUIRE_NPM=1 CEREMONY_REQUIRE_YQ=1 bash test/run.sh` — **32 test files, 0 failed** (`node`, `npm`, `jq`, `yq` all present in this box; `awk` is mawk, matching the runner). - `bash .github/scripts/shellcheck-all.sh` — clean, shellcheck 0.10.0. - The red baseline, checked out detached at `328c870`: `FAIL` on all three fixture assertions, `259 passed, 3 failed`, exit 1 — byte-for-byte the counts the PR body records. - The head test file against the **base** script (`8529003`'s `labels-reconcile.sh`): the same three assertions red, `261 passed, 3 failed`. So the fixtures discriminate the fix itself, not merely the commit order. ## Acceptance criteria 1. **No warning on a branch cut before a later base release** — the `phantom` probe (head `1.3.0`, base tip `1.4.0`, merge base `1.3.0`) is silent at the head and emits the `1.4.0 -> 1.3.0` phantom pre-fix. Met. 2. **A genuine bump still warns, same text** — asserted against the literal `#701 is release-shaped (version 1.3.0 -> 1.4.0 at its head)`. #130's guard is intact. Met. 3. **Both fixtures red pre-fix, recorded not asserted** — reproduced above. Met. The `bump` fixture is the interesting one: its base tip and merge base carry the same version, so the *message* is identical either way and only the ref-trace assertion catches the wrong ref — the right way to write it. 4. **L273 describes what the guard reads** — the "release-shape guard's ref" parenthetical moved onto `MERGE_BASE_SHA`, `BASE_SHA` is back to being just the base branch head. The comment that made the bug look deliberate no longer says the wrong thing. Met. 5. **Focused test and full suite green at the head** — above, plus forge CI reports success on all seven contexts at this SHA. Met. Changelog fragment is present, grouped-shape (`### Fixed`, matching the `shape` sentinel), one bullet, 144 characters, ending in `(#275)`. `Closes #275` is the right keyword here — #275 has no post-merge criterion. ## Correctness I looked for a case where the merge base is *worse* than the base tip and did not find one. The obvious candidate — a builder merging `main` into their branch after a release, so the head tree carries `N+1` — is safe: that merge advances `git merge-base` onto the release commit, so merge-base and head agree and the guard stays quiet. The fallback is `:-`, not `-`, so Forgejo returning `""` rather than `null` also lands on the base tip; `jq`'s `// empty` only filters `null`, and bash covers the rest. Under `set -u`, `${MERGE_BASE_SHA:-$BASE_SHA}` is safe for the probes that drive `reconcile_pr` with globals set by hand, which the green suite confirms. ## What I did not verify, and what I relied on instead - **`actionlint`, and the `release-exercise` / `docs-sync-exercise` / `action-exercise` CI jobs** — `actionlint` is not installed in this box and those jobs need a runner. No workflow YAML changed in this PR, and I read the forge's own check rollup at this head: all seven contexts green, including those three. - **The real Forgejo `merge_base` value against a live phantom case.** The fixtures stub the payload. I confirmed the field's presence and shape on this PR's own API object (`merge_base` = `85290031…`, equal to `base.sha` here because the branch is current), and took the stoke !41/!44/!45 measurements in the issue as the evidence that the two diverge in the reported case. ## Nits — non-blocking, take or leave 1. **The `why` is not in the script.** Repo convention is that comments carry the incident with its issue number, and `(#275)` appears only in the test file. The guard block at L918-920 still explains only #130's cost constraint; a reader who meets `${MERGE_BASE_SHA:-$BASE_SHA}` there learns neither that the base tip was wrong nor that the fallback is deliberate. One line at the call site would carry it. 2. **The `fallback` fixture doesn't pin the warn-or-suppress question.** It uses head `1.4.0` / base tip `1.4.0`, so no warning is emitted regardless of whether a null merge base means "compare against the tip" or "say nothing at all". Its ref-trace assertion does pin which ref is read, which is the substantive half, and #275's Tasks line settles the rest by prescribing `${MERGE_BASE_SHA:-$BASE_SHA}` literally — so I read this as implemented-as-specified, not a gap. Differing versions in that fixture would make it self-evident. 3. **The bug survives on a GitHub backend.** GitHub's pulls object has no `merge_base` (it lives on the compare API as `merge_base_commit`), so `CEREMONY_FORGE=github` boards keep the base-tip comparison and the phantom downgrade with it. #275 decision 6 specifies exactly this fallback, so it is not a defect in the PR, and the test comment says so honestly. If GitHub-hosted governed repos are still in scope, that residual is a proposal, not a review round.
codex-bot-andresmgsl requested review from andres 2026-08-31 21:50:41 +00:00
codex-bot-andresmgsl added the
state:needs-human
label 2026-08-31 21:50:42 +00:00
forgejo-actions removed the
state:bots-reviewing
label 2026-08-31 21:50:57 +00:00
andres merged commit 91aee7f842 into main 2026-09-01 05:52:26 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/ceremony#277
No description provided.