Skip to content

feat: explicit fetch refspec — wildcard map + touchpoint discipline, managed config keys - #29

Merged
zheng-weihao merged 1 commit into
mainfrom
explicit-fetch-refspec
Aug 8, 2026
Merged

zheng-weihao merged 1 commit into
mainfrom
explicit-fetch-refspec

Conversation

@zheng-weihao

@zheng-weihao zheng-weihao commented Aug 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Replaces the per-branch fetch-refspec machinery (three layers each fixing the previous layer's side effects) with a single wildcard map plus a touchpoint discipline, and turns every git config key orbit depends on into managed state with a three-mode escape hatch.

Core mechanism

  • One wildcard map +refs/heads/*:refs/remotes/origin/* written at clone, converged at every fetching touchpoint (sync / info / context --startup / prune) — one predicate per key, no remote comparison, no per-branch bookkeeping.
  • Touchpoint fetch discipline: maintain config first, then fetch the default branch plus every tracked branch with one explicit colon refspec each — never a bare fetch (preserves the single-branch economy). A tracked branch the remote lost fails silently (no more couldn't find remote ref leakage); one closing git remote prune origin, gated on the wildcard shape, converges the refs. The default branch is the one loud failure: an ls-remote --exit-code probe tells "remote lost its default branch" (WARNING) from offline (silent).
  • Config ownership: three managed keys (remote.origin.fetch, fetch.prune, push.default=upstream), each with a three-mode switch — git.fetchAllBranches / git.fetchPrune / git.pushUpstreamByDefault = always (default) / once / never. Every convergence is reported per key with its escape-hatch command; once/never pools are untouched and unreported. The switches govern config ownership, not ref hygiene — ref cleanup follows the layout shape.
  • push.autoSetupRemote handling and the doctor 2.37 soft gate removed; raw mode is plain git. orbit switch -c wires upstream config up front; the first push materializes the tracking ref on the spot. sync --branch writes no fetch config (the wildcard already covers the new default).

Also in this PR

  • orbit config key-identity checks (repos.* refusal, branch.prefix validation, the three-mode switches) now compare the lowercased key — git config key names are case-insensitive, so a cased spelling must not bypass its guard.
  • Docs restructure: spec-branching → spec-worktree (Root Decision, Config Ownership, Touchpoint Fetch Discipline, Prune's Git Binding, Git Dependency Closure — orbit's git dependencies enumerated as a closed set that only shrinks); spec-lifecycle keeps substrate-independent workspace invariants and points at the binding. Recovery narrative corrected: branch/worktree deletion takes its reflogs with it; the recovery handle is (was <sha>) + objects surviving gc.
  • Tests: hermetic git config layers (GIT_CONFIG_GLOBAL/SYSTEM=/dev/null); new coverage for convergence + one-shot quiet, once/never modes, the emptied-config (count=0) shape, the probe tri-state, residue ordering after the sweep, named-only fetch, raw bare push, and the config-key case bypass.

Breaking changes (in CHANGELOG): per-branch fetch refspec reconciliation removed (converges automatically at the next touchpoint); push.autoSetupRemote no longer set (raw-mode users who relied on it: git push -u origin <branch> once).

Test plan

  • make test — 341/341 green
  • Convergence steering lines verified byte-exact against spec-warnings contract

(The one-time full-fetch step this change introduces on user-run git fetch/git pull stays qualitative in the CHANGELOG by design; quantifying it on giant repos is a release-time measurement, tracked on the 0.2.0 checklist — not a gate for this PR.)

…managed config keys, spec-worktree restructure

- Replace per-branch refspec reconciliation with one wildcard map
  (+refs/heads/*:refs/remotes/origin/*) written at clone and converged
  at every fetching touchpoint; one predicate per key, no remote
  comparison, no per-branch bookkeeping.
- Touchpoint fetch discipline (sync / info / context --startup / prune):
  maintain config first, then fetch the default branch plus every
  tracked branch with one explicit colon refspec each — never a bare
  fetch. A tracked branch the remote lost fails silently; one closing
  `git remote prune origin` (gated on the wildcard shape) converges the
  refs. The default branch is the one loud failure: an ls-remote probe
  tells "remote lost its default" (reported) from offline (silent).
- Config ownership: three managed keys (remote.origin.fetch,
  fetch.prune, push.default=upstream), each with a three-mode switch —
  git.fetchAllBranches / git.fetchPrune / git.pushUpstreamByDefault
  (always/once/never). Every convergence is reported per key with its
  escape-hatch command; once/never pools are untouched and unreported.
  The switches govern config ownership, not ref hygiene.
- Remove push.autoSetupRemote handling and the doctor 2.37 soft gate;
  raw mode is plain git. `orbit switch -c` wires upstream config up
  front; the first push materializes the tracking ref on the spot.
- orbit config: key-identity checks (repos.* refusal, branch.prefix
  validation, the three-mode switches) compare the lowercased key —
  git config key names are case-insensitive, so a cased spelling must
  not bypass its guard. Shell completions list the registered keys.
- docs: spec-branching -> spec-worktree restructure (Root Decision,
  Config Ownership, Touchpoint Fetch Discipline, Prune's Git Binding,
  Git Dependency Closure); spec-lifecycle keeps substrate-independent
  workspace invariants with the git binding pointed into spec-worktree.
  Recovery narrative corrected: a branch/worktree deletion takes its
  reflogs with it; the handle is (was <sha>) + objects surviving gc.
- tests: hermetic git config layers (GIT_CONFIG_GLOBAL/SYSTEM=/dev/null);
  coverage for convergence and one-shot quiet, once/never modes, the
  count=0 shape, probe tri-state, residue ordering after the sweep,
  named-only fetch, raw bare push, and the config-key case bypass.

Signed-off-by: zheng-weihao <zheng-weihao@outlook.com>
@zheng-weihao
zheng-weihao merged commit a7427d9 into main Aug 8, 2026
2 checks passed
zheng-weihao added a commit to zheng-weihao/orbit that referenced this pull request Aug 13, 2026
…ocal

- orbcli#29's touchpoint fetch made every `orbit info` and every session start
  with worktrees pay N serial remote round-trips (default branch + each
  tracked branch, one fetch each), multiplying with scoped-branch residue;
  measured baselines: `orbit info` 4.83s wall / ~0.4s CPU on a repo with
  4 tracked branches, 19.7s on a pool carrying more scoped-branch residue,
  `context --startup` 24.5s with two repos added
- ruling: without an async daemon, auto-fetch on a main path taxes a
  synchronous caller for advisory freshness — low friction outranks it
  (cf. VSCode's background autofetch never blocking startup); auto-fetch
  may return only off the main path
- info and the context --startup reignite block drop the touchpoint fetch
  and keep config maintenance (local writes); remoteAhead now reads
  last-fetched refs, refreshed by sync / prune or the user's own fetch/pull;
  fetching touchpoints narrow to sync / prune
- skill contract (SKILL.md + CONSTRAINTS.md): steps 3/5 state the
  last-fetched-refs semantics; cold-start sync becomes a two-trigger rule
  (remoteAhead > 0, or a stale last fetch when the task depends on fresh code)
- spec-docs, USAGE, ROADMAP, CHANGELOG and the two info-fetch bats cases
  sync to the new contract; full suite 367/367 on latest main

Signed-off-by: Zheng Weihao <zheng-weihao@outlook.com>
@zheng-weihao
zheng-weihao deleted the explicit-fetch-refspec branch August 23, 2026 18:16
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