Operation requests

The problem this solves. An agent working for you often reaches an operation it is not allowed to perform — removing a Space the repo owns, rewriting nodes across a partition, asking a NodeType to recompile — because on a system-synced Space no human or agent identity holds Delete, by design. Until 2026-09-04 the agent's only honest answer was a list of GUI links, one per node, one per instance. The maintainer's verdict on that: "I should get a screen with your request where I can approve and then it executes."

An Essentials/OperationRequest node is that screen.

How it works

  1. Propose. The agent (or you) creates a request node anywhere it may write — its own home is the natural place — with a title, the reason, and the operation as a C# script written against the fluent Plan DSL below. Filing needs no rights beyond writing the node.
  2. Read the script. It is on the page in full — that is what runs. A script is general C#, so it may do more than the DSL table lists, which is why the script is the thing to read and why even a preview is admin-gated (it runs the code).
  3. Approve. A global admin — not the requester — presses Approve & run as System, the page's primary action. It needs no preview: the platform runs the script in execute mode as System — the identity that owns synced Spaces — strictly in order, fail-fast, one log line per step, recording the plan as it goes. The outcome lands on the request; the full kernel log is the activity under it.
  4. Preview (optional). Pressing it first runs the same script in preview mode: every DSL call records a step, each target is probed (does it exist? what type? how many nodes below it?), and the plan comes back as a table. Nothing is executed. Worth it for anything destructive or large — the chunk count of a partition drain is how you learn it will take eight minutes.
  5. Reject at any time; a rejected request keeps its history.

🚨 An approval is bound to the script the approver saw. The Approve button carries the hash of the text it rendered (approvedScriptHash); if the stored script no longer matches it, nothing runs and the request says so. A request that WAS previewed additionally refuses a script changed since the preview. So editing a script under an approver cannot get it executed.

Who pressed what is never a field anyone types: the control plane reads the framework-stamped author of the write that set the action (lastModifiedBy), and refuses a blank one outright.

The DSL

The script sees one object, Plan, and chains what it wants. Every call records; nothing runs until the plan completes at the end of the script (the platform appends that line).

Plan.Because("UWDeepfield and ClaimsDeepfield are retired legacy modules (#159)")
    .Space("UWDeepfield").Delete()
    .Space("ClaimsDeepfield").Delete();
Call Records
Plan.Because(reason) why — shown first on the page
Plan.Note(text) a line of explanation between steps; never executed
Plan.Space(id).Delete() two steps: the Space's _GitSync source first (so no later sync re-imports it), then the Space root, recursively — absent parts are no-ops, so a re-run heals a half-removed Space
Plan.Node(path).Read() reads the node; the safest first step in any plan
Plan.Node(path).Delete() deletes the node and its subtree
Plan.Node(path).Update(n => n with { … }) rewrites the node through a record with; content included (n.ContentAs<T>(…) to type it)
Plan.Node(path).Create(nodeType, content, name) creates the node; an existing one is left as is
Plan.Query(query).Read() / .Delete() / .Update(…) the same over every match of an anchored mesh query (namespace:X scope:descendants nodeType:Y) — the store refuses one that names no partition
Plan.NodeType(path).Recompile() flips the type's compilationStatus to Pending; the framework rebuilds it
Plan.Node(path).Recycle() disposes that node's hub, so the next access re-reads it from the mesh
Plan.NodeType(path).Recycle() disposes the TYPE's hub and cascades to the types sharing its sources and every existing instance of each — prefer this
Plan.Do(kind, target, effect, run, probe?) anything the verbs above do not cover — still recorded. run executes only in execute mode; probe is read-only and renders in preview. A step with no run is refused when it is written.

Because the script is C#, the fluent APIs of the records themselves compose with it: a .Update(n => n with { Content = (n.ContentAs<Workbench>(opts)) with { Partitions = ["Acme"] } }) is an ordinary record expression.

🚨 Everything that changes the mesh goes through the DSL — and since Do exists, everything can. A raw Mesh call in the script still runs in both modes, but it is INVISIBLE to preview: it does not probe, it does not appear in the plan table, and the approver approves a list that does not mention it. That was the one hole in the promise "you approve the steps that will run", and it was open only because an unforeseen operation had nowhere else to go. It now does:

Plan.Because("retire the anonymous grant on Edu")
    .Do("revoke", "Edu/_Access/Anonymous", "removes the anonymous viewer grant",
        run:   ct => Plan.DeleteAt("Edu/_Access/Anonymous", ct),
        probe: async ct => OperationPlan.Describe(await Plan.Find("Edu/_Access/Anonymous", ct)));

An unforeseen operation should cost a step in the table, never a step outside it.

🚨 A plan that rewrites nodes is only half a migration — recycle in the same plan

Recycle and dispose are one act under two names. The platform's verb is a RECYCLE; the wire carries a DisposeRequest. Plan.…Recycle() is that act, recorded as a step like any other.

A per-node hub binds its NodeType and its compiled assembly once, while activating, and is then pinned by address — nothing re-reads it while it lives. So a plan that retypes nodes changes the STORE and reaches every running activation through nothing at all. They keep answering from what they hold, with no error and no log line. Measured 2026-09-21: a Crm/Client → Crm/Counterparty retype of eight partition roots wrote correctly — the query flipped to 8 Counterparty, 0 Client — and the pages went on serving through hubs whose type registry had never heard of CounterpartyContent, so the content read as ABSENT and the views rendered empty.

Plan.Because("Crm/Client is retired; Crm/Counterparty replaces it")
    .Node("ATIOZ").Update(toCounterparty)
    // … the other seven …
    .Note("The writes are done; now make the live hubs notice.")
    .NodeType("Crm/Counterparty").Recycle();

Why it has to be a DSL verb rather than a follow-up click. A recycle needs Update on the target, and on a system-synced space no account holds that — not the maintainer, not a global admin, by design. So the MCP recycle tool and the node's Recycle menu both refuse, and the only route left is a proposal executed as System. That made recycling the one step of this shape the DSL could not express, which is why the retype above shipped without it.

🚨 What a recycle cannot reach. It re-READS the mesh, so it picks up node content and an in-place recompile — and it does not touch a compiled MODULE assembly or the portal image, which are pinned at PROCESS start and need a roll through CD. If a recycle changes nothing, the activation was never the problem and a second one proves nothing the first did not. Never pin an image instead.

Full account: /recycle-after-deploy and Hub Disposal Model.

Where the pieces live

When a request looks inert

A request that keeps its pending action and never previews is not a request the API could not file — filing one through the API and watching it preview and run takes under a second, measured. It is a request whose watcher stopped, and why that could happen, what the control plane now guarantees, and the one gap still open is written up beside this page.

Why both buttons need a global admin

A preview runs the script. The DSL records instead of executing in preview mode, but the script is not confined to the DSL — a line of raw Mesh code runs in both modes. So the gate is on running code at all, and it is the same gate Store/Publishing's SystemRemoval puts in front of System impersonation: SystemAuthorization.Authorize, fail-closed (a probe that answers nothing is a no). The request's own page tells the approver exactly that.

The first use

The Deepfield retirement of 2026-09-04 (MeshWeaver.Reinsurance#159): two Spaces on memex, then twenty-two reinsurance and education Spaces on systemorph — twenty-four removals that were twenty-four links before this existed, and are two requests now.

Reconnecting…
The connection to the server was interrupted. Trying to restore it…
Trying again…
The connection could not be restored. Reloading the page…
The server was updated. Reloading the page to pick up the latest version.