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)]
38pub struct PrepareContext {
39 pub schema_version: u32,
40 pub control_id: String,
41 pub run_id: String,
42 pub run_dir: PathBuf,
43 pub started_at: DateTime<Utc>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub operator: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub note: Option<String>,
48 pub scope_layout: ScopeLayout,
49 pub resolved_scope: Vec<ResolvedSystem>,
50 pub registry_git_sha: String,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub period_id: Option<String>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct RunResult {
59 pub schema_version: u32,
60 pub control_id: String,
61 pub run_id: String,
62 pub status: RunOutcome,
63 #[serde(default)]
64 pub by_system: Vec<SystemResult>,
65 #[serde(default)]
66 pub draft_risks: Vec<serde_json::Value>,
67 #[serde(default)]
68 pub draft_issues: Vec<serde_json::Value>,
69 #[serde(default)]
70 pub external_links: Vec<serde_json::Value>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct SystemResult {
75 pub name: String,
76 pub status: SystemOutcome,
77 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub note: Option<String>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct AgentInfo {
85 pub model: String,
86 pub skill: String,
87 pub skill_sha256: String,
88 pub control_sha256: String,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct PriorRun {
93 pub run_id: String,
94 pub manifest_sha256: String,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct Artifact {
99 pub path: String,
100 pub sha256: String,
101 pub bytes: u64,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct BySystemBlock {
106 pub name: String,
107 pub status: SystemOutcome,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
109 pub summary: Option<BTreeMap<String, serde_json::Value>>,
110 pub artifacts: Vec<Artifact>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Manifest {
115 pub schema_version: u32,
116 pub control_id: String,
117 pub run_id: String,
118 pub started_at: DateTime<Utc>,
119 pub completed_at: DateTime<Utc>,
120 #[serde(default, skip_serializing_if = "Option::is_none")]
121 pub operator: Option<String>,
122 pub agent: AgentInfo,
123 pub registry_git_sha: String,
124 pub scope_layout: ScopeLayout,
125 pub resolved_scope: Vec<ResolvedSystem>,
126 #[serde(default, skip_serializing_if = "Option::is_none")]
127 pub prior_run: Option<PriorRun>,
128 pub artifacts: Vec<Artifact>,
129 #[serde(default, skip_serializing_if = "Vec::is_empty")]
130 pub by_system: Vec<BySystemBlock>,
131 pub status: RunOutcome,
132 #[serde(default, skip_serializing_if = "Option::is_none")]
133 pub failure_reason: Option<String>,
134 #[serde(default)]
135 pub draft_risks: Vec<serde_json::Value>,
136 #[serde(default)]
137 pub draft_issues: Vec<serde_json::Value>,
138 #[serde(default)]
139 pub external_links: Vec<serde_json::Value>,
140 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub period_id: Option<String>,
142}