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
//! The open, data-driven catalog of EU product groups.
//!
//! This is one of two catalogs and it carries **no law**. The acts, their
//! bindings and the obligations they create live in
//! [`crate::instrument`], which was lifted out of here because it is a
//! different axis that changes for different reasons.
//!
//! [`ProductGroupCatalog`] is the single source of truth for *what product groups
//! exist*. Unlike a closed `enum` they are described by **data** — one embedded
//! manifest per group at `crates/dpp-domain/product-groups/{key}.json` — and new ones
//! can be added at runtime via [`ProductGroupCatalog::register`] without recompiling.
//!
//! Each [`ProductGroupDescriptor`] ties together a group's canonical key, schema
//! versions, product categories, disclosure classes and plugin binding —
//! resolving the "four spellings of a product group" problem by giving every component
//! one record to agree on. It carries **no law**; see its own docs for why.
//!
//! ## Module layout
//!
//! - [`descriptor`] — the [`ProductGroupDescriptor`] record shape.
//! - [`error`] — [`CatalogError`].
//! - [`granularity`] — the [`Granularity`] level a passport describes.
//! - [`product_group`] — [`ProductGroupCatalog`] itself, plus the embedded manifests.
//! - [`retention`] — the [`RetentionBasis`] provenance marker.
//! - [`status`] — the [`RegulatoryStatus`] determination gate, per binding.
//!
//! ## Where the law is, and is not
//!
//! Not here. A product group's law does not fit on the product group: ESPR Art.
//! 5(7) lets acts overlap with no precedence rule between them, so the
//! applicable set is a *set*; and an act may reach a group no manifest models,
//! so the reach has to be recorded on the act rather than the group.
//!
//! [`ProductGroupDescriptor`] used to carry a singular `regime`, `status`,
//! `dppAppliesFrom` and `retentionYears`, each assuming one act governs one
//! group. Those fields are gone. The acts, their bindings and the obligations
//! they create live in [`crate::instrument`], and the two catalogs no
//! longer overlap and so cannot disagree: this one answers *what groups exist
//! and how we serve them*, that one answers *what binds them*. Anything asking
//! whether an obligation applies goes there.
pub use ProductGroupDescriptor;
pub use CatalogError;
pub use Granularity;
pub use ProductGroupCatalog;
pub use RetentionBasis;
pub use RegulatoryStatus;