zenkey_fleet/report/registry.rs
1//! The registry plane (RFC 08 §5/§6): a served slice against a local one,
2//! per producer and in aggregate.
3
4use serde::Serialize;
5
6/// One producer, as the bus serves it versus as the checkout declares it
7/// (issue #50). A `None` version means "not present on that side", which is a
8/// fact with two very different explanations — the findings say which.
9#[derive(Debug, Clone, Serialize)]
10pub struct ProducerDiff {
11 pub producer: String,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub served_version: Option<String>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub local_version: Option<String>,
16 /// RFC 08 §6 findings, rendered. Empty = the two agree.
17 pub findings: Vec<String>,
18}
19
20/// `zenctl registry diff` (issue #50).
21#[derive(Debug, Clone, Serialize)]
22pub struct RegistryDiff {
23 pub producers: Vec<ProducerDiff>,
24}
25
26impl RegistryDiff {
27 /// Producers whose two sides disagree.
28 pub fn disagreeing(&self) -> usize {
29 self.producers
30 .iter()
31 .filter(|p| !p.findings.is_empty())
32 .count()
33 }
34}
35
36/// One producer where the served slice and the on-disk slice disagree.
37///
38/// A disagreement is **data**, not an error: served wins in the union (the
39/// bus is the runtime truth, RFC 08 §6.1), and the difference is retained for
40/// `doctor` to report instead of being silently overwritten.
41#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
42pub struct SliceDisagreement {
43 pub producer: String,
44 pub bus_version: String,
45 pub dirs_version: String,
46 /// Whether anything beyond the version string differs (subjects,
47 /// procedures, blob tiers).
48 pub shape_differs: bool,
49}