Plot exclusions
Which plots are left out of the DDS package, and the audit trail that records why.
An exclusion IS a finding on the exclusion axis (EPO-1983). It used to live in
its own table alongside the finding that recorded its reason, and while both
existed they could disagree — PUT /verdict-overrides wrote the attestation
while the table decided the filing, so the API could report a plot excluded that
the DDS still contained. One row now decides both.
Exclusions are version-scoped and carry forward when a new version is cut, with plot ids remapped if a re-ingest changed them.
| Endpoint | Purpose |
|---|---|
List Excluded Plots | Read the current version's exclusions, each with its attestation |
▶Writing an exclusion
The single-plot Exclude Plot / Include Plot endpoints and the bulk
add_excluded / remove_excluded fields on PATCH /:recordId/config were all
removed. Use the axis-generic pair instead:
PUT /regulations/eudr/audit-trail/:recordId/verdict-overrides # exclude
DELETE /regulations/eudr/audit-trail/:recordId/verdict-overrides # re-include
with axis: "exclusion", subject_type: "plot", the plot's id as subject_id,
a narrative, and a basis from the Article 10 negligible-risk vocabulary. See
Verdict Overrides/.
This is not a rename. The removed exclude endpoint accepted a bare {reason};
the replacement requires a stated ground, because an exclusion with no basis
renders as "none stated" on a legal document.
Two rules the replacement enforces that the old pair did not:
- No validity window. An exclusion is a scope decision, not time-bounded
evidence, so
valid_from/valid_toare refused with a 400 — and a CHECK constraint makes the state unrepresentable. Letting an exclusion expire would return a plot to a filing with nobody acting and no audit event. - No verdict. The finding's presence is what excludes the plot, so
verdict_overrideis refused on this axis. A stored verdict would be ignored and could contradict the filing it sat on.
▶What an exclusion does downstream
| Surface | An excluded plot |
|---|---|
| Audit-trail PDF | kept, under Operator-Excluded Plots, with its basis, narrative and signatory |
report.geojson | dropped, under every include= value |
| TRACES submission | never sent — producers are a one-to-one map over the GeoJSON features |
Removing a plot's scope is not the same as removing the evidence for it: an inspector has to see what was excluded and on what ground.
▶Audit trail
A write appends config.finding_set, a removal config.finding_removed, both
carrying payload.note = reason and payload.source = "user".
The submit-time auto-exclude writes its own exclusions with
provenance: "system": basis non_compliant_not_filed for a non-compliant
plot, or pending_review_not_filed for one still awaiting human review. Both are logged as
config.exclusion_added with systemAuthored: true. Those are not
operator-removable — a DELETE against one answers 409 naming the remedy,
because the audit trail must not record an operator withdrawing the platform's
own reconciliation.
Required scope:
eudr:readto list,eudr:writeto change.