runProvisioner now follows the retirement model of hq ADR 0230, in place of 0.1.11's hourly release.
Loop
Retires a set only after the same unasked set has held for 5 consecutive readable passes.
More than 3, or more than half of those held, waits for a person.
Approve accepts only the exact set waiting. Reject keeps the set active. A set the mesh asks for again settles. A retired consumer asked for again is re-enabled and announced.
An unreadable pass resets the count.
Adapter
New optional methods: retire, retired, delete, held.
retire falls back to remove, so existing adapters keep working unchanged.
Options and API
New options: announce (emits provisioner.retirement) and module (registers the four tools via registerModuleTools).
New export: provisionerTools(handle).
The returned stop function also carries retirement, approve, reject and deleteRetired.
Removed: withdrawAtOnce, withdrawFraction, releaseEveryMs. Nothing in the catalogue passes them.
Tests: 33 pass (12 new in test/retire.test.ts); tsc is clean.
TS providers. All 11 use ^0.1.x with no lockfile, so each picks this up on its next build: redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea, cloudflare-dns.
They get the stable count and the threshold for free.
To be approvable, each must pass { module, announce }. That is one line where it already imports emit.
To be cleanable, each needs retired/delete in its adapter.
Those provider bumps are not in this PR. Until they land, a set over the bound in a TS provider waits, safely, with no approval path except a restart.
The module option assumes the runtime loads provisioner/index.js into the same process that collects tool registrations; that is unverified.
Rollout: merge, then publish 0.1.12. The go/ module is unchanged, so no go/ tag is needed.
`runProvisioner` now follows the retirement model of hq ADR 0230, in place of 0.1.11's hourly release.
**Loop**
- Retires a set only after the same unasked set has held for 5 consecutive readable passes.
- More than 3, or more than half of those held, waits for a person.
- Approve accepts only the exact set waiting. Reject keeps the set active. A set the mesh asks for again settles. A retired consumer asked for again is re-enabled and announced.
- An unreadable pass resets the count.
**Adapter**
- New optional methods: `retire`, `retired`, `delete`, `held`.
- `retire` falls back to `remove`, so existing adapters keep working unchanged.
**Options and API**
- New options: `announce` (emits `provisioner.retirement`) and `module` (registers the four tools via registerModuleTools).
- New export: `provisionerTools(handle)`.
- The returned stop function also carries `retirement`, `approve`, `reject` and `deleteRetired`.
- Removed: `withdrawAtOnce`, `withdrawFraction`, `releaseEveryMs`. Nothing in the catalogue passes them.
**Tests:** 33 pass (12 new in test/retire.test.ts); tsc is clean.
**TS providers.** All 11 use `^0.1.x` with no lockfile, so each picks this up on its next build: redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea, cloudflare-dns.
- They get the stable count and the threshold for free.
- To be approvable, each must pass `{ module, announce }`. That is one line where it already imports emit.
- To be cleanable, each needs `retired`/`delete` in its adapter.
- Those provider bumps are not in this PR. Until they land, a set over the bound in a TS provider waits, safely, with no approval path except a restart.
The `module` option assumes the runtime loads provisioner/index.js into the same process that collects tool registrations; that is unverified.
**Rollout:** merge, then publish 0.1.12. The go/ module is unchanged, so no go/ tag is needed.
The hourly release let a mistaken bulk unassignment drain one consumer an hour
with nobody deciding. Per novox/hq ADR 0230 a consumer is retired (disabled,
marked, data kept) only after the same unasked set in five consecutive passes;
more than 3, or more than half of those held, waits for approve or reject.
Deletion is a separate act of a person, of a retired consumer only.
Five passes are 25 s, shorter than a real hiccup. And a provider's remove can
destroy — a ledger file, a public DNS record — so an adapter without a retire
of its own is mark-only: the consumer keeps its access, is marked and said, and
remove is reached only by a person's delete (hq ADR 0230).
Updated in 0704908. This supersedes two points in the description above.
Stability now needs two conditions. A consumer is retired only after 5 consecutive identical passes and after the same unasked set has held for stableForMs. The default is STABLE_FOR_MS = 10 min. An unreadable pass restarts both.
Mark-only.remove is no longer called to retire.
New optional adapter pair: retire (disable) and reenable. reenable runs before create when a retired consumer is asked for again.
An adapter without retire is mark-only. Nothing changes in its backend and the consumer keeps its access. The loop records it as retired with access: "kept". It is logged loudly (RETIRED, MARK ONLY ... KEEPS ITS ACCESS) and announced.
provisioner_retirement reports retires_by: mark-only and stable_for_seconds.
remove is reached only through a person's provisioner_delete, and only when the adapter has no delete.
All 11 catalogue TS providers are mark-only until they add retire: redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea and cloudflare-dns.
A mark-only mark lives in the provider's process, so a restart forgets it.
Tests: 36/36 pass, run twice. New tests:
five passes are not enough without the hold, and the default hold is 10 minutes;
mark-only never calls remove on retire, and remove runs only on delete;
retire/reenable work as a pair.
The sdk.test withdrawal tests were rewritten so remove runs only on delete. tsc is clean.
Updated in 0704908. This supersedes two points in the description above.
1. **Stability now needs two conditions.** A consumer is retired only after 5 consecutive identical passes **and** after the same unasked set has held for `stableForMs`. The default is `STABLE_FOR_MS` = 10 min. An unreadable pass restarts both.
2. **Mark-only.** `remove` is no longer called to retire.
- New optional adapter pair: `retire` (disable) and `reenable`. `reenable` runs before `create` when a retired consumer is asked for again.
- An adapter without `retire` is **mark-only**. Nothing changes in its backend and the consumer keeps its access. The loop records it as retired with `access: "kept"`. It is logged loudly (`RETIRED, MARK ONLY ... KEEPS ITS ACCESS`) and announced.
- `provisioner_retirement` reports `retires_by: mark-only` and `stable_for_seconds`.
- `remove` is reached only through a person's `provisioner_delete`, and only when the adapter has no `delete`.
**All 11 catalogue TS providers are mark-only until they add `retire`:** redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea and cloudflare-dns.
A mark-only mark lives in the provider's process, so a restart forgets it.
Tests: 36/36 pass, run twice. New tests:
- five passes are not enough without the hold, and the default hold is 10 minutes;
- mark-only never calls `remove` on retire, and `remove` runs only on delete;
- `retire`/`reenable` work as a pair.
The sdk.test withdrawal tests were rewritten so `remove` runs only on delete. tsc is clean.
Deliverynovox/mesh-sdk@e08a10f55f5b — 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 mesh-sdk, sent nowhere; no bus step
tier 0: mesh-sdk
Transitions
2026-10-06 23:05 (new) → proposed (announced): novox/mesh-sdk#9 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-sdk@e08a10f55f5b` — **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 mesh-sdk, sent nowhere; no bus step
- tier 0: mesh-sdk
**Transitions**
- 2026-10-06 23:05 (new) → proposed (announced): novox/mesh-sdk#9 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`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
runProvisionernow follows the retirement model of hq ADR 0230, in place of 0.1.11's hourly release.Loop
Adapter
retire,retired,delete,held.retirefalls back toremove, so existing adapters keep working unchanged.Options and API
announce(emitsprovisioner.retirement) andmodule(registers the four tools via registerModuleTools).provisionerTools(handle).retirement,approve,rejectanddeleteRetired.withdrawAtOnce,withdrawFraction,releaseEveryMs. Nothing in the catalogue passes them.Tests: 33 pass (12 new in test/retire.test.ts); tsc is clean.
TS providers. All 11 use
^0.1.xwith no lockfile, so each picks this up on its next build: redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea, cloudflare-dns.{ module, announce }. That is one line where it already imports emit.retired/deletein its adapter.The
moduleoption assumes the runtime loads provisioner/index.js into the same process that collects tool registrations; that is unverified.Rollout: merge, then publish 0.1.12. The go/ module is unchanged, so no go/ tag is needed.
Updated in
0704908. This supersedes two points in the description above.stableForMs. The default isSTABLE_FOR_MS= 10 min. An unreadable pass restarts both.removeis no longer called to retire.retire(disable) andreenable.reenableruns beforecreatewhen a retired consumer is asked for again.retireis mark-only. Nothing changes in its backend and the consumer keeps its access. The loop records it as retired withaccess: "kept". It is logged loudly (RETIRED, MARK ONLY ... KEEPS ITS ACCESS) and announced.provisioner_retirementreportsretires_by: mark-onlyandstable_for_seconds.removeis reached only through a person'sprovisioner_delete, and only when the adapter has nodelete.All 11 catalogue TS providers are mark-only until they add
retire: redis, mosquitto, minio, umami, mssql, mongodb, influxdb, mesh-vault, mailu, gitea and cloudflare-dns.A mark-only mark lives in the provider's process, so a restart forgets it.
Tests: 36/36 pass, run twice. New tests:
removeon retire, andremoveruns only on delete;retire/reenablework as a pair.The sdk.test withdrawal tests were rewritten so
removeruns only on delete. tsc is clean.Delivery
novox/mesh-sdk@e08a10f55f5b— held since 2026-10-06T23:05:28ZHeld for a person: merged without a passing check: only a person decides that it goes on —
mesh-delivery.releasewith why lets it go on.Delivery plan — builds mesh-sdk, sent nowhere; no bus step
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.