wiring

package
v0.1.0-rc.1 Latest Latest
Warning

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

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

Documentation

Overview

Package wiring records ownership of the gateway entries gridctl merges into client MCP configs (the `gridctl link` surface). It is the wiring-kind tenant of the pkg/project engine, with key-level ownership inside files gridctl does not otherwise own: every link records the (client, config path, entry name) it wrote plus a canonical hash of the written value, so unlink, drift, adopt, and doctor are decided from recorded state, never inferred from entry shape (Article XVI). All client-format knowledge stays in pkg/provisioner; this package only decides ownership and delegates the byte-level work.

Index

Constants

View Source
const (
	StateInSync        = "in-sync"
	StateStale         = "stale"
	StateDrifted       = "drifted"
	StateTargetMissing = "target-missing"
	// StateForeign marks an entry at a gridctl name with no record: it
	// is never deleted and only overwritten with --force (or adopted).
	StateForeign = "foreign"
	// StateMissing marks a detected client with nothing recorded and
	// nothing present: the doctor "detected but not linked" row.
	StateMissing = "missing"
)

Wiring states. in-sync, stale, drifted, and target-missing come from the engine vocabulary; foreign and missing are wiring extensions.

View Source
const (
	ActionLinked             = "linked"
	ActionUpdated            = "updated"
	ActionUnchanged          = "unchanged"
	ActionAdopted            = "adopted"
	ActionRemoved            = "removed"
	ActionAlreadyGone        = "already-gone"
	ActionNotLinked          = "not-linked"
	ActionSkippedForeign     = "skipped-foreign"
	ActionSkippedDrift       = "skipped-drift"
	ActionSkippedUnavailable = "skipped-unavailable"
	ActionError              = "error"
	ActionWouldLink          = "would-link"
	ActionWouldUpdate        = "would-update"
	ActionWouldAdopt         = "would-adopt"
	ActionWouldRemove        = "would-remove"
)

Result actions.

View Source
const ChannelMergeKey = "merge-key"

ChannelMergeKey is the only wiring channel: gridctl owns one key inside a shared client config file, never the file itself.

View Source
const DefaultServerName = "gridctl"

DefaultServerName is the config entry key gridctl writes when no group-specific name applies.

Variables

View Source
var (
	// ErrForeign marks an entry at gridctl's name that gridctl never
	// recorded. It is never deleted, and only overwritten with --force.
	ErrForeign = errors.New("entry was not recorded by gridctl")
	// ErrDrifted marks a recorded entry whose current value matches no
	// recorded hash: it was edited after gridctl wrote it.
	ErrDrifted = errors.New("entry was edited since gridctl wrote it")
	// ErrNotRecorded marks an unlink of something neither present nor
	// recorded.
	ErrNotRecorded = errors.New("nothing recorded for this client entry")
	// ErrNothingToAdopt marks an adopt of an entry that does not exist.
	ErrNothingToAdopt = errors.New("nothing to adopt")
	// ErrCannotPlan marks a provisioner that cannot report its planned
	// entry value; ownership hashing is impossible without it.
	ErrCannotPlan = errors.New("provisioner cannot plan its entry value")
	// ErrUnknownClient marks a slug the provisioner registry does not know.
	ErrUnknownClient = errors.New("unknown client")
	// ErrNotDetected marks a known client with no config detected on this
	// system.
	ErrNotDetected = errors.New("client is not detected on this system")
)

Sentinel errors callers branch on.

Functions

func HasFailures

func HasFailures(results []Result) bool

HasFailures reports whether any result needs the caller's attention.

func NeedsAttention

func NeedsAttention(rows []Row) bool

NeedsAttention reports whether any row requires action. Missing rows (detected but never linked) are advisory and do not count.

func ValueHash

func ValueHash(value map[string]any) (string, error)

ValueHash canonicalizes an entry value per RFC 8785 and hashes it with the engine's scheme. Values decoded from TOML or YAML configs hash identically to their JSON form, so a client rewriting its file in a different style never reads as drift. Only the hash is ever stored: entry values can carry secrets in env blocks.

Types

type Entry

type Entry struct {
	// ConfigPath is the client config file holding the owned key.
	ConfigPath string
	// Group and ClientID reproduce the link's endpoint composition so
	// status can rebuild the planned value against the current port.
	Group    string
	ClientID string
	// Hashes is the canonical value-hash history, newest last. The
	// current value matching any of them means gridctl wrote it.
	Hashes []string
	// CreatedByGridctl is false for adopted entries: gridctl owns them
	// now but did not author their current value.
	CreatedByGridctl bool
	// Pack tags the record with the pack that applied it (empty = not
	// pack-managed).
	Pack     string
	SyncedAt time.Time
}

Entry is one recorded (client, entry name) ownership record.

type LockFile

type LockFile struct {
	// Records maps client slug → entry name → record.
	Records map[string]map[string]*Entry
}

LockFile is the wiring-kind view over the unified project lockfile, keyed client slug → entry name. The engine owns the on-disk schema, versioning, and locking; this view keeps the ops code in the same shape as the other kind packages.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager owns wiring records and every ownership decision around client config entries. Mutating operations serialize on mu in-process and on the engine's cross-process lock.

func NewManager

func NewManager() (*Manager, error)

