The provisioner client's account stays named while the client is held: a held client keeps the node's handing (issue 774)

provisionerAccount reads the user of the client's process from this pass's plan, and a client held as its stub (or
carried as it runs) composes no process: on ace, 2026-11-04 01:29 to 01:33, the node's own composition named no
account, the node-engine refused every filled write, and no module was handed (postgres's consumers, restic, power).
A node now carries the account its client runs as (Node.RunningProvisioner: its own composition's account as it runs,
else the user of the client's running process), and a placed client that composes none this pass keeps it. A row holds
the client in the provisioned mesh, both ways: the account stays and restic keeps its filled files; both were lost
before.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
This commit is contained in:
2026-11-04 01:47:19 +01:00
parent 95b509e0d2
commit 514cf23aef
4 changed files with 104 additions and 0 deletions
+21
View File
@@ -74,6 +74,12 @@ func (c *composer) places(nodeName string, resolved Resolved) (Placed, error) {
// not sent the field they would refuse.
r.Hands = takesHanded(node)
r.Provisioner = provisionerAccount(plan)
if r.Provisioner == "" && provisionerPlaced(plan) {
// The provisioner's client is placed here but composes no account this pass (held as its stub, which runs no
// process of its own composition): it keeps running as it runs, so the account it runs as stays named, and every
// module stays handed to it.
r.Provisioner = node.RunningProvisioner
}
r.Assigned = node.Handed
r.ReadsHealth = node.Stated && node.Contract >= ReadinessContract
r.JudgesRoot = node.Stated && node.Contract >= RootContract
@@ -190,6 +196,21 @@ func provisionerAccount(plan catalogue.Resolution) string {
return ""
}
// provisionerPlaced says the plan places a module claiming the provisioner client's seat on the machine, whether or not
// it composes the client's process this pass.
func provisionerPlaced(plan catalogue.Resolution) bool {
for _, m := range plan.Modules {
if m.ClaimsSeat(NodeProvisionerSeat) {
return true
}
}
return false
}
// RunsTheProvisionerClient says a module runs its machine's provisioner client (runsTheProvisionerClient), for a reader
// of what runs.
func RunsTheProvisionerClient(m catalogue.Manifest) bool { return runsTheProvisionerClient(m) }
// runsTheProvisionerClient says a module runs its machine's provisioner client: it claims the seat and declares the own
// secret that account is delivered in.
func runsTheProvisionerClient(m catalogue.Manifest) bool {