diff --git a/.claude/hooks/session-start.sh b/.claude/hooks/session-start.sh index eb26ee4e..5c3cef9a 100755 --- a/.claude/hooks/session-start.sh +++ b/.claude/hooks/session-start.sh @@ -30,6 +30,41 @@ fi log() { printf '[session-start] %s\n' "$*"; } +# Install a verified database at .beads/embeddeddolt. +# +# The staged copy lives on another filesystem, so it is brought alongside the +# live one FIRST. Every step after that is a same-filesystem rename, which +# either happens or does not — no half-finished copy. The previous database is +# removed only once the new one is in place, so no failure path leaves the repo +# without a tracker, and every move is checked: an unchecked one would let the +# new database land *inside* the old directory and still report success. +install_tracker() { + staged=$1 + live=.beads/embeddeddolt + incoming=$live.incoming + previous=$live.previous + + rm -rf "$incoming" "$previous" || return 1 + cp -rf "$staged" "$incoming" || { rm -rf "$incoming"; return 1; } + + if [ -d "$live" ] && ! mv "$live" "$previous"; then + rm -rf "$incoming" + return 1 + fi + + if mv "$incoming" "$live"; then + rm -rf "$previous" + return 0 + fi + + # Could not put the new one in place; restore what was there. + if [ -d "$previous" ] && ! mv "$previous" "$live"; then + log "ERROR: tracker left at $previous — move it back to $live by hand" + fi + rm -rf "$incoming" + return 1 +} + # ── 1. bd on PATH ────────────────────────────────────────────────────────── # The embedded Dolt engine needs CGO, so this builds from source (~3 min). # The container image is cached after the hook, so it is paid once. @@ -91,22 +126,8 @@ if command -v bd >/dev/null 2>&1; then esac fi - if [ "$sync_ok" -eq 1 ]; then - # Swap the verified result in, parking the old database inside $TMP - # until the move succeeds — a failed install must leave the previous - # tracker in place rather than none at all. The holding spot is under - # $TMP, not .beads/, so nothing untracked ever appears in the repo. - [ -d .beads/embeddeddolt ] && mv .beads/embeddeddolt "$TMP/previous-db" - if mv "$STAGE/.beads/embeddeddolt" .beads/embeddeddolt; then - log "issue tracker synced — 'bd ready' now reflects the remote, not issues.jsonl" - elif [ -d "$TMP/previous-db" ]; then - mv "$TMP/previous-db" .beads/embeddeddolt - log "WARNING: could not install the synced tracker; kept the previous database." - log " It may be out of date — verify any bead against the code." - else - log "WARNING: could not install the synced tracker and there is no previous one." - log " .beads/issues.jsonl is a STALE export — verify any bead against the code." - fi + if [ "$sync_ok" -eq 1 ] && install_tracker "$STAGE/.beads/embeddeddolt"; then + log "issue tracker synced — 'bd ready' now reflects the remote, not issues.jsonl" elif [ -d .beads/embeddeddolt ]; then log "WARNING: tracker sync failed (see /tmp/bd-sync.log); kept the previous database." log " It may be out of date — verify any bead against the code." diff --git a/.gitignore b/.gitignore index b5c597f5..28d2cac3 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ prolog-sessions/* # Beads runtime locks (bd creates these next to .beads/) *.gate.lock* +.beads/embeddeddolt.incoming/ +.beads/embeddeddolt.previous/