Merge branch 'main' into soph/doctor-failed-sync-election

Commit

Stefan Haubold1mo ago

main restructured this area while the branch sat, so six files conflicted. Resolutions worth knowing:

remote_topology.go: both sides added struct fields and both call ResolveCheckpointSyncRemote โ€” main for explicitRemote (an explicit checkpoint_push_remote suppresses the ambiguity advice), this branch for electionErr. Kept both fields and collapsed the two calls into one election read two ways.

status.go: kept main's push/read-direction split (PushDisabled, resolveDedicatedReadSource, ReadFallback) and layered this branch's per-remote pinned probe on the error path. newDedicatedCheckpointSyncInfo now takes the partially built info so main's fields survive it.

setup.go / setup_checkpoint_remote.go: took main's printSetupCheckpointDestinationNote gate (silent when enable's picker already asked) and gave it this branch's headers.

remote_topology_test.go was an add/add โ€” main grew its own file at that path. Unioned both; main's two tests now pass the headers struct.

CLAUDE.md became an index over docs/development/*, so this branch's election paragraph moved to docs/development/checkpoint-implementation.md.

One expectation from main is deliberately superseded: TestCheckpointDestinationNote_ExplicitSelection/missing_selection_is_not_resolved asserted the ambiguity note still prints when checkpoint_push_remote names a missing remote. That is the case this branch changes โ€” the election fails closed, so no push carries checkpoints and the note's "any OTHER remote" framing is false. It now expects the disabled report.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com Entire-Checkpoint: 01M2QYDJH9G3JDAV0PW3X0R3ZK