seam

package
v1.0.0-rc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

Documentation

Overview

Package seam holds the registration mechanism the open-core seams share.

Per D6 the private companion repository replaces a seam's implementation by blank-importing a package whose init() registers its own. Go initialises an imported package before its importer, so a default registered in the seam package's own init() is always in place before a companion's init() runs, and the companion always wins. No build tags, no stubbed files in the public tree. It is the mechanism swarmcli-be already uses.

That argument holds only while the default lives in the package the companion imports. A default in a package of its own — swarms/local, which is there so that the seam does not drag the Docker applier in behind it — is an unrelated sibling of the companion's, and gc initialises siblings in import-path order, which nothing about the two implementations controls. Such a default must register only if nothing has, and swarms/local says why at its own init(). The rule for anything added here: a default that is not in the seam package does not overwrite.

Two shapes cover every seam. Slot holds one implementation and registering replaces it: there is exactly one answer to "which swarm registry is in force". List holds every implementation and returns all of them: a companion adding a Slack notifier must not remove the log notifier or the API's event stream.

When registration is over

The two shapes settle at different times, and consumers may rely on it.

A Slot is settled by the end of init(). Every replacement comes from a blank import, so by the time main runs there is nothing left to register, and a consumer may read Get once and keep the result — which api.New, reconcile.New and prune.New all do.

A List is not. The API server registers itself as a notifier during wiring, long after every init() has run, so notify.Dispatch re-reads All on every event. A consumer that snapshotted a List at construction would silently drop whatever registered after it, and for notify that is the UI's live updates.

Entitlement gating is not a re-registration

The consequence, for the licence package docs/extensibility.md sketches: an implementation whose entitlement lapses must start refusing, from inside itself. It must not be swapped out of a Slot at runtime. Half the consumers would never see the swap — they hold the old value — and the half that did would see it mid-flight: replacing a swarms.Registry under a running reconcile hands a half-finished sync a different daemon. The mutexes here make registration safe against a concurrent read; they do not make a live replacement meaningful.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type List

type List[T any] struct {
	// contains filtered or unexported fields
}

List holds every registered implementation of T, in registration order. The zero List is ready to use.

func (*List[T]) All

func (l *List[T]) All() []T

All returns every registered implementation. The result is a copy, so a caller ranging over it cannot race a late registration.

func (*List[T]) Names

func (l *List[T]) Names() []string

Names returns the names of every registered implementation, in the same order as All.

func (*List[T]) Register

func (l *List[T]) Register(name string, v T)

Register appends an implementation. Unlike Slot.Register it removes nothing.

type Slot

type Slot[T any] struct {
	// contains filtered or unexported fields
}

Slot holds exactly one implementation of T. The zero Slot is ready to use and returns the zero T until something registers.

func (*Slot[T]) Get

func (s *Slot[T]) Get() T

Get returns the registered implementation.

func (*Slot[T]) Name

func (s *Slot[T]) Name() string

Name returns the name of the registered implementation, or "" if nothing has registered.

func (*Slot[T]) Register

func (s *Slot[T]) Register(name string, v T)

Register replaces the current implementation. Name is what the controller logs at startup, so an operator can tell from the logs whether a companion's implementation actually loaded.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL