1use crate::{ActorRef, ArtifactRef, NodeId, PatchId};
2use serde::{Deserialize, Serialize};
3use serde_json::Value as JsonValue;
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub enum StateOp {
7 CreateNode {
8 id: NodeId,
9 kind: String,
10 props: JsonValue,
11 },
12 UpdateNode {
13 id: NodeId,
14 props: JsonValue,
15 },
16 TombstoneNode {
17 id: NodeId,
18 reason: String,
19 },
20 CreateRelation {
21 from: NodeId,
22 rel: String,
23 to: NodeId,
24 props: JsonValue,
25 },
26 DeleteRelation {
27 from: NodeId,
28 rel: String,
29 to: NodeId,
30 },
31 MarkStale {
32 id: NodeId,
33 reason: String,
34 },
35 AttachArtifact {
36 id: NodeId,
37 artifact: ArtifactRef,
38 },
39}
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct StatePatch {
43 pub id: PatchId,
44 pub title: String,
45 pub summary: String,
46 pub base_state_version: u64,
47 pub base_project_ref: Option<ProjectRef>,
48 pub ops: Vec<StateOp>,
49 pub preconditions: Vec<Precondition>,
50 pub expected_effects: Vec<ExpectedEffect>,
51 pub evidence: Vec<NodeId>,
52 pub artifacts: Vec<ArtifactRef>,
53 pub status: PatchStatus,
54 pub created_by: ActorRef,
55}
56
57impl StatePatch {
58 pub fn new(
59 id: PatchId,
60 title: impl Into<String>,
61 summary: impl Into<String>,
62 created_by: ActorRef,
63 ) -> Self {
64 Self {
65 id,
66 title: title.into(),
67 summary: summary.into(),
68 base_state_version: 0,
69 base_project_ref: None,
70 ops: Vec::new(),
71 preconditions: Vec::new(),
72 expected_effects: Vec::new(),
73 evidence: Vec::new(),
74 artifacts: Vec::new(),
75 status: PatchStatus::Proposed,
76 created_by,
77 }
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub enum PatchStatus {
83 Proposed,
84 AppliedInFork,
85 Evaluated,
86 Approved,
87 Rejected,
88 Promoted,
89 Stale,
90 Conflicted,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94pub struct ProjectRef {
95 pub repo: String,
96 pub branch: Option<String>,
97 pub commit: Option<String>,
98 pub worktree: Option<String>,
99}
100
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102pub enum Precondition {
103 StateVersionIs(u64),
104 ProjectCommitIs(String),
105 NodeExists(NodeId),
106 NodeDoesNotExist(NodeId),
107 TestStillFailing { name: String },
108 FileHashIs { path: String, hash: String },
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub enum ExpectedEffect {
113 TestPasses { name: String },
114 EvalScoreAtLeast { metric: String, value: f64 },
115 FailureResolved { failure: NodeId },
116 NoRegression { metric: String },
117}