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.

EndpointPurpose
List Excluded PlotsRead 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_to are 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_override is refused on this axis. A stored verdict would be ignored and could contradict the filing it sat on.

What an exclusion does downstream

SurfaceAn excluded plot
Audit-trail PDFkept, under Operator-Excluded Plots, with its basis, narrative and signatory
report.geojsondropped, under every include= value
TRACES submissionnever 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:read to list, eudr:write to change.