# GS1 EPCIS 2.0 → Annex II Scenario mapping

Each **ObjectEvent** in an EPCIS 2.0 JSON-LD document becomes one
`Scenario` that the engine compiles into a signed Annex II DDS per
Regulation (EU) 2023/1115. The endpoint is **parser-only**: it does
not call the pipeline. The dashboard or A2A runner submits the
returned scenarios for compilation.

Wire format: `application/ld+json`. We accept the EPCIS 2.0 JSON-LD
context only — see the GS1 vocabulary at
<https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld>. The
XML binding is not accepted at v0.2.0.

## Field mapping

| EPCIS / ilmd field                  | Scenario field                                | Annex II ref. | Notes                                                                                  |
| ----------------------------------- | --------------------------------------------- | ------------- | -------------------------------------------------------------------------------------- |
| `epcisBody.eventList[*]`            | one `Scenario` per element                    | —             | Also tolerates legacy `eventList.objectEvent` path.                                    |
| `eventTime`                         | seed for `Scenario.id`; fallback harvest date | 1, 3          | Last 4 bytes of `sha256(eventTime)` make the id stable for re-ingest.                  |
| `bizLocation.id`                    | `supplier.id`                                 | 6             | SGLN URN. Supplier name is left blank for the operator to fill.                        |
| `epcList[*]`                        | `product.description` (GTIN list)             | 2             | Bare strings or `{"epc": "..."}` accepted.                                             |
| `ilmd['gs1:countryOfOrigin']`       | `production.country`, `supplier.country`      | 3             | ISO-3166-1 alpha-2; uppercased.                                                        |
| `ilmd['gs1:cpcv']`                  | `product.quantity_kg`                         | 2             | `{value, unitCode}` (UN/CEFACT Rec. 20) or bare number. `KGM`/`kg` → kg, `TNE`/`t` → ×1000. |
| `ilmd['gs1:harvestWindow']`         | `production.harvest_window`                   | 3             | Preferred. `YYYY-MM-DD/YYYY-MM-DD`.                                                    |
| `ilmd['gs1:harvestDate']`           | `production.harvest_window`                   | 3             | Used when `harvestWindow` is absent.                                                   |
| `ilmd['eudr:plotGeolocation']`      | `production.plot_geojson`                     | 3 (Art. 9(1)(d)) | GeoJSON `Polygon`, `MultiPolygon`, or `Point`. Validated for shape only.            |
| `ilmd['eudr:hsCode']`               | `product.hs_code`                             | 1, 2          | HS code per Annex I of Regulation 2023/1115.                                            |
| `ilmd['eudr:producer']`             | `producer.name`                               | 6             | Optional. Cooperative or farmer name.                                                  |
| — (set by parser)                   | `from_connector`                              | —             | `{ connector_id, kind: "gs1_epcis", source_ref: "event-<idx>" }`. Lineage for receipts.|

## Validation behaviour

- Wrong or missing `@context` → **400** for the whole document.
- Non-`EPCISDocument` `type` → **400**.
- Per-event errors (missing `ilmd`, missing `gs1:countryOfOrigin`,
  missing `eudr:plotGeolocation`, bad geometry type) → the event is
  skipped and a warning is added to the response. The HTTP status is
  **200** if at least one event parsed, **400** if none did.
- The operator block on each scenario is left blank; the dashboard
  fills it from the org profile (Annex II point 1) before signing.

## Why prefixed names

We read both the canonical prefixed form (`gs1:countryOfOrigin`) and
the unprefixed legacy form (`countryOfOrigin`) some EPCIS emitters
still produce. The GS1 EUDR application standard is an in-progress
profile on top of EPCIS 2.0; this pragmatic relaxation lets early
implementers feed us without waiting for full JSON-LD context
hygiene.
