fix: stop branch-reconcile probing origin on a repo that has none - #6080
Merged
Conversation
The read-only leftover-branch detector calls gatherBranchState once per managed app, and an app's repoPath can be a directory that was never a clone (a static-site folder, a checkout whose remote was never added). gatherBranchState resolved origin and computed hasOrigin, then ran `git ls-remote --heads origin` anyway — so every detector cycle logged `❌ branch-reconcile: git ls-remote origin failed` for that app, for a repo with no remote to read and no candidate branches to judge. It does not throw on a non-repo either, so the detector's own try/catch never fired and nothing named the app. Gate the remote read on the hasOrigin the gather already has, matching the gate reconcile() applies at both of its own remote reads for exactly this reason. `null` there is the established "could not ask" value that reconcile() already passes explicitly for an origin-less repo. Also name the repo and git's own reason in the failure line: one log line serves three call sites across every managed app, so a bare "ls-remote failed" told you neither which repo went unread nor whether it was a network blip, an unauthenticated remote, or no remote at all. Claude-Session: https://claude.ai/code/session_01FBgckWpLV6qzytK9vKnVvU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The server log was emitting an unactionable error on a loop:
Root cause.
gatherBranchStateresolvesoriginand computeshasOrigin, then firedgit ls-remote --heads originin its read fan-out regardless of that verdict.reconcile()gates both of its own remote reads onhasOriginprecisely because "probing one every cycle would log a failure forever" — the gather never got that gate.The caller that made it visible is the read-only leftover-branch detector (
userActionDetectors.js:75), which callsgatherBranchStateonce for every managed app. An app'srepoPathcan be a directory that was never a clone (a static-site folder, a checkout whose remote was never added), sols-remoteexited 128 there on every detector cycle — for a repo with no remote to read and zero candidate branches to judge.gatherBranchStatedoesn't throw on a non-repo (it returns 0 inputs), so the detector's owntry/catchnever fired and nothing named the offending app.What changed
gatherBranchStategates the remote read on thehasOriginit already has — the same gatereconcile()applies at both of its remote-reading sites.nullthere is the established "could not ask" value thatreconcile()already passes explicitly for an origin-less repo, so the sole consumer (upstreamGone) is unaffected: it requiresfalsefor both senses ofnull, and an origin-less repo has noorigin/*upstream to begin with. Fail-safe direction — nothing reads as "shipped", nothing gets reaped.execGit(30s timeout, spawn failure) and a non-zero exit previously collapsed into the same message; they are now distinguishable.Test plan
gatherBranchState"skips the remote probe on a repo with no origin" — asserts nols-remotespawn and no error log (failed pre-fix:ls-remotewas called).reapOrphanedRemotes"names the repo and git's own reason when the remote cannot be read" (failed pre-fix: the line contained neither).server/services/branchReconcile.test.js+userActionDetectors.test.js: 156 passed.npm test(server + client): 1908 files / 38506 tests passed, 0 failures.gatherBranchStateon the real non-git app path no longer logs, PortOS's own gather still resolves its branches, and a directlistRemoteHeadscall still reports — now naming the repo and the cause.https://claude.ai/code/session_01FBgckWpLV6qzytK9vKnVvU