Skip to main content

ExecutionPolicy

Struct ExecutionPolicy 

Source
pub struct ExecutionPolicy {
    pub effect: Effect,
    pub cancellable: bool,
    pub concurrency: Concurrency,
    pub signed_input: bool,
}
Expand description

What running a capability as an execution means: what it changes, whether asking it to stop achieves anything, and whether two of them may overlap.

The effect and the concurrency are classified from the kind by ExecutionPolicy::classify, for the same reason Availability is: the facts are already on the declaration, and asking each capability! block to restate them would be one more thing that can disagree with itself.

Cancellability is the one thing the kind cannot decide, because it is a fact about the handler: whether it looks at its cancellation flag and stops. A handler that does says so with crate::capability::Executable::cancellable, and a client is then told whether a Cancel button will achieve anything instead of being given one that lies.

Fields§

§effect: Effect

What it changes.

§cancellable: bool

Whether asking it to stop does anything. A task looks at its cancellation flag; a query and a command do not, and a client is told so rather than being given a button that lies.

§concurrency: Concurrency

Whether two of them may overlap.

§signed_input: bool

Whether the input authenticates its caller.

A handler whose input is a signed message, and which verifies the signature against the trust policy before anything changes, admits its caller by that signature and not by the address the request came from. Only such a handler changes state for a caller on another host; see ExecutionPolicy::admits_remote.

Implementations§

Source§

impl ExecutionPolicy

Source

pub fn classify(kind: CapabilityKind) -> Self

The policy of a kind.

use majordomus_cli::capability::{CapabilityKind, Concurrency, Effect, ExecutionPolicy};
let query = ExecutionPolicy::classify(CapabilityKind::Query);
assert_eq!(query.effect, Effect::Read);
assert_eq!(query.concurrency, Concurrency::Unrestricted);
assert!(!query.cancellable, "until its handler says it looks at the flag");
assert!(query.stoppable().cancellable);
let command = ExecutionPolicy::classify(CapabilityKind::Command);
assert_eq!(command.effect, Effect::ProcessState);
assert_eq!(command.concurrency, Concurrency::Serial);
Source

pub fn stoppable(self) -> Self

The same policy, for a handler that looks at its cancellation flag and stops.

use majordomus_cli::capability::{CapabilityKind, ExecutionPolicy};
let p = ExecutionPolicy::classify(CapabilityKind::Query).stoppable();
assert!(p.cancellable);
assert_eq!(p.effect, ExecutionPolicy::classify(CapabilityKind::Query).effect);
Source

pub fn writes_repository(self) -> Self

The same policy, for a handler that writes the repository’s own tracked files.

The second and last thing the kind cannot decide. Two commands are the same kind whether one announces a peer into this process’s memory and the other stamps a field into a record a commit will carry, and the difference is the whole of what a caller needs to know before saying yes. It is stated by the handler because only the handler knows it.

This is a widening and never a narrowing: a query cannot reach for it, because the registry accepts a declared policy only when it is the kind’s own or one of these two documented additions to it.

use majordomus_cli::capability::{CapabilityKind, Effect, ExecutionPolicy};
let p = ExecutionPolicy::classify(CapabilityKind::Command).writes_repository();
assert_eq!(p.effect, Effect::RepositoryMutation);
assert!(p.needs_confirmation());
Source

pub fn authenticates_its_input(self) -> Self

The same policy, for a command whose input is a signed message the handler verifies against the trust policy before it changes anything.

The third documented addition, and the narrowest: the mesh’s link and registration handlers, whose callers are other machines by design and are admitted by a key the trust policy names. It never combines with writing the repository: a signature proves who sent a message, not that its sender may change tracked files here.

use majordomus_cli::capability::{CapabilityKind, ExecutionPolicy};
let p = ExecutionPolicy::classify(CapabilityKind::Command).authenticates_its_input();
assert!(p.signed_input && p.admits_remote());
Source

pub fn admits_remote(self) -> bool

May a caller on another host run this?

A request that arrives from an address that is not loopback has proved nothing about who sent it: the server has no accounts and no tokens, and the Origin check stops a browser, not a program. Such a caller reads, and changes nothing, unless the input itself authenticates it (ExecutionPolicy::authenticates_its_input). A command that only changes this process’s memory is refused too, because some of that memory is signed by this node and replicated to every runtime that trusts it (ADR 0126).

use majordomus_cli::capability::{CapabilityKind, ExecutionPolicy};
assert!(ExecutionPolicy::classify(CapabilityKind::Query).admits_remote());
assert!(!ExecutionPolicy::classify(CapabilityKind::Command).admits_remote());
assert!(!ExecutionPolicy::classify(CapabilityKind::Command).writes_repository().admits_remote());
Source

pub fn needs_confirmation(self) -> bool

Should a client ask before running this? True for anything that changes something.

use majordomus_cli::capability::{CapabilityKind, ExecutionPolicy};
assert!(!ExecutionPolicy::classify(CapabilityKind::Query).needs_confirmation());
assert!(ExecutionPolicy::classify(CapabilityKind::Command).needs_confirmation());
Source

pub fn hints(self) -> Hints

What a caller may assume about a call before making it, classified from the effect.

A projection that tells a client how careful to be — MCP’s tool annotations, the site’s table of tools, the Cockpit’s — renders this value and states none of its own. Until it existed the MCP projection wrote destructiveHint: false and idempotentHint: true as constants, which was true of every tool on the day they were written and false of the first one that wrote the repository: a sweep that unlinks files was announced as safe to repeat and unable to destroy anything.

The classification is conservative in the one direction a caller can survive. Anything that changes something is not assumed repeatable, because whether a second call is a no-op is a fact about the handler and no handler has declared it; and anything that writes the repository may overwrite or remove what was there. A change to this process’s own memory destroys nothing outside it.

use majordomus_cli::capability::{CapabilityKind, ExecutionPolicy};
let read = ExecutionPolicy::classify(CapabilityKind::Query).hints();
assert!(read.read_only && read.idempotent && !read.destructive);
let memory = ExecutionPolicy::classify(CapabilityKind::Command).hints();
assert!(!memory.read_only && !memory.idempotent && !memory.destructive);
let writer = ExecutionPolicy::classify(CapabilityKind::Command).writes_repository().hints();
assert!(!writer.read_only && !writer.idempotent && writer.destructive);
assert!(!writer.open_world, "no handler of this executable reaches beyond the machine");

Trait Implementations§

Source§

impl Clone for ExecutionPolicy

Source§

fn clone(&self) -> ExecutionPolicy

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for ExecutionPolicy

Source§

impl Debug for ExecutionPolicy

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for ExecutionPolicy

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for ExecutionPolicy

Source§

impl JsonSchema for ExecutionPolicy

Source§

fn schema_name() -> Cow<'static, str>

The name of the generated JSON Schema. Read more
Source§

fn schema_id() -> Cow<'static, str>

Returns a string that uniquely identifies the schema produced by this type. Read more
Source§

fn json_schema(generator: &mut SchemaGenerator) -> Schema

Generates a JSON Schema for this type. Read more
Source§

fn inline_schema() -> bool

Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being re-used where possible using the $ref keyword. Read more
Source§

impl PartialEq for ExecutionPolicy

Source§

fn eq(&self, other: &ExecutionPolicy) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for ExecutionPolicy

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for ExecutionPolicy

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> AsOut<T> for T
where T: Copy,

§

fn as_out(&mut self) -> Out<'_, T>

Returns an out reference to self.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more