You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
laptop repo-keeper snapshot commits diverged ~/git/code main from origin (pm-git-sync failing) #4464
Found 2026-11-02 during #3026 deploy work (not caused by it):
Laptop primary ~/git/code sits on local-only commits b60e569 + 30c079f ("repo-keeper: snapshot code 2026-11-02 08:27 / 09:26 CST") on top of aebaa7f; origin/main is 548 commits ahead and no longer descends from them, so fast-forward is impossible.
pm-git-sync.service now FAILS every cycle (journal 2026-11-02 10:43:55 CST: "FAIL git pull --ff-only b60e569..c403aad"), so the primary no longer tracks origin/main and subtree-change redeploys do not fire.
The snapshot commits presumably carry live local state (the working tree is clean); reconciling them needs an owner who can judge what in the snapshots is live config vs already-upstream - do not blind-reset.
Workaround used for the #3026 claimant deploy: verified the merged files were byte-identical to origin/main and ran the claimant installer from a worktree at the merge content.
Acceptance criteria
The laptop's ~/git/code main is realigned with origin/main (fast-forward or an explicit, reviewed merge of the repo-keeper snapshot commits) with no work lost — every snapshot commit is either landed via PR or named as dropped with a reason.
pm-git-sync timer runs succeed again on the laptop (journal shows ff-pull or clean no-op, not the divergence failure).
The repo-keeper snapshot mechanism is adjusted or documented so snapshot commits stop diverging the primary clone (or the divergence is alarmed before it blocks sync).
Related: Relates to the standing fleet rule that primary clones stay on main + clean (pm-git-sync enforcement); code issue #1413 is the CI-first/primary-clone policy issue. No PR fixes this — it is a laptop state repair.
Notes: Filed with no labels; this pass adds kind/infrastructure, status/needs-triage, priority/high (fleet sync infrastructure is blocked), effort/m, acceptance criteria, meta/enriched.
Risks: The snapshot commits may contain the only copy of laptop-side session state; realignment must inventory them before any reset — discarding them risks the 2026-10-25-class loss. No force-push and no destructive reset under any reading of this issue.
Suggested approach: Inventory the snapshot commits vs origin/main, land or archive each, then ff the primary and watch one pm-git-sync cycle succeed.
Structural follow-on filed as #4544: split .opencode/opencode.jsonc into the tracked configured default plus a runtime overlay at ~/.local/state/opencode/opencode-runtime.jsonc, so the automated writers named there (sync-models' provider-catalog sync, the server's shell write) stop dirtying this tree at the source. #4525 fixed the keeper's stale-base commit; #4544 removes the drift the keeper was committing.
Not a runaway process. Diffing all three snapshot commits:
30c079fcc (08:27) and b60e5695e (09:26): only .opencode/opencode.jsonc — deliberate config edits (the 2026-11-02 Luna seat trim, its same-morning refinement/revert, and the Spark #xhigh effort-audit pin) written into the live primary tree, which is where the OpenCode server reads that config from. Legitimate content; the venue is the hazard.
laptop-repo-keeper snapshot-committed dirty tracked files before checking ahead/behind. pm-git-sync (every 30s) cannot pull a dirty tree, so any in-tree edit leaves the primary behind within minutes; the hourly keeper then committed that dirt onto the stale base, putting the primary ahead AND behind in a single step. After that, the keeper's own rules make it permanent: diverged → "left alone", push → rejected, pm-git-sync ff-only → FAIL every cycle (first FAIL 09:51; still failing at 11:40 while the keeper kept committing on top).
Fix at the source
PR #4525 (merged 72239e49a): the keeper now computes ahead/behind immediately after its fetch and refuses to snapshot when behind > 0 — loud report line, dirt left visible in the tree for reconciliation instead of becoming a poison commit. Dirty + up-to-date keeps the existing snapshot + push safety net. New tests in nixos/home/laptop-repo-keeper.test.sh (dirty+behind → no commit, edit left dirty, refusal reported; dirty+current → snapshot commits and pushes); full suite passes on the laptop.
Deployment note: the keeper unit is store-built, so the patched keeper takes effect at the next Nix switch. Until then, the reconciled tree + pm-git-sync keep the primary current, which keeps any old-keeper snapshot on an up-to-date base (the healthy path).
All six local-only commits were diffed before any surgery:
Snapshots 30c079fcc, b60e5695e, d5359cb64: content is identical to what is on origin/main now (local-side diff since merge-base = flake.lock only) — the same config/poll.py content reached origin through the normal flow. Verdict: content-redundant, zero unique work.
Pins cfc9b9256, cf7c6f93f (opencode_2 → 424c8d6f → 401ba065) and the deploy merges 1cb899ba8/01d736c81: real deploy work — preserved by reconciling via merge + push, not reset.
Reconciliation: scratch-clone merge test was clean first; then the primary merged origin/main and pushed (c9f0309cf..ecb96bbc8). GitHub's main ref verified == local HEAD ecb96bbc8 via API read; no switch was in progress and no switch was run by this fix.
Soak evidence (2026-11-02 12:31 → 13:31 CST)
pm-git-sync's first post-push cycle: ok clean main, up to date at ecb96bbc8; it then kept the primary tracking origin continuously as origin advanced.
31-minute soak, checks every 5 min: zero new snapshot commits, tree clean at all 6 readings, ahead/behind closing to 0/0 at the final reading (c84bbcfa1).
One transient: 12:52:05 fetch ref-lock collision between concurrent fetchers — one FAIL git fetch, self-healed next cycle; not a divergence event.
First post-reconciliation keeper run (13:23): completed with no snapshot on the code primary and no divergence.
Handoff / watch (postdates this fix)
As of ~13:30 the primary has fresh tracked dirt — pkgs/id/src/world/core.rs, pkgs/id/src/world/tests.rs (+1 more file, ~194 insertions and growing) — the deploy side's in-flight compile fix being edited in the primary. pm-git-sync is (correctly) holding pulls while the tree is dirty. Until PR #4525's keeper is deployed, if that dirt is still present at a keeper run after the base has gone stale, the old keeper can re-create this divergence, this time carrying WIP. Owner of that dirt should land it or move it to a worktree promptly; the durable protection lands with the next switch.
Activity
dezren39 commentedon Nov 2, 2026
Intake review
Related: Relates to the standing fleet rule that primary clones stay on main + clean (pm-git-sync enforcement); code issue #1413 is the CI-first/primary-clone policy issue. No PR fixes this — it is a laptop state repair.
Notes: Filed with no labels; this pass adds kind/infrastructure, status/needs-triage, priority/high (fleet sync infrastructure is blocked), effort/m, acceptance criteria, meta/enriched.
Risks: The snapshot commits may contain the only copy of laptop-side session state; realignment must inventory them before any reset — discarding them risks the 2026-10-25-class loss. No force-push and no destructive reset under any reading of this issue.
Suggested approach: Inventory the snapshot commits vs origin/main, land or archive each, then ff the primary and watch one pm-git-sync cycle succeed.
— fleet monitor intake enrichment, 2026-11-02.
dezren39 commentedon Nov 2, 2026
Structural follow-on filed as #4544: split
.opencode/opencode.jsoncinto the tracked configured default plus a runtime overlay at~/.local/state/opencode/opencode-runtime.jsonc, so the automated writers named there (sync-models' provider-catalog sync, the server'sshellwrite) stop dirtying this tree at the source. #4525 fixed the keeper's stale-base commit; #4544 removes the drift the keeper was committing.dezren39 commentedon Nov 2, 2026
Fixed at the root and reconciled — closing.
What was constantly changing, and who wrote it
Not a runaway process. Diffing all three snapshot commits:
30c079fcc(08:27) andb60e5695e(09:26): only.opencode/opencode.jsonc— deliberate config edits (the 2026-11-02 Luna seat trim, its same-morning refinement/revert, and the Spark#xhigheffort-audit pin) written into the live primary tree, which is where the OpenCode server reads that config from. Legitimate content; the venue is the hazard.d5359cb64(11:40):pm-stack/opencode-claimant/poll.py+10 — the Move opencode executions to laptop-side scheduled tasks — retire the Muse boot handoff #3026 claimant stopgap deploy.The mechanism (the actual bug)
laptop-repo-keepersnapshot-committed dirty tracked files before checking ahead/behind. pm-git-sync (every 30s) cannot pull a dirty tree, so any in-tree edit leaves the primary behind within minutes; the hourly keeper then committed that dirt onto the stale base, putting the primary ahead AND behind in a single step. After that, the keeper's own rules make it permanent: diverged → "left alone", push → rejected, pm-git-sync ff-only → FAIL every cycle (first FAIL 09:51; still failing at 11:40 while the keeper kept committing on top).Fix at the source
PR #4525 (merged
72239e49a): the keeper now computes ahead/behind immediately after its fetch and refuses to snapshot when behind > 0 — loud report line, dirt left visible in the tree for reconciliation instead of becoming a poison commit. Dirty + up-to-date keeps the existing snapshot + push safety net. New tests innixos/home/laptop-repo-keeper.test.sh(dirty+behind → no commit, edit left dirty, refusal reported; dirty+current → snapshot commits and pushes); full suite passes on the laptop.Deployment note: the keeper unit is store-built, so the patched keeper takes effect at the next Nix switch. Until then, the reconciled tree + pm-git-sync keep the primary current, which keeps any old-keeper snapshot on an up-to-date base (the healthy path).
Local-only commits dispositioned (nothing discarded blind)
All six local-only commits were diffed before any surgery:
30c079fcc,b60e5695e,d5359cb64: content is identical to what is on origin/main now (local-side diff since merge-base =flake.lockonly) — the same config/poll.py content reached origin through the normal flow. Verdict: content-redundant, zero unique work.cfc9b9256,cf7c6f93f(opencode_2→424c8d6f→401ba065) and the deploy merges1cb899ba8/01d736c81: real deploy work — preserved by reconciling via merge + push, not reset.Reconciliation: scratch-clone merge test was clean first; then the primary merged origin/main and pushed (
c9f0309cf..ecb96bbc8). GitHub's main ref verified == local HEADecb96bbc8via API read; no switch was in progress and no switch was run by this fix.Soak evidence (2026-11-02 12:31 → 13:31 CST)
ok clean main, up to date at ecb96bbc8; it then kept the primary tracking origin continuously as origin advanced.c84bbcfa1).FAIL git fetch, self-healed next cycle; not a divergence event.Handoff / watch (postdates this fix)
As of ~13:30 the primary has fresh tracked dirt —
pkgs/id/src/world/core.rs,pkgs/id/src/world/tests.rs(+1 more file, ~194 insertions and growing) — the deploy side's in-flight compile fix being edited in the primary. pm-git-sync is (correctly) holding pulls while the tree is dirty. Until PR #4525's keeper is deployed, if that dirt is still present at a keeper run after the base has gone stale, the old keeper can re-create this divergence, this time carrying WIP. Owner of that dirt should land it or move it to a worktree promptly; the durable protection lands with the next switch.feat(opencode): split opencode.jsonc into tracked default + runtime o…