From 111485560ed8072b7ea3fd452e563ea3007b477c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 17 Sep 2026 18:00:47 +0200 Subject: [PATCH 1/3] fix(scripts): never abandon a detached local commit; model the dry-run relock after a nested server bump Follow-up to #1447 (Codex findings that landed after the merge): - a clean submodule detached at a commit not on origin/master was flagged DIVERGED in the preflight table ("will NOT be moved") but ff_master only checked the local master branch, so `checkout master` abandoned the commit. ff_master now refuses any HEAD with commits outside origin/master. - under --dry-run, a nested pointer bump inside aw-server-rust means the real run relocks aw-tauri to a server commit that does not exist yet; the preview reported the old lock as aligned and omitted both the lock commit and the aw-tauri pointer. It now says so and counts aw-tauri as moved. Verified on a scratch clone: aw-core detached on a local commit is left alone; a synthetic aw-webui commit under aw-server-rust yields "would relock" and a 2-pointer bundle plan. The real bundle moves nothing. --- scripts/bump-submodules.sh | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/scripts/bump-submodules.sh b/scripts/bump-submodules.sh index 30382806b..38678e66e 100755 --- a/scripts/bump-submodules.sh +++ b/scripts/bump-submodules.sh @@ -139,6 +139,7 @@ pointer_to_commit() { # origin/master has not moved for them, but the preview must carry the # hypothetical commit upwards (media -> aw-webui -> aw-server -> bundle). DRY_BUMPED="" +dry_bumped() { case " $DRY_BUMPED " in *" $1 "*) return 0 ;; esac; return 1; } # Where will be after this run: its HEAD normally, but under --dry-run # nothing moves, so reason about origin/master instead (unless it is dirty @@ -154,7 +155,7 @@ target_sha() { pointer_changed() { if [ "$DRY" = 1 ]; then local key=$2; [ "$1" = . ] || key="$1/$2" - case " $DRY_BUMPED " in *" $key "*) return 0 ;; esac + dry_bumped "$key" && return 0 [ "$(git -C "$1" rev-parse "HEAD:$2")" != "$(target_sha "$1/$2")" ] else ! git -C "$1" diff --quiet --ignore-submodules=dirty -- "$2" @@ -172,8 +173,14 @@ ff_master() { before=$(git -C "$dir" rev-parse HEAD) git -C "$dir" fetch -q origin master after=$(git -C "$dir" rev-parse origin/master) - # `pull --ff-only` is happy with a local master that is *ahead*: it would - # quietly make that unrelated commit the new pointer. Refuse. + # Local commits that are not upstream must never be abandoned or turned + # into the pointer: a detached HEAD or another branch would be dropped + # by `checkout master`, and `pull --ff-only` is happy with a local + # master that is *ahead*. Refuse both (the preflight table said so). + if [ "$(git -C "$dir" rev-list --count origin/master..HEAD)" != 0 ]; then + warn "$dir: HEAD has $(git -C "$dir" rev-list --count origin/master..HEAD) commit(s) not on origin/master; leaving as-is (push or drop them first)" + return 1 + fi if git -C "$dir" show-ref -q --verify refs/heads/master \ && [ "$(git -C "$dir" rev-list --count origin/master..master)" != 0 ]; then warn "$dir: local master has $(git -C "$dir" rev-list --count origin/master..master) commit(s) not on origin/master; leaving as-is (push or drop them first)" @@ -211,10 +218,8 @@ commit_pointer() { fi if [ "$DRY" = 1 ]; then local key=$path to; [ "$repo" = . ] || key="$repo/$path" - case " $DRY_BUMPED " in - *" $key "*) to="(new commit from its own pointer bump)" ;; - *) to=$(git -C "$repo/$path" rev-parse --short origin/master) ;; - esac + if dry_bumped "$key"; then to="(new commit from its own pointer bump)" + else to=$(git -C "$repo/$path" rev-parse --short origin/master); fi echo " [dry-run] $repo: $path $(git -C "$repo" rev-parse --short "HEAD:$path") -> $to" DRY_BUMPED="$DRY_BUMPED ${repo#./}" else @@ -415,6 +420,12 @@ if [ ! -e aw-server-rust/.git ] || [ ! -e aw-tauri/.git ]; then elif [ "$PAIR_FIXED" = 1 ]; then echo " aw-tauri or aw-server-rust is skipped/held; judging the lock at the pointers to be committed (aw-tauri ${TAURI_REV:0:7}, aw-server-rust ${SERVER_SHA:0:7})" if lock_at_server; then LOCK_ALIGNED=1; echo " aligned"; fi +elif [ "$DRY" = 1 ] && dry_bumped aw-server-rust; then + # Step 1 would commit a nested pointer in aw-server-rust, so the real + # run relocks to a commit that does not exist yet. + echo " [dry-run] aw-server-rust would get a new commit (nested bump); would relock aw-tauri to it and commit the lock" + LOCK_ALIGNED=1 + DRY_BUMPED="$DRY_BUMPED aw-tauri" elif lock_at_server; then echo " $LOCK already at ${SERVER_SHA:0:7} for every aw-* crate" LOCK_ALIGNED=1 From f51717800287f47c2302d25d93bf38f81fe36a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 17 Sep 2026 18:04:26 +0200 Subject: [PATCH 2/3] fix(scripts): the dry-run nested-server relock preview requires pushing, like the real relock Under --dry-run --no-push a nested aw-server-rust bump previewed a lock commit and an aw-tauri pointer move that a real --no-push run cannot make (cargo can only relock to a revision on GitHub). The preview now falls through to the same warning. --- scripts/bump-submodules.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/bump-submodules.sh b/scripts/bump-submodules.sh index 38678e66e..409d0281e 100755 --- a/scripts/bump-submodules.sh +++ b/scripts/bump-submodules.sh @@ -420,9 +420,10 @@ if [ ! -e aw-server-rust/.git ] || [ ! -e aw-tauri/.git ]; then elif [ "$PAIR_FIXED" = 1 ]; then echo " aw-tauri or aw-server-rust is skipped/held; judging the lock at the pointers to be committed (aw-tauri ${TAURI_REV:0:7}, aw-server-rust ${SERVER_SHA:0:7})" if lock_at_server; then LOCK_ALIGNED=1; echo " aligned"; fi -elif [ "$DRY" = 1 ] && dry_bumped aw-server-rust; then +elif [ "$DRY" = 1 ] && [ "$PUSH" = 1 ] && dry_bumped aw-server-rust; then # Step 1 would commit a nested pointer in aw-server-rust, so the real - # run relocks to a commit that does not exist yet. + # run relocks to a commit that does not exist yet (under --no-push it + # cannot: the branch below says so). echo " [dry-run] aw-server-rust would get a new commit (nested bump); would relock aw-tauri to it and commit the lock" LOCK_ALIGNED=1 DRY_BUMPED="$DRY_BUMPED aw-tauri" From 01ce54eca55bb5d2f333297a8d3b72e47cdfa106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 17 Sep 2026 18:06:37 +0200 Subject: [PATCH 3/3] fix(scripts): under --dry-run --no-push a nested server bump previews the relock refusal, not the stale lock The previous commit only skipped the relock preview; the chain then reached lock_at_server, judged at the old origin/master revision, and reported the lock as already aligned. The real --no-push run relocks against the new local commit, fails, and withholds both pointers. The preview now says the same. --- scripts/bump-submodules.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/bump-submodules.sh b/scripts/bump-submodules.sh index 409d0281e..4f9ff6755 100755 --- a/scripts/bump-submodules.sh +++ b/scripts/bump-submodules.sh @@ -420,13 +420,17 @@ if [ ! -e aw-server-rust/.git ] || [ ! -e aw-tauri/.git ]; then elif [ "$PAIR_FIXED" = 1 ]; then echo " aw-tauri or aw-server-rust is skipped/held; judging the lock at the pointers to be committed (aw-tauri ${TAURI_REV:0:7}, aw-server-rust ${SERVER_SHA:0:7})" if lock_at_server; then LOCK_ALIGNED=1; echo " aligned"; fi -elif [ "$DRY" = 1 ] && [ "$PUSH" = 1 ] && dry_bumped aw-server-rust; then +elif [ "$DRY" = 1 ] && dry_bumped aw-server-rust; then # Step 1 would commit a nested pointer in aw-server-rust, so the real - # run relocks to a commit that does not exist yet (under --no-push it - # cannot: the branch below says so). - echo " [dry-run] aw-server-rust would get a new commit (nested bump); would relock aw-tauri to it and commit the lock" - LOCK_ALIGNED=1 - DRY_BUMPED="$DRY_BUMPED aw-tauri" + # run relocks to a commit that does not exist yet — or, under + # --no-push, cannot relock at all (that commit would stay local-only). + if [ "$PUSH" = 1 ]; then + echo " [dry-run] aw-server-rust would get a new commit (nested bump); would relock aw-tauri to it and commit the lock" + LOCK_ALIGNED=1 + DRY_BUMPED="$DRY_BUMPED aw-tauri" + else + warn "skipped: aw-server-rust would get a new commit (nested bump) that --no-push leaves local-only; cargo can only relock to a revision on GitHub" + fi elif lock_at_server; then echo " $LOCK already at ${SERVER_SHA:0:7} for every aw-* crate" LOCK_ALIGNED=1