The blog · 2026-07-31
The record knows a case arrived. It should know who received it.
Written for ED-3 — the in-house supply-chain platform team — the platform engineer whose record has to survive an audit question.
One thesis: a receiving event that carries its despatch advice and its purchase order answers the auditor's first question — which shipment, against which order — and cannot answer the second — who received it — because the standard has no performer dimension; so the record carries who, the attested observer, permanently distinct from capturedBy, the warrantor account, on the same event that carries the paperwork.
The two questions
Put a receiving event in front of an auditor and the questions arrive in a fixed order. First: what is this receipt, in business terms? — which ASN, which PO, which counterparty. The transaction layer answers that one completely, with core-spec machinery: the why dimension rides on every event type, as a core field, not an extension, and the compile fills it from the documents themselves.
Second: who received it? Not which company — which observer. The person at the dock door, the agent that processed the feed, the embodied unit that scanned the pallet. And here the standard goes quiet.
The structural absence, cited so you can check it
This is a claim about a public specification, so take the citations rather than our word — the reading takes ten minutes.
EPCIS 2.0 §7.2.2 organizes the event model around five dimensions: what (the EPCs and quantity elements), when (eventTime), where (readPoint, bizLocation), why (bizStep, disposition, the business-transaction, source, and destination lists), and how (sensorElementList). Read the enumeration end to end: there is no performer dimension. No field on any event type names the worker, human or otherwise, who performed or observed the step.
The nearest thing the vocabulary offers is party grain. CBV §8.7 gives source and destination identifiers as PGLNs — parties, organizational endpoints of the transfer. A PGLN says "the receiving party is this company." It structurally cannot say "the receiver was this picker on this shift" or "this agent processed this receipt under this account" — the grain does not exist in the standard, at any field, on any event type.
So a fully conformant, fully contextualized receiving event — paperwork joined, parties resolved, schema-valid — still answers the auditor's second question with an organization chart. That is the missing dimension, and it is not a gap in your implementation. It is a gap in the specification.
The two grains of who, never collapsed
The record completes the dimension with two fields, and the distinction between them is load-bearing:
- who — the attested observer: the human, agent, or embodied agent that performed or witnessed the step. This is the worker-doing-a-task grain the standard has no room for.
- capturedBy — the warrantor account: who stands behind the capture, the authority under which the event entered the record.
These are never the same field wearing two names, because they routinely diverge: an agent may observe under an account it does not own. The integration agent that processes a WMS receiving feed observes as itself (who) under the platform team's service account (capturedBy). The temp worker scanning at the dock observes as themselves under the site's capture account. Collapse the two and you lose exactly the distinction an audit turns on — who saw it versus who vouches for the record of it. So the record never collapses them, by law.
Equally deliberate is what the event does not carry: party and organization grain beyond the event's own endpoints is derived at read time from grant chains, never stamped onto the event — which is what keeps the record true through reorgs and revocations.
The worked event
One case received against one ASN, all four joins present — the machine- legible field table for the agent reading this page:
{
"type": "ObjectEvent",
"action": "OBSERVE",
"bizStep": "receiving",
"disposition": "in_progress",
"quantityList": [
{ "epcClass": "urn:epc:class:lgtin:0614141.107346.LOT2026C", "quantity": 48, "uom": "EA" }
],
"bizTransactionList": [
{ "type": "desadv", "bizTransaction": "urn:epc:id:gdti:0614141.00001.8560012" },
{ "type": "po", "bizTransaction": "urn:epc:id:gdti:0614141.00001.4500987" }
],
"who": "id:worker:7f3a-dock-14",
"capturedBy": "id:account:acme-receiving-svc"
}
The paperwork dimension (bizTransactionList) and the performer dimension (who, capturedBy) on one event. The who resolves to a verified identity — human, agent, or thing — through id.org.ai; the projection of this event into pure EPCIS 2.0 validates against the pinned official JSON schema, because the superset is only credible while the conformant projection is exact — the two words travel together or the claim is empty.
What "defensible" means in field terms
Run the consequence through the scenarios that actually happen. A shortage dispute: the reconcile verdict says the ASN claimed 48 and the dock saw 46 — and the record names the observer of the 46, so the counterparty's "your scan was wrong" has a specific answer instead of a shrug. A mock recall: the lot's receiving events name not just the facility but the shift's observers, so the interview list writes itself. An access review: capturedBy says which accounts warrant which slices of the record, independent of who observed.
None of that is available from paperwork context alone, and none of it required breaking conformance to get. The executive telling of the same argument — the trace that carries its paperwork and its performers — is the family's brief at visibility.cloud; the capture door the events flow through is epcis.dev.
The paperwork tells you which shipment. The who tells you who was standing there. A record that holds both answers the whole audit — tell us where your receiving happens, and the flow asks the questions that decide which capture surfaces get wired first.
915 words. The access flow is at /get-access/; the family's event door is epcis.dev.