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

Once both sides speak GTIN and SSCC, reconciling an ASN against captured events is a deterministic set comparison — matched, missing, unexpected, lot-mismatch — and its typed output is precisely the input a receiving advice needs.

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 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, 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:

{
  "document": "urn:epcglobal:cbv60728002",
  "po": "urn:epcglobal:cbv: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.or34567890" },
    { "class": "matched", "sscc": "https://id.gs1.or76543210" },
    { "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, 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, 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: 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: the onboarding flow asks what record your receiving side holds today and at what grain the last shift actually captured.

Get access.

The engine runs from npx today with no key. The hosted layer opens from the access list.