1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! [`ProductGroupPayload`] — what every product-group payload can answer about
//! itself.
//!
//! # Why a trait and not a shared struct
//!
//! Eleven payloads declare a `gtin`, nine a `country_of_origin`, six a
//! `recycled_content_pct`. That looks like duplication and mostly is not: the
//! *obligation* differs. Eight acts require country of origin and put it in the
//! schema's `required` block; the battery and electronics acts declare it and do
//! not require it. A shared base has to pick one, and either choice writes a
//! false statement about EU law into a Rust struct.
//!
//! So the sharing here is on **behaviour**, which is safe, rather than on
//! **data**, which would encode a legal claim. Each payload keeps its own fields
//! exactly as its act defines them and answers a common question about them.
//!
//! # No default implementations, deliberately
//!
//! Every method is required. A default returning `None` would let a newly added
//! product group inherit "no model identifier" silently, and a registry would be
//! told that as fact. Requiring the answer makes adding a group a compile error
//! until someone has read the act and written it down — the same property the
//! exhaustive `match` this trait replaced was protecting, but now stated in the
//! group's own file instead of three matches away from it.
/// The questions any product-group payload can answer, whatever its act.