Artifact dd0c8f90b63247e1514ad8dfd4e0f9f0e0651a5f8993f0c9bb2826a248d51389:
- File
hub/clone.go
— part of check-in
[6f9e3e40d0]
at
2026-05-12 20:27:38
on branch trunk
— feat(hub): cross-leaf fossil sync over NATS (#156) (#157)
Add Config.ProjectCode + Config.SeedFromUpstream so multiple hubs sharing a project-code propagate commits over a single .sync subject. Adds an auto-publish notification on a sibling .commit subject + pull-on-notify subscriber, closing the cross-process Fossil sharing gap from #156.
- hub/nats_transport.go: libfossil.Transport over nats request/reply - hub/clone.go: HTTP-based SeedFromUpstream helper (NATS-clone deferred) - hub/repo.go: Repo.publish hook fired after successful Commit - hub/hub.go: startCommitSubscriber + Config plumbing + NoEcho - hub/cross_leaf_test.go: gold-path propagation, subject alignment, drift guard - libfossil pin -> v0.6.1 (CreateOpts.ProjectCode)
Design: docs/superpowers/specs/2026-05-12-cross-leaf-fossil-sync-design.md Protocol: docs/architecture/sync-protocol.md ("NATS-Wrapped Sync")
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> (user: [email protected], size: 1797) [annotate] [blame] [check-ins using]
package hub import ( "context" "fmt" "net/url" "os" libfossil "github.com/danmestas/libfossil" ) // seedFromUpstream clones a fossil repo at path from the given HTTP xfer // endpoint URL. The cloned repo carries the upstream's project-code, so // it can join the upstream's NATS fossil-sync subject after open. // // Validates that the URL is well-formed and has an http(s) scheme. // NATS-native clone is deferred until libfossil HandleSync supports the // clone protocol upstream (CDG-148). // // If expectedProjectCode is non-empty, asserts the cloned repo's // project-code matches it. The cloned repo is removed before returning // the mismatch error so the caller can retry or give up cleanly. func seedFromUpstream(ctx context.Context, path, upstreamURL, bootstrapUser, expectedProjectCode string) error { u, err := url.Parse(upstreamURL) if err != nil { return fmt.Errorf("hub: parse SeedFromUpstream %q: %w", upstreamURL, err) } if u.Scheme != "http" && u.Scheme != "https" { return fmt.Errorf("hub: SeedFromUpstream %q: only http(s) is supported (NATS-clone deferred to libfossil HandleSync support)", upstreamURL) } transport := libfossil.NewHTTPTransport(upstreamURL) repo, result, err := libfossil.Clone(ctx, path, transport, libfossil.CloneOpts{ User: bootstrapUser, ProjectCode: expectedProjectCode, }) if err != nil { return fmt.Errorf("hub: clone from %s: %w", upstreamURL, err) } if err := repo.Close(); err != nil { return fmt.Errorf("hub: close cloned repo: %w", err) } if expectedProjectCode != "" && result.ProjectCode != expectedProjectCode { _ = os.Remove(path) return fmt.Errorf("hub: cloned repo has project-code %q, want %q (config drift between hub and upstream)", result.ProjectCode, expectedProjectCode) } return nil }