Retire, approve, reject, cleanup: the controller's half of hq ADR 0230 #84

Merged
mesh-admin merged 3 commits from feat/retired-consumers into main 2026-10-06 12:46:33 +00:00
Contributor

Implements the controller side of hq ADR 0230, which replaces ADR 0229's withdrawal brake.

Events and conditions

  • Hears provisioner.retirement from every module.
  • Permission to publish it is derived for every module that receives contributions (catalogue.EmitsAll). The writers table row, the consumer filter subject and the contract test are added.
  • New conditions:
    • provider.<module>.<node>.retire (retire-waiting, urgent): lists the set waiting and names the verb to answer it.
    • provider.<module>.<node>.retire-rejected (retire-rejected, warning).
    • provider.<module>.<node>.cleanup (cleanup-waiting, warning), raised by the new probe D11 when something has been retired for more than 30 days.
  • All three clear when the provider is unassigned.

Verbs (CLI and mesh-controller seat verbs)

  • retire [--json]
  • retire approve|reject <node> <module> --why
  • cleanup [list]
  • cleanup delete <node> <module> <consumer> --why
  • cleanup delete --older-than <days> --why [--confirm]: lists only, deletes nothing without --confirm.
  • Each verb asks the provider's own tool on that machine (mesh.mod.<module>.tool.<tool>.<node>). Approve sends the exact set the provider reports waiting.
  • Each act is written to the hand-act log. An approve, reject or delete event that did not come through the controller is recorded as a hand act too.

No migration needed.

Tests: the full suite passes with GOFLAGS=-mod=vendor GOPROXY=off against throwaway postgres:17 and nats:2.11 (both removed afterwards). New tests cover:

  • event to condition: waiting urgent, rejected warning, retired and settled clear, unassigned clears;
  • approve and reject against a fake provider on a real bus;
  • cleanup deleting only the named consumer;
  • --older-than without confirm deleting nothing;
  • D11 at 31 days (condition), 29 days (none), and no responders (not a failure);
  • seat-verb argv.

Rollout: merge and roll this out before the catalogue PR (mesh-catalog feat/retired-consumers). Otherwise the providers' new event is refused by the bus; it would only be logged.

Implements the controller side of hq ADR 0230, which replaces ADR 0229's withdrawal brake. **Events and conditions** - Hears `provisioner.retirement` from every module. - Permission to publish it is derived for every module that receives contributions (`catalogue.EmitsAll`). The writers table row, the consumer filter subject and the contract test are added. - New conditions: - `provider.<module>.<node>.retire` (`retire-waiting`, urgent): lists the set waiting and names the verb to answer it. - `provider.<module>.<node>.retire-rejected` (`retire-rejected`, warning). - `provider.<module>.<node>.cleanup` (`cleanup-waiting`, warning), raised by the new probe D11 when something has been retired for more than 30 days. - All three clear when the provider is unassigned. **Verbs** (CLI and mesh-controller seat verbs) - `retire [--json]` - `retire approve|reject <node> <module> --why` - `cleanup [list]` - `cleanup delete <node> <module> <consumer> --why` - `cleanup delete --older-than <days> --why [--confirm]`: lists only, deletes nothing without `--confirm`. - Each verb asks the provider's own tool on that machine (`mesh.mod.<module>.tool.<tool>.<node>`). Approve sends the exact set the provider reports waiting. - Each act is written to the hand-act log. An approve, reject or delete event that did not come through the controller is recorded as a hand act too. No migration needed. **Tests:** the full suite passes with GOFLAGS=-mod=vendor GOPROXY=off against throwaway postgres:17 and nats:2.11 (both removed afterwards). New tests cover: - event to condition: waiting urgent, rejected warning, retired and settled clear, unassigned clears; - approve and reject against a fake provider on a real bus; - cleanup deleting only the named consumer; - `--older-than` without confirm deleting nothing; - D11 at 31 days (condition), 29 days (none), and no responders (not a failure); - seat-verb argv. **Rollout:** merge and roll this out before the catalogue PR (mesh-catalog feat/retired-consumers). Otherwise the providers' new event is refused by the bus; it would only be logged.
Author
Contributor

