Skip to main content

runx_contracts/
act.rs

1//! Act algebra: intents, governed acts, success criteria, and verification details.
2pub mod assignment;
3pub mod result;
4
5use serde::{Deserialize, Serialize};
6
7use crate::schema::{IsoDateTime, NonEmptyString, RunxSchema};
8use crate::{ActRef, Closure, Reference, Verification};
9
10#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
11pub enum ActSchema {
12    #[serde(rename = "runx.act.v1")]
13    V1,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
17#[serde(deny_unknown_fields)]
18pub struct SuccessCriterion {
19    pub criterion_id: NonEmptyString,
20    pub statement: NonEmptyString,
21    pub required: bool,
22}
23
24#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
25#[serde(deny_unknown_fields)]
26pub struct Intent {
27    pub purpose: NonEmptyString,
28    pub legitimacy: NonEmptyString,
29    #[serde(default)]
30    pub success_criteria: Vec<SuccessCriterion>,
31    #[serde(default)]
32    pub constraints: Vec<NonEmptyString>,
33    #[serde(default)]
34    pub derived_from: Vec<Reference>,
35}
36
37#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
38#[serde(rename_all = "snake_case")]
39pub enum CriterionStatus {
40    Verified,
41    Failed,
42    Pending,
43    NotApplicable,
44    Unknown,
45}
46
47#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
48#[serde(rename_all = "snake_case")]
49pub enum ActForm {
50    Revision,
51    Reply,
52    Review,
53    Observation,
54    Verification,
55}
56
57#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
58#[serde(deny_unknown_fields)]
59pub struct CriterionBinding {
60    pub criterion_id: NonEmptyString,
61    pub status: CriterionStatus,
62    #[serde(default)]
63    pub evidence_refs: Vec<Reference>,
64    #[serde(default)]
65    pub verification_refs: Vec<Reference>,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub summary: Option<NonEmptyString>,
68}
69
70#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
71#[serde(deny_unknown_fields)]
72pub struct TargetSurface {
73    pub surface_ref: Reference,
74    pub mutating: bool,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub rationale: Option<NonEmptyString>,
77}
78
79#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
80#[serde(deny_unknown_fields)]
81pub struct ChangeRequest {
82    pub request_id: NonEmptyString,
83    pub summary: NonEmptyString,
84    #[serde(default)]
85    pub target_surfaces: Vec<TargetSurface>,
86    #[serde(default)]
87    pub success_criteria: Vec<SuccessCriterion>,
88}
89
90#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
91#[serde(deny_unknown_fields)]
92pub struct ChangePlan {
93    pub plan_id: NonEmptyString,
94    pub summary: NonEmptyString,
95    #[serde(default)]
96    pub steps: Vec<NonEmptyString>,
97    #[serde(default)]
98    pub risks: Vec<NonEmptyString>,
99}
100
101#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
102#[serde(deny_unknown_fields)]
103pub struct RevisionDetails {
104    pub change_request: ChangeRequest,
105    pub change_plan: ChangePlan,
106    #[serde(default)]
107    pub target_surfaces: Vec<TargetSurface>,
108    #[serde(default)]
109    pub invariants: Vec<NonEmptyString>,
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub verification: Option<Verification>,
112    #[serde(default)]
113    pub handoff_refs: Vec<Reference>,
114    #[serde(default)]
115    pub revision_refs: Vec<Reference>,
116}
117
118#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
119#[serde(deny_unknown_fields)]
120pub struct VerificationDetails {
121    pub criterion_ids: Vec<NonEmptyString>,
122    pub verification: Verification,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub deployment_ref: Option<Reference>,
125}
126
127#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
128#[serde(deny_unknown_fields)]
129#[runx_schema(id = "runx.act.v1")]
130pub struct Act {
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub schema: Option<ActSchema>,
133    pub act_id: NonEmptyString,
134    pub form: ActForm,
135    pub intent: Intent,
136    pub summary: NonEmptyString,
137    pub closure: Closure,
138    #[serde(default)]
139    pub criterion_bindings: Vec<CriterionBinding>,
140    #[serde(default)]
141    pub source_refs: Vec<Reference>,
142    #[serde(default)]
143    pub target_refs: Vec<Reference>,
144    #[serde(default)]
145    pub surface_refs: Vec<Reference>,
146    #[serde(default)]
147    pub artifact_refs: Vec<Reference>,
148    #[serde(default)]
149    pub verification_refs: Vec<Reference>,
150    #[serde(default)]
151    pub harness_refs: Vec<Reference>,
152    #[serde(skip_serializing_if = "Option::is_none")]
153    pub revision: Option<RevisionDetails>,
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub verification: Option<VerificationDetails>,
156    pub performed_at: IsoDateTime,
157}
158
159#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
160#[serde(deny_unknown_fields)]
161pub struct GovernedActRef {
162    pub act_ref: ActRef,
163}