A checkpoint that verifies a good's provenance offline — and stays honest when it can't reach the issuer. A reference implementation.
Goods cross checkpoints carrying provenance claims. Two questions matter at the gate: is this claim authentic, and does it still stand? A signed credential answers the first offline and forever. The second — whether the issuer has since revoked the claim — is a fact that lives at the issuer and changes over time, and at a real checkpoint the issuer is often unreachable. Border Authority is a small, runnable answer to what a verifier should do in that moment.
A good presents a provenance credential issued upstream. The checkpoint verifies it — it never issues one of its own — and renders one decision, allow or hold, sealed into a record that cannot be edited without the edit showing. When it cannot reach the issuer to confirm revocation, it does not hang and it does not silently wave the good through. It follows a posture it committed to in advance, and it seals the decision together with the visibility it had when it made it.
This is infrastructure, published as a reference. It is not a product.
It is built on a shared trust primitive, provenance-core — revocable
verifiable credentials and a tamper-evident hash-chained ledger — vendored into
this repo at core/. The same primitive underlies two sibling implementations:
one for the agent that acts (an agent whose every action is authorized by a
revocable credential and sealed into a tamper-evident log) and one for the
person who presents (a privacy-preserving, revocable eligibility credential).
This repository is the primitive applied to the good that moves — the subject
that is checked rather than the one that acts.
- Open a checkpoint and commit it to a posture for issuer-unreachable
moments:
fail_closed(hold what you can't confirm) orfail_open(allow, but flagged provisional). - Present a good with the issuer reachable. The credential's signature verifies and the issuer confirms it isn't revoked → ALLOW.
- Present a good while the issuer is unreachable. Under
fail_openthe checkpoint allows it provisionally — explicitly without a live revocation check, never a clean allow. Underfail_closedit holds. - Revoke the credential at the issuer and present the same good again, now reachable → HOLD, while every earlier decision stays intact. Withdrawal does not rewrite history.
- Tamper with a sealed decision (a sandbox button) — flip a hold into an allow — and the chain verification catches it, pointing at the exact decision where trust ends.
Never used a terminal? Follow the step-by-step guide instead — it assumes no prior experience and takes about five minutes.
make dev # install the vendored core, then this package + test deps
make test # the trust checks, no services required (throwaway SQLite)
make run # serve on http://localhost:8000
# in another terminal:
make demo # drive the full flow above via curlThen open http://localhost:8000 and walk the story.
# Or drive it directly:
curl -X POST localhost:8000/checkpoint -H 'content-type: application/json' \
-d '{"name":"South Gate","posture":"fail_open"}' # -> checkpoint_id
curl -X POST localhost:8000/present -H 'content-type: application/json' \
-d '{"checkpoint_id":"<id>","issuer_reachable":false}' # -> allow_provisional
curl localhost:8000/decisions/<id> # sealed log + chain check
curl -X POST localhost:8000/scenario/offline-posture # both postures, side by sideCredentials come from provenance_core and follow the W3C Verifiable
Credentials data model, signed with Ed25519. A good's provenance credential is
typed GoodsProvenanceCredential and carries one capability, attest:provenance.
The checkpoint verifies it offline against the issuer's public key; it never
issues one. (issue_good_credential models the upstream authority, so the demo
can mint and revoke a good.)
The decision (border_authority/checkpoint.py) is the heart of this repo.
The signature is always checked offline — that never depends on reachability,
and a forged claim is a definite HOLD. What depends on reachability is whether
revocation standing can be known; when it cannot, the checkpoint applies its
committed posture rather than guessing. The four honest outcomes are allow,
hold, allow_provisional, and (under fail-closed) hold. See
ADR-0001.
The decision record is sealed into the checkpoint's hash chain using
provenance_core.ledger, unchanged. The sequence of decisions is tamper-evident:
edit a past HOLD into an ALLOW and the chain breaks from there to the head, and
verify_chain names the first break. Each sealed decision records not just the
outcome but the visibility under which it was made — reachable or not,
signature ok or not, revoked or not, provisional or not.
Two axes, as in the agent implementation: chain integrity (was the record edited?) and the decision itself (allow / hold / provisional). Revoking and re-presenting moves the second axis and leaves the first untouched — accountability without rewriting.
A good's credential is revoked upstream while two checkpoints are offline and
cannot see it. One is fail_closed, one is fail_open. The fail-closed gate
holds what it cannot confirm. The fail-open gate allows it provisionally — never
a clean allow. When connectivity returns and the revocation becomes visible, the
fail-open gate re-decides and holds, and the earlier provisional allow stays
in the record, flagged, not rewritten. The gap is surfaced, not laundered.
This is the mirror of the agent implementation's offline beat. There, an actor kept acting on a credential revoked while it was offline. Here, a verifier recorded a decision while blind to a revocation — and the posture plus the provisional flag are what keep that decision honest.
core/ provenance-core, vendored via git subtree
provenance_core/ canonical, keys, credentials, ledger, reconcile
docs/adr/ the core's own decisions
border_authority/
checkpoint.py the verifier: decide allow/hold, the offline posture (the new beat)
scenario.py the both-postures, revoke-during-outage story
storage.py SQLite persistence (checkpoints, decisions, credentials, revocations)
app.py FastAPI — endpoints + the decision-log replay, serves the UI
fixtures/ a static demo good with a provenance chain
web/ single-page decision-log UI (vanilla JS, no build step)
tests/ the trust guarantees, including pinned invariants
docs/
DESIGN.md architecture narrative, how it relates to the shared core
adr/ ADR-0001: the offline posture (this implementation's own)
RUNNING.md step-by-step run guide for a non-technical first-time user
scripts/demo.sh terminal walkthrough of the full flow
The trust primitives live in core/ (provenance-core) because they are
domain-neutral; this repository builds the goods/checkpoint implementation on top
of them. core/ is vendored with git subtree, so git clone of this repo is
self-contained — there is no submodule init step, and make dev installs the
core from the local path before this package.
- Not a customs or compliance tool. The good's "provenance" is a few origin hops in a fixture — set-dressing. The subject is the credential, the decision, and the tamper-evident record, not real origin scoring.
- Not a real network probe. Reachability is a modeled flag so the demo is deterministic and needs no services. Production swaps in a real, time-bounded revocation lookup; the decision logic is unchanged by that.
- Not a peer revocation network. An offline checkpoint does not know, and does not reconstruct what it missed from other checkpoints. Gossiping revocation between nodes is a harder problem, deliberately out of scope.
- Not the barrier arm. It records and proves a decision; it does not actuate
a gate or decide who-may-cross at runtime. The receipt, not the gate — the
boundary shared across the whole
provenance-corefamily.
Apache-2.0. Copyright 2026 SurroundApps, Inc.