Skip to content

Crate boundaries: split AAS and the trust layer out of core - #74

Open
LKSNDRTMLKV wants to merge 37 commits into
mainfrom
refactor/crate-boundaries
Open

Crate boundaries: split AAS and the trust layer out of core#74
LKSNDRTMLKV wants to merge 37 commits into
mainfrom
refactor/crate-boundaries

Conversation

@LKSNDRTMLKV

Copy link
Copy Markdown
Member

Supersedes #73, whose branch is an ancestor of this one — the two semanticId commits are included here unchanged. Close #73 in favour of this.

Implements the 0.13.0 scope of ADR-010 (sealed). Every commit is a pure move or a pure fix; no behaviour changes.

Crate layout after this

dpp-digital-link  GS1 Digital Link + link-type negotiation   (name kept, AAS/JSON-LD removed)
dpp-aas           AAS shells + submodels                      (new)
dpp-vc            credentials, did:web, status lists, JSON-LD (new)
dpp-crypto        jws + keystore                              (now a leaf: zero workspace deps)
dpp-domain        + access/, + domain/{compliance,seal}

dpp-digital-link keeps its published name — what remains is exactly what the name says, so no crates.io name is abandoned and no shim is needed. dpp-aas and dpp-vc are new names, claimed permanently at publish.

Commits

64b12f7 Replace six wrong third-party semanticIds with urn:odal-node:*
0869214 Gate semanticId provenance in CI
09c5b1e Move AAS mapping to dpp-aas (53 files, 25 renames)
ecc6474 Move credentials and DIDs to dpp-vc (38 files, 17 renames)
fa5f72c CHANGELOG
5377cae Add missing crate READMEs, align all to one pattern
cebc002 Move the disclosure policy to dpp-domain
a9e2a00 Move value objects out of ports/ into domain/
9309099 Compile README examples in the gate

The semanticId fix

Six of seven third-party identifiers were wrong — the URI scheme, not the versions. IDTA's are name-based (https://admin-shell.io/idta/nameplate/3/0/Nameplate); ours used a document-number form IDTA does not use. The ECLASS IRDI carried Code Space Identifier 01 (Classification Class) while serving as a Property semanticId, where 02 is the Property space. One, urn:idta:aas:submodel:digital-product-passport:1.0, was coined — IDTA's is https://admin-shell.io/idta/cds/dppMetadata/1.

They are removed, not corrected: substituting one unverified identifier for another repeats the defect. An own-namespace identifier truthfully says a concept is ours; a wrong IRDI falsely says it is IDTA's, to a machine. Catena-X verified and kept.

Gate mutation-checked — reintroducing a bad identifier fails with the identifier, JSON path and sector named.

Why dpp-crypto is now a leaf

access/ was the only module in dpp-crypto referencing dpp_domain. Moving it leaves the crate with zero workspace dependencies, which is what "primitives" should mean. LocalIdentityService had to move to dpp-vc as well — it depends on both jws/keystore and did_builder/passport_credential, so leaving it would have closed a dependency cycle.

KeyStore::public_key and PublicKeyInfo widen from pub(crate) to pub so the did:web builder can read public key material and revocation state. No private key material is reachable.

The doctest harness found real defects

cargo nextest does not run doctests, so no README example in this workspace had ever been compiled. Adding a ReadmeDoctests item per crate and a test-doc recipe to just check surfaced:

  • dpp-domain: Passport::new does not exist; three wrong field names
  • dpp-registry: RegistryEnvelope and RegistryStatus do not exist; issuer_did is not a field
  • dpp-plugin-sdk: trait impl missing five required methods, comment naming the wrong ones
  • dpp-calc: three examples with top-level ?, one with no imports
  • Two directory trees compiled as Rust (bare fences are Rust to rustdoc)

All fixed; harness mutation-checked.

Blocking before publish

The Catena-X allowlist entry reads verifiedBy: "assisted web verification, pending founder sign-off". It was checked against the Eclipse Tractus-X repository with the source recorded, but the allowlist is meant to record what a person read. Replace that field with a name before publishing.

just check green — fmt, clippy, workspace tests, doctests, all ten plugins, docs with -D warnings, cargo audit.

Engine repin prepared in odal-node/dpp-engine#66 (blocked on this publishing).

LKSNDRTMLKV and others added 30 commits July 14, 2026 02:46
* fix: harden input validation and error handling
* docs: pin transfer-of-responsibility articles

* fix: tier lintResult above the public view

* chore: gate all features in test, lint and doc

* refactor: share one canonical content hasher

* docs: add product lineage design proposal

* fix: protect lineage edges from field patches

* docs: correct registry status and pin seal requirements

* docs: remove stale unpublished-registry claims

* docs: scope the public-tier invariant to content

* docs: record open-issue fixes in the changelog
* docs: pin registry rules to the official journal text

* chore(release): bump workspace to 0.10.0
24 commits of redundancy cleanup across every crate, plus the version bump (0.10.0 -> 0.11.0) and CHANGELOG entry the 5 breaking changes require. Full detail in CHANGELOG.md [0.11.0]. Codacy-reviewed: 2 genuine perf findings fixed, 1 pre-existing wasm32 validation-gap note reviewed and declined (documented, not a regression), 4 informational comments needed no action.
* fix(rules): cite Art. 8 and Art. 10(5) correctly

* feat(rules): select Art. 8 phase by market date

* feat(domain): add battery schema v2.1.0

* feat(plugins): derive Art. 8 phase by date

* refactor(calc): select rulesets by law date

* chore(build): run plugin tests in check gate
* refactor(domain): model access as an Art. 77(2) lattice

* fix(domain): redact lintResult from the public view
* fix(rules): cite Art. 8 and Art. 10(5) correctly

* feat(rules): select Art. 8 phase by market date

* feat(domain): add battery schema v2.1.0

* feat(plugins): derive Art. 8 phase by date

* refactor(calc): select rulesets by law date

* chore(build): run plugin tests in check gate

* fix(domain): preserve carbon class label verbatim
Seven files asserted an "EU Electronics DPP adopted 18 March 2026" that no
instrument supports. Two of them — the electronics v1.0.0 and v1.1.0 schema
descriptions, which ship to crates.io — extended it into a fabricated
timeline naming AI servers, high-end PCBs and foldable phones with a
1 January 2027 second phase. Replaced with the real basis: Reg. (EU)
2023/1670 and 2023/1669, in force 2025-06-20, with dates left to the sector
manifest rather than restated.

cfb.rs described the battery carbon-footprint delegated act as adopted in
March 2025. It has not been adopted; it was due February 2025 and has
slipped. The module now says so and warns against mistaking (EU) 2025/606
(recycling efficiency) for it.

smartphone.rs gains a precision note only: the 2023/1669 method is in
Annex IV point 5 and the class boundaries in Annex II Table 4, and the
enacted index runs 1,00-5,00 against this heuristic's 0-10. The existing
Annex IV citations were correct and are unchanged.

No behaviour change. Full gate green.
The embedded ECHA snapshot held 30 CAS numbers against an official list
of 253 at the 2026-02-04 revision. Callers had no machine-readable way
to know how partial it was, so a finding set produced from a 12 percent
snapshot was indistinguishable from one produced against the full list.

Adds ECHA_CANDIDATE_LIST_AS_OF, ECHA_CANDIDATE_LIST_OFFICIAL_COUNT and
candidate_list_provenance(), so a caller can record what a passport was
actually checked against rather than inferring completeness.

Adds the two substances from the 2026-02-04 revision, n-Hexane and BPAF,
whose SCIP notification deadline is 2026-08-04. The snapshot is now 32
of 253 — still partial, and a test asserts it reports itself so.

Corrects the update cadence in the module docs: additions do not follow
the stated June/December rhythm, the most recent being February 2026.

Classification semantics are unchanged and were already correct — an
absent CAS yields NotInEmbeddedList, meaning unknown to this snapshot,
never cleared. A test now guards that against a well-meaning rename.
Adding a sector currently ships a silently degraded AAS mapping. The
dispatch in aas::sectors ends in a deliberate catch-all that renders an
unmodelled SectorData variant as a generic key-value submodel with no
semantic IDs. The fallback is right for forward compatibility, but it
means a missing builder produces no build error and no test failure —
just lower-fidelity interop output on a surface the EN 1822x work
depends on.

Two tests close the gap without removing the fallback: every catalog
sector must appear in the AAS case table, and no sector may resolve to
the generic builder.

The coverage test found battery absent from a table whose own docs claim
it feeds every sector. Battery is exercised by battery_end_to_end.rs, so
it is listed as covered elsewhere rather than duplicated here.
RegulatoryStatus conflated two independent questions: which legal
instrument a sector derives from, and whether its obligations bind yet.
Five of eleven sectors are not ESPR sectors — battery, toy, detergent,
construction and electronics each derive from their own instrument — and
the catalog had no way to say so.

Adds Regime as a separate axis and a Watch status for sectors tracked
with no DPP instrument at all. Watch is never determinable, inheriting
the safe answer from the existing matches!(InForce) rather than a new
branch.

Tightens the InForce doc comment, which read "legally in force, or has a
firm adopted applicability date". That trailing clause invited marking a
sector in-force on the strength of a future date. InForce now means
obligations are determinable now.

Documents dppAppliesFrom as the passport-obligation date, explicitly not
the determination gate. Gating determinations on it would suppress valid
findings: battery's passport is required from 2027-02-18, but its Art. 9
mercury and cadmium prohibitions have applied since 2008 and are
determinable today. A regression test guards this.

Breaking: SectorDescriptor gains a required `regime` field.
dpp-calc shipped only a non-regulatory six-factor heuristic on a 0-10
scale, while the index actually displayed on the energy label for
smartphones and slate tablets has applied since 2025-06-20.

Adds it, extracted from the primary text: the Annex IV point 5 formula
R = SDD*0,25 + SF*0,15 + ST*0,15 + SSP*0,15 + SSU*0,15 + SRI*0,15, all
six parameters scored 1-5 across ten priority parts, both weight sets
(rigid and foldable), and the Annex II Table 4 class boundaries. R runs
1,00-5,00.

Shipped alongside the heuristic rather than replacing it. The receipt
model identifies a ruleset by id and version, so changing the
heuristic's semantics in place would invalidate every receipt already
issued against it. The heuristic also covers product categories this
regulation does not.

The resolver is deliberately untouched: smartphone-tablet would now have
two candidate rulesets active on the same date, and picking between them
by row order is not a decision to make silently.

Twelve tests, including both weight sets summing to 1, every class
boundary driven through the calculator, and a guard that the two scales
stay distinguishable.
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](Stranger6667/jsonschema@cli-v0.46.0...ruby-v0.48.1)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-version: 0.48.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updates the requirements on [criterion](https://github.com/criterion-rs/criterion.rs) to permit the latest version.
- [Release notes](https://github.com/criterion-rs/criterion.rs/releases)
- [Changelog](https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md)
- [Commits](criterion-rs/criterion.rs@0.5.0...criterion-v0.8.2)

---
updated-dependencies:
- dependency-name: criterion
  dependency-version: 0.8.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs: refresh READMEs for the access lattice

* chore(release): date 0.11.0 and log its changes

* docs: correct ESPR citations against the OJ text

* docs: retire access-tier vocabulary and refresh dpp-calc

* docs: correct the CI coverage note on plugin tests
Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version.
- [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md)
- [Commits](marshallpierce/rust-base64@v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: base64
  dependency-version: 0.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](Stranger6667/jsonschema@ruby-v0.48.0...ruby-v0.49.1)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-version: 0.49.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

ESPR Annex III specifies the DPP data elements including the product (b), operator (g)/(h) and facility (i) identifiers - three types, not four - while Art. 13 is the registry that stores them; ProductItemIdentifier is the product identifier at item granularity rather than a fourth Annex III class.
* ci: run sector plugin tests and build all ten in CI

* ci: pin install-action to a commit SHA
@codacy-production

codacy-production Bot commented Jul 30, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 9 high

Alerts:
⚠ 9 issues (≤ 0 issues of at least minor severity)

Results:
9 new issues

Category Results
Security 9 high

View in Codacy

🟢 Metrics 640 complexity · -9 duplication

Metric Results
Complexity 640
Duplication -9

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant