Do not re-push an indivisible span while later gaps still split

can you gather context on https://github.com/entireio/git-sync/pull/118 I have some questions
Context loaded. Here's the state of entireio/git-sync#118 — "Let the target decide when a bootstrap checkpoint cannot be split further".
Status: open, nodo/ent-2060-bottom-out-server-verdict → main, +835/−26 across 7 files, head 3e55d75b. CI green (test/lint/govulncheck/licenses); reviewDecision: REVIEW_REQUIRED — no human review yet, only Cursor Bugbot.
Core change (internal/strategy/bootstrap/bootstrap.go): when checkpoint subdivision bottoms out at one commit per gap, the push abort ceiling escalates from TargetMaxPack (self-imposed, ~512 MiB default) to AnnouncedTargetLimit (new Params field, parsed from a target rejection), with no 95% margin and no projection at that ceiling. Gated by isIndivisibleCheckpoint(batch, current, idx) and !budgetFromObservation (measured-cutoff guard). Terminal condition isTargetBodyLimitError(pushErr) || (atAnnounced && abortedEarly) returns ErrCheckpointExceedsTargetLimit, aliased into the root package in errors.go.
Secondary change: partial Result on error paths — bootstrapWithInputs now returns route facts (RelayMode, Batching, BatchCount, TempRefs, Plans) instead of Result{}; Batching/RelayMode set before checkpoint planning; client.go and unstable/client.go stop zeroing on error.
One open Bugbot finding (medium, unaddressed, posted 15:23 against current head 3e55d75b) — "Doomed pack retried while later gaps split":
atAnnouncedand the permanent sentinel both key off the current span being one commit, but the retry still runssubdivideToFactorover all remaining checkpoints. A later gap that can still split makescontinuere-fetch and re-push the same indivisible pack at the announced ceiling. The sentinel only fires after every later gap is also one commit, so a commit the target already refused can be uploaded several times in one run.
An earlier Bugbot finding (high, "sentinel misfires on non-size errors") was against the pre-rebase d4649ff1 and you've replied that both halves are fixed.
Two things worth knowing before you ask:
- Your local
git-syncworktree is on the pre-rebase branch —ahead 5, behind 10, tipb06c763d. The remote was force-pushed to the squashed 2-commit version. Local code ≠ PR code. - The PR body carries three rollout blockers: worker-side classification must ship in the same release as the pin bump (branch
nodo/ent-2060-worker-permanent-checkpointin mirror-pipeline,go.modstill points at this branch); needs an entiredb owner's sign-off for multi-GiB receive-pack from batched mode; scoped to entiredb→entiredb until thelookupGitHubRepoSizeKBpreflight-auth fix lands.
Minor: bootstrap_test.go has a duplicated drainAbort doc comment (the comment block appears twice, once orphaned).
What are your questions?
The one-sentence version: git-sync was giving up on packs the server would have happily accepted, because it was measuring against its own much stricter rule and never actually asking the server.
The story
You're mailing a huge pile of books to a friend. The post office's limit is 10 kg per box. But you made yourself a stricter house rule: never pack more than 0.5 kg per box.
Why the stricter rule? Two good reasons. If a box gets rejected, you only wasted a little effort. And lots of small boxes means your friend can tick off "got it!" often, so if you get interrupted you don't start over.
So you pack: too heavy → split the pile in half. Still too heavy → split again. Again. Again.
Eventually you're down to one single book. And that book weighs 0.6 kg.
You can't split a book in half.
Old behavior: you look at your 0.5 kg house rule, say "too heavy, I give up," and stop. The whole delivery fails. But the post office would have taken it fine — it's 0.6 kg, and their limit is 10 kg. You never asked them. And then you'd try the whole thing again tomorrow, hauling the entire pile from home each time, and fail identically. Ten times.
New behavior: when you're down to one unsplittable book, you stop using your own house rule and use the post office's actual limit instead. Let them decide.
Two nice things about this:
- It costs nothing. A weight limit is a "when do I stop," not a "how much do I send." A book that fits sends exactly the same book either way.
- You find out the truth. If the post office genuinely says "no, too heavy" — now you know. That's a real, permanent no. So git-sync raises a special flag (
ErrCheckpointExceedsTargetLimit) meaning "stop retrying, this will never work", and the worker stops hauling the pile from home ten more times to learn the same thing.
The rules for who gets blamed:
| What happened | Verdict |
|---|---|
| Your own house rule stopped you | keep trying — a bigger rule might work |
| The post office actually refused it | permanent — stop |
| The post office was closed / slow | keep trying — that's not about weight |
The second, smaller change
Separately: the delivery receipt used to only get filled in if the delivery succeeded. So when things failed, nobody could tell whether you'd gone by truck or by mail — you had to go dig through the original pile to find out. Now the receipt records which route you took as soon as you pick it, even if the trip then fails.
Translation table
| Story | Real thing |
|---|---|
| the pile of books | the repo's git history |
| a box | one pack pushed to the target |
| your 0.5 kg house rule | TargetMaxPack (512 MiB default) |
| the post office's 10 kg limit | AnnouncedTargetLimit (what entiredb says) |
| splitting the pile | checkpoint subdivision |
| one unsplittable book | a single commit — subdivision splits between commits |
| hauling the pile from home | a full multi-GiB source fetch, per retry |
Anytime. That open Bugbot finding about re-pushing the doomed pack when later gaps can still split is the one thing still worth a look before merge — ping me if you want to dig into whether it's real.