Compliance & regulations
A compliance evaluation is a version-pinned execution of every applicable rule — including explicit not-evaluated outcomes. Compliance is a passing result for a named, complete evaluation set. It is not publication, and it is never guessed.
Fail-closed by design
- A product with no compliance data scores
0 / Indeterminate, with findings naming exactly what is missing — neverFullyCompliant. Unknownmeans evidence was unavailable or execution failed. It is never synonymous with "safe" or "zero".- Sector projectors are exposed per category under
/products/{id}/compliance/<sector>/full(ESPR among them), each returning score, status, and findings sourced from the requirements SSOT (obligation IDsESPR_ART<N>_<TOPIC>).
Selecting regulations
POST /api/v2/compliance/regulations/select
{ "context": { "region": "EU", "productCategory": "battery",
"lifecycleStage": "production", "effectiveDate": "2026-07-20T00:00:00Z" },
"minimumPriorityLevel": "HIGH" }curl -X POST "$BASE_URL/api/v2/compliance/regulations/select" \
-d '{
"context": {
"region": "EU",
"productCategory": "battery",
"lifecycleStage": "production",
"effectiveDate": "2026-07-20T00:00:00Z"
},
"minimumPriorityLevel": "HIGH"
}'const baseUrl = process.env.NORRUVA_BASE_URL;
const res = await fetch(`${baseUrl}/api/v2/compliance/regulations/select`, {
method: "POST",
headers: {
},
body: JSON.stringify({
"context": {
"region": "EU",
"productCategory": "battery",
"lifecycleStage": "production",
"effectiveDate": "2026-07-20T00:00:00Z"
},
"minimumPriorityLevel": "HIGH"
})
});
if (!res.ok) {
const err = await res.json(); // typed envelope: { error: { code, message, details? } }
throw new Error(`${res.status} ${err.error?.code}: ${err.error?.message}`);
}
const data = await res.json();import os, uuid, requests
base_url = os.environ["NORRUVA_BASE_URL"]
resp = requests.post(
f"{base_url}/api/v2/compliance/regulations/select",
headers={
},
json={
"context": {
"region": "EU",
"productCategory": "battery",
"lifecycleStage": "production",
"effectiveDate": "2026-07-20T00:00:00Z"
},
"minimumPriorityLevel": "HIGH"
},
)
resp.raise_for_status() # error body is the typed envelope: {"error": {"code", "message", "details"}}
data = resp.json()package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
baseURL := os.Getenv("NORRUVA_BASE_URL")
url := fmt.Sprintf("%s/api/v2/compliance/regulations/select", baseURL)
payload := []byte(`{
"context": {
"region": "EU",
"productCategory": "battery",
"lifecycleStage": "production",
"effectiveDate": "2026-07-20T00:00:00Z"
},
"minimumPriorityLevel": "HIGH"
}`)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status) // non-2xx bodies use the typed envelope {error:{code,message,details}}
}Regulations are versioned rule packs identified by CELEX id + semver, with an effective/draft/superseded lifecycle. A pack is never edited in place — new versions supersede old ones, which are retained immutably.
Reserved verdict semantics
Validation chain + ready-to-print (PRD F6):
GET /passports/{id}/validations returns the anchored validation chain ({ upi, validations[], readyToPrint }; each entry carries eventId, occurredAt, digest, signatureAlgorithm, jrcAnchor) plus the derived readyToPrint flag = validated ∧ published — true only when at least one validation result is anchored AND the passport is currently published. Publish itself is not validation-gated; treat readyToPrint as the go/no-go signal before printing carriers.