made_api/ceremony_engine_api.rs
1use crate::{
2 ApiCapabilities, ApiError, CeremonySummary, DefinitionAnalysisView, PublishedDefinitionView,
3 RaiseInterventionRequest, RespondToInterventionRequest, StartCeremonyRequest,
4};
5
6/// What a consuming product may ask of the embedded engine.
7///
8/// Reads, plus one mutation: starting an instance from a **published**
9/// definition. Advancing and publishing stay behind the engine's own surfaces,
10/// where their transactionality and audit live; the contract grows by adding
11/// named capabilities, never by widening what an existing one means (ADR-004).
12/// A consumer checks the capability report before relying on any of this — and
13/// keeps working, with a stub, when the engine is absent.
14#[async_trait::async_trait]
15pub trait CeremonyEngineApi: Send + Sync {
16 /// What this implementation is and what it can do. Checked by consumers at
17 /// startup, before anything is at stake.
18 fn capabilities(&self) -> ApiCapabilities;
19
20 /// Every ceremony instance the engine holds.
21 ///
22 /// The consumer filters by its own context keys; the engine does not know
23 /// what they mean and is not asked to.
24 async fn ceremonies(&self) -> Result<Vec<CeremonySummary>, ApiError>;
25
26 /// One ceremony instance by identity.
27 async fn ceremony(&self, ceremony_id: &str) -> Result<CeremonySummary, ApiError>;
28
29 /// Start an instance from a published definition. Capability
30 /// `start_ceremony`.
31 ///
32 /// `CeremonyNotFound` when nothing is published under that name and
33 /// version — publishing is the remedy, not retrying. A taken instance
34 /// identity is `Refused`: an identity is one instance forever, and the
35 /// answer is a new identity, never a restart of someone else's.
36 async fn start_ceremony(
37 &self,
38 request: StartCeremonyRequest,
39 ) -> Result<CeremonySummary, ApiError>;
40
41 /// Put a question, investigation or proposed action to the table.
42 /// Capability `raise_intervention`.
43 async fn raise_intervention(
44 &self,
45 request: RaiseInterventionRequest,
46 ) -> Result<CeremonySummary, ApiError>;
47
48 /// Answer an open intervention. Capability `respond_to_intervention`.
49 ///
50 /// A closed intervention refuses: the answer arrived after the table moved
51 /// on, and recording it as if it had been heard would misstate the
52 /// conversation the audit trail exists to keep.
53 async fn respond_to_intervention(
54 &self,
55 request: RespondToInterventionRequest,
56 ) -> Result<CeremonySummary, ApiError>;
57
58 /// Analyze a definition draft, reporting every defect at once.
59 /// Capability `analyze_definition`.
60 ///
61 /// A draft that does not even parse is `Refused` — it is not a defective
62 /// definition, it is not a definition. Anything that parses gets the full
63 /// report, publishable or not.
64 async fn analyze_definition(
65 &self,
66 definition_yaml: &str,
67 ) -> Result<DefinitionAnalysisView, ApiError>;
68
69 /// Publish a definition, immutably. Capability `publish_definition`.
70 ///
71 /// Idempotent on identical content: republishing the same bytes under the
72 /// same name and version answers `already_published` rather than refusing,
73 /// which is what makes a retry safe. A version taken by *different*
74 /// content is `Refused` — a published version is immutable, and the
75 /// answer is a new version, never an overwrite.
76 async fn publish_definition(
77 &self,
78 definition_yaml: &str,
79 ) -> Result<PublishedDefinitionView, ApiError>;
80}