Introduce the RuntimeArtifactPaths struct
Intent: Create a self-contained struct that owns the three runtime artifact paths (events, status, result), each with serde defaults pointing at the canonical constants, a Default impl, and a validate_canonical_paths method that can be called independently of GuestStartupArtifacts.
Affected files: crates/pika-cloud/src/paths.rs
@@ -17,6 +17,56 @@ pub const RUNTIME_ARTIFACTS_DIR: &str = ARTIFACTS_DIR;
+#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
+pub struct RuntimeArtifactPaths {
+ #[serde(default = "events_path")]
+ pub events_path: String,
+ #[serde(default = "status_path")]
+ pub status_path: String,
+ #[serde(default = "result_path")]
+ pub result_path: String,
+}
@@ +31,0 +31,25 @@
+impl RuntimeArtifactPaths {
+ pub fn validate_canonical_paths(&self, field_prefix: &str) -> Result<(), String> {
+ let canonical = Self::default();
+ for (field, actual, expected) in [
+ ("status_path", self.status_path.as_str(), canonical.status_path.as_str()),
+ ("events_path", self.events_path.as_str(), canonical.events_path.as_str()),
+ ("result_path", self.result_path.as_str(), canonical.result_path.as_str()),
+ ] {
+ if actual != expected {
+ return Err(format!(
+ "{field_prefix}.{field} must use canonical path {expected:?}, got {actual:?}"
+ ));
+ }
+ }
+ Ok(())
+ }
+}
A new RuntimeArtifactPaths struct is added to crates/pika-cloud/src/paths.rs alongside the existing RuntimePaths. It groups three fields that were previously scattered across GuestStartupArtifacts:
events_pathstatus_pathresult_path
Each field uses #[serde(default = "…")] referencing the same private helper functions (events_path(), status_path(), result_path()) that already existed in the module, so deserialization from JSON that omits these keys still produces the canonical values.
The struct also owns a validate_canonical_paths method that iterates over all three fields and returns a descriptive error if any path deviates from the canonical default. The field_prefix parameter lets callers control how the error message is scoped (e.g. "artifacts.status_path").