Registros de decisão · ADR-006
ADR-006: Open codes instead of closed enumerations
Commodity, unit, lifecycle status and attestation topic are open codes (bytes32 or uint8), so a new crop, unit, lifecycle or certification never requires a new version of the standard.
- ID do documento
- ADR-006
- Data
- 2026-09-21
- Fonte
- docs/adr/ADR-006.md
| Field | Value |
|---|---|
| ID | ADR-006 |
| Subject area | Data model |
| Status | Accepted |
| Date | 2026-09-21 |
| Owners | A-REX Contributors |
| Related requirements | FR-03, C-02 (SDD §3) |
| Supersedes / superseded by | — |
Context
The earlier design encoded commodity, unit, lifecycle state and certification type as Solidity enums. Adding quinoa, a new grading scheme or a new certification meant redeploying, and the function that registered assets could not accept the dynamic commodity ids another function created. Crops, grading schemes and labels are unbounded and differ by jurisdiction.
Issue
How should the batch record identify what a lot is, in which unit it is counted, which state it is in and what has been certified about it?
Assumptions
- The set of commodities, schemes and certifications is open-ended and jurisdiction-specific.
- Established code lists exist (HS, FAO, GTIN, UN/CEFACT Rec. 20).
Constraints
- No closed enumerations in normative interfaces (C-02).
Alternatives considered
| Alternative | For | Against | Outcome |
|---|---|---|---|
| Enums with a CUSTOM escape value | Type-safe for the common cases | The escape value becomes the norm; every addition is a redeploy | Rejected |
| Free strings | Human-readable | Expensive, unbounded, not comparable | Rejected |
bytes32 codes from public schemes, uint8 status with two fixed points | Zero-redeploy extensibility; cheap; comparable | Meaning lives in off-chain dictionaries | Accepted |
Decision
commodity is keccak256("<scheme>:<code>") (for example HS:100199); unit is a UN/CEFACT Rec. 20 code as bytes32; originRef and attestation topics are bytes32; status is a uint8 in which only 0 (ACTIVE) and 255 (RETIRED, terminal) are fixed and 1..254 are issuer-defined.
Argument
Fixing only the two statuses that carry an invariant keeps what matters (retired is final) and leaves lifecycles, which really do differ between a grain elevator and a cold chain, to the issuer.
Consequences
Positive
- Any crop, unit, lifecycle or certification works on day one.
- Codes are cheap to store and compare.
Negative
- A code alone is opaque; the issuer must publish its dictionary and status table.
Obligations it creates
- The metadata document carries the status table (
status.table) and the code schemes used. ARexCodesoffers helpers for common codes.
Implementation and evidence
| What | Where |
|---|---|
| Batch record | IARexBatch.BatchInit, IARexBatch.Batch |
| Metadata schema | standard/schema/batch-metadata.schema.json |
| Issuer-defined status | test/standard/ARexToken.test.js: status is changed by STATUS_ROLE only, and RETIRED is terminal |