From f174d1b7fa38c382af756b568a0a91255cb68137 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 5 Jun 2026 19:39:02 -0700 Subject: [PATCH] feat(sync): best-effort coord visibility signal (git_sync_ component) sync.sh now posts a per-machine coord component (claudetools/git_sync_) flipped syncing -> idle/degraded around each run, so the fleet can see who is mid-sync / last sync state. Fully best-effort: a 3s-capped curl guarded with || true + return 0, emitted only after the lock is acquired (contention/exit-75 emits nothing), and finalize captures $? first and returns it so the signal can never change the sync's real exit code. Reviewed (verified it cannot break sync). --- .claude/scripts/sync.sh | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.claude/scripts/sync.sh b/.claude/scripts/sync.sh index f6f7043..6fcf7e9 100755 --- a/.claude/scripts/sync.sh +++ b/.claude/scripts/sync.sh @@ -91,6 +91,22 @@ else fi TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S") +# --- Coord visibility signal (BEST-EFFORT, never blocks/fails the sync) ------- +# Publishes a per-machine coord component so the fleet can see this machine's +# sync state. Pure visibility: every call is guarded so it can NEVER trip the +# script's `set -e`, slow the sync beyond a tiny timeout, or change the exit code. +COORD_BASE="http://172.16.3.30:8001/api/coord" +COORD_SYNC_STARTED=0 +coord_signal() { + local state="${1:-}" + curl -s --connect-timeout 2 -m 3 -o /dev/null -X PUT \ + "$COORD_BASE/components/claudetools/git_sync_${MACHINE}" \ + -H "Content-Type: application/json" \ + -d "{\"state\":\"${state}\",\"version\":\"1.0.0\",\"notes\":\"${state} at ${TIMESTAMP} (${USER_DISPLAY:-?})\",\"updated_by\":\"${MACHINE}/sync\"}" \ + 2>/dev/null || true + return 0 +} + echo -e "${GREEN}[OK]${NC} Starting ClaudeTools sync from $MACHINE at $TIMESTAMP" # Navigate to ClaudeTools directory @@ -141,9 +157,23 @@ SYNC_LOCK_DIR="$REPO_ROOT/.git/claudetools-sync.lock" # shellcheck source=./sync-lock.sh source "$REPO_ROOT/.claude/scripts/sync-lock.sh" -trap release_sync_lock EXIT INT TERM +# Finalize: best-effort coord signal (only if we actually started a sync), then +# ALWAYS release the lock (idempotent + ownership-gated). $? is captured FIRST so +# the coord branch reflects the real script outcome. This trap must NOT call +# `exit` — letting it return preserves the script's true exit code. +sync_finalize() { + local rc=$? + if [ "$COORD_SYNC_STARTED" = "1" ]; then + if [ "$rc" = "0" ]; then coord_signal idle; else coord_signal degraded; fi + fi + release_sync_lock + return "$rc" # preserve the script's true exit code regardless of release_sync_lock's status +} +trap sync_finalize EXIT INT TERM acquire_sync_lock echo -e "${GREEN}[OK]${NC} Acquired sync lock ($SYNC_LOCK_DIR)" +COORD_SYNC_STARTED=1 # set BEFORE the signal so a crash in the gap still finalizes (degraded) +coord_signal syncing # --- end concurrency lock ---------------------------------------------------- # Detect Python interpreter — read from identity.json first, fall back to detection