pub struct Context {Show 13 fields
pub index: Arc<Index>,
pub registry: Arc<CapabilityRegistry>,
pub peers: Arc<PeerBoard>,
pub episodes: Arc<EpisodeBoard>,
pub why: Arc<Catalogue>,
pub product: Arc<ProductModel>,
pub executor: Arc<CapabilityExecutor>,
pub caller: Option<PeerId>,
pub executions: Arc<ExecutionEngine>,
pub progress: Progress,
pub web: Arc<Topology>,
pub mesh: Arc<MeshRuntime>,
pub reading: u64,
}Expand description
What a handler may read: the index of the repository, the registry it belongs to, the board of peers attached to this process, and, when the call came through an MCP session, which peer made it. Index and registry are immutable for the life of a process; the board is the one thing that changes, and it lives in memory only.
Fields§
§index: Arc<Index>The index of the repository’s objects.
registry: Arc<CapabilityRegistry>The registry the handler belongs to, for introspection capabilities.
peers: Arc<PeerBoard>The peers attached to this process.
episodes: Arc<EpisodeBoard>The execution episodes this process holds: one per client that asked for one, keyed by the client’s own durable identity and driven by the connection (ADR 0103).
Beside the peer board and not inside it, because a peer and an episode are not the same thing: a connection holds zero or one episode, and an episode outlives the connection that opened it so that a client which reconnects comes back to its own.
why: Arc<Catalogue>The Why catalogue, derived from the index once when this context is composed and shared by every projection that reads it. A request never rebuilds it.
product: Arc<ProductModel>The product model: the features of the layer with every fact a surface may say about them derived from the registry, the index, the catalogue and the topology. Built once, after the three it reads, and shared the same way.
executor: Arc<CapabilityExecutor>The one execution path: counters, cache, handler dispatch. Shared by every transport and every session of this process.
caller: Option<PeerId>The peer this call came from, when it came through an MCP session; None for the
command line and for a plain HTTP request.
executions: Arc<ExecutionEngine>The executions this process is running, and the engine that starts them.
One per process, so that an execution started from a browser is the same execution
an MCP client asks about and the command line lists. A handler reads it only when
it is itself the execution plane’s own capability; every other handler reports
through Context::progress and never learns whether anything was listening.
progress: ProgressWhat this call reports its steps and progress to, and how it learns it should stop.
Silent unless the call came through the execution engine, which is why a handler may report unconditionally and a benchmark sample costs nothing.
web: Arc<Topology>The repository’s web surfaces, resolved once for this process.
Resolved here and never again: a projection that serves a subset of it narrows this
value rather than discovering its own, so what the HTTP router serves, what the home
page lists and what web.surfaces answers are three readings of one resolution.
mesh: Arc<MeshRuntime>The mesh runtime: the discovered nodes of this process, and the machinery that
observes them. Inactive (an empty registry with a reason) until a shared server
activates it from the repository’s mesh declaration; the capabilities of the
mesh module are its projections.
reading: u64Which reading of the repository this is: a number no other Context::new of this
process was given, shared by every view of it (Context::for_caller,
Context::reporting, Context::with_web). A reload is a new reading. It is what
a crate::capability::CachePolicy::Generation entry is kept under, because the
registry fingerprint covers what is declared and not the git state an index was read
at.
Implementations§
Source§impl Context
impl Context
Sourcepub fn new(index: Arc<Index>, registry: Arc<CapabilityRegistry>) -> Self
pub fn new(index: Arc<Index>, registry: Arc<CapabilityRegistry>) -> Self
A context over an index and a registry, with an empty board, a fresh executor and no caller.
Sourcepub fn continuing(&self, previous: &Context) -> Self
pub fn continuing(&self, previous: &Context) -> Self
This context’s reading of the repository, carrying on the in-memory life of an
earlier one: what crate::live::Live hands out after the repository has moved.
A reload is not a restart. The index, the registry and everything derived from them — the Why catalogue, the product model, the web topology — are pictures of the repository and are replaced wholesale, which is the point. The peer board, the executions this process is running, the episodes its clients opened and the capability executor are not pictures of anything: they are this process’s own life, and a peer that announced its intent must not vanish from the board because somebody else committed. The executor is carried because its cache is keyed by the registry’s fingerprint, so the entries of an older generation are already unreachable and the ones of an unchanged capability are still worth having.
let renewed = after.continuing(&before);
assert!(Arc::ptr_eq(&renewed.peers, &before.peers), "the board survives a reload");
assert!(Arc::ptr_eq(&renewed.episodes, &before.episodes), "so do the episodes");
assert!(Arc::ptr_eq(&renewed.index, &after.index), "the picture does not");Sourcepub fn for_caller(&self, caller: PeerId) -> Self
pub fn for_caller(&self, caller: PeerId) -> Self
The same context, seen from one peer: what a session hands its handlers.
Sourcepub fn reporting(&self, progress: Progress) -> Self
pub fn reporting(&self, progress: Progress) -> Self
The same context, seen by one execution: what the engine hands the handler it runs.
Everything else is shared, the engine included, so a capability that reads the executions of this process sees its own while it runs.
Sourcepub fn with_web(&self, web: Arc<Topology>) -> Self
pub fn with_web(&self, web: Arc<Topology>) -> Self
The same context with the web topology narrowed to what one projection serves.
The narrowing is a filter over the value this context already holds, never a second discovery: a projection cannot serve a surface the process did not resolve.
Sourcepub fn execute(&self, id: &str, input: Value) -> Result<Value, CapabilityError>
pub fn execute(&self, id: &str, input: Value) -> Result<Value, CapabilityError>
Execute a capability by id: the one way anything calls a handler.
Sourcepub fn execute_observed(
&self,
id: &str,
input: Value,
) -> Result<Value, CapabilityError>
pub fn execute_observed( &self, id: &str, input: Value, ) -> Result<Value, CapabilityError>
The same, with the cache stepped over: what an execution runs.
See CapabilityExecutor::execute_uncached for why watching something happen and
being handed a remembered answer are not the same request.
Sourcepub fn read(&self, id: &str, input: Value) -> Latest
pub fn read(&self, id: &str, input: Value) -> Latest
The latest reading of a capability, at once, with how old it is: what a page shows.
Never an answer: see crate::capability::readings for what it is instead, and
what it costs.
use majordomus_cli::capability::readings::Freshness;
use majordomus_cli::synthetic::SyntheticRepository;
let repo = SyntheticRepository::small().unwrap();
let ctx = repo.context().unwrap();
let reading = ctx.read("plan.status", serde_json::json!({}));
// a first reading is waited for, so it holds what `execute` answers, and says how it
// stands: read just now, in the repository as it is
assert_eq!(reading.value.ok(), ctx.execute("plan.status", serde_json::json!({})).ok());
assert_eq!(reading.freshness, Freshness::Current);
assert!(reading.age.is_some());