# In EPCIS 2.0 the Who is a company. Here's how to carry the performer conformantly anyway.

You went looking for the field. You had a real requirement — record which associate signed for the
delivery, which technician ran the transformation, which agent captured the scan — and you assumed a
standard this thorough would have a slot for it. It doesn't. This is not your mistake; it's a structural
gap in the model, and once you see it you can't unsee it. This article is the ten-minute version of what
that gap is, why it's there, and how to carry a performer through an EPCIS 2.0 repository *without*
breaking conformance — which is the only way to carry it that's worth anything.

Don't take the gap on our word. Two spec sections settle it, both public, both linked once below. Open
them; the whole argument is checkable in ten minutes.

## The gap, exactly

[EPCIS 2.0 §7.2.2](https://ref.gs1.org/standards/epcis/) defines an event as answering five dimensions,
and enumerates them:

- **What** — the EPCs and quantities the event is about.
- **When** — the event time (and record time).
- **Where** — the read point and business location.
- **Why** — the business step and disposition.
- **How** — sensor readings and other extensions.

Read the list again. The Who the standard does have lives in its party fields, and it is a **company** —
a GLN-identified legal entity. There is no performer field: no slot an auditor could point at and ask
you to fill in with the worker or the agent. A *Company* doing a *Process* is fully expressible; a
*worker or agent doing a task at the instant of the scan* is not.

"But there are party fields," you'll say — and there are, and they are the trap. The source/destination
and other party fields in EPCIS, and the CBV party role vocabulary, are **organization-grain**: they
carry a **PGLN**, a Party GLN, identifying a *company or a location's operator*, not a person and not an
agent. The relevant definitions live in [CBV 2.0](https://ref.gs1.org/standards/cbv/) alongside the
EPCIS party fields. So if you cram a worker into a party field you have done two wrong things at once:
you've mislabeled a human as an organization, and you've written a value into a slot whose vocabulary
says it isn't that. It'll pass a lax validator and fail the moment anyone reasons about the data.

That's the whole gap: **the grain the standard carries is the organization; the grain your requirement
needs is the actor.** They are one level apart, and the level you need is the one that isn't there.

## The wrong fixes, and why they cost you later

Three tempting fixes, all of which reintroduce the reinvention tax:

- **Overload a party field.** Passes today, wrong grain, and any downstream partner who trusts party
  fields as org-grain now has dirty data. Silent divergence — the exact failure EPCIS exists to prevent.
- **Fork the schema — add a top-level `who`.** Now your events don't validate against GS1's official
  schema. You've left conformance to gain a field, and every partner integration becomes bespoke.
- **Keep the performer in a side table keyed by event.** Now the "who" isn't in the event, isn't in the
  hash, isn't shareable, and drifts out of sync the first time an event is re-captured. You've built a
  second source of truth for the most disputable fact in the record.

Each of these feels like the pragmatic move and each one is a Friday you'll pay back with interest.

## The conformant way: extend up, stamp at the door, project down

The move that keeps conformance is three parts, and it's the one this repository implements:

**1. Carry the performer as a namespaced user-extension, not a fork.** EPCIS 2.0 explicitly allows
user extensions in a vendor namespace — that's a first-class part of the model, not a hack. A performer
travels as a namespaced `who` on the event. Because it's namespaced and additive, the event *still
validates against GS1's official JSON schema*: a repository that doesn't understand the extension
ignores it; one that does can reason about it. You gained a field and kept conformance — the two things
the wrong fixes make you choose between.

**2. Stamp provenance at the gateway; strip it from the payload.** The dangerous part of "who did it" is
that a sender can lie about it. So the gateway asserts `capturedBy` and an `attestationGrade` at the
door, and **caller-supplied values in those fields are stripped.** The performer identity in the record
is something the gateway *witnessed* at capture, not something the payload *claimed* about itself. That
distinction is the entire difference between a name in a log and evidence.

**3. Derive org-grain at read time from grant chains; project down losslessly.** The organization the
performer acted for isn't stored redundantly on the event and left to rot — it's derived from the grant
chain at read time, so party/org-grain answers stay correct even as relationships change. And when a
consumer wants **plain, conformant EPCIS 2.0**, the repository projects the event *down* to the official
schema **losslessly** — the extension either travels intact (partner understands it) or is cleanly
omitted (partner doesn't), and either way what's left validates. You are never forced to choose between
"has a performer" and "is conformant EPCIS."

```
# the shape (illustrative): a namespaced performer
# rides an otherwise-standard ObjectEvent
{
  "type": "ObjectEvent",
  "eventTime": "2026-07-29T14:02:11.000Z",
  "action": "OBSERVE",
  "bizStep": "receiving",
  "epcList": ["urn:epc:id:sgtin:0614141.107346.2018"],
  "readPoint": { "id": "urn:epc:id:sgln:0614141.00777.0" },
  "orgai:who": "the performer — namespaced, additive, ignorable",
  // the two below: stamped by the gateway, caller values stripped
  "orgai:capturedBy": "STAMPED AT THE DOOR",
  "orgai:attestationGrade": "STAMPED AT THE DOOR"
}
# project(event) → validates against the official
# EPCIS 2.0 JSON schema, extension intact-or-omitted
```

*(The `orgai:` extension terms above are illustrative of the shape; they are held for a later context
flip and are not asserted as a live GS1-registered namespace. The point is the pattern — namespaced,
additive, gateway-stamped, losslessly projectable — not the exact prefix.)*

## The same interface for a person and an agent

Here's why this matters more now than it did five years ago. The performer at the moment of a scan is
increasingly *not a person* — it's a logistics agent, a coding agent, an automated line controller. If
"who did it" is a human-shaped afterthought bolted onto a side table, you get to rebuild it the day an
agent becomes the actor.

This design doesn't have that day. A person and that person's agent capture through **one door with one
key** — the MCP door is re-dispatched through the same gateway fetch as the HTTP interface, so there is
no parallel agent path to drift from the human one. The performer extension carries a worker or an agent
with the same shape; the gateway stamps `capturedBy`/`attestationGrade` for both; the org-grain derives
from the same grant chains. A gateway-stamped, reference-vector-checked hash is exactly what lets a
*verifier agent* trust a "who" it did not itself witness. The structural gap the standard leaves is the
same gap whether a human or an agent stands in it — so you solve it once.

**Proof, not adjectives.** The capture gateway, the extension carry, the gateway stamping and the
MCP door pass their conformance tests against GS1's normative artifacts; the agent-seat provisioning
verbs, the hosted capture spine and the issued keys are dated entries in the
ledger: [What ships today](https://epcis.dev/what-ships-today/). What you
can check without believing any of that is the claim in this article: read §7.2.2 and the CBV party
fields yourself and confirm the gap is real, then re-hash the published pins on
[/conformance/](https://epcis.dev/conformance/) against GS1's own artifacts. The projection law that
keeps the fix conformant is enforced in code and graded by the same suite.

## Record the performer

If an agent — logistics, coding, or line — is going to capture and query on your behalf, with the same
key a person would use and the same performer grain, that's the intent the door is built for:

**→ [Get a capture key — segment: agent](/get-a-key?segment=agent)**

*The promise, in full: One email when your key is ready — and follow up about it from there. We
don’t sell your address or hand it to advertisers. If we stop, we say so rather than go quiet.*

Prefer not to wait? The gap is checkable without us — open the two spec sections linked above. And the
full performer model, the eight capture laws it rides on, and the provenance design are in the full write-up:

**→ [Build an EPCIS 2.0 repository — the full write-up](https://epcis.dev/build-an-epcis-repository)**

---
---

---

**Proof, not adjectives.** This build could not verify the gateway's test suite green, so no sentence on this page claims a passing run — the last verified run is recorded in the repository's own CI, not here. Live on this origin, no key: POST /translate, /validate, /hash. No conformance attestation has ever been issued. The dated ledger is /what-ships-today/.
