Skip to content
docsv0.30.2

Operation

The atom: one operation defined once — schema of inputs + handler + metadata — that the family projects to N surfaces (CLI, MCP, HTTP, web, TUI). A `SurfaceProjector` turns this into each surface's native shape; the operation is written once and surfaced wherever it is enabled. `readonly` (not `final`) so that the deprecated `Milpa\Runtime\CommandDefinition` can remain a subclass during the transition — a readonly class may only be extended by a readonly class.

Operation::__construct()

public function __construct(string $name, string $description, ?mixed $handler, ?array $inputSchema = null, bool $mutating = false, bool $requiresConfirmation = false, array $scopes = [], ?array $outputSchema = null, ?string $version = null, ?string $path = null, ?array $surfaces = null, ?string $permission = null, ?string $namedTarget = null, ?Milpa\Command\Effect\EffectProfile $effects = null, array $preconditions = [], array $postconditions = [], array $artifacts = [], ?string $observableEvidence = null, bool $createsNamedTarget = false, ?Closure $continues = null, array $citesReceiptsOf = [], bool $amendsNamedTarget = false, ?Closure $actsOn = null):

Parameters

Parameters of __construct()
NameTypeDescription
$namestring
$descriptionstring
$handler(callable | array{0: class-string, 1: string})A plain PHP callable, or a `[class-string, method]` pair a host resolves through DI. Typed `mixed` because PHP forbids the native `callable` type on a property. Called with the coerced `array<string,mixed> $input`; returns domain data.
$inputSchema(array<string, mixed> | null)JSON-Schema-shaped input definition; null = no typed inputs.
$mutatingbool
$requiresConfirmationbool
$scopeslist<string>Auth scopes enforced by a policy gate on surfaces that have one wired — MCP via tool-runtime's PolicyGate, and HTTP via the HttpProjector's scope gate: a non-empty `$scopes` makes the projector attach a per-route RequireScope middleware and build the `ToolContext::web()` the same PolicyGate reads, so HTTP now enforces scopes instead of ignoring them.
$outputSchema(array<string, mixed> | null)JSON-Schema-shaped output definition.
$version?string
$path(string | null)HTTP path; declared here, or (null) derived from `$name`.
$surfaces(list<string> | null)Surfaces this operation opts into; null = all.
$permission(string | null)The semantic permission key (`{namespace}.{resource}:{action}`) a permission-aware surface enforces; mutually exclusive with `$scopes`.
$namedTarget?string
$effects?Milpa\Command\Effect\EffectProfile
$preconditionsarray
$postconditionsarray
$artifactsarray
$observableEvidence?string
$createsNamedTargetbool
$continues?Closure
$citesReceiptsOfarray
$amendsNamedTargetbool
$actsOn?Closure

Operation::effectCeiling()

public function effectCeiling(): Milpa\Command\Effect\EffectProfile

The effect ceiling of this operation — never `null`. An operation that declared nothing gets `unclassified()`, which is every dimension at its maximum. Callers therefore never have to write `?? something-safe`, and cannot accidentally write `?? readOnly()` — which is precisely the permissive default GOV-13 forbids and the shape a tired reviewer would wave through.

Operation::ceilingForCall()

public function ceilingForCall(array $arguments, ?Milpa\Command\Effect\AuthorityPolicy $policy = null, ?Milpa\Command\Effect\ContextFacts $facts = null): Milpa\Command\Effect\EffectProfile

The ceiling THIS CALL carries, with the handler that is about to run named. The operation is the only place holding both the handler and its declared effects, so it is the only honest place to join them: a caller computing the digest itself would either hand out descents nobody watched or refuse ones that were earned. The policy and the facts travel when the caller has them (greenhouse decisions/0054): the authority axis is judged live by its own producer, and a caller with nothing to offer simply gets no authority descent — fail-closed, not an error.

Parameters

Parameters of ceilingForCall()
NameTypeDescription
$argumentsarray<string, mixed>
$policy?Milpa\Command\Effect\AuthorityPolicy
$facts?Milpa\Command\Effect\ContextFacts

Operation::handlerDigest()

public function handlerDigest(): ?string

The digest of the handler body, which is what a descent certificate is bound to. ITS LIMIT IS PART OF THE CONTRACT, not an oversight: this hashes the CODE OF THE HANDLER ITSELF. A handler that delegates changes behaviour without changing this digest, so a certificate stays valid across a change it never watched. Saying so is half the value — greenhouse decisions/0050 `F-3` exists to be paid, and hiding it would turn currency into a promise. `null` when the handler cannot be read, and `null` buys nothing: a descent whose certificate cannot be compared does not lower anything.

Operation::actsOnDigest()

public function actsOnDigest(array $arguments): ?string

The digest of the content this call acts on, or `null` when this operation cannot say. Asked of the SAME declaration for the call that measures and for the call that acts, so the two meet only when both answers agree. `null` covers every way of not knowing — no declaration, a declaration that answered nothing for these arguments, one that threw because the candidate is not there — and all of them mean the same to a judge: nothing can be bound to this call.

Parameters

Parameters of actsOnDigest()
NameTypeDescription
$argumentsarray<string, mixed>

Operation::instrumentDigest()

public function instrumentDigest(): ?string

What makes this operation the INSTRUMENT it is today: its identity, its inputs, its declared effects, the body of its handler and the body of what says what it acts on — in one digest (greenhouse decisions/0615). A condition receipt pins it. A guard that did not see, hardened afterwards, is another instrument: what the old one measured green says nothing about what the new one would find, so a receipt taken by a different digest does not count. It carries the limit {@see self::handlerDigest()} declares — a handler that delegates changes behaviour without changing this — and says so rather than hide it. `null` when either body cannot be read, or when the operation does not say what it acts on: an instrument that cannot be pinned, or that measures nothing in particular, yields no receipt worth keeping.

Operation::supportsSurface()

public function supportsSurface(string $surface): bool

Whether this operation is projected to the given surface. `null` $surfaces means every surface; a list is an explicit opt-in.

Parameters

Parameters of supportsSurface()
NameTypeDescription
$surfacestring

Operation::sequenceFor()

public function sequenceFor(array $arguments): ?string

The sequence these arguments continue, or null when this operation declares none. Asked of the SAME declaration for the call about to run and for the arguments a receipt signed, so a receipt binds to a sequence only when both answers agree. A blank id is no sequence: an empty string would let every unnamed call cite the same receipt.

Parameters

Parameters of sequenceFor()
NameTypeDescription
$argumentsarray<string, mixed>

Operation::mayCiteReceiptOf()

public function mayCiteReceiptOf(string $operation): bool

Whether a call of this operation may cite a standing receipt that `$operation` signed: its own, or one it names in {@see self::$citesReceiptsOf}. The sequence binding is the door's to check, not this answer's.

Parameters

Parameters of mayCiteReceiptOf()
NameTypeDescription
$operationstring