Lot traceability by containment
Stamp the lots each unit consumed onto its row as an array facet. Every row that used a lot is then one containment query.
The situation
A supplier reports a bad resin lot, LOT-7. Quality needs every part that used it, across every station, today, without a reporting pipeline.
The recipe
await lt.escalations.resolve({ id: stepRowId, resolverPayload: { ok: true }, metadata: { lots: ['LOT-7', 'LOT-12'], units: ['SN-101', 'SN-102'] },});curl -G https://lt.acme.dev/api/escalations \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode 'facets={"lots":["LOT-7"]}'The outcome patch lands on the row as it closes. Containment on an array matches any row whose list includes the value, and the GIN index serves it.
The guarantee
The lots are written in the same atomic update as the resolve, so a closed step always carries its trace. A unit’s whole path is every row whose units holds it. Machines on MQTT get this stamped for them: the gateway merges trace and lots facets as each unit is released. See Machines.
Related patterns
The escalation boundary
Find a container by held key
Which bin holds order ORD-9 is one GIN-indexed containment query on the bin rows. No side table tracks membership.
Resolving from anywhere
The row is the production log
A station resolves its in-flight row with the run's result, so the work queue is also the record of what was produced and how long it took.
The physical world
Handoff row
Each hop between stations is one row naming the units that move; it resolves with a receipt or a typed error code.
The escalation boundary
Reciprocal add
A bag joins a bin and the bin records the bag in one statement. Both rows change or neither.
