checkpoint: choose the write ref name after the backfill fetch

Commit

Stefan Haubold3d ago

updateCheckpointRef resolved the write name before calling base(), which is wrong whenever base() can fetch. The backfill paths pass refBaseForBackfill, which pulls a checkpoint that exists only on the remote and materializes its ref under whichever spelling the remote publishes. Resolving first, writeRefName found nothing locally and chose the canonical spelling; the CAS then targeted a name the fetch never populated while expecting the fetched ref's tip, so every attempt missed and the backfill failed with "CAS retry budget exhausted" โ€” the exact fork writeRefName exists to prevent.

The name is now chosen after a priming base() call, whose result the builder reuses for its first attempt rather than re-reading. That keeps the cost at zero fetches: a genuinely absent checkpoint pays one remote probe per spelling, and re-reading would double it. Reading before the lock is safe because the CAS is what makes it safe โ€” a ref that moved in between fails the compare, and the retry re-reads under the lock.

The regression test packs inside the fake fetcher. Without that it passes on a case-insensitive filesystem for the wrong reason: a loose folded ref still answers to the canonical name there, so the CAS succeeds and hides the bug that is unconditional on Linux.

Refs #2402

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com Entire-Checkpoint: 01M2K05N6ZJA7G7HGD7FNDTVZS