PBO Tech
← All projects

Lost in Handover

An AI agent reasoning over a real parcel's tracking history, built and running rather than just drawn as a diagram - honest about what it knows, what it's inferring, and what it doesn't know at all.

A parcel sent from the UK to Germany in October 2026 had a tracking history that was technically accurate at almost every step, and misleading at almost every step that mattered. Customs said a stage was “completed” five days before a charge turned up. A hold at what was actually a customs office looked identical, in the tracking feed, to an ordinary parcel waiting to be collected. A whole leg of the journey - the Netherlands - never showed up as its own country at all.

This demo takes that real history and asks a narrower, more useful question than “can an AI answer questions about a parcel”: can an agent built on top of a system like that one tell a customer the truth, including being honest about what it’s guessing and what it genuinely doesn’t know - rather than just repeating whatever the upstream system says, more confidently?

flowchart LR
    person["Visitor (Person)"]
    system["Lost in Handover (Software System)"]
    anthropic[("Anthropic API (Software System)")]

    person -->|"Steps through the real incident, asks the agent questions"| system
    system -.->|"reasoning mode only"| anthropic

    classDef person fill:#0a6b3a,stroke:#064a28,color:#fff
    classDef system fill:#1168bd,stroke:#0b4884,color:#fff
    class person person
    class system,anthropic system

Two ways to translate the same event

This is the part worth understanding first, because everything else in the demo builds on it.

Four fictional companies (the real companies’ own tracking pages were the source; the names here are invented, since this demonstrates a pattern of failure, not a claim about anyone specific) each hand off the parcel to the next. A tracking service sits between them and the customer, and it can translate each handover’s events one of two ways.

Lossy is what the real tracker appeared to do: squash everything down to a generic status code and a short label. Fast to build, easy to display - and structurally incapable of saying “this isn’t finished yet,” because there’s no field for that concept at all.

Source-preserving keeps what actually matters: which party said it, whether clearance is genuinely complete, where the parcel is if that’s known - and, just as importantly, an honest unknown wherever it genuinely isn’t known, rather than a blank that invites a guess.

The screenshot below is one real event from the incident, read both ways at once. Every source this is grounded in worded this moment as if customs processing were finished:

The source-preserving reading of the 16 October event: status code ZOLLWERK_RELEASED_FOR_FORWARDING, clearance complete False, with location, amount, currency and collect-by all honestly marked as not known

clearance_complete is False - because the event’s own type says this is a release for forwarding, not a final clearance, regardless of how confident the wording sounds. Nothing about this is inferred; it’s read directly off the structured data. Everything that genuinely isn’t known yet - the address, the amount, the deadline - says so plainly, rather than being left blank or guessed at.

Ask the agent the same question, at the same moment, in lossy mode, and here’s what it says instead - because that’s genuinely all lossy mode has to go on:

The lossy reading of the same event, repeated verbatim by the agent’s naive mode: ‘The customs clearance process has been completed’

Same event. Same moment in the story. One reading is honestly incomplete; the other sounds finished and isn’t.

An agent that knows what it doesn’t know

The demo’s chat panel has two modes, side by side, so the difference is something you can actually see rather than take on trust.

Naive mode needs no AI at all - it’s literally the screenshot above, the latest lossy status, repeated back verbatim. This is what the real tracker’s own interface effectively did.

Reasoning mode calls Claude with a fixed, scoped set of tools - the parcel’s full history, raw events from any one of the four parties, its current location, whether a charge looks likely, and the rules behind holding periods - and a small number of rules it has to follow: answer only from what a tool actually said; label an inference as an inference; say plainly when something isn’t known, rather than filling the gap; and treat whatever the customer typed as something to answer, never as an instruction to follow.

Both modes only ever see events up to whichever point in the real incident you’re currently viewing - asking “where’s my parcel?” on 16 October gets an answer grounded in what was known on 16 October, never a later page of the same story.

Escalation that doesn’t depend on the validation it’s meant to bypass

The real incident’s second failure, after the misleading status text, was worse: the carrier’s own automated channels - the phone system and the chatbot alike - checked the recipient’s postcode against a UK-only pattern before letting an escalation to a human through. The parcel was going to Germany. Both channels failed the same way, for the same reason: built and tested against UK postcodes, with nothing checked against anything else. The one route meant to work when automation fails was blocked by the exact same assumption that caused the earlier problems. If you’re going to automate a process and take the human out of it, the automation has to be genuinely robust across the real range of cases - not just the common one - because there’s nothing left to catch what it misses.

The demo reproduces this exactly, and lets you flip it: a “poor” toggle applies that same UK-only check, rejecting the real German postcode outright; a “good” toggle checks it against the right country instead, and the escalation goes through.

What isn’t built yet

This is an honest prototype, not a finished demo. Done: the full translation pipeline above, both agent modes, and the escalation fix. Not yet built: a monitor that proactively warns a customer before a problem lands (rather than staying silent, which is what really happened), write permissions scoped more formally than “it’s a separate tool,” a scenario showing what happens when a partner changes its event format without warning, and a proper evaluation suite.

The video above is a real, unedited recording - not mocked up - and it’s deliberately what’s shown here rather than a live link. Reasoning mode calls a real model, and running that safely for anyone passing by needs spend limits this prototype doesn’t have in place yet.

Also in this series

Third in the same “built and running rather than just drawn as a diagram” series as the Microservices Pattern Demo and the Strangler Fig Demo - a different pattern each time, kept deliberately separate rather than bolted onto one growing demo.