Files
mesh-sdk/go/catalogue/resolve.go
T
jschoubben 1c7356c247
mesh/delivery-group group feat/sdk1 rejected: composed together: the checker's verdict at the members' heads (428d048dd50a): unit: git.novox.be/novox/mesh-sdk/…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: unit: git.novox.be/novox/mesh-sdk/go/process.TestStatePutWritesAKeyWhole: a Put through a short blackout: 0, mesh-mail's state send…
catalogue: the composition's rules and refusals leave for the node-engine, so mesh-sdk renders no declaration and refuses no composition (ADR 0593 §7)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 19:19:25 +01:00

272 lines
15 KiB
Go

package catalogue
// Node is what resolution needs to know about the machine.
type Node struct {
Name string
Site string
// Capabilities the machine actually has, as its profile reported them. Only the present ones
// — a capability that was looked for and not found is the same as one nobody looked for, as
// far as deciding what may run here goes.
Capabilities map[string]bool
// At is this machine's own name on the private network, empty if it is not on one. Needed to
// tell whether it can reach the node answering its requirements at all.
At string
// PublicDomain is the domain this node composes its routed names under, empty if it has none
// (novox/hq ADR 0066). A route contribution carries only a label — the subdomain — and the mesh
// joins <label>.<public-domain> to make the name it grants, interpreting neither half.
PublicDomain string
// Account is the operator's login on this machine, AccountHome where its home is (novox/hq
// to-be 29). What a home-scoped file is owned by and what ${machine:account} resolves to.
Account string
AccountHome string
// AgentAccount is the login agents run as here when it is not the operator's, AgentAccountHome its
// home when not derived (novox/hq ADR 0266). What ${machine:agent-account} resolves to; empty means
// agents run as the operator account.
AgentAccount string
AgentAccountHome string
}
// World is what the rest of the mesh already has.
//
// Some requirements cannot be answered on the machine that has them — a database runs somewhere
// and is reached over the network — so resolving one node needs to know what the others offer.
type World struct {
// Held is the claims already taken, for the scopes wider than one node.
Held []Held
// Holdings is every seat whose holder is **on record** (novox/hq ADR 0131): the one assignment
// that holds it, chosen by a handover. A seat absent here is held by derivation — the sole
// eligible assignment — as it always was. Present, it decides, and any other assignment whose
// module could hold the seat is eligible and silent rather than refused.
Holdings []Held
// Offered is what other nodes provide at mesh scope, and everything needed to use it.
Offered map[string][]Provider
// Pinned is which provider this machine was told to get a provision from, by name: a module and
// the node it runs on, both (novox/hq #258). Only consulted when more than one could answer -- a
// choice recorded before it was needed should not start meaning something the day a second
// provider appears, and one recorded and then made unnecessary should not quietly stop applying
// either.
Pinned map[string]Chosen
// Bound is where each of this machine's consumers was bound for a provision that keeps its data
// (novox/hq ADR 0232), by consumer module then provision: the provider it was last sent, as the
// store recorded it. A resolution that would answer such a consumer from anywhere else keeps it
// where it is and says so (Resolution.Kept); only a pin naming the other provider moves it.
Bound map[string]map[string]Chosen
// Licences is every provision answered by a **record rather than a node**, by provision name.
//
// novox/hq ADR 0024: a hosted model is on nobody's machine and is reached over the public
// internet, so the rule that refuses two ends sharing no private network must not apply to
// it. These are the candidates a refusal names.
Licences map[string][]Record
// Using is which record this node's modules were put on, keyed by module then provision.
//
// Per consumer, because that is the whole point: saying WHICH licence a given thing uses. Two
// modules on one machine using different accounts is ordinary rather than a collision.
Using map[string]map[string]Record
// Unchecked takes brokered requirements on trust instead of refusing when nothing answers
// them.
//
// For the first of two passes. Working out what a node offers the mesh needs that node
// resolved, and resolving it may need what the mesh offers — so the first pass answers only
// *what does each node offer*, and the second pass answers everything with that in hand. A
// declaration is never built from an unchecked resolution.
Unchecked bool
}
// Record is a provision answered by something the mesh holds rather than by a machine.
//
// The name is the operator's — *the personal account*, *the organisation's* — because the whole
// point is saying which one a consumer uses, and an anonymous credential hanging off a provider
// cannot be said (novox/hq ADR 0024).
type Record struct {
// Name is what a person calls it, and what a consumer is put on.
Name string
// Serves is what a consumer must know that is not secret — a base URL, a model name.
Serves map[string]any
}
// Provider is one node answering a mesh-scoped requirement.
type Provider struct {
// Node is the machine.
Node string
// At is its name on the private network, or empty if it is not on one. The mesh's half of
// the answer: a module can say it serves on port 5432, and only the mesh knows where.
At string
// Serves is what the providing module said a consumer needs to know, settled.
Serves map[string]any
// Module is which module on that node provides it. A provider is a (node, module) pair
// (novox/hq to-be 23), and the pair is what tells the holder of a seat apart from another module
// providing the same thing (ADR 0110).
Module string
// LeftOut says each served key left out of Serves because that node composes no name it asks
// for (novox/hq ADR 0346 §3): said under each consumer's need.
LeftOut []string
}
// Held is a claim somebody already has, used for the scopes wider than one node.
type Held struct {
Claim string
Scope string
Node string
Module string
Site string
// Kind is the kind a kinded bench is held as (novox/hq ADR 0234 §2): each kind is its own holder.
Kind string
}
// Resolution is what a node should run, and why.
type Resolution struct {
// Node is which machine this was resolved for, so a generator can be asked about it.
Node string
// At is this machine's own name on the private network, empty if it is not on one. Kept
// because a consumer bound to something answered on this same machine still has to be told
// where it is — the answer being local does not make the port guessable.
At string
// PublicDomain is the domain this node composes its routed names under, empty if it has none
// (novox/hq ADR 0066). Carried from the node so that composing <label>.<public-domain> for a
// route contribution needs no store lookup here — the join is a fact about this one machine.
PublicDomain string
// Account and AccountHome are the operator's login on this machine and where its home is
// (novox/hq to-be 29), carried from the node so a home-scoped file's owner and path resolve
// here without a store lookup.
Account string
AccountHome string
// AgentAccount and AgentAccountHome are the account agents run as here when it is not the
// operator's, and its home (novox/hq ADR 0266); empty when agents run as the operator account.
AgentAccount string
AgentAccountHome string
// Capabilities are the machine's, as its profile reported them, carried from the node so a
// contribution placed only where the machine has something (`if-capability`, novox/hq ADR 0255)
// is decided here without a store lookup.
Capabilities map[string]bool
// Modules in the order they were resolved: assigned first, then what they pulled in.
Modules []Manifest
// Because says why each module is here — assigned, or required by something.
Because map[string]string
// Claims is what this node's set holds, so wider scopes can be checked against it.
Claims []Held
// Needs is what this node's set gets from other nodes. Recorded rather than resolved away,
// because it is where a credential will have to be handed back once there is a mechanism for
// that, and because "what does this machine depend on that is not on it" has no other answer.
Needs []Needed
// Unhostable is what a person assigned to this machine that this machine cannot run — a module
// whose declared capability has no detector here. Kept out of Modules rather than refusing the
// whole set: a module put on the wrong machine is that one module's problem, and the healthy
// modules beside it still resolve, declare, and converge. Reported so it is neither silently
// dropped nor fatal to the rest. A module that is *required* by something running here is a
// different case — that set is incoherent and is refused (see checkCapabilities).
Unhostable []Unhostable
// Unheld is every dependency of this node's modules on a seat nothing here holds (novox/hq ADR
// 0207) — reported rather than refused while enforceSeatDependencies is off, so a node short of a
// holder still converges and `status` says what it is short of.
Unheld []Unheld
// Kept is every consumer this resolution would have moved to another provider of a provision
// that keeps its data, and did not (novox/hq ADR 0232): it stays bound where its data is, and the
// controller raises an urgent condition naming the move until a person pins one or the other.
Kept []KeptBinding
// Absent is every optional requirement of this node's modules that nothing assigned answers
// (novox/hq ADR 0330 §3): left unbound rather than refused, with nothing installed for it, and
// listed by `plan` and `node` (§7). It binds on the first composition after a provider is assigned.
Absent []Absent
}
// Unhostable is one directly-assigned module the machine cannot run.
type Unhostable struct {
// Module is the assigned module the machine cannot host.
Module string
// Missing is the capabilities it declares that this machine does not have.
Missing []string
}
// Needed is one thing this node's set takes from elsewhere in the mesh.
type Needed struct {
// Name is the provision, as required.
Name string
// From is the node providing it.
From string
// At is where that node is on the private network.
At string
// Serves is what the providing module said a consumer needs to know.
Serves map[string]any
// ByRecord means this was answered by something the mesh holds rather than by a machine, so
// there is no node to reach and no private network to share. Its credential comes from
// wherever that record's does, not from the pair-wise secret two machines share.
ByRecord bool
// Sealed is the credential, closed to this node. Filled in after resolving, because whose
// credential it is only becomes answerable once which node answers has been settled.
Sealed string
// For is the module that wanted it.
For string
// Local is the name this credential goes by inside that module, where the module wants several
// for one requirement (ADR 0094); empty for the ordinary one. Part of what identifies the pair
// credential, so two secrets from one provider to one module are two secrets.
Local string
// SharedOwn is set when the provision's credential is one of the provider's own secrets, shared
// by every consumer (novox/hq ADR 0158): the name of that secret in the provider's definition.
// The plan mints the pair's copy from the provider's value rather than a value of its own.
SharedOwn string
// CredentialForm is the credential form the provider's offer declares (Manifest.CredentialFormOf, issue 768),
// named in a handed consumer's plan for the vault; empty where the provider's manifest is not in hand.
CredentialForm string
// CredentialTool is the tool of the offer that the provider's software issues the credential through (issue 928).
CredentialTool string
// Manager is set when this holder is a refreshable-grant licence's MANAGER, delivered the refresh
// token rather than an access token (novox/hq ADR 0050). It changes one thing downstream: an empty
// Sealed is tolerated — the manager has not adopted a refresh token yet, which is a real waiting
// state, not a consumer missing its key. Set by the plan, which is the only layer that knows a
// licence's manager; empty for every consumer.
Manager bool
// LeftOut says each served key the provider left out, because its machine composes no name the
// value asks for (novox/hq ADR 0346 §3).
LeftOut []string
// Module is the providing module on From, empty for a need answered by a record or by nothing
// that serves it. A provider is a (node, module) pair (novox/hq to-be 23), and a binding to data
// is a binding to the pair (ADR 0232).
Module string
// KeepsData is set when the provision keeps what its consumer writes (novox/hq ADR 0232): the
// binding is to the consumer's data, recorded when it is sent and moved only by a pin.
KeepsData bool
// Identity is the longest consumer identity the answering provision keeps (novox/hq ADR 0225),
// from the provider's own offer: what the mesh judges this consumer's identity against, on the
// consumer's side for `status` and on the provider's before it grants. No bound for a provision
// answered by a record, which keeps no name of anybody's.
Identity IdentityBound
// IssuedToHolder is set when the vault keeps this need's credential for this holder alone (issue 757): the
// providing module is marked moved and its software issues the provision's credential for each holder (issue
// 749), kept as provision/<From>/<Name>/<node>/<For>. Where the consumer is handed to the provisioner, its
// machine's client asks the vault for it and the declaration carries no value. Set by the plan, which reads the
// provider's manifest.
IssuedToHolder bool
// ProviderMoved is set when the providing module is marked moved (issue 788): a handed consumer's template may
// then name `${bound:<provision>:<key>}` and `${secret:<provision>}`, which its machine's client fills from the
// provider's entry and the vault. Set by the plan, which reads the provider's manifest.
ProviderMoved bool
// AnsweredByHelper is set when the providing module's offer says the provider helper answers it (issue 792): a
// provision the seat mesh-provisioner keys whether or not its consumer is handed (Keyed). Set by the plan, which
// reads the provider's manifest.
AnsweredByHelper bool
}
// Offers is a list of node-scoped provisions, which is what nearly everything is.
func Offers(names ...string) []Offer {
out := make([]Offer, 0, len(names))
for _, n := range names {
out = append(out, Offer{Name: n})
}
return out
}
// FromAnywhere is a provision answered by whichever node in the mesh runs it.
func FromAnywhere(names ...string) []Offer {
out := make([]Offer, 0, len(names))
for _, n := range names {
out = append(out, Offer{Name: n, Scope: ScopeMesh})
}
return out
}
// ContainerGroups is the capability a node-engine reports when it reads a container's `groups` and passes each as a
// supplementary group (novox/hq ADR 0480 clause 7, issue 1638). An older engine refuses the key (strict decoding).
const ContainerGroups = "container-groups"