Updated in c4406aa.

A provider can now be mark-only: SDK providers without retire keep the consumer's access. The controller reads two new fields from the retirement state, retires_by and stable_for_seconds, and a per-consumer access field.

  • cleanup list marks those consumers [MARK ONLY: access kept until deleted] and carries access in the JSON output.
  • retire approve against a mark-only provider says the consumers were marked, not disabled.

New test: TestNatsAMarkOnlyRetirementIsSaidAsSuch.

The full suite passes again with GOFLAGS=-mod=vendor GOPROXY=off against throwaway postgres:17 and nats:2.11, both removed afterwards.

Updated in c4406aa. A provider can now be mark-only: SDK providers without `retire` keep the consumer's access. The controller reads two new fields from the retirement state, `retires_by` and `stable_for_seconds`, and a per-consumer `access` field. - **`cleanup list`** marks those consumers `[MARK ONLY: access kept until deleted]` and carries `access` in the JSON output. - **`retire approve`** against a mark-only provider says the consumers were marked, not disabled. New test: `TestNatsAMarkOnlyRetirementIsSaidAsSuch`. The full suite passes again with GOFLAGS=-mod=vendor GOPROXY=off against throwaway postgres:17 and nats:2.11, both removed afterwards.
jschoubben added 3 commits 2026-10-06 12:45:59 +00:00
A provider now waits for a person before retiring more than three consumers
or half of what it holds, and deletes only when asked. The controller is that
person's way in: it keeps waiting and rejected sets as conditions, answers them
with retire approve|reject, lists and deletes retired consumers through the
provider's own tools on its machine, records each act in the hand-act log, and
probes for anything retired longer than thirty days (D11).
A provider that cannot disable keeps the consumer reachable until a person
deletes it (hq ADR 0230); the listing and the approval say so instead of
claiming access was disabled.
Approving a retirement and deleting what was retired are a person's act by
design (hq ADR 0230); counted by S15 they would ask for a healer that must not
exist.
jschoubben force-pushed feat/retired-consumers from c4406aafbf to 08e11ad761 2026-10-06 12:45:59 +00:00 Compare
mesh-admin merged commit 4f4d365360 into main 2026-10-06 12:46:33 +00:00
mesh-admin deleted branch feat/retired-consumers 2026-10-06 12:46:34 +00:00
Author
Contributor

Delivery novox/mesh-controller@4f4d3653605a — held since 2026-10-06T23:05:28Z

Held for a person: merged without a passing check: only a person decides that it goes on — mesh-delivery.release with why lets it go on.

Delivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step

  • tier 0: mesh-controller
  • tier 1: build-agent
  • tier 2: route-proxy
  • ace: receives build-agent, route-proxy
  • g14: receives build-agent
  • novox: receives mesh-controller, build-agent, route-proxy
  • shanks: receives build-agent
  • build-agent keeps data (ADR 0233): what it holds is backed up before it moves
  • route-proxy provides route: its consumers are sent again after it
  • route-proxy keeps data (ADR 0233): what it holds is backed up before it moves

Transitions

  • 2026-10-06 23:05 (new) → proposed (announced): novox/mesh-controller#84 merged; its head was not heard by this owner, so it is made from the forge's word
  • 2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-controller@4f4d3653605a` — **held** since 2026-10-06T23:05:28Z Held for a person: merged without a passing check: only a person decides that it goes on — `mesh-delivery.release` with why lets it go on. **Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step - tier 0: mesh-controller - tier 1: build-agent - tier 2: route-proxy - ace: receives build-agent, route-proxy - g14: receives build-agent - novox: receives mesh-controller, build-agent, route-proxy - shanks: receives build-agent - build-agent keeps data (ADR 0233): what it holds is backed up before it moves - route-proxy provides route: its consumers are sent again after it - route-proxy keeps data (ADR 0233): what it holds is backed up before it moves **Transitions** - 2026-10-06 23:05 (new) → proposed (announced): novox/mesh-controller#84 merged; its head was not heard by this owner, so it is made from the forge's word - 2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
This repo is archived. You cannot comment on pull requests.