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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! The Apache-2.0 [`ComplianceStrategy`] implementations.
//!
//! Each one lifts the metrics a manufacturer supplied into a
//! [`ComplianceResult`] **verbatim**. None of them calculates, scores, or
//! decides anything: computing a determination is the job of the Wasm product group
//! plugins on the open-source path, or of a proprietary tier's own strategies.
//! Every result here therefore carries
//! [`ComplianceStatus::PassthroughNoValidation`](crate::compliance::ComplianceStatus::PassthroughNoValidation)
//! and no findings.
//!
//! # Why these exist rather than a single product group-agnostic passthrough
//!
//! [`ComplianceRegistry`](crate::ports::compliance::ComplianceRegistry) is the
//! seam a proprietary binary swaps out wholesale;
//! [`ComplianceStrategy`] is the
//! seam it swaps out **one product group at a time**, which is the useful granularity:
//! a tier that computes a real battery determination still wants the passthrough
//! behaviour for the eleven product groups it does not model.
//!
//! That seam previously had no implementation anywhere — the trait was
//! published, documented as having two, and dispatched to by nothing. These are
//! those two, and [`PassthroughRegistry`](super::PassthroughRegistry) now
//! routes through them, so the extension point is exercised by the default
//! build rather than asserted by a doc comment.
//!
//! # Which metric goes where
//!
//! [`ComplianceResult`]'s three metric fields are product group-agnostic, and the
//! product group data types are not, so each strategy states its own mapping rather
//! than leaving it to be inferred:
//!
//! | Result field | Battery | Textile |
//! |---|---|---|
//! | `co2e_score` | `co2ePerUnitKg` | `carbonFootprintKgCo2e` |
//! | `recycled_content_pct` | — see below | `recycledContentPct` |
//! | `repairability_index` | not modelled | `repairScore` |
use NaiveDate;
use crate;
use crateComplianceStrategy;
use crateProductGroupData;
/// Battery passthrough — Regulation (EU) 2023/1542.
///
/// # Recycled content is deliberately absent
///
/// `ComplianceResult::recycled_content_pct` is one number.
/// Art. 8(2) and 8(3) set **per-metal** minima — cobalt, lead, lithium and
/// nickel — and `BatteryData` carries them as four separate fields because that
/// is what the regulation requires be documented. There is no defensible way to
/// collapse four into one: averaging them invents a figure the regulation never
/// asks for, and picking one silently drops three.
///
/// The measurement bases are not even the same. For cobalt, lithium and nickel
/// the share is measured "in active materials"; for lead it is the share
/// "present in the battery". A single percentage would conflate two
/// denominators as well as four metals.
///
/// So this strategy leaves the field `None` rather than filling it with
/// something arithmetically clean and regulatorily meaningless. The four values
/// travel where they belong — on `BatteryData`, in the passport, against their
/// own thresholds.
;
/// Textile passthrough.
///
/// The product group is `provisional` in the catalog — no delegated act is in force —
/// so every field here is a manufacturer declaration against a data model that
/// is not yet ratified. `PassthroughNoValidation` is the only honest status, and
/// `gate_determination` would downgrade a binding one anyway.
;
/// The error for a strategy handed data for a different product group.
///
/// A dispatch bug rather than bad user input, but it is reported as
/// [`ComplianceErrorKind::InvalidInput`](crate::compliance::ComplianceErrorKind::InvalidInput) because from the strategy's position
/// that is exactly what it received, and because the alternative — panicking on
/// a mismatch — would make a routing mistake in a host take the process down.