Skip to content

Say a remote obsync has never reached, and an origin that authenticates differently - #52

Merged
andyroberts2 merged 1 commit into
mainfrom
fix/remote-scheme-and-never-reached
Sep 1, 2026
Merged

Say a remote obsync has never reached, and an origin that authenticates differently#52
andyroberts2 merged 1 commit into
mainfrom
fix/remote-scheme-and-never-reached

Conversation

@andyroberts2

Copy link
Copy Markdown
Owner

A vault whose own origin was an ssh URL under an https:// OBSYNC_REPO committed for an hour, pushed nothing, and said one line about it — the startup line. Found while diagnosing a real deployment.

Three separate things made that silence, and this fixes all three.

Why it was silent

  • The network half fails before the push, so no push is ever attempted and §9's stateNeverPushed is never reached.
  • A fetch that fails is an aborted run, reported at debug alone (internal/loop/tier.go:149).
  • An unreachable remote is healthy until the 24h ceiling (internal/status/status.go:175).

So a deployment nobody has ever seen work reads exactly like one with nothing to do, for a day.

And gate 5 passed it: the comparison discards the scheme by design, so [email protected]:owner/vault.git and https://github.com/owner/vault.git are the same (host, path) pair. That is right about where bytes go and blind to how obsync authenticates.

What changed

  1. A network half that has never once got all the way through says so, once, at the persistence threshold (5 ticks), and says so again when the remote finally answers. A WARN, not a verdict — the health surface is deliberately untouched, because an unhealthy container invites the restart §7 refuses on a remote that is merely down. TestAVaultWaitingOnADownRemoteHasNotAttemptedAPush still passes unchanged.
  2. The credential path is compared where the scheme belongs. New config.CredentialPath — a credential file, key material, or nothing. An origin whose credential path differs from the configured remote's is one WARN at bootstrap and refuses nothing: a mounted deploy key under an https:// OBSYNC_REPO syncs perfectly, and TestAnOriginSwappedFromHttpsToSshIsTheSameRepoAndNotAFreeze still passes unchanged.
  3. obsync says what it resolved beside what it was told: one INFO line with the origin's scheme, its normalised pair and the tracked branch. Never the raw URL — an operator may put a token in an origin.

Plus the folder question that came with it: git records files, so a folder with no notes in it is not something any git can carry. Measured, documented in README.md and docs/operations.md, and obsync will not write a .gitkeep into a human's vault to hide it.

Declared surface

Unchanged. No new variable, no subcommand, no change to the health contract or to what obsync writes into the vault. docs/interface.md is untouched.

Verification

Run in the image the Dockerfile pins, plus golangci-lint at the version CI pins:

  • go test ./... — ok, full suite; -count=5 on the new tests and the two closest existing ones.
  • go vet ./..., gofmt -l . — clean. golangci-lint run ./... — 0 issues.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VeCuDU56kAB5yuJ3N9jZyp

…es differently

A vault whose own `origin` was an ssh URL under an `https://` OBSYNC_REPO
committed for an hour and pushed nothing, and said one line about it: the
startup line. Three separate things made that silence, and this fixes all
three.

The network half fails before the push, so nothing was ever attempted and
§9's never-pushed state was never reached; a fetch that fails is an aborted
run, which reports nothing above debug; and an unreachable remote is healthy
until the 24h ceiling. A deployment nobody has ever seen work therefore reads
exactly like one with nothing to do, for a day.

  * A network half that has never once got all the way through says so, once,
    at the persistence threshold, and says so again when the remote finally
    answers. A WARN and not a verdict: the health surface is deliberately
    untouched, because an unreachable remote is healthy until the ceiling
    whatever obsync says about it, and an unhealthy container invites the
    restart §7 refuses on a remote that is merely down.

  * Gate 5 goes on comparing host and path alone — that is right, and a
    mounted deploy key under an https OBSYNC_REPO syncs perfectly. What the
    scheme decides is named instead: the credential path, which is a
    credential file, key material, or nothing. An origin whose credential path
    differs from the configured remote's is one WARN at bootstrap, and refuses
    nothing.

  * obsync says what it resolved beside what it was told: one INFO line
    carrying the origin's scheme and normalised pair, and the tracked branch.
    OBSYNC_REPO is read for the clone and for gate 5, and every fetch and push
    goes to the vault's own origin — so an operator was otherwise reading a
    URL obsync may never have contacted. The normalised pair and never the URL
    itself, because an operator may put a token in an origin.

Also documents the folder question that came with it: git records files, so a
folder with no notes in it is not something any git can carry, and obsync will
not write a .gitkeep into a human's vault to hide that.

The three tests asserting that a run which changed nothing says nothing now
read the log with bootstrap's own line taken off. §9's quiet is a property of
a run, and bootstrap is not one — the startup line it sits beside was already
excluded from that buffer.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VeCuDU56kAB5yuJ3N9jZyp
@andyroberts2
andyroberts2 merged commit f0d5ecf into main Sep 1, 2026
5 checks passed
@andyroberts2
andyroberts2 deleted the fix/remote-scheme-and-never-reached branch September 1, 2026 14:56
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