pub enum Half<T> {
Consulted {
observed_at: u64,
items: Vec<T>,
},
NotConsulted {
observed_at: u64,
},
}Expand description
One collection a responder either consulted — and can therefore answer for — or did not: dig-rewards-coin SPEC §12.5 clause 6.
§Why the items live INSIDE the variant
Clause 6: “the absence MUST be surfaced, not swallowed”, and it “MUST be
dated by an observed_at and MUST NOT be presented as a bare zero”. A bare
claimable: [] cannot tell an operator apart “I looked and I hold no mirror
claims” from “nothing looked” — a funder-only responder emitting the empty
vector reads as the former while meaning the latter.
An observation carried beside its collection would leave
{"outcome": "not_consulted", "items": [seven things]} expressible, forbidden
only by prose. Folding the items into
Consulted makes that contradiction unconstructible in
Rust and unparseable on the wire: the arm that says nothing looked has no
field to put items in, and the arm that carries items has already said it
looked. A partially consulted half, if this crate ever needs one, is a third
arm rather than a new convention layered over the same two fields.
§What it deliberately cannot say
It describes the responder’s own consultation of the collection, never a
chain fact about any one member. Clause 7 forbids a consumer reconstructing
“never admitted” from “evicted after settlement”, and there is no arm, reason
code or per-member record here that could carry that split: after a
Consulted read, a distributor the peer was never admitted to and one it was
evicted from are both simply absent from items, exactly as before.
This does not discharge clause 6’s per-member dated absence, which needs a field this wire does not yet carry. What it closes is the per-collection consultation record.
§Relation to absence_established
AvailabilityAnswer::absence_established is this crate’s earlier, weaker
expression of the same idea: a marker beside the data, so “absence not
established, and here are seven items” stays representable and is forbidden
only by prose. Half is the intended direction for new shapes.
AvailabilityAnswer keeps its form because it has shipped consumers; it is
not a second pattern to copy.
§Fail-closed
Matching ProverState: internally tagged on outcome, no
#[serde(other)], no Default, no skip_serializing_if, and observed_at
required in every arm. An unknown or missing outcome, or a missing date,
is a hard parse error rather than a silently coerced “consulted”.
use dig_rpc_protocol::types::Half;
let looked: Half<u32> = Half::Consulted { observed_at: 1_700, items: vec![] };
let did_not: Half<u32> = Half::NotConsulted { observed_at: 1_700 };
assert_eq!(looked.items(), Some(&[][..]));
assert_eq!(did_not.items(), None);
assert_eq!(did_not.observed_at(), 1_700);Variants§
Consulted
The collection WAS consulted, and items is its complete answer as of
observed_at (Unix seconds). An empty items here means “none”, and the
reader derives staleness itself from observed_at.
Fields
NotConsulted
The collection was NOT consulted as of observed_at (Unix seconds):
nothing looked, so there is no answer here to read as “none”.