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
- Variables
- func HasFailures(results []Result) bool
- func NeedsAttention(rows []Row) bool
- func ValueHash(value map[string]any) (string, error)
- type Entry
- type LockFile
- type Manager
- func (m *Manager) Adopt(ctx context.Context, client, name string) (Result, error)
- func (m *Manager) DriftedClients(ctx context.Context, port int) (map[string]bool, error)
- func (m *Manager) DropRecord(ctx context.Context, client, name string) (Result, error)
- func (m *Manager) LinkClient(ctx context.Context, prov provisioner.ClientProvisioner, configPath string, ...) (Result, error)
- func (m *Manager) LockPath() string
- func (m *Manager) RecordedHash(ctx context.Context, client, name string) (string, error)
- func (m *Manager) Registry() *provisioner.Registry
- func (m *Manager) Statuses(ctx context.Context, opts StatusOptions) ([]Row, error)
- func (m *Manager) Sync(ctx context.Context, opts SyncOptions) ([]Result, error)
- func (m *Manager) UnlinkClient(ctx context.Context, prov provisioner.ClientProvisioner, ...) (Result, error)
- type Result
- type Row
- type StatusOptions
- type SyncOptions
Constants ¶
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.
const ( ActionLinked = "linked" ActionUpdated = "updated" ActionUnchanged = "unchanged" ActionAdopted = "adopted" ActionRemoved = "removed" ActionAlreadyGone = "already-gone" ActionNotLinked = "not-linked" ActionSkippedForeign = "skipped-foreign" ActionSkippedDrift = "skipped-drift" ActionError = "error" ActionWouldLink = "would-link" ActionWouldUpdate = "would-update" ActionWouldAdopt = "would-adopt" ActionWouldRemove = "would-remove" )
Result actions.
const ChannelMergeKey = "merge-key"
ChannelMergeKey is the only wiring channel: gridctl owns one key inside a shared client config file, never the file itself.
const DefaultServerName = "gridctl"
DefaultServerName is the config entry key gridctl writes when no group-specific name applies.
Variables ¶
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 ¶
HasFailures reports whether any result needs the caller's attention.
func NeedsAttention ¶
NeedsAttention reports whether any row requires action. Missing rows (detected but never linked) are advisory and do not count.
func ValueHash ¶
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 ¶
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 ¶
NewManagerWithHome builds a Manager rooted at an explicit home directory, with the full client registry.
func (*Manager) Adopt ¶
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 ¶
DriftedClients reports which clients currently have at least one recorded entry in the drifted state. Feeds the Connections badge.
func (*Manager) DropRecord ¶
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) RecordedHash ¶
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 ¶
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 ¶
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).