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