Skip to content

feature: graceful fallback to timestamp based diff on unreachable gitHead#385

Open
Joseph Zhang (jzhn) wants to merge 1 commit into
langchain-ai:mainfrom
jzhn:feature/rebase-support
Open

feature: graceful fallback to timestamp based diff on unreachable gitHead#385
Joseph Zhang (jzhn) wants to merge 1 commit into
langchain-ai:mainfrom
jzhn:feature/rebase-support

Conversation

@jzhn

Copy link
Copy Markdown

Problem

After each run, OpenWiki records the HEAD SHA in openwiki/.last-update.json and diffs git log <gitHead>..HEAD to find what changed since the last update. When git history is rewritten with squash or rebase, the recorded SHA becomes orphaned (no longer reachable from HEAD) — or is absent entirely on a fresh/shallow clone.

When that happens, OpenWiki silently misbehaves:

  • runGit() swallows git's non-zero exit and returns the fatal: Invalid revision range … text as if it were normal output.
  • No-op check (getUpdateNoopStatus) only "worked" by accident — it misinterpreted the error string as a changed path.
  • Agent evidence (createGitSummary) fed the model the fatal: string as its diff, and the timestamp fallback was structurally unreachable: the if/else-if was keyed on whether gitHead was present, not on whether the git command succeeded.

Net effect: incremental updates run blind (under-update or hallucinate) with no signal that anything went wrong.

Solution

Detect an unreachable baseline explicitly and degrade gracefully:

  • Add commitExists(cwd, sha) (git cat-file -e <sha>^{commit}).
  • getUpdateNoopStatus: if the recorded gitHead isn't reachable, return "not a no-op" with a clear reason instead of parsing git's error text — safe default is to run the update.
  • createGitSummary: guard the gitHead..HEAD branch with commitExists. If the commit is gone, fall through to the existing time-based git log --since <updatedAt> evidence and prepend an explicit note. The model never receives a fatal: string again.

Alternatives considered

  1. Repair the orphaned SHA to the last commit that modified .last-update.json (the approach in our CI workaround). git log -1 --format=%H -- .last-update.json is always reachable (log only walks HEAD's ancestors) and is a more precise incremental baseline than a timestamp. Not chosen for the core fix because of too much added complexity.
  2. Make runGit fail loudly / distinguish "empty diff" from "command failed." Correct as defense-in-depth, but larger blast radius across all git calls; the commitExists guards prevent the bad range from ever running, so it's deferred.

Notes

Before this is merged, my team is using below to "repair" the gitHead in our CI setup.

    # Orphaned-baseline repair: OpenWiki records the HEAD SHA in
    # ${OPENWIKI_DOCS_PATH}/.last-update.json after each run and diffs
    # `git log <gitHead>..HEAD` to find what changed. When a merge uses
    # squash/rebase the recorded SHA is orphaned (no longer reachable from
    # HEAD), and OpenWiki silently treats it as "no changes" — its `runGit`
    # helper swallows the non-zero exit, and the timestamp fallback is
    # structurally unreachable when gitHead is present (if/else-if keyed on
    # the input, not the git-command result).
    # Fix: if the recorded gitHead is unreachable, replace it with the last
    # commit that actually *modified* .last-update.json. That commit is always
    # reachable (git-log only walks ancestors of HEAD), and it represents the
    # true incremental baseline even after squash/rebase rewrites.
    - |
      LAST_UPDATE_FILE="${OPENWIKI_DOCS_PATH}/.last-update.json"
      if [ -f "$LAST_UPDATE_FILE" ]; then
        RECORDED=$(jq -r '.gitHead // empty' "$LAST_UPDATE_FILE" 2>/dev/null || true)
        if [ -n "$RECORDED" ] && ! git cat-file -e "${RECORDED}^{commit}" 2>/dev/null; then
          REPAIR=$(git log -1 --format=%H -- "$LAST_UPDATE_FILE" 2>/dev/null || true)
          if [ -n "$REPAIR" ]; then
            echo "Recorded gitHead ${RECORDED} is unreachable (squash/rebase merge) — resetting to last reachable baseline ${REPAIR}."
            tmp=$(mktemp)
            jq --arg h "$REPAIR" '.gitHead = $h' "$LAST_UPDATE_FILE" > "$tmp" && mv "$tmp" "$LAST_UPDATE_FILE"
          else
            echo "No reachable baseline found for ${LAST_UPDATE_FILE} — OpenWiki will fall back to its timestamp/recent-commits path."
          fi
        fi
      fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant