Compliance audit · eudr-a2a
Last audited 2026-10-11 against the primary sources below. Every claim in this document is a code reference (file:line) and a regulation citation.
Earlier passes are dated in the audit log at the foot of this page. The 2026-10-11 pass re-read Art. 3 end to end against the code and found the Art. 3(b) aggregate wrong; what it changed is in that log.
Sources
- Reg. (EU) 2023/1115: base EUDR (CELEX:32023R1115).- Reg. (EU) 2025/2650: December 2025 amendment. Annex II point 4 deleted, Art. 38 replaced (CELEX:32025R2650).
- Implementing Reg. (EU) 2025/1093: first country benchmark list.- Reg. (EU) 952/2013 Art. 9. EORI definition (CELEX:32013R0952).
- Reg. (EU) 2016/679: GDPR.- Consolidated EUDR text: CELEX:02023R1115-20241226.
Annex II. Fields the DDS carries
| Annex II item | Regulation text (short) | Engine field | Code |
|---|---|---|---|
| 1 | Operator's name, address, and EORI (per Reg. 952/2013 Art. 9) | 1_operator | AnnexII::operator |
| 2 | HS code, free-text description (incl. trade name, scientific name where applicable), and quantity (kg + supplementary unit where applicable) | 2_product | ProductDescriptor |
| 3 | Country of production + geolocation of every plot | 3_geolocation (Vec\<Geolocation\>) | Geolocation |
| ~~4~~ | ~~Upstream-DDS reference~~ deleted by 2025/2650 | absent | AnnexII — comment block confirms intentional absence |
| 5 | Verbatim declaration text | 5_declaration | ANNEX_II_VERBATIM_DECLARATION; byte-exact, 287 bytes |
| 6 | Signature block (signed-for-and-on-behalf-of / date / function / signature) | 6_signature | Signature; ed25519 base64 + DID + pubkey. key_held_by names who holds the signing key, so the block never reads as though a person signed what a machine signed. The operator's own sign-off is a separate record (OperatorSignOff, POST /app/api/orgs/:org/shipments/:id/sign-off). |
The engine emits these as JSON keys exactly as written, so an auditor can hold the regulation open next to the JSON and read top-to-bottom.
Articles. What the engine enforces and where
Art. 2(13). Cut-off date
"deforestation-free" means produced on land not subject to deforestation after 31 December 2020
| Where | What |
|---|---|
CUT_OFF_DATE | "2020-12-31" constant |
runner.rs | Passed verbatim to emem's /v1/eudr_dds request as cut_off_date |
| Report | "CUT-OFF 31 Dec 2020" tag in the tags strip; cut-off vertical line on field-history timeline |
Art. 2(28). Geolocation precision and polygon rule
"geolocation" means the geographical location of a plot of land described by means of latitude and longitude coordinates corresponding to at least one latitude and one longitude point and using at least six decimal digits [..] for plots of more than 4 hectares used for the production of the relevant commodities other than cattle, polygons [..]. For cattle, the geolocation refers to all establishments [..]
| Rule | Code | Status |
|---|---|---|
| ≥ 6 decimal digits required on every coordinate | validate_plot_geometry | Enforced. Server returns 400 with the exact precision reported. |
| Cattle requires polygon regardless of area | Commodity::polygon_always_required consulted by validate_plot_geometry | Enforced. Cattle + Point → 400. |
| Non-cattle plots > 4 ha must be polygons | ring_area_ha computed; Point geometries are accepted under that area | Polygon shape is the operator's responsibility above 4 ha; the validator records area_ha so the DDS document carries it. |
Test: art_2_28_rejects_under_6_decimal_precision. Test: art_2_28_cattle_rejects_point_geometry. Sample data: every samples/scenarios/.json polygon now meets the 6-digit minimum.
Art. 3. Prohibition on placement
Relevant commodities and relevant products shall not be placed on the market [..] unless [..] (a) [..] deforestation-free; (b) [..] in accordance with the relevant legislation of the country of production; (c) [a DDS] has been made available [..].
| Where | What |
|---|---|
runner.rs | When verdict is NonNegligible, the DDS document carries a non-attestation declaration instead of the Annex II point-5 wording, and the schema id is suffixed .assessment so downstream verifiers can refuse to forward it as a DDS. |
| Report | When verdict is non-negligible the printable report renders "Don't ship yet" + an explicit Art. 4(1) sentence. |
legality_assessments | Art. 3(b) is the operator's assessment, not a satellite's. The operator records one per supplier — assessor, function, date, validity, and the documents read, at least one required — and the compile reads it from the organisation's own records at the choke point. A value supplied in the request is dropped. |
Conclusion | Carries article_3a_deforestation_free and article_3b_legality as two separate findings, because they are two separate conditions and a document that merges them hides which one is unmet. |
| Stage model | needs_legality is its own stage. Without a recorded assessment a statement is indeterminate and says what to record; Art. 13 simplified due diligence is evaluated after the legality gate, not instead of it. |
This avoids the false-attestation trap: a signed document with the verbatim "no or only a negligible risk was found" wording over a non-negligible verdict would be a literal false statement.
Found 2026-10-11. legally_produced aggregated the legality findings as all(status != Failed), so an unresolved check counted as a clear one — and the tenure-and-permits check is unresolved on every statement by construction, because no satellite reads a land registry. Every statement the engine had ever issued therefore said the goods were legally produced, beside a land_tenure_and_permits: unknown of its own. The aggregate now requires every applicable finding to be Verified, which is what the field's own doc comment had always said.
Test: composite_risk tests cover every tier × fail-fraction combination including the high-risk floor.
Art. 4(1). Operator must not place product
The runner emits PipelineEvent::Blocked on non-negligible verdicts. The CLI and server present this state and refuse to mark a task paid on the assessment-only schema.
Art. 4(2). DDS reference with the customs declaration
The scenario carries an optional production.customs_declaration_ref (MRN or local reference). The report's Customs & Shipping (3b) section surfaces this field; the engine does not pre-validate the MRN format (operators in different member states use different formats).
Art. 4(3). Five-year retention
Operators shall keep [..] the due diligence statements they have submitted [..] for a period of five years from the date of submission.
| Where | What |
|---|---|
RECORD_RETENTION_YEARS = 5 | Constant surfaced in the report footer and Art. 12 panel |
EUDR_TASK_RETENTION_DAYS env (default 7) | In-process working-memory window. The 5-year archive is the operator's responsibility. |
DELETE /a2a/tasks/:id | Clears scenario + DDS payload but preserves the receipt CID + audit aggregate (Art. 17(3)(b) GDPR). |
Art. 8. Three steps of due diligence
| Step | Engine stage |
|---|---|
| Art. 8(2)(a) — information collection (Art. 9) | geo + forest stages |
| Art. 8(2)(b) — risk assessment (Art. 10) | legality + risk stages |
| Art. 8(2)(c) — risk mitigation (Art. 11) | The engine signals required mitigation in the report's Article 11 panel; the act of mitigating belongs to the operator. |
Art. 9(1). What the operator collects
Coverage matrix is surfaced in the report as the "Article 9(1) · information collected" panel.
| Sub-article | Field on Scenario | Engine behaviour |
|---|---|---|
| (a) description, type, scientific name | product.description, product.trade_name, product.scientific_name | Description and HS required; trade name + scientific name optional but recommended |
| (b) quantity (kg + supplementary unit where applicable) | product.quantity_kg, product.supplementary_unit, product.supplementary_quantity | Quantity > 0 enforced |
| (c) country (and sub-region where relevant) of production | production.country, production.country_subregion | Country required |
| (d) geolocation of every plot + date or interval of production | production.plot_geojson + additional_plots; production.harvest_window | Required; ≥ 6 decimals enforced |
| (e) supplier name, postal address, email | supplier.name, supplier.address, supplier.email | Name + ID required; address + email optional but the report flags absence in the Art. 9 coverage matrix |
| (f) downstream recipient details (when applicable) | Out of scope (operator is the recipient on first placement) | Coverage matrix marks (f) with a contextual note |
| (g) deforestation-free evidence (conclusive + verifiable) | source_receipts.emem.per_cell[].fact_cids | Every per-cell verdict carries fact CIDs; signed receipt envelope verifies offline |
| (h) lawful production evidence | legality.findings | Baseline runs country-tier + supplier-id checks; land tenure and harvest permits remain in scope for a partner provider behind LegalityProvider |
Art. 9(1). Five-year retention
Same five-year horizon as Art. 4(3). The receipt CID stays as the audit anchor even after operator-side erasure (Art. 17(3)(b) GDPR).
Art. 10. Risk assessment
Reported in the report's "Article 10 · risk assessment" panel. Criteria (a)–(k) listed with what the engine assessed and what it did not. The composite-risk function is exposed and tested:
composite = clamp(fail_fraction × 0.85 × tier_mult, 0, 1)
- Tier multipliers: Low ×0.5, Standard ×1.0, High ×1.2
- High-tier floor:
composite >= 0.15regardless of fail_fraction
Test: 8 cases in composite_risk tests.
Art. 10(2)(j). Risk of mixing / substitution
Operator-declared third-party certifications (RSPO, FSC, RA, Fairtrade, ISCC_EU, PEFC, …) are recorded in scenario.certifications and rendered in the report. They are surfaced in the Art. 10 row as mitigation evidence, not a substitute for due diligence.
Art. 11. Risk mitigation
The report's Article 11 panel is verdict-aware:
- Verdict
negligible→ "No mitigation required." - Verdict
non_negligible→ "Mitigation required" with the four
Art. 11 measures listed, plus a note that the report must NOT be submitted as a negligible-risk attestation.
Art. 12. DD system + Art. 4(2) submission
The report's Article 12 panel records the engine identity (eudr-a2a, vortx-ai/eudr), notes annual reporting under Art. 12(3), and flags submission status:
- Pre-submission with engine-issued reference (
eudr-a2a:engine:…) - After TRACES SOAP submission, the official reference replaces it
TRACES SOAP submission is on the roadmap; the engine output is otherwise submission-ready.
Art. 13. Simplified due diligence
simplified_dd_applied is set true only when the production country is on the Implementing Reg. 2025/1093 low-risk list. The flag is recorded in conclusion.simplified_dd_applied and surfaced as a tag on the report.
Art. 29. Country benchmarking
The country tier table is data/country_benchmarks_2025_1093.json, loaded at startup. High-risk (4): BY, MM, KP, RU. Conservative low-risk list (~140). Anything unlisted resolves to STANDARD.
Art. 38 (replaced by 2025/2650). Application dates
| Group | Application date | Constant |
|---|---|---|
| Default (most operators + medium-sized undertakings) | 30 December 2026 | APPLICATION_DATE_DEFAULT |
| Natural persons + micro / small operators established by 31 Dec 2024 (FLEGT-Annex products excluded) | 30 June 2027 | APPLICATION_DATE_DEFERRED_MICRO_SMALL_NATURAL |
Surfaced in the agent card's /spec page on the public console.
Signed proof
| Property | Value |
|---|---|
| Algorithm | ed25519 over canonical JSON bytes |
| CID | CIDv1, raw codec (0x55), BLAKE3-256 multihash |
| Canonicalisation | Hand-implemented JCS-style: sorted keys, no insignificant whitespace |
| Round-trip safety | canonical_b64 field carries the exact bytes that were signed and hashed, so JSON re-serialisation cannot break verification |
| Verifier | eudr verify <path> (offline); POST /api/verify_receipt (online via emem) |
Tamper detection test: tamper_detected.
TRACES NT submission output
Three formats, one CLI:
eudr compile samples/scenarios/civ-cocoa.json --out civ.json
# Engine-annotated XML (verbose; namespace urn:vortx-ai:eudr-a2a)
eudr export-traces civ.json --format engine --out civ.engine.xml
# EU Commission TRACES NT v2 shape. The wire format the Information System accepts
eudr export-traces civ.json --format official --activity IMPORT --out civ.official.xml
# Full SOAP envelope with WS-Security UsernameToken-Digest, ready to POST
EUDR_TRACES_USERNAME=service@deployer.eu EUDR_TRACES_PASSWORD=… \
eudr export-traces civ.json --format soap --activity IMPORT --out civ.soap.xml
civ.official.xml namespace: http://ec.europa.eu/tracesnt/certificate/eudr/submission/v2. Root element: <eudr:SubmitStatementRequest>. Field names match the EU Commission's v2 API spec (operatorType, statement.activityType, statement.countryOfActivity, statement.commodities[].hsHeading, statement.commodities[].producers[].geometryGeojson base64-encoded, operator.operatorAddress.fullAddress, …).
civ.soap.xml adds a SOAP 1.1 envelope with the WS-Security header: UsernameToken with PasswordDigest = base64(SHA1(nonce ‖ created ‖ password)), fresh 16-byte CSPRNG nonce, RFC-3339 UTC Created timestamp. TRACES NT's EUDRSubmissionServiceV2 endpoint accepts this verbatim.
civ.engine.xml is what we already emitted. Useful for archival and internal audit because every <EngineConclusion> and source-cited element is namespaced separately from the official submission shape.
Continuous monitoring (Art. 8(2))
# A2A SendMessage on the new skill (advertised in the agent card):
curl -X POST https://eudr.dev/a2a/rpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":"r","method":"SendMessage",
"params":{"task_type":"eudr.monitor.subscribe",
"input":{"dds_reference":"eudr-a2a:engine:CI:…","cadence":"monthly"}}}'
The agent re-runs the deforestation check on the cadence, when a new Hansen loss year appears post-cut-off for any sampled cell, the subscription emits a SignedReceipt-shaped event citing Art. 8(2). The first re-check after each annual Hansen update is free; later checks are priced per call.
civ.xml is a namespaced XML carrying every Annex II point that TRACES NT requires:
<DueDiligenceStatement
xmlns="urn:vortx-ai:eudr-a2a:dds:v2025_2650"
schema="eu.eudr.dds.v2025_2650"
submission_status="pre_submission">
<Header>..</Header>
<Operator>..<EORI>..</EORI>..</Operator> <!-- point 1 -->
<Product><HsCode>..</HsCode><Cn8>..</Cn8>..</Product> <!-- point 2 -->
<Geolocation><Plot index="0">..</Plot>..</Geolocation> <!-- point 3 -->
<!-- point 4 deleted by Reg. (EU) 2025/2650 -->
<Declaration verbatim="true">..</Declaration> <!-- point 5 -->
<Signature>
<Name>..</Name><Place>..</Place><Date>..</Date>
<Function>..</Function>
<CryptographicProof>
<Algorithm>ed25519</Algorithm>
<SignatureBase64>..</SignatureBase64>
<PublicKeyBase32>..</PublicKeyBase32>
<SignerDid>..</SignerDid>
</CryptographicProof>
</Signature> <!-- point 6 -->
<EngineConclusion>..</EngineConclusion>
</DueDiligenceStatement>
submission_status is pre_submission for filable, not_filable when the schema is .assessment, draft when the document is unsigned. A production TRACES adapter replaces the engine namespace with urn:eu:eudr:dds:v1, wraps the document in the official SOAP envelope, and POSTs to https://eudr.webcloud.ec.europa.eu/tracesnt/. The <EngineConclusion> block is dropped on submission (it is the engine's audit annex, not part of Annex II).
What the engine does NOT do
Documented openly so an auditor can see the boundary:
- Art. 9(1)(b). Lawful production. emem.dev's own response carries
a legality_disclaimer saying production-law checks are structurally outside Earth-observation scope, and that is still true: nothing here reads a land registry, a harvest permit or a record of free, prior and informed consent. What changed on 2026-10-11 is who answers. The engine no longer guesses from a country tier; the operator records their own Art. 3(b) assessment against the supplier, naming the assessor, the documents read and how long it holds, and the statement carries that verbatim. Without one, the statement is indeterminate. A partner legality provider can still sit behind the LegalityProvider trait; it is no longer the only way to reach a filable statement. The report's Article 10 panel marks (c)–(e), (j) and (k) as "Not assessed by this engine."
- TRACES NT submission. The engine produces a submission-ready
document. The SOAP envelope and CIRCABC credential flow are on the roadmap.
- HSM-backed signing in production. The bundled dev key is
deterministic and useful only for development. The server refuses to boot with the dev key over HTTPS. Production deployments must set EUDR_AGENT_PRIVKEY_B64 to a real 32-byte secret (ideally sourced from an HSM via KMS).
- Replacement for the operator's compliance programme. The
regulation places the obligation on the operator. The engine is a processor that runs steps required by Art. 8(2) and emits a signed record. The operator retains responsibility for verifying inputs and for the final submission decision.
Audit log
| Date | Auditor | Finding | Fix |
|---|---|---|---|
| 2026-10-11 | self-audit | Art. 3(b). legally_produced was all(status != Failed), so an unresolved check counted as a clear one. Every statement the engine had issued said the goods were legally produced, beside its own land_tenure_and_permits: unknown. | The aggregate requires every applicable finding Verified. New legality_assessments table and API: the operator records the assessment per supplier with assessor, function, date, validity and documents; the compile injects it server-side and drops any value in the request. New needs_legality stage; Art. 13 moved after the gate. |
| 2026-10-11 | self-audit | Annex II point 6. The operator block arrived with the request: the console overwrote the name but fell back to request-supplied EORI, and the agent surface overwrote nothing. One account could sign a statement naming another company. | name_the_operator() takes identity from the organisation record only; an unset field cannot be supplied by the request (409). Anonymous compiles must name a bundled demo operator. Added 6_signature.key_held_by and a separate operator_sign_off record. |
| 2026-10-11 | self-audit | Art. 9(1)(d) proxies. Four pack rules, including "outside protected areas", returned PASSED from OpenStreetMap boundaries while the same page said the official registers had not been checked. | HowChecked.establishes + CheckState::LooksClear: a proxy can no longer pass a rule. Amber, counted apart, still open. |
| 2026-10-11 | self-audit | Art. 4(3) / 12(5) retention. A statement's report, event stream and TRACES exports answered anyone holding the task id. | statement_access.rs gates every read to a member or a labelled, expiring, revocable share link whose token is stored as a hash. Submit is members-only. |
| 2026-10-11 | self-audit | The verifier page wrote every answer into a box it had just set to display:none. Valid, invalid and malformed receipts looked identical. | Fixed; scripts/verify_page_check.py asserts the computed display of the result box rather than its text. |
| 2026-05-17 | self-audit | Art. 2(28) ≥ 6-decimal precision not enforced (sample data had 4 decimals; engine accepted) | Added validate_plot_geometry rejecting < 6 decimals; regenerated every sample to 6-decimal coords; geom test threshold raised. |
| 2026-05-17 | self-audit | Art. 2(28) cattle-polygon rule not enforced | validate_plot_geometry rejects Point + cattle. |
| 2026-05-17 | self-audit | Non-negligible verdict still produced a signed Annex II document carrying the verbatim attestation ("no or only a negligible risk was found") | Schema id now suffixed .assessment on non-negligible verdicts; declaration text replaced with a non-attestation explanation. The receipt schema matches so downstream verifiers can route or reject without parsing the payload. |
| 2026-05-17 | self-audit | Polygon-area Hansen post-cut-off loss could be missed by the 16-cell eudr_dds sampler and silently produce a "low risk" verdict | Report's live land-cover panel now compares the polygon-area Hansen scan to the per-cell sampler and emits an amber warning when they disagree, citing Art. 8(2). |
| 2026-05-17 | self-audit | Threshold-based verdict (composite < 0.20 → negligible) ignored confirmed per-cell post-cut-off loss. Art. 2(13) is a binary condition. | Runner now flips to NonNegligible when any per-cell entry has hansen_lossyear >= 21 (or >= 2021 full-year) OR a fail-class label. Threshold is now a secondary gate. |
| 2026-05-17 | self-audit | No TRACES NT submission output. The PDF / JSON cannot be filed; the EU Information System accepts SOAP/XML only. | Added eudr-core::traces::to_traces_xml + eudr export-traces CLI. Output is a namespaced XML carrying every Annex II field plus <EngineConclusion> + cryptographic proof. A TRACES adapter swaps the namespace for the official one and wraps in the SOAP envelope. |
| 2026-05-17 | self-audit | Annex II point 6 missed the Place of signing. Regulation lists "Place" in the signature block. | New Operator.signing_place (optional) + Signature.place. Defaults to country of establishment when absent. Rendered in the PDF signature block AND in the TRACES XML. |
| 2026-05-17 | self-audit | EORI format not validated. Any string was accepted. | New is_valid_eori: ISO-alpha-2 + 1.15 alphanumeric (Reg. 952/2013 Art. 9). Server returns 400 with the exact failure mode. |
| 2026-05-17 | self-audit | Polygon GIS sanity (self-intersection, degenerate) not checked. A bow-tie polygon would pass shape + precision checks and produce an ambiguous verdict. | check_polygon_simple runs OGC-Simple-Features pair-wise edge crossing + degeneracy check on every plot. |
| 2026-05-17 | self-audit | CN8 (8-digit Combined Nomenclature) not surfaced. EU customs declaration + TRACES require CN8; engine accepted HS6. | TRACES XML carries both <HsCode> (operator-supplied) and <Cn8> (derived via zero-pad from HS≥4). Operator-supplied CN8 round-trips unchanged. |
| 2026-05-17 | self-audit | Report didn't disclose it's the audit record, not the legal submission. | Cover page now has a .status-strip panel: submission status (filable vs assessment vs draft), document role (5-year audit record per Art. 4(3)/9(1)/12(5)), and the verification path (eudr verify, fact-CID dereference URL). |
| 2026-05-17 | self-audit | Report carried only the per-cell verdict matrix and a single satellite chip. No NDVI scalar with capture date, no SAR, no crop-calendar cross-check. | Runner now does a second emem pass after eudr_dds: pulls indices.ndvi + sentinel1_raw across the polygon bbox. Each fact carries its Sentinel-2 / Sentinel-1 scene id + captured_at. Surfaced in a new "Sentinel-1 SAR + Sentinel-2 NDVI · single-snapshot per cell" panel with per-cell table, statistics, and the regulation-cited interpretation bands. Disclosed honestly: emem returns single-snapshot, not time-series. |
| 2026-05-17 | self-audit | No reference cross-check for the operator-declared harvest window. | New data/crop_calendars.json table sourced from FAO GIEWS, USDA FAS, ICCO, RSPO. New eudr-core::crop_calendar module performs cross-check per commodity × country and returns in_main_season / in_secondary_season / off_season / no_reference. Surfaced as a 12-month grid in the report comparing the declared window to the reference calendar. Five new tests covering Côte d'Ivoire cocoa, Brazil soy (main + off-season), and the no-reference fallback. |
Test coverage
cargo test --workspace. 58 tests passing across the workspace.
| Crate / file | Tests |
|---|---|
eudr-core::commodity — from_hs | 18 |
eudr-core::country — BenchmarkTable::tier (loads shipped JSON) | 6 |
eudr-core::eu — EU_MEMBER_STATES sanity | 5 |
eudr-pipeline::runner — composite_risk | 8 |
eudr-pipeline::geom — inspect (incl. civ-cocoa sample) | 4 |
eudr-receipts — sign / verify / tamper | 6 |
eudr-a2a::skills — skill catalog shape and prices | 5 |
eudr-server::routes::validation_tests — Art. 2(28) cases | 6 |
Verbatim declaration. Byte-exact check
The Annex II point 5 declaration text is mandated wording. The string in ANNEX_II_VERBATIM_DECLARATION is 287 bytes long and round-trips through the JSON serialiser unchanged:
By submitting this due diligence statement the operator confirms that due
diligence in accordance with Regulation (EU) 2023/1115 was carried out and
that no or only a negligible risk was found that the relevant products do
not comply with Article 3, point (a) or (b), of that Regulation.
This is the consolidated text from CELEX:02023R1115-20241226 Annex II, unchanged by Reg. 2025/2650.
Re-running this audit
cargo test --workspace
cargo run --bin eudr -- compile samples/scenarios/civ-cocoa.json --out /tmp/civ.json
cargo run --bin eudr -- verify /tmp/civ.json
python3 -c "
import json; d=json.load(open('/tmp/civ.json'))['payload']
print('Annex II keys:', sorted(k for k in d if k[:1].isdigit()))
print('Point 4 absent:', '4_' not in str(list(d.keys())))
for g in d['3_geolocation']:
ring = g['plot_geojson']['coordinates'][0]
md = min(min(len(repr(c).split('.')[-1]) for c in pt) for pt in ring)
print(f'plot {g[\"cell64\"]}: precision={md} digits. Art. 2(28):', 'PASS' if md >= 6 else 'FAIL')
print('Verdict:', d['conclusion']['verdict'], '· schema:', d['schema'])
"
AI Act and product-safety posture (verified 2026-06-04)
Because this engine serves other AI agents (A2A v1.0 + MCP), not only humans, its own AI-regulation posture is part of the compliance surface:
| rule | status | where enforced |
|---|---|---|
| AI Act (EU) 2024/1689 Art. 50(1) — disclose AI interaction (applies 2 Aug 2026) | Implemented early. Human surfaces brand the service as an AI agent (obvious-from-context limb); the agent card carries a machine-readable ai_system_disclosure block for agent callers. | crates/eudr-a2a/src/card.rs (AiSystemDisclosure); test guard agent_card_carries_ai_act_disclosure |
| AI Act role classification | Downstream deployer; not a GPAI model provider; not Annex III high-risk. No in-force obligation binds the service today. | REGULATORY_CROSSWALK.md §Adjacent EU rules |
| GPSR (EU) 2023/988 | Out of scope — consumer-product regulation; this is a B2B operator/trader service with no consumer nexus. | legal/terms.md §2 (B2B scope) |
| MDR 2017/745 Annex I ("GSPR") | Out of scope — medical devices only. Listed to disambiguate the acronym. | — |
Human oversight invariant: a non-negligible or indeterminate verdict is never auto-filed; TRACES submission is the operator's regulatory act under their own EU Login identity.
This page last changed on . It describes the Regulation as it stood then; where a date or a code matters to a decision, check it against the EUR-Lex text it cites.