# The ASN said 48 cases. The dock saw 47. Now what?

> transactions.dev · by visibility.cloud — 2026-07-31
> Written for the RFID systems-integrator / VAR practice — the field deployment engineer commissioning a receiving site who needs a result to show the client today.

One thesis: **once the paperwork and the portal both speak GTIN and SSCC,
"does what was shipped match what was seen" stops being a phone call and
becomes a set comparison — four typed verdict classes, one exit code, and
an output that is exactly what a receiving advice needs.**

## The question, stated as set algebra

You are on site. The readers are mounted, the events are flowing, and the
client's operations lead asks the only question that ever matters at
commissioning: *is it right?* Strip the question to its structure and it
is set algebra over identifiers.

The ASN contributes the **document set**: the cases and lots the sender
claims shipped — class-grain quantities per GTIN and lot, serial sets
where the sender serializes, all of it [compiled from the 856 into
events](/blog/from-856-to-epcis-document/) with the `desadv` and `po`
references attached. The dock contributes the **observed set**: the EPCs
and classes the receiving events actually captured. Both sides are keyed
the same way — [the GTIN join](/blog/the-gtin-is-the-join-key/), SSCC for
logistic units — so the comparison is intersection and difference, not
interpretation.

## The four verdict classes

Every element of the comparison lands in exactly one class, and each
class is typed — a machine token, not a prose remark:

- `matched` — claimed and seen; identifiers agree at the finest grain
  both sides carry.
- `missing` — claimed by the document, absent from the events. The
  short-ship, the stolen case, the mis-read.
- `unexpected` — seen at the dock, absent from the document. The
  over-ship, the wrong-truck case, the substitution's other half.
- `lot_mismatch` — the GTIN matched but the lot did not: the document
  said L42, the dock read L57. The class that matters most in a
  food-safety deployment and the one a quantity-only comparison can
  never see.

## The worked report

One synthetic 856 claiming 60 cases across two pallets and three lines,
against a captured receiving-event set with one case never seen, one lot
substituted, and one GTIN nobody announced. The reconcile report, as the verb
emits it — a verbatim run over the pinned pair
`corpus/reconcile/856-receipt-01.edi` and `corpus/reconcile/events-receipt-01.jsonl`:

```json
{
  "document": "urn:epcglobal:cbv:bt:0614141000012:SHIP20260728002",
  "po": "urn:epcglobal:cbv:bt:0724142000017:PO-8813",
  "claimed":  { "pallets": 2, "cases": 60, "lots": ["2026A", "2026B", "L57"] },
  "observed": { "pallets": 2, "cases": 61, "lots": ["2026A", "2026B", "L58"] },
  "verdicts": [
    { "class": "matched", "sscc": "https://id.gs1.org/00/006141411234567890" },
    { "class": "matched", "sscc": "https://id.gs1.org/00/006141419876543210" },
    { "class": "matched", "gtin": "00614141073467", "lot": "2026A",
      "claimed": 36, "observed": 36 },
    { "class": "missing", "gtin": "00614141073467", "lot": "2026B",
      "claimed": 12, "observed": 11, "delta": -1 },
    { "class": "lot_mismatch", "gtin": "00614141765430",
      "documentLot": "L57", "observedLot": "L58", "quantity": 12 },
    { "class": "unexpected", "gtin": "00614141073474", "observed": 2,
      "note": "no ASN line covers this GTIN" }
  ],
  "verdict": "DISCREPANT",
  "exit": 1
}
```

Three findings out of six verdict entries, which is what a bad day at a
receiving bay actually looks like: a case that never arrived, a pallet
carrying the wrong lot, and two units of something nobody announced.

The first two entries are the **handling units**, compared by SSCC rather
than counted. That distinction is the difference between a report and a
number: `pallets` reading 2 against 2 tells you nothing about whether they are
the *same* two, and a claimed pallet no event ever observed is the most common
receiving discrepancy there is. It gets a verdict of its own, in the same
closed vocabulary as everything else.

And look at the totals against the findings. Sixty claimed, sixty-one
observed — the arithmetic is off by one in the wrong direction, and the
lot substitution does not move it at all, because twelve went out and twelve
came in. Only a comparison at identifier grain sees it.

Read the exit-code line carefully, because it is the contract the whole
report rides on: exit `0` means clean reconciliation, exit `1` means the
comparison ran to completion and returned a negative verdict, exit `2`
means the inputs were unusable. A discrepancy is a *result*, not a
failure — the full argument for that contract is
[the reconcile-is-a-verdict post](/blog/reconcile-is-a-verdict/), and it
is what lets you wire this report into a go-live gate: the site passes
commissioning when the reconcile job runs discrepant-free for the agreed
window, and the transcript is the acceptance artifact you hand the
client. On go-live day, the demo is one shipment, one report, printed —
the client watches their own ASN meet their own dock.

A field note that matters at real sites: the comparison is a pure
function of two sets, so it re-runs. A portal that buffered reads
through a network outage changes the observed set when it flushes;
re-running reconcile over the same ASN then upgrades this morning's
`missing` case to `matched` without human edits — the verdict history is
itself evidence of when the site actually knew what.

## Why this is a phone call today

At a franchise or co-manufacturing boundary, the two sets live in two
companies. The sender's WMS knows what it claims; the receiver's system
knows what it saw; neither speaks the other's grain, so the discrepancy
surfaces days later as an invoice deduction and gets resolved by a phone
call between two people reading two screens. What changes the physics is
shared identifiers on a shared record shape: when the claim is a
conformant EPCIS document with `desadv` and `po` references and the
observation is the same, the comparison needs no meeting — either party,
or [the read-side view both of them
buy](https://visibility.cloud/asn-po-context-in-traces), computes the
same four classes from the same two sets.

## From verdict to receiving advice

The report is not the end of the cycle; it is the input to the document
that closes it. Received 47, accepted 47, one line short, one lot
substituted — that is, field for field, what a receiving advice says.
The `recadv` reference and the receiving event it rides on are
[the next post](/blog/recadv-closes-the-loop/): the reconcile verdict
becomes the counterparty's paperwork, and the loop — `po` to `desadv` to
`recadv` on one record — closes without a spreadsheet.

If your next commissioning has a receiving bay and a skeptical
operations lead, [start at the door](/get-access/): the onboarding flow
asks what record your receiving side holds today and at what grain the
last shift actually captured.

---
Access: https://transactions.dev/get-access/ · All posts: https://transactions.dev/blog/ · Machine face: https://transactions.dev/llms.txt