NewManager builds a Manager rooted at the user's home directory. CLI call sites only; anything tests can reach uses NewManagerWithHome.

func NewManagerWith

func NewManagerWith(home string, registry *provisioner.Registry) *Manager

NewManagerWith builds a Manager with an explicit registry. Tests use it to drive ownership decisions with fake clients.

func NewManagerWithHome

func NewManagerWithHome(home string) *Manager

NewManagerWithHome builds a Manager rooted at an explicit home directory, with the full client registry.

func (*Manager) Adopt

func (m *Manager) Adopt(ctx context.Context, client, name string) (Result, error)

Adopt records ownership of the entry's current value without rewriting it: the explicit take-ownership verb (terraform import, stow --adopt). It works both for foreign entries (pre-lockfile links) and for recorded entries that drifted (keep the user's edit).

func (*Manager) DriftedClients

func (m *Manager) DriftedClients(ctx context.Context, port int) (map[string]bool, error)

DriftedClients reports which clients currently have at least one recorded entry in the drifted state. Feeds the Connections badge.

func (*Manager) DropRecord

func (m *Manager) DropRecord(ctx context.Context, client, name string) (Result, error)

DropRecord purges an ownership record without touching any config file: the cleanup path for records whose client is no longer detected on this machine.

func (*Manager) LinkClient

func (m *Manager) LinkClient(ctx context.Context, prov provisioner.ClientProvisioner, configPath string, opts provisioner.LinkOptions) (Result, error)

LinkClient links one client with ownership recorded: the decision (write, adopt, refuse) comes from the lockfile and value hashes, and the provisioner is invoked with ownership pre-resolved. All three gridctl link surfaces (CLI, declarative apply reconcile, UI API) route through here so the lockfile never lies.

func (*Manager) LockPath

func (m *Manager) LockPath() string

LockPath returns the unified projection lockfile path.

func (*Manager) RecordedHash

func (m *Manager) RecordedHash(ctx context.Context, client, name string) (string, error)

RecordedHash returns the newest recorded hash for (client, name), or "" when nothing is recorded.

func (*Manager) Registry

func (m *Manager) Registry() *provisioner.Registry

Registry exposes the client registry the manager decides over.

func (*Manager) Statuses

func (m *Manager) Statuses(ctx context.Context, opts StatusOptions) ([]Row, error)

Statuses computes the wiring state matrix: every recorded entry, plus foreign rows (gridctl-named entries never recorded) and missing rows (clients detected with nothing recorded and nothing present) for detected clients. Reads are lock-free.

func (*Manager) Sync

func (m *Manager) Sync(ctx context.Context, opts SyncOptions) ([]Result, error)

Sync links every detected client (or the named subset) with ownership recorded: the wiring-kind counterpart of `gridctl link --all`. Bridge clients without npx are skipped, matching the CLI.

func (*Manager) UnlinkClient

func (m *Manager) UnlinkClient(ctx context.Context, prov provisioner.ClientProvisioner, configPath, name string, force, dryRun bool) (Result, error)

UnlinkClient removes one owned entry: the key is deleted only when its current value is one gridctl recorded (or --force), and the record is always purged once the key is gone so a later relink never trips over stale bookkeeping. Foreign entries are never deleted, with or without force (the Stow invariant: never delete what you do not own).

type Result

type Result struct {
	Client      string `json:"client"`
	Name        string `json:"name"`
	Target      string `json:"target,omitempty"`
	Action      string `json:"action"`
	Detail      string `json:"detail,omitempty"`
	Remediation string `json:"remediation,omitempty"`
	Error       string `json:"error,omitempty"`
}

Result describes one ownership decision for a (client, entry) pair.

type Row

type Row struct {
	Client      string     `json:"client"`
	Name        string     `json:"name"`
	Channel     string     `json:"channel"`
	Pack        string     `json:"pack,omitempty"`
	Target      string     `json:"target,omitempty"`
	State       string     `json:"state"`
	Detail      string     `json:"detail,omitempty"`
	Remediation string     `json:"remediation,omitempty"`
	SyncedAt    *time.Time `json:"synced_at,omitempty"`
}

Row is one (client, entry) line in status output.

type StatusOptions

type StatusOptions struct {
	// Port anchors the planned-value comparison (staleness) to the
	// current gateway port.
	Port int
	// ServerName is the default entry name scanned for foreign and
	// missing rows (default "gridctl").
	ServerName string
}

StatusOptions configure a status pass.

type SyncOptions

type SyncOptions struct {
	// Clients restricts the pass to these slugs. Empty means every
	// detected client.
	Clients []string
	// ServerName is the entry key to write (default "gridctl";
	// "gridctl-<group>" for group links).
	ServerName string
	// GatewayURL, Port, Group, and ClientID compose the entry exactly as
	// `gridctl link` flags do.
	GatewayURL string
	Port       int
	Group      string
	ClientID   string
	// Force overwrites foreign and drifted entries (after backup).
	Force bool
	// DryRun reports the plan without writing anything.
	DryRun bool
	// Pack tags recorded entries with the applying pack. Empty keeps any
	// existing tag (a plain link or sync never strips pack ownership).
	Pack string
}

SyncOptions configure a sync pass (the ownership-aware link --all).

Jump to

Keyboard shortcuts

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