@tracepass/dpp-validate
Evaluate an EU Digital Product Passport against its category field spec. Pure functions, no third-party runtime dependencies, 46 tests.
Part of tracepass-open · Maintained by TracePass
Given a passport and the template for its product category, evaluateCompliance returns a
three-tier verdict with findings that cite the article of EU law each one rests on. It
reads no database, opens no socket, and consults no clock.
npm install @tracepass/dpp-validate @tracepass/dpp-schemas
import { evaluateCompliance } from "@tracepass/dpp-validate";
const result = evaluateCompliance(passport, batteryTemplate, "battery");
result.verdict; // "compliant" | "compliant_with_warnings" | "incomplete"
result.critical; // findings that block
result.warnings; // findings that don't
result.conditionalCoverage; // "evaluated" | "static-only"
result.checkedRules; // ["static:required-fields", ..., "BAT-1", "CC-1"]
Three tiers
Static — required fields are present and approved, required economic operators are identified, values match their datatype, enum, pattern, and bounds.
Conditional — obligations that only fire under a condition. Battery carbon-footprint fields apply only to rechargeable batteries; CE-marking coherence triggers when a conformity status is recorded. Five categories carry these rules — battery, construction, electronics, steel and toys — plus one cross-cutting rule for every category.
Some obligations start on a date. The battery passport is mandatory from 18 February 2027 (Regulation (EU) 2023/1542 Art. 77(1)), so a missing passport identifier is a warning before that day and critical from it. The engine reads the date from an optional fourth argument, which defaults to now; pass one to evaluate as of a given day:
evaluateCompliance(passport, batteryTemplate, "battery", new Date("2027-02-18"));
Coverage — the engine reports whether it evaluated conditionals at all. For the other
six categories conditionalCoverage is "static-only", so silence is never mistaken for
a compliance claim.
It will not pass what it could not check
When the field that decides a conditional is absent, the result is an
unverifiable_conditional warning naming what could not be determined — never a quiet
pass:
{
"type": "unverifiable_conditional",
"ruleId": "BAT-1",
"target": "batteryCategory",
"article": "Art. 77(1)",
"why": "Battery category isn't set, so battery-passport scope couldn't be evaluated.",
"fix": "Set batteryCategory. Portable and SLI batteries are out of scope; LMT, EV and industrial >2 kWh require a battery passport."
}
The same principle governs the battery applicability gates: an unknown classifier shows the dependent field and warns. A mis-classified battery must never silently lose a legally-required field.
Not legal advice
A compliant verdict means this passport satisfies the rules encoded here — not this
product may be placed on the market. Delegated acts are still landing. Verify against
EUR-Lex.
Battery identifier requirement (BAT-1)
The battery passport must carry a unique product identifier. Battery Regulation Art. 77(3) requires ISO/IEC 15459 until a delegated act replaces it with EN 18219. A GS1 Digital Link URI satisfies that requirement because GS1 is an ISO/IEC 15459 issuing agency. The BAT-1 fix text in findings explains this:
{
"fix": "Provide identifier — an ISO/IEC 15459 unique identifier, e.g. a GS1 Digital Link URI
(Battery Regulation Art. 77(3) requires ISO/IEC 15459 until a delegated act replaces
it with EN 18219)."
}
Plain-language background on the rules encoded here:
- Holding data is not compliance — where DPP duties are actually discharged, and why the verdict is narrower than market placement.
- Article 77 battery passport — Regulation (EU) 2023/1542 — the article behind the battery checks and applicability gates.