1use std::collections::BTreeMap;
5use std::path::PathBuf;
6
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10use crate::model::ResolvedSystem;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "kebab-case")]
14pub enum ScopeLayout {
15 BySystem,
16 Flat,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(rename_all = "lowercase")]
21pub enum RunOutcome {
22 Complete,
23 Partial,
24 Failed,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28#[serde(rename_all = "lowercase")]
29pub enum SystemOutcome {
30 Complete,
31 Skipped,
32 Failed,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct SkillRef {
42 pub name: String,
43 pub source: String,
46 pub sha256: String,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct PrepareContext {
51 pub schema_version: u32,
52 pub control_id: String,
53 pub run_id: String,
54 pub run_dir: PathBuf,
55 pub started_at: DateTime<Utc>,
56 pub skill: SkillRef,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub operator: Option<String>,
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub note: Option<String>,
62 pub scope_layout: ScopeLayout,
63 pub resolved_scope: Vec<ResolvedSystem>,
64 pub registry_git_sha: String,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub period_id: Option<String>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct RunResult {
73 pub schema_version: u32,
74 pub control_id: String,
75 pub run_id: String,
76 pub status: RunOutcome,
77 #[serde(default)]
78 pub by_system: Vec<SystemResult>,
79 #[serde(default)]
80 pub draft_risks: Vec<serde_json::Value>,
81 #[serde(default)]
82 pub draft_issues: Vec<serde_json::Value>,
83 #[serde(default)]
84 pub external_links: Vec<serde_json::Value>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct SystemResult {
89 pub name: String,
90 pub status: SystemOutcome,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub note: Option<String>,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct AgentInfo {
99 pub model: String,
100 pub skill: String,
101 pub skill_sha256: String,
102 pub control_sha256: String,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct PriorRun {
107 pub run_id: String,
108 pub manifest_sha256: String,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct Artifact {
113 pub path: String,
114 pub sha256: String,
115 pub bytes: u64,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct BySystemBlock {
120 pub name: String,
121 pub status: SystemOutcome,
122 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub summary: Option<BTreeMap<String, serde_json::Value>>,
124 pub artifacts: Vec<Artifact>,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct Manifest {
129 pub schema_version: u32,
130 pub control_id: String,
131 pub run_id: String,
132 pub started_at: DateTime<Utc>,
133 pub completed_at: DateTime<Utc>,
134 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub operator: Option<String>,
136 pub agent: AgentInfo,
137 pub registry_git_sha: String,
138 pub scope_layout: ScopeLayout,
139 pub resolved_scope: Vec<ResolvedSystem>,
140 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub prior_run: Option<PriorRun>,
142 pub artifacts: Vec<Artifact>,
143 #[serde(default, skip_serializing_if = "Vec::is_empty")]
144 pub by_system: Vec<BySystemBlock>,
145 pub status: RunOutcome,
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub failure_reason: Option<String>,
148 #[serde(default)]
149 pub draft_risks: Vec<serde_json::Value>,
150 #[serde(default)]
151 pub draft_issues: Vec<serde_json::Value>,
152 #[serde(default)]
153 pub external_links: Vec<serde_json::Value>,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub period_id: Option<String>,
156}