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
//! EU-methodology compliance calculators for Odal Node.
//!
//! Pure, stateless calculation of regulatory metrics from typed inputs. No I/O,
//! no infrastructure — every function is deterministic and side-effect free.
//!
//! **Placement:** these compute *EU methodology* (cradle-to-gate CO₂e, battery
//! CFB stub) plus a non-regulatory repairability heuristic, so they change when a
//! regulation changes and therefore live in `dpp-core` under Apache-2.0 — not in
//! the platform.
//! The licensing split: the methodology is open; licensed LCI datasets are
//! never bundled here and are injected at runtime via [`factor::FactorProvider`].
//!
//! # Architecture
//!
//! ```text
//! ┌──────────────────────────────────────────────────────────────────────┐
//! │ dpp-calc (Apache-2.0, open) │
//! │ │
//! │ co2e::calculate() — cradle-to-gate, operator-supplied EFs │
//! │ repairability::calculate() — non-regulatory heuristic → A–E band │
//! │ co2e::cfb::calculate_cfb() — STUB → CalcError::NotImplemented │
//! │ │
//! │ ruleset_registry — date-based ruleset resolution │
//! │ Ruleset / RegulatoryBasis — legal citation in every ruleset │
//! │ FactorProvider — runtime injection point for LCI data │
//! │ CalculationReceipt — proof-of-calculation envelope │
//! └──────────────────────────────────────────────────────────────────────┘
//! ```
//!
//! Every calculator emits a [`receipt::CalculationReceipt`] that records the
//! input hash, ruleset id + version, factor dataset version and table hash —
//! ready to be stored in the proof-bound store for notified-body audit.
//!
//! # Adding a new sector calculator
//!
//! ## New methodology (algorithm not yet in dpp-calc)
//!
//! 1. Add `src/{methodology}/` with four files (see `co2e/` or `repairability/`):
//! - `mod.rs` — `pub fn calculate(inputs, ruleset) -> Result<...>` + output types
//! - `parameters.rs` — typed input struct (derives `Serialize` for receipt hashing)
//! - `thresholds.rs` — `pub trait {Methodology}Ruleset: Ruleset { ... }` + concrete impls
//! - `golden_vectors.rs` — `#[cfg(test)]` regression tests
//! 2. Every `impl RepairabilityRuleset / Co2eRuleset / CfbRuleset` must also
//! `impl Ruleset` and fill `regulatory_basis()` with the EU citation.
//! 3. Add a `resolve_{methodology}()` function to `ruleset_registry/resolve.rs`
//! and a `&NewRuleset` row to `all_rulesets()`.
//! 4. Write golden vectors, including the `all_concrete_rulesets_have_non_empty_regulatory_basis` pattern.
//! 5. Register the module in `lib.rs`.
//!
//! ## New product category on an existing methodology
//!
//! 1. Add `impl Ruleset + impl {Methodology}Ruleset` for the new struct in `thresholds.rs`.
//! Fill `regulatory_basis` from the product-specific delegated act.
//! 2. Add a row to the resolver table in `ruleset_registry/resolve.rs` and to
//! `all_rulesets()` (one-liner each).
//! 3. Add golden vectors. Run `cargo test -p dpp-calc`.
//!
//! # Effective dates
//!
//! How a governing ruleset is selected, why `Pending` has no date, and the
//! conditional `max(floor, entry-into-force + N months)` arithmetic that is
//! deliberately not built yet:
//! see `docs/architecture/EFFECTIVE-DATES.md`.
//!
//! ## Pending delegated act (stub)
//!
//! Use `Effectivity::pending(empowerment, adoption_deadline)` and
//! `regulatory_basis.regulation = "pending — {PEFCR title}"`.
//!
//! There is **no date sentinel**. A pending ruleset has no application date, so
//! it resolves for no date at all and `ensure_active_on` returns
//! `CalcError::RulesetUndetermined` naming the instrument being waited on. The
//! type stays compile-visible for future wiring. A far-future `from` date would
//! assert something the regulation does not say — EU staged obligations are
//! written as *"from <date> or N months after entry into force, whichever
//! is the latest"*, so until the act lands the date is unknown, not distant.
//!
//! ## Superseded ruleset
//!
//! - Set the ruleset's `Effectivity` to `closed(from, last_valid_day)`.
//! - Set `regulatory_basis.superseded_by` to the new ruleset's ID string.
//! - Keep the row in `ruleset_registry` — receipts reference rulesets by
//! ID + version, so removing a row makes old receipts unverifiable.
// Methodology-agnostic spine. Kept private and re-exported below so the internal
// grouping never leaks: external callers keep using `dpp_calc::error`,
// `dpp_calc::factor`, `dpp_calc::receipt`, and `dpp_calc::ruleset`.
// ── Stable public paths for the spine ────────────────────────────────────────
pub use ;