Point messenger, mesh-watcher, restic and mesh-issues away from the controller

The controller is not placed (ADR 0590): messenger no longer treats it as
a condition owner or a walk's subject, mesh-watcher reads only where the bus
runs, restic tells the operator to compose the machine or set config through
the seats that do it now, and mesh-issues' examples name a placed repository.
mesh-issues keeps mesh-controller among its owners: issues located there,
issue 1126 among them, and route-proxy until it moves, still name it
(issue 1126 B11).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 12:29:56 +01:00
parent 40c4fabff6
commit e009088150
15 changed files with 49 additions and 114 deletions
+3 -3
View File
@@ -167,7 +167,7 @@ func (o Owners) locatedIn(e string) (string, error) {
}
if o.owns(v) == "" {
return "", fmt.Errorf("located-in %q names no registered owner: an entry starts with a repository such as "+
"mesh-controller, or a module such as \"mesh-catalog modules/nats\", optionally followed by where in it; "+
"mesh-host, or a module such as \"mesh-catalog modules/nats\", optionally followed by where in it; "+
"the registered list is the module's setting `owners`", v)
}
return v, nil
@@ -277,7 +277,7 @@ func checkTarget(kind, target string) (string, error) {
case LinkDuplicates, LinkRelatesTo, LinkDependsOn:
ok, shape = issueNumber.MatchString(t), "another issue's number, such as 312"
case LinkPullRequest:
ok, shape = pullRequest.MatchString(t), "a repository and a pull request's number, such as mesh-controller#246"
ok, shape = pullRequest.MatchString(t), "a repository and a pull request's number, such as mesh-host#246"
case LinkDecision:
ok, shape = decision.MatchString(t), "a decision record's four-digit number, such as 0275"
case LinkDesign:
@@ -287,7 +287,7 @@ func checkTarget(kind, target string) (string, error) {
"the scope one of "+strings.Join(conditionScopes, ", ")+", each part of letters, digits and _=/-"
case LinkDelivery:
ok, shape = deliveryID.MatchString(t), "a delivery's id as mesh-delivery names it: the repository as owner/name, @ and twelve "+
"characters of its commit, such as novox/mesh-controller@d2e9dc61590f"
"characters of its commit, such as novox/mesh-host@d2e9dc61590f"
case LinkMilestone:
var c string
c, ok = checkMilestoneTarget(t)
+6 -6
View File
@@ -383,7 +383,7 @@ func Tools(t *Tracker) []stdio.Tool {
Input: schema([]string{"title", "report"}, map[string]any{
"title": text("one line: the symptom, in plain words"),
"report": text("what was seen, what was expected, and how it was found"),
"located-in": texts("the owners it is in, each a repository such as mesh-controller or a module such as \"mesh-catalog modules/nats\", optionally followed by where in it"),
"located-in": texts("the owners it is in, each a repository such as mesh-host or a module such as \"mesh-catalog modules/nats\", optionally followed by where in it"),
"record": text("for an issue with a folder in hq: the folder's name without its number, such as the-counter-skips-a-number"),
"severity": map[string]any{"type": "string", "enum": Severities, "description": "when known: critical (something the operator relies on is broken, or data at risk), major (a rule does not hold, or people work around it), minor (a contained fix, nothing the operator sees changes); left out, the triage estimates it"},
"needs": map[string]any{"type": "string", "enum": NeedsKinds, "description": "when known: none, decision (a decision record first) or operator (the operator's answer is required); left out, the triage estimates it"},
@@ -469,7 +469,7 @@ func Tools(t *Tracker) []stdio.Tool {
"opened, moved, noted, linked, worked on, or its fix's delivery said a new state.",
Input: schema(nil, map[string]any{
"status": map[string]any{"type": "string", "enum": Statuses, "description": "only issues at this status"},
"owner": text("only issues located in this owner, such as mesh-controller"),
"owner": text("only issues located in this owner, such as mesh-host"),
"phrase": text("only issues whose title or report holds these words"),
"limit": map[string]any{"type": "integer", "minimum": 1, "maximum": MostListResult, "description": "at most this many rows (default 50)"},
"severity": map[string]any{"type": "string", "enum": Severities, "description": "only issues at this severity"},
@@ -554,7 +554,7 @@ func Tools(t *Tracker) []stdio.Tool {
"number": number("the issue's number"),
"status": map[string]any{"type": "string", "enum": Statuses, "description": "the status it moves to"},
"located-in": texts("the owners it is in; replaces what it said"),
"fixed-by": texts("what fixed it: pull requests or commits, such as mesh-controller#246; replaces what it said"),
"fixed-by": texts("what fixed it: pull requests or commits, such as mesh-host#246; replaces what it said"),
"amended-design": texts("the design documents the fix changed, such as 03-DESIGN/00-as-is/12-the-controller.md"),
"replay": text("for a core issue resolved: the replay's id in mesh-lab's replays register, such as R361"),
"replay-none": text("for a core issue resolved: why no replay is possible"),
@@ -615,9 +615,9 @@ func Tools(t *Tracker) []stdio.Tool {
}},
{Name: Seat + ".link",
Description: "Link an issue to something, or with remove, take a link away. Kinds: duplicates or relates-to " +
"another issue (its number), pull-request (such as mesh-controller#246), decision (a decision record's " +
"another issue (its number), pull-request (such as mesh-host#246), decision (a decision record's " +
"number, such as 0275), design (a design document's path), condition (a condition's key) and delivery " +
"(a delivery's id, such as novox/mesh-controller@d2e9dc61590f), milestone (the one milestone it belongs to, design/id such as " +
"(a delivery's id, such as novox/mesh-host@d2e9dc61590f), milestone (the one milestone it belongs to, design/id such as " +
"47/R6) and commit (a commit that fixes it, repository@full sha). Refused: a target not of its kind's shape, an issue that does not exist, a link it " +
"already has, a second milestone (remove the first to move it), a milestone that does not exist or is closed.",
Input: schema([]string{"number", "kind", "target"}, map[string]any{
@@ -827,7 +827,7 @@ func Tools(t *Tracker) []stdio.Tool {
"number": number("the issue's number"),
"severity": map[string]any{"type": "string", "enum": Severities},
"needs": map[string]any{"type": "string", "enum": NeedsKinds},
"suggested-owner": text("an owner on the registered list, such as mesh-controller"),
"suggested-owner": text("an owner on the registered list, such as mesh-host"),
}),
Run: func(m map[string]any) (any, error) {
a, err := readArgs("set", m, "number", "severity", "needs", "suggested-owner")
+4 -4
View File
@@ -3,11 +3,11 @@
The watcher's watcher (novox/hq to-be 45 §5, signal S10, ADR 0227 rule 6): what tells the operator
when the parts that would tell them are what failed.
- **Assigned to one machine that is not the control node.** It reads where the controller and the
bus run (`mesh-controller.seats`) every ten minutes; on the same machine its status says
`MISPLACED`.
- **Assigned to one machine that is not the control node.** It reads where the bus runs (the seat
`mesh-broker`'s holders, from the placement seat's state of who holds which seat) every ten minutes;
on the same machine its status says `MISPLACED`.
- **Watches two signals.**
- **The self-check:** the controller's `doctor` heartbeat, `mesh-controller.doctor-heartbeat`.
- **The self-check:** the seat `mesh-self-check`'s `checked` event.
Bound: twice the interval the heartbeat says doctor runs at (five minutes when it says none).
Heard by the time the heartbeat says it was made, so a backlog delivered after a restart is not a
sign of life. The heartbeat is read in one place, `cmd/mesh-watcher/heartbeat.go`, which states
@@ -95,7 +95,7 @@ func run(w *Watcher, l *listening, node string) {
if nodes, err := controlNodes(); err == nil {
w.Placed(nodes)
} else {
logf("[mesh-watcher] cannot read where the controller runs (%v); asking again in ten minutes", err)
logf("[mesh-watcher] cannot read where the bus runs (%v); asking again in ten minutes", err)
}
time.Sleep(10 * time.Minute)
}
@@ -146,8 +146,8 @@ func roundTrip(node string) error {
}
}
// controlNodes reads which machines hold the controller and the bus, from the placement seat's state of who holds
// which seat (novox/hq ADR 0571 clause 4).
// controlNodes reads which machines hold the bus, from the placement seat's state of who holds which seat (novox/hq
// ADR 0571 clause 4). The controller is not placed (ADR 0590), so the bus's machines are the control node.
func controlNodes() ([]string, error) {
st := stdio.State(delivery.SeatHoldersRead)
names, err := st.Keys()
@@ -164,7 +164,7 @@ func controlNodes() ([]string, error) {
keys[k] = e.Value
}
}
return holderNodes(keys, "mesh-controller", "mesh-broker")
return holderNodes(keys, "mesh-broker")
}
// holderNodes is the machines holding any of the seats, in the order the seats are named, each once.
@@ -215,15 +215,14 @@ func TestOnTheControlNodeItSaysItIsMisplaced(t *testing.T) {
func TestTheHoldersAreReadFromThePlacementSeatsState(t *testing.T) {
keys := map[string][]byte{
"mesh-controller": []byte(`{"v":1,"seat":"mesh-controller","scope":"mesh","holders":[{"module":"mesh-controller","node":"n1"}]}`),
"mesh-broker": []byte(`{"v":1,"seat":"mesh-broker","scope":"mesh","holders":[{"module":"nats","node":"n1"},{"module":"nats","node":"n2"}]}`),
"git": []byte(`{"v":1,"seat":"git","scope":"mesh","holders":[{"module":"gitea","node":"n3"}]}`),
"mesh-broker": []byte(`{"v":1,"seat":"mesh-broker","scope":"mesh","holders":[{"module":"nats","node":"n1"},{"module":"nats","node":"n2"},{"module":"nats","node":"n1"}]}`),
"git": []byte(`{"v":1,"seat":"git","scope":"mesh","holders":[{"module":"gitea","node":"n3"}]}`),
}
got, err := holderNodes(keys, "mesh-controller", "mesh-broker")
got, err := holderNodes(keys, "mesh-broker")
if err != nil || strings.Join(got, ",") != "n1,n2" {
t.Errorf("%v %v", got, err)
}
if _, err := holderNodes(map[string][]byte{}, "mesh-controller", "mesh-broker"); err == nil {
if _, err := holderNodes(map[string][]byte{}, "mesh-broker"); err == nil {
t.Error("no holder named, and no error")
}
}
+1 -3
View File
@@ -201,9 +201,7 @@ The controller's `plan-moved` says each walk's start and end: `walk`, `phase` (`
module it touches (on a machine it touches, when the subject names one), is held: kept on the walk with when
and what, and the history says `held`. A message several open walks touch is told when the last ends or passes
its bound. At a walk's end, a later open walk that touches a message takes it over only as a first hold would:
still open, not silenced, not said since, and not one that is never held. The controller's own lease, bus and
health conditions (`core.controller.…`, `bus.controller.…`) are about the module `mesh-controller`, wherever a
walk moves it (ADR 0505 §2).
still open, not silenced, not said since, and not one that is never held.
- **The settle (ADR 0505 §3, §6):** a walk that ended delivered holds on for the setting `settle-seconds`
(120 by default): what it touched stays held, a condition raised then on what it touched is held too, and its
end is told when the settle has passed. A walk that failed or stopped is told at once; for its settle after
@@ -44,53 +44,6 @@ func TestTheSettleIsReadFromTheSettingsFileAndIsTwoMinutesByDefault(t *testing.T
}
}
// controllerConditions are the controller's own conditions as it raises them: the lease's (mesh-controller
// signals.go watchLease: scope core, id controller.lease, the machine its host names, which need not be a node's
// name) and the bus's (reconnects.go: scope bus, id the bus user).
func controllerConditions(c *clock) []Condition {
lease := cond("core.controller.lease.lost", Urgent, "the controller lost its lease")
lease.ID, lease.Machine, lease.Raised = "controller.lease", "a-host-name", c.now()
bus := cond("bus.controller.bus-reconnects", Urgent, "the controller reconnects to the bus")
bus.Raised = c.now()
health := cond("module.controller.unhealthy", Urgent, "the controller is not healthy")
health.Raised = c.now()
return []Condition{lease, bus, health}
}
// ADR 0505 §2a: the controller's lease, bus and health conditions are held while a walk moving mesh-controller is
// open, whatever name their keys give the controller and whatever host they name.
func TestTheControllersOwnConditionsAreHeldWhileAWalkMovesMeshController(t *testing.T) {
h, tg, dt, c, _ := newHolder(t)
walk(t, h, "plan-c", WalkStarted, "", c.now(), 1200, novox("mesh-controller"))
for _, k := range controllerConditions(c) {
h.Condition(EventRaised, k)
}
runFor(h, c, time.Minute)
if saidOn(tg, dt) != 0 {
t.Fatalf("the controller's own conditions were said during its delivery: %+v %+v", tg.sends, dt.sends)
}
for _, k := range controllerConditions(c) {
if !has(outcomes(h, k.Key), "held") {
t.Errorf("%s was not held: %v", k.Key, outcomes(h, k.Key))
}
}
}
// ADR 0505 §2a: a walk that does not move mesh-controller holds none of them.
func TestTheControllersOwnConditionsAreNotHeldByAWalkOfAnotherModule(t *testing.T) {
h, tg, dt, c, _ := newHolder(t)
walk(t, h, "plan-g", WalkStarted, "", c.now(), 1200, Touch{Machine: "ace", Modules: []string{"gitea"}})
for _, k := range controllerConditions(c) {
h.Condition(EventRaised, k)
}
runFor(h, c, time.Minute)
for _, k := range controllerConditions(c) {
if has(outcomes(h, k.Key), "held") || !heard(headlineOf(k.Key), tg, dt) {
t.Errorf("%s was held by a walk of gitea, or not said: %v", k.Key, outcomes(h, k.Key))
}
}
}
// shanksDeclared is a touch as the controller says a machine whose declaration the walk's merges change and to which
// it sends nothing (mesh-controller walk_said.go walkTouch, `declared`, ADR 0505 §2b).
var shanksDeclared = Touch{Machine: "shanks", Modules: []string{"mesh-build-image"}, Declared: true}
@@ -677,7 +677,7 @@ func TestAnAskAboutAConditionIsAnsweredOnItsMessage(t *testing.T) {
settle(h, c)
a := ackAsk(c, "d-1")
a.About = "delivery.hq.held"
submit(t, h, "mesh-controller", a)
submit(t, h, ConditionOwner, a)
settle(h, c)
// Its first message was on the desk alone (a warning, the desk ready); the ask re-shows it with answers.
var shown Message
@@ -687,14 +687,14 @@ func TestAnAskAboutAConditionIsAnsweredOnItsMessage(t *testing.T) {
if got := labelsOf(shown); got != "Silence for a week, Details" {
t.Errorf("the desk's copy offers %q: %+v", got, shown)
}
if store.asks["mesh-controller.d-1"].Record != "delivery.hq.held" {
t.Errorf("the ask is shown on %q", store.asks["mesh-controller.d-1"].Record)
if store.asks[ConditionOwner+".d-1"].Record != "delivery.hq.held" {
t.Errorf("the ask is shown on %q", store.asks[ConditionOwner+".d-1"].Record)
}
silence := ticketFor(shown, "Silence for a week")
if out, err := h.Chosen("desktop", choiceOf(silence, "g14", c.now())); err != nil || out != "chosen" {
t.Fatalf("%s %v", out, err)
}
if got := w.of("mesh-controller"); len(got) != 1 || got[0].About != "delivery.hq.held" {
if got := w.of(ConditionOwner); len(got) != 1 || got[0].About != "delivery.hq.held" {
t.Errorf("%+v", got)
}
_ = tg
+4 -4
View File
@@ -479,9 +479,9 @@ func answerLevel(a asks.Ask) asks.Level {
return asks.Acknowledge
}
// ConditionOwner is the module whose asks may be shown on a condition's message: the controller, which raised the
// conditions; the condition keeper (ConditionSeat), which raises them now, is one too.
const ConditionOwner = "mesh-controller"
// ConditionOwner is the module whose asks may be shown on a condition's message: the condition keeper, which raises
// the conditions (the controller, which raised them before it, is not placed; novox/hq ADR 0590).
const ConditionOwner = ConditionSeat
// TakeAsk takes one ask or cancel from the seat's queue. asker is the subject's last token, which the bus
// grants that module alone. An error is returned only when the ask could not be recorded, so the queue
@@ -651,7 +651,7 @@ func (h *Holder) recordFor(asker, key string, a asks.Ask) string {
defer h.mu.Unlock()
// Shown on a condition's message only when asked by the condition's owner: another asker naming a
// condition's key does not take its message over.
if a.About != "" && (asker == ConditionOwner || asker == ConditionSeat) {
if a.About != "" && asker == ConditionOwner {
if r := h.open[a.About]; r != nil && r.Cleared.IsZero() && r.Origin == "condition" {
return r.Key
}
@@ -158,7 +158,7 @@ func TestDetailsOnAMessageWithAnOpenAskNeverAnswersIt(t *testing.T) {
older := detailsOf(t, dt.sends[0])
a := ackAsk(c, "d-1")
a.About = "delivery.hq.held"
submit(t, h, "mesh-controller", a)
submit(t, h, ConditionOwner, a)
settle(h, c)
var shown Message
for _, m := range dt.edits {
@@ -169,10 +169,10 @@ func TestDetailsOnAMessageWithAnOpenAskNeverAnswersIt(t *testing.T) {
t.Fatalf("Details: %q %v", out, err)
}
}
if got := w.of("mesh-controller"); len(got) != 0 {
if got := w.of(ConditionOwner); len(got) != 0 {
t.Errorf("Details issued a warrant: %+v", got)
}
if st := store.asks["mesh-controller.d-1"].State; st != StateOpen {
if st := store.asks[ConditionOwner+".d-1"].State; st != StateOpen {
t.Errorf("Details ended the ask: %s", st)
}
}
+1 -16
View File
@@ -255,7 +255,7 @@ func (w *Walk) touches(s subject) bool {
}
}
}
if s.machineNamed && !s.controller {
if s.machineNamed {
return false
}
for _, t := range w.Touches {
@@ -982,18 +982,8 @@ type subject struct {
machineNamed bool
// tokens are every name it carries, to tell a message about a walk itself.
tokens []string
// controller: the subject is the controller itself — its lease, its bus connection, its health — matched to the
// module mesh-controller wherever a walk moves it, whatever machine or host the condition names (ADR 0505 §2a).
controller bool
}
// controllerNames are the names the controller's own conditions give it in their keys (`core.controller.lease.lost`,
// `bus.controller.bus-reconnects`, `module.controller...`): each is the module ControllerModule (ADR 0505 §2a).
var controllerNames = map[string]bool{"controller": true, ControllerModule: true}
// ControllerModule is the controller's module, as a walk that moves it names it.
const ControllerModule = "mesh-controller"
// subjectOf is a record's subject: a condition's scope and id (`<scope>.<id>.<kind>` when the record kept no
// subject of its own), a notice's subject words.
func subjectOf(r *Record) subject {
@@ -1015,11 +1005,6 @@ func subjectOf(r *Record) subject {
if r.Machine != "" {
s.machines, s.machineNamed = append(s.machines, r.Machine), true
}
if (scope == "core" || scope == "bus" || scope == "module" || scope == "seat") && len(tokens) > 0 && controllerNames[tokens[0]] {
// The controller's own subject: the module mesh-controller, wherever it runs (ADR 0505 §2a).
s.modules, s.controller = append(s.modules, ControllerModule), true
return s
}
switch scope {
case "machine", "node", "bus":
s.machines, s.machineNamed = append(s.machines, tokens[0]), true
@@ -126,9 +126,9 @@ func TestAnAskWhoseWholeWordsCarryASecretIsRefused(t *testing.T) {
settle(h, c)
a := proposalAsk(c, "s-5")
a.About = "delivery.hq.held"
submit(t, h, "mesh-controller", a)
submit(t, h, ConditionOwner, a)
settle(h, c)
if r := h.open["delivery.hq.held"]; r == nil || r.Ask != "mesh-controller.s-5" || h.wholeOf(r, "telegram") != "" {
if r := h.open["delivery.hq.held"]; r == nil || r.Ask != ConditionOwner+".s-5" || h.wholeOf(r, "telegram") != "" {
t.Errorf("a condition's record is given an ask's whole words")
}
}
+7 -7
View File
@@ -63,7 +63,7 @@ func Judge(s Seen) Health {
var waits []health.Wait
if s.DeclaredErr != nil {
found = append(found, fmt.Sprintf("What the modules here declare to back up does not read (%v), so no night can "+
"back anything up; push this machine (mesh-controller.push) so the mesh writes it again.", s.DeclaredErr))
"back anything up; compose this machine again (node-engine.compose on it) so the mesh writes it again.", s.DeclaredErr))
}
if s.Run.Failed != "" {
found = append(found, fmt.Sprintf("The night of %s did not run: %s. No module was backed up; fix what the error "+
@@ -134,24 +134,24 @@ func Judge(s Seen) Health {
}
line := fmt.Sprintf("The retention setting %s is refused: it is %s, and it is a count from 1 to 9999. Until it is, "+
"nothing is thinned and every restore point is kept, so the repository grows; set %s for restic on this machine "+
"(mesh-controller.settings).", r.Setting, value, r.Setting)
"(mesh-config.config).", r.Setting, value, r.Setting)
said = append(said, line)
waits = append(waits, health.Wait{Part: "night", Setting: r.Setting,
What: "a count from 1 to 9999 for " + r.Setting})
case strings.Contains(r.Refused, Unreadable):
found = append(found, fmt.Sprintf("The retention is refused: %s; nothing is thinned and every restore point is "+
"kept, so the repository grows. The mesh writes the file readable (0644) and root's; one the account cannot "+
"read was written by an older build of this module, or changed on the machine, and the next push of this "+
"machine (mesh-controller.push) writes it readable again.", r.Refused))
"read was written by an older build of this module, or changed on the machine, and the next composition of this "+
"machine (node-engine.compose on it) writes it readable again.", r.Refused))
case strings.HasSuffix(r.Refused, Missing):
found = append(found, fmt.Sprintf("The retention is refused: %s; nothing is thinned and every restore point is "+
"kept until it is there again, rather than thinned by a number nobody set; push this machine "+
"(mesh-controller.push) so the mesh writes it again.", r.Refused))
"kept until it is there again, rather than thinned by a number nobody set; compose this machine again "+
"(node-engine.compose on it) so the mesh writes it again.", r.Refused))
case strings.Contains(r.Refused, RetentionFile+": "):
// Read, and not in the form the mesh writes: something other than the mesh wrote it.
found = append(found, fmt.Sprintf("The retention is refused: %s; nothing is thinned and every restore point is "+
"kept, so the repository grows. The mesh writes only daily=, weekly=, monthly= and hand=, so something else wrote "+
"this file; push this machine (mesh-controller.push) so the mesh writes it again.", r.Refused))
"this file; compose this machine again (node-engine.compose on it) so the mesh writes it again.", r.Refused))
default:
found = append(found, fmt.Sprintf("The retention is refused: %s; nothing is thinned and every restore point is "+
"kept, so the repository grows. Fix what the error names.", r.Refused))
@@ -135,7 +135,7 @@ func TestAMissingRetentionFileIsUnhealthy(t *testing.T) {
if h.State != health.StateUnhealthy {
t.Fatalf("a missing retention file is %s: %s", h.State, h.Why)
}
for _, want := range []string{"retention.conf is missing", "nothing is thinned", "mesh-controller.push"} {
for _, want := range []string{"retention.conf is missing", "nothing is thinned", "node-engine.compose"} {
if !strings.Contains(h.Why, want) {
t.Errorf("said %q, want it to hold %q", h.Why, want)
}
@@ -390,7 +390,7 @@ func TestARetentionWithoutHandSaysToPushTheMachine(t *testing.T) {
if h.State != health.StateUnhealthy || len(h.Waits) != 0 {
t.Fatalf("a file without hand= is %s waiting for %+v: %s", h.State, h.Waits, h.Why)
}
for _, want := range []string{"hand= line is missing", "mesh-controller.push"} {
for _, want := range []string{"hand= line is missing", "node-engine.compose"} {
if !strings.Contains(h.Why, want) {
t.Errorf("said %q, want it to hold %q", h.Why, want)
}
+4 -4
View File
@@ -176,15 +176,15 @@ func tools(b *Backups) []stdio.Tool {
"did not run, the last thinning failed, or the retention file is missing or unreadable — each said with what " +
"to do; waits, naming the setting, when a retention setting is refused. (r)",
Run: func(map[string]any) (any, error) { return b.Health(context.Background()), nil }},
// Deleting a retired item, when a person decided (novox/hq ADR 0233): the controller's `cleanup
// delete` asks these. Not seat verbs — nobody else calls them.
// Deleting a retired item, when a person decided (novox/hq ADR 0233). Not seat verbs: a person asks them
// through the mesh MCP server, and records the hand act (the controller's `cleanup delete` went with it).
{Name: "backup_delete_retired", Description: "Delete one item of data the mesh retired on this machine — " +
"its module is gone from here — after taking a last restore point of it, tagged retired, so it can be " +
"restored until that restore point is forgotten. Refuses anything declared now. Answers at once; " +
"backup_deleted says how it went. Use the controller's `cleanup delete`, which records the hand act.",
"backup_deleted says how it went. Record the act with mesh-hand-acts.hand-act beside it.",
Input: map[string]any{"module": str("the module it was"), "item": str("the item"), "path": str("where it is"),
"confirm": str("the item's name again"), "why": str("why — required"), "by": str("who decided"),
"via": str("mesh-controller when asked through its verbs")},
"via": str("what it was asked through, when not by a person directly")},
Run: func(a map[string]any) (any, error) {
return b.DeleteRetired(context.Background(), arg(a, "module"), arg(a, "item"), arg(a, "path"),
arg(a, "confirm"), arg(a, "by"), arg(a, "why"))