1#[must_use]
5pub const fn scope() -> &'static str {
6 "phase-4-v1"
7}
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum ToolVerb {
12 Inspect,
14 Validate,
16 Benchmark,
18 Report,
20}
21
22impl ToolVerb {
23 #[must_use]
25 pub const fn as_str(self) -> &'static str {
26 match self {
27 Self::Inspect => "inspect",
28 Self::Validate => "validate",
29 Self::Benchmark => "benchmark",
30 Self::Report => "report",
31 }
32 }
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub struct CommandSpec<'a> {
38 pub verb: ToolVerb,
40 pub artifact_class: &'a str,
42 pub description: &'a str,
44}
45
46const CORE_COMMANDS: [CommandSpec<'static>; 4] = [
47 CommandSpec {
48 verb: ToolVerb::Inspect,
49 artifact_class: "plan",
50 description: "Inspect a plan, config, or evaluator surface.",
51 },
52 CommandSpec {
53 verb: ToolVerb::Validate,
54 artifact_class: "validation",
55 description: "Validate environment, inputs, or supported capabilities.",
56 },
57 CommandSpec {
58 verb: ToolVerb::Benchmark,
59 artifact_class: "benchmark",
60 description: "Run benchmark capture for the selected workload.",
61 },
62 CommandSpec {
63 verb: ToolVerb::Report,
64 artifact_class: "report",
65 description: "Produce evidence, summaries, and operator-facing reports.",
66 },
67];
68
69#[must_use]
71pub const fn core_command_catalog() -> &'static [CommandSpec<'static>] {
72 &CORE_COMMANDS
73}
74
75#[must_use]
77pub fn artifact_name(
78 package_name: &str,
79 version: &str,
80 maturity_tier: &str,
81 artifact_class: &str,
82) -> String {
83 format!("{package_name}-{version}-{maturity_tier}-{artifact_class}")
84}
85
86#[derive(Clone, Copy, Debug, Eq, PartialEq)]
88pub struct OwnershipRecord<'a> {
89 pub area: &'a str,
91 pub owner: &'a str,
93 pub artifact: &'a str,
95}
96
97impl<'a> OwnershipRecord<'a> {
98 #[must_use]
100 pub const fn new(area: &'a str, owner: &'a str, artifact: &'a str) -> Self {
101 Self {
102 area,
103 owner,
104 artifact,
105 }
106 }
107}
108
109#[derive(Clone, Copy, Debug, Eq, PartialEq)]
111pub struct TopologyAssemblyPacket<'a> {
112 pub packet_id: &'a str,
114 pub topology_profile: &'a str,
116 pub scope: &'a str,
118 pub ownership: &'a [OwnershipRecord<'a>],
120}
121
122impl<'a> TopologyAssemblyPacket<'a> {
123 #[must_use]
125 pub const fn new(
126 packet_id: &'a str,
127 topology_profile: &'a str,
128 scope: &'a str,
129 ownership: &'a [OwnershipRecord<'a>],
130 ) -> Self {
131 Self {
132 packet_id,
133 topology_profile,
134 scope,
135 ownership,
136 }
137 }
138
139 #[must_use]
141 pub fn has_owners(&self) -> bool {
142 !self.ownership.is_empty()
143 }
144}
145
146#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub struct ReleaseChecklistItem<'a> {
149 pub item_id: &'a str,
151 pub owner: &'a str,
153 pub required_artifact: &'a str,
155}
156
157impl<'a> ReleaseChecklistItem<'a> {
158 #[must_use]
160 pub const fn new(item_id: &'a str, owner: &'a str, required_artifact: &'a str) -> Self {
161 Self {
162 item_id,
163 owner,
164 required_artifact,
165 }
166 }
167}
168
169#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171pub struct ReleaseCloseoutPacket<'a> {
172 pub packet_id: &'a str,
174 pub release_family: &'a str,
176 pub scope: &'a str,
178 pub attachments: &'a [OwnershipRecord<'a>],
180}
181
182impl<'a> ReleaseCloseoutPacket<'a> {
183 #[must_use]
185 pub const fn new(
186 packet_id: &'a str,
187 release_family: &'a str,
188 scope: &'a str,
189 attachments: &'a [OwnershipRecord<'a>],
190 ) -> Self {
191 Self {
192 packet_id,
193 release_family,
194 scope,
195 attachments,
196 }
197 }
198
199 #[must_use]
201 pub fn has_attachments(&self) -> bool {
202 !self.attachments.is_empty()
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::{
209 OwnershipRecord, ReleaseChecklistItem, ReleaseCloseoutPacket, ToolVerb,
210 TopologyAssemblyPacket, artifact_name, core_command_catalog, scope,
211 };
212
213 #[test]
214 fn sprint_9_scope_is_exposed() {
215 assert_eq!(scope(), "phase-4-v1");
216 }
217
218 #[test]
219 fn catalog_contains_required_shared_verbs() {
220 let verbs: Vec<_> = core_command_catalog()
221 .iter()
222 .map(|command| command.verb)
223 .collect();
224
225 assert!(verbs.contains(&ToolVerb::Inspect));
226 assert!(verbs.contains(&ToolVerb::Validate));
227 assert!(verbs.contains(&ToolVerb::Benchmark));
228 assert!(verbs.contains(&ToolVerb::Report));
229 }
230
231 #[test]
232 fn artifact_name_is_stable_and_portfolio_readable() {
233 assert_eq!(
234 artifact_name(
235 "graph-rag-evaluator",
236 "0.1.0",
237 "embedded-evaluator",
238 "report"
239 ),
240 "graph-rag-evaluator-0.1.0-embedded-evaluator-report"
241 );
242 }
243
244 #[test]
245 fn topology_assembly_packet_tracks_ownership_inputs() {
246 let owners = [OwnershipRecord::new(
247 "compiled-plan-cache",
248 "rhodium",
249 "compiled-plan-cache-contract",
250 )];
251 let packet = TopologyAssemblyPacket::new(
252 "phase-3-topology-packet",
253 "reference-stack-v1",
254 "phase-3-v1",
255 &owners,
256 );
257
258 assert!(packet.has_owners());
259 assert_eq!(packet.topology_profile, "reference-stack-v1");
260 assert_eq!(packet.ownership[0].owner, "rhodium");
261 }
262
263 #[test]
264 fn release_checklist_item_carries_owner_and_artifact() {
265 let item = ReleaseChecklistItem::new(
266 "flagship-benchmark-evidence",
267 "rhodium",
268 "benchmark-evidence-packet",
269 );
270
271 assert_eq!(item.owner, "rhodium");
272 assert_eq!(item.required_artifact, "benchmark-evidence-packet");
273 }
274
275 #[test]
276 fn closeout_packet_tracks_attachment_points() {
277 let attachments = [
278 OwnershipRecord::new("appliance-profile", "rhodium", "appliance-package"),
279 OwnershipRecord::new(
280 "certification-support",
281 "strontium",
282 "certification-starter-pack",
283 ),
284 ];
285 let packet = ReleaseCloseoutPacket::new(
286 "phase-4-closeout-packet",
287 "appliance-and-support",
288 "phase-4-v1",
289 &attachments,
290 );
291
292 assert!(packet.has_attachments());
293 assert_eq!(packet.release_family, "appliance-and-support");
294 assert_eq!(packet.attachments[0].owner, "rhodium");
295 }
296}