Skip to content

Local checkout can silently go stale between sessions — force fetch/sync check before trusting reads or starting a run #785

Closed

Description

@proagentstore

PROBLEM — The local checkout at ~/dev/stores/pags/platform (the same folder both the orchestrator's read-only repo tools and the coder's sessions operate against) can fall behind origin/main between sessions. This happened concretely: after coder run 97903fb3 pushed commit 6da7c9a to main (issue #772), a later orchestrator session used repo_read_file/repo_find/repo_git against that same folder and found none of the newly-shipped files — they genuinely were not on disk yet, because nothing had fetched/pulled since the push. This produced a false alarm (filed as #782, since resolved: root cause was a stale checkout, not a missing feature) and wasted a full investigation cycle.

COMPOUNDING ISSUE — repo_git's log subcommand appears to ignore arguments entirely (tested with custom --format, with -1 <sha>, with --stat <sha>) and returns an identical fixed ~20-line list regardless of input. This made the staleness harder to diagnose — the tool gave no signal that anything was wrong, it just silently returned stale-looking data. Worth checking as a separate bug in the repo_git tool implementation itself, since ignoring the cmd/args and returning a canned result is dangerous beyond just this staleness scenario — any caller trusting repo_git log output could be misled the same way.

ASK — Two independent fixes:

  1. ORCHESTRATOR-SIDE (read tools): repo_read_file / repo_find / repo_grep / repo_git (and any other local-checkout read tool) should have a way to cheaply signal staleness — at minimum, compare local HEAD against origin/main's HEAD (a lightweight git fetch + rev-parse comparison) and surface a warning in the response if they differ, rather than silently serving whatever happens to be on disk. This does not need to auto-pull — a caller should be told "local HEAD is N commits behind origin/main" and decide what to do, since auto-pulling on every read could itself race with a coder mid-edit.

  2. CODER-SIDE (coding_loop_start / session start): every coding session/loop should pull (or at minimum fetch and check ahead/behind) at the very start, before beginning work, so it never plans a diff against a stale base. This should also run again immediately before the session ends / before the final push, as a last check that nothing else landed on main while the session ran (the repo's one-active-session-per-repo rule limits but does not eliminate this race — e.g. a human or a different tool could push directly). Report explicitly in session output if a pull/fetch found and merged upstream changes, don't do it silently.

ALSO FIX — the repo_git log argument-ignoring bug described above; a git-log implementation that doesn't respect its own arguments should not ship regardless of the staleness issue.

No code changes should be needed to "fix" this from the orchestrator's own conversational instructions — that side is a process fix (always fetch/compare before trusting a read), not a code fix. This issue is scoped to the tool-level and coder-level fixes only.

Activity

  1. serge-ivo commented on Sep 8, 2026

    @serge-ivo
    Contributor

    Shipped in 35fbf6d (CLI 0.4.58 / runner 0.2.10, publishing via CI). Three notes for the record, because the fix does not match the issue's wording in three places and each was checked against the code before deciding:

    1. repo_git log never "ignored its arguments" — it never had them. The schema was {cmd, path, n} and the handler read nothing else, so --format, -1 <sha> and --stat <sha> were dropped before git ran and the canned twenty lines came back. The argv is fixed on purpose (gitArgv in inspect.ts: no caller string can become a flag), so it is NOT now running arbitrary arguments. Instead: a validated ref input ({cmd:"log", ref:"6da7c9a1", n:1}), a show command ({cmd:"show", ref} = --stat <sha>), and any input the tool has no slot for is refused by name with the honest spelling. --format stays unavailable.

    2. The staleness check runs on the runner, not in the Worker. git runs on the machine. POST /coding/sync fetches remote-tracking refs (never the branch, never the working tree — safe under a live session), cached a minute, and counts ahead/behind. Every repo-local read tool appends STALE CHECKOUT: N commits BEHIND origin/main … nothing was pulled when behind; repo_git status always states the position. Nothing auto-pulls, as the issue asked.

    3. The coder-side check lives in the workflow, not in coding-loop.ts. The loop is a pure function over CodingDeps and the Pilot never pushes — the Engine does. So: the run's repo-state-start step fetches and briefs the Pilot (fast-forward a clean behind checkout first; never merge a dirty/diverged tree unasked; fetch before any push and name what landed), and a new repo-sync-end step records the final position in the timeline and says so in chat when behind, diverged or ahead. The Pilot prompt carries the standing rules; the platform reports, it does not merge.

    Also fixed while there: runRepoGit, repoSearch and readGitRemoteOrigin gated on existsSync(".git"), so a monorepo subdirectory workdir was "healthy" to checkWorkdir (which asks git rev-parse) and "not a git repo" to repo_git in the same folder. All three now use rev-parse.

    The orchestrator-side process ask (fetch/compare before trusting a read) is now unnecessary: the read carries the answer.

  2. serge-ivo commented on Sep 8, 2026

    @serge-ivo
    Contributor

    Confirmed green on 35fbf6d: CI (run 34208498007), Deploy API Worker, Deploy Host Worker and Publish to npm all completed with success. CLI 0.4.58 is published; a machine running an older pags up keeps its previous behaviour (reads are served without the sync note, repo_git without ref/show) and the cloud names the release it needs when asked for either.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions