fix(#1404): version-only manifest bumps no longer park the back-merge (#1405)

auto-backmerge's needs_review safety net parked the PR whenever a code
file existed only on main. The version manifests (package.json,
package-lock.json, .claude-plugin/plugin.json, gemini-extension.json)
diverge every release by design (next runs a -dev version), so the net
misfired on every release — and that manual-review park is what let the
back-merge sit and go stale (e.g. #1379, which then conflicted with a
later #1777 purity-gate edit to fragments it had deleted).

Exclude the generated package-lock.json outright (it carries a version
per package entry, so a dep bump is indistinguishable from a release
stamp; it only mirrors package.json, still checked). For package.json /
plugin.json / gemini-extension.json, ignore a drop whose main-vs-base
diff touches only the top-level "version" field. A substantive
(non-version) straight-to-main change still parks, preserving the
safety net's real purpose.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-17 21:02:18 -04:00
committed by GitHub
parent 666d933e16
commit 0c9f86d495
2 changed files with 51 additions and 0 deletions

View File

@@ -108,6 +108,27 @@ jobs:
NEXT_CODE=$(git diff --name-only "$BASE" origin/next -- . ':(exclude)CHANGELOG.md' ':(exclude).changeset' | sort)
DROPPED=$(comm -23 <(printf '%s\n' "$MAIN_CODE") <(printf '%s\n' "$NEXT_CODE") | grep -v '^$' || true)
# The version-bearing manifests diverge every release by design (next
# runs a -dev version). A drop whose main-vs-base diff touches ONLY
# "version" lines is just the release stamp, not a straight-to-main
# fix — parking on it is what lets the back-merge sit and go stale, so
# filter those out. A substantive change still parks: it leaves
# non-"version" lines (deps in package.json; resolved/integrity in the
# lockfile when a dependency actually changes).
VERSION_STAMP_MANIFESTS='package.json package-lock.json .claude-plugin/plugin.json gemini-extension.json'
DROPPED=$(printf '%s\n' "$DROPPED" | while IFS= read -r f; do
[ -n "$f" ] || continue
case " $VERSION_STAMP_MANIFESTS " in
*" $f "*)
changed=$(git diff "$BASE" origin/main -- "$f" | grep -E '^[+-]' | grep -vE '^[+-]{3} ' || true)
if [ -z "$(printf '%s\n' "$changed" | grep -vE '^[+-][[:space:]]*"version":' || true)" ]; then
continue
fi
;;
esac
printf '%s\n' "$f"
done | grep -v '^$' || true)
git commit -m "chore: back-merge main into next (${SHORT_SHA})"
git push --force origin "$BR"

View File

@@ -103,3 +103,33 @@ describe('Require Issue Link back-merge automation carve-out', () => {
assert.match(workflow, /steps\.check\.outputs\.found == 'false'/);
});
});
describe('Auto-backmerge needs_review version-manifest carve-out (#1404)', () => {
const workflow = readWorkflow('.github/workflows/auto-backmerge.yml');
test('all four version manifests are filtered via version-only detection', () => {
// package.json / package-lock.json / plugin.json / gemini-extension.json
// diverge every release; a drop that is ONLY "version" lines must not park
// (parking is what lets the back-merge go stale). A substantive change still
// parks. (#1404)
assert.ok(
workflow.includes("VERSION_STAMP_MANIFESTS='package.json package-lock.json .claude-plugin/plugin.json gemini-extension.json'"),
'auto-backmerge.yml must version-only-filter all four version manifests'
);
assert.ok(
workflow.includes(`grep -vE '^[+-][[:space:]]*"version":'`),
'auto-backmerge.yml must filter version-only diffs via the "version" grep'
);
});
test('package-lock.json is NOT blindly excluded (lockfile-only changes still park)', () => {
// A lockfile-only substantive change (e.g. npm audit fix) rewrites
// resolved/integrity lines, so version-only filtering lets it through to
// review rather than dropping it silently. Guard against regression to a
// blanket exclude. (#1404)
assert.ok(
!workflow.includes(":(exclude)package-lock.json"),
'package-lock.json must not be globally excluded; rely on version-only filtering'
);
});
});