Fix filter reconciliation for pre-v1.2 state and unrelated histories

Three bugs found during first CI run after enabling :exclude:

- Derive old filter (:/subfolder) when state has no josh_filter stored
  (pre-v1.2 upgrade path)
- Detect unrelated histories in forward_sync() and fall back to
  reconcile_filter_change() instead of creating a useless conflict PR
- Skip state update on conflict result (prevents storing wrong filter
  and mono SHA that blocks retries)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 13:30:24 +03:00
parent 22bd59a9d7
commit c0ddb887ff
2 changed files with 29 additions and 2 deletions

View File

@@ -214,6 +214,18 @@ _sync_direction() {
local prev_filter local prev_filter
prev_filter=$(echo "$state" | jq -r '.last_forward.josh_filter // empty') prev_filter=$(echo "$state" | jq -r '.last_forward.josh_filter // empty')
# If no filter stored (pre-v1.2 state) but a previous sync exists,
# the old filter was the simple :/subfolder (before exclude was added)
if [ -z "$prev_filter" ]; then
local prev_mono_sha
prev_mono_sha=$(echo "$state" | jq -r '.last_forward.mono_sha // empty')
if [ -n "$prev_mono_sha" ]; then
local subfolder
subfolder=$(echo "$TARGET_JSON" | jq -r '.subfolder')
prev_filter=":/${subfolder}"
fi
fi
if [ -n "$prev_filter" ] && [ "$prev_filter" != "$JOSH_FILTER" ]; then if [ -n "$prev_filter" ] && [ "$prev_filter" != "$JOSH_FILTER" ]; then
log "WARN" "Josh filter changed — reconciling histories" log "WARN" "Josh filter changed — reconciling histories"
log "INFO" "Old: ${prev_filter}" log "INFO" "Old: ${prev_filter}"
@@ -225,6 +237,13 @@ _sync_direction() {
else else
result=$(reverse_sync) result=$(reverse_sync)
fi fi
# If forward sync hit unrelated histories, fall back to reconciliation
if [ "$result" = "unrelated" ]; then
log "WARN" "Unrelated histories detected — falling back to filter reconciliation"
result=$(reconcile_filter_change)
log "INFO" "Reconciliation result: ${result}"
fi
log "INFO" "Result: ${result}" log "INFO" "Result: ${result}"
# Handle warnings # Handle warnings
@@ -234,6 +253,7 @@ _sync_direction() {
fi fi
if [ "$result" = "conflict" ]; then if [ "$result" = "conflict" ]; then
echo "::warning::Target ${target_name}, branch ${branch}: merge conflict — PR created on subrepo" echo "::warning::Target ${target_name}, branch ${branch}: merge conflict — PR created on subrepo"
continue
fi fi
if [ "$result" = "josh-rejected" ]; then if [ "$result" = "josh-rejected" ]; then
echo "::error::Target ${target_name}, branch ${branch}: josh rejected push — check proxy logs" echo "::error::Target ${target_name}, branch ${branch}: josh rejected push — check proxy logs"

View File

@@ -11,7 +11,7 @@
# ─── Forward Sync: Monorepo → Subrepo ────────────────────────────── # ─── Forward Sync: Monorepo → Subrepo ──────────────────────────────
# #
# Returns: fresh | skip | clean | lease-rejected | conflict # Returns: fresh | skip | clean | lease-rejected | conflict | unrelated
forward_sync() { forward_sync() {
local mono_branch="$SYNC_BRANCH_MONO" local mono_branch="$SYNC_BRANCH_MONO"
@@ -97,7 +97,14 @@ ${BOT_TRAILER}: forward/${mono_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)" >&2
fi fi
else else
# Conflict! # Check: unrelated histories (filter change) vs normal merge conflict
if ! git merge-base "subrepo/${subrepo_branch}" "$mono_head" >/dev/null 2>&1; then
log "INFO" "No common ancestor — histories are unrelated (filter change?)"
echo "unrelated"
return
fi
# Normal merge conflict
local conflicted local conflicted
conflicted=$(git diff --name-only --diff-filter=U 2>/dev/null || echo "(unknown)") conflicted=$(git diff --name-only --diff-filter=U 2>/dev/null || echo "(unknown)")
git merge --abort git merge --abort