open-standards/tools/branch-drift-audit.sh
Transaction Science d356377433 repo hygiene: cross-arch byte-equality CI + branch-drift audit
Two maintenance pieces, both salvaged from the stale-branch cleanup:

- .github/workflows/wai-byte-equality.yml — the one genuinely-unlanded
  artifact stranded on harness-econ: a 5-arch matrix (linux x86_64/aarch64,
  macos arm64/x86_64, windows x86_64) that decodes WAI fixtures and asserts
  byte-identical golden output — the `replicate` determinism contract checked
  on real silicon. main had wai-conformance + wai-neural-e2e but no
  cross-architecture byte-equality job. Dropped the stale rans.rs path
  trigger (that source was merged away); the tested crate
  (wai-byte-exact-conformance) and the remaining neural sources are current.

- tools/branch-drift-audit.sh — surfaces branch drift BEFORE it rots: per
  branch, ahead/behind main, unpushed, and patch-stranded count with a
  verdict (absorbed → delete vs LAND → cherry-pick forward). The fix for the
  "long-lived branches drift past clean-merge and strand work" failure this
  cleanup addressed.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-03 00:52:55 -04:00

45 lines
2.4 KiB
Shell
Executable file

#!/usr/bin/env bash
# branch-drift-audit.sh — surface stale/stranded branches BEFORE they rot.
#
# The failure this prevents: a feature branch left unlanded while main moves 100+
# commits drifts into an un-mergeable state, stranding real work. This makes drift
# VISIBLE and, crucially, distinguishes "far behind but fully absorbed" (safe to
# delete) from "far behind with genuinely-unlanded commits" (cherry-pick forward
# NOW, before it rots further). Run it in CI or from a cron; act on anything with
# STRANDED > 0 or a large BEHIND.
#
# Usage: branch-drift-audit.sh [base-ref] (default: origin/main)
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
git fetch -q origin 2>/dev/null || true
BASE="${1:-origin/main}"
WARN_BEHIND="${WARN_BEHIND:-50}" # flag branches this far behind base
printf "%-28s %6s %6s %9s %9s %s\n" "BRANCH" "AHEAD" "BEHIND" "UNPUSHED" "STRANDED" "VERDICT"
printf '%.0s─' {1..96}; echo
# Dedup local + origin refs into one branch list.
branches=$(git for-each-ref --format='%(refname:short)' refs/heads/ refs/remotes/origin/ \
| sed 's#^origin/##' | grep -vx 'HEAD' | grep -vx 'main' | sort -u)
for b in $branches; do
ref="refs/heads/$b"; git show-ref -q --verify "$ref" || ref="refs/remotes/origin/$b"
ab=$(git rev-list --left-right --count "$BASE...$ref" 2>/dev/null) || continue
behind=$(awk '{print $1}' <<<"$ab"); ahead=$(awk '{print $2}' <<<"$ab")
# Genuinely-unlanded = commits whose PATCH is not on base (git cherry '+').
stranded=$(git cherry "$BASE" "$ref" 2>/dev/null | grep -c '^+' || true)
# Unpushed = local commits not on the same-named remote branch.
if git show-ref -q --verify "refs/heads/$b" && git show-ref -q --verify "refs/remotes/origin/$b"; then
unpushed=$(git rev-list --count "origin/$b..refs/heads/$b" 2>/dev/null || echo 0)
elif git show-ref -q --verify "refs/heads/$b"; then unpushed="NO-REMOTE"; else unpushed=0; fi
if [ "$stranded" -gt 0 ]; then verdict="⚠ LAND $stranded unlanded commit(s) — cherry-pick forward"
elif [ "$ahead" -eq 0 ]; then verdict="✓ absorbed — safe to delete"
else verdict="✓ ahead-commits all on $BASE (patch-equiv) — deletable"; fi
[ "$unpushed" != "0" ] && [ "$unpushed" != 0 ] && verdict="$verdict · PUSH first"
[ "$behind" -gt "$WARN_BEHIND" ] && verdict="$verdict · ${behind} behind"
printf "%-28s %6s %6s %9s %9s %s\n" "$b" "$ahead" "$behind" "$unpushed" "$stranded" "$verdict"
done