Registros de decisiones · ADR-024
ADR-024: Places in batch metadata are ISO codes (schema 1.3.0)
How is the region of a batch's origin written in the metadata document, and how is the change introduced without invalidating documents whose hashes are already on chain?
- ID del documento
- ADR-024
- Fecha de la decisión
- 2026-10-30
- Fuente
- docs/adr/ADR-024.md
From schema 1.3.0, origin.region is an ISO 3166-2 subdivision code (or the ISO 3166-1 code of the country where
no subdivision applies), checked by pattern; a name for people goes in the optional origin.regionName, which no
reader or mapping uses.
| Field | Value |
|---|---|
| ID | ADR-024 |
| Subject area | Metadata schema, places |
| Status | Proposed (2026-10-30). In schema/batch-metadata.schema.json 1.3.0, unreleased; not accepted: it needs the confirmation of two independent implementers (GOVERNANCE.md) |
| Date | 2026-10-30 |
| Owners | A-REX Contributors; requested by the A-REX Platform (owner decision 2026-10-30: places are always ISO codes) |
| Related requirements | AREX-CORE §3.5 (metadata), §8 (personal data), ADR-006, ADR-008, ADR-019 |
| Supersedes / superseded by | — |
Context
origin.country has been an ISO 3166-1 alpha-2 code since schema 1.0.0, but origin.region was free text ("First-level
administrative region"). The published examples show what that produces: "Buenos Aires, partido de Tres Arroyos", "Mato
Grosso". The same state is written in several languages and spellings, a district can slip in next to the state, and
nothing stops a farm's town or a plot name from being written there. A reader cannot group lots by region, an EPCIS or
UNTP exporter cannot map the value (interop/UNTP.md, Places as codes, maps only codes), and a
regulator's regional lists (EUDR country benchmarking, which may classify parts of a country; US state rules) cannot be matched
without guessing. The A-REX Platform has stored places as ISO 3166-2 codes since its geo migrations and exports them
as codes; its documents still had to declare a version whose region means "any text".
Issue
How is the region of a batch's origin written in the metadata document, and how is the change introduced without invalidating documents whose hashes are already on chain?
Assumptions
- ISO 3166-2 codes are the country's ISO 3166-1 alpha-2 code, a hyphen and one to three letters or digits
(
BR-MG,US-NY,AR-B,GB-ENG,FR-75C). ISO maintains them; changes are published in its newsletters. - A metadata document is committed by
metadataHashand cannot be edited; a correction is a new document (setBatchMetadata). - Codes are language-neutral; names belong to the reader's language and are best produced by the reader.
Constraints
- Every document valid under 1.0.0, 1.1.0 or 1.2.0 stays valid (its
schemaVersionkeeps its rules). - No coordinates, plots or natural-person identifiers (ADR-008), and
originRefis never derived from location (ADR-019). - JSON Schema cannot compare two fields: that a code belongs to
countryis checked beside the schema.
Alternatives considered
| Alternative | For | Against | Outcome |
|---|---|---|---|
| Keep free text, recommend codes in prose | nothing changes | nothing is checked; exporters and readers keep guessing | Rejected |
A new field regionCode next to the free-text region | no field changes meaning | two fields for one fact that can disagree; the text field stays the one people fill | Rejected |
Full ISO 3166-2 code list as an enum | exact | about 5,000 codes, updated by ISO several times a year: the schema would need a release for each change | Rejected |
region is a code from 1.3.0 by pattern, older versions keep text, an optional display name | one field, one meaning; checked; old documents valid | the pattern cannot tell that MG is Madagascar and not Minas Gerais: validators check the country prefix | Proposed |
Decision (proposed)
Schema 1.3.0 (together with ADR-017's extensions):
origin.regionis the ISO 3166-2 code of the subdivision where the goods were produced, normally first level (state, province, department), for exampleBR-MG. Where no subdivision applies (a city state, a country without subdivisions in ISO 3166-2, or an issuer that knows only the country), it is the ISO 3166-1 alpha-2 code of the country. Pattern:^[A-Z]{2}(-[A-Z0-9]{1,3})?$, applied whenschemaVersionis not1.0.0,1.1.0or1.2.0.- The code belongs to
origin.country: its first two letters equalcountry. A validator SHOULD check this beside the schema. - New optional
origin.regionName: a display name in any language, informative only. Readers, validators and mappings use the code. - A region is never a plot, a farm's town, a name or coordinates.
Migration for 1.2.0 producers: declare "1.3.0", write the code in region (move any name to regionName, and drop
anything finer than the subdivision, such as a district or a town). Documents already committed stay as they are; a
correction (setBatchMetadata) that declares 1.3.0 carries the code.
Argument
One field with one meaning is easier to fill, check and map than two that can disagree. Tying the rule to the
declared schemaVersion keeps every committed document valid, which an immutable metadataHash requires. A pattern
instead of the code list keeps the schema stable while ISO updates its list; the country-prefix check catches the one
confusion the pattern allows.
Consequences
Positive
- Lots can be grouped, filtered and matched against regulators' regional lists by code.
- EPCIS and UNTP exports carry the region without guessing (UNTP
characteristics.productionPlace.subdivisionCode). - Names are shown in the reader's language from the code.
Negative
- Producers moving to 1.3.0 must map their region names to codes.
- The pattern accepts well-formed codes that ISO has not assigned; checking assignment needs the current ISO list.
Obligations it creates
- Tests in
test/metadata-schema.test.mjs(codes accepted, names and malformed codes refused from 1.3.0, free text still valid for 1.0.0 to 1.2.0, the examples' codes belong to their country). - The examples declare 1.3.0 with codes.
- interop/UNTP.md and interop/EPCIS.md map
regionas a code.
Implementation and evidence
| What | Where |
|---|---|
| Schema | schema/batch-metadata.schema.json 1.3.0: origin.region (pattern through if/else on schemaVersion), origin.regionName |
| Tests | test/metadata-schema.test.mjs: "from 1.3.0, origin.region is an ISO 3166-2 code, or the ISO 3166-1 code where no subdivision applies" |
| Examples | examples/batch-metadata.example.json (AR-B), batch-metadata.pact-pcf.example.json (BR-MT), batch-metadata.upstream.example.json (AR-B) |
| First implementer | A-REX Platform (places stored as ISO 3166-2 codes; documents declare 1.3.0) |
Related decisions
- ADR-006: open codes for commodities and units; places use the ISO lists the world already uses
- ADR-008: no coordinates or natural-person identifiers in the batch record
- ADR-017:
extensions, the other addition of schema 1.3.0 - ADR-019: capabilities in the standard, policy in profiles;
originRefis never derived from location