Treeship
Get started

Replay levels

What each replay-check level actually proves — and what it doesn't.

When treeship verify or treeship package verify runs against a package that contains an action consuming an Approval Grant, it can speak to up to four replay levels. Each level is a separate check, emitted as its own row, with its own evidence requirement. The output reports the strongest level it actually achieved — never overclaims, never silently downgrades.

✓ approval binding         nonce matched a signed approval
✓ approval scope           actor / action / subject matched approval scope
✓ replay package-local     no duplicate approval use inside package
✓ replay local-journal     local Approval Use Journal passed, use 1/1
✓ replay checkpoint        included journal checkpoint verified
✓ replay hub-org           cp_42 signed by hub://zerker-org verifies; covers 1 use

(when no Hub-signed checkpoint is embedded, the last row reads - replay hub-org not checked (no Hub checkpoint in package) instead).

The four levels

LevelWhat it provesWhat it doesn'tAvailable in
package-localNo duplicate use inside this packageSays nothing about uses on this machine outside the package, or on other machinesAlways
local-journalThe recorded use is within max_uses per the workspace's local journalSays nothing about other machinesVerifier has Treeship workspace
included-checkpointAn embedded JournalCheckpoint's record_digest verifies offlineDoesn't bind to your workspace journal; only proves the checkpoint records weren't tampered after sealingPackage carries checkpoints
hub-orgA signed Hub checkpoint validates global single-use across machinesAvailable since v0.9.9 (consumer side). Verifies an embedded Hub-signed JournalCheckpoint and its coverage. The Hub server itself is out of scope for v0.9.9.

How each level is checked

package-local (always offline, always available)

Reads the package's embedded approvals/uses/*.json files. Counts uses sharing (grant_id, nonce_digest) and compares to the use record's max_uses snapshot.

  • Pass: every grant's recorded uses are within max_uses. Two legitimate uses of a max_uses=2 grant pass.
  • Fail: uses exceed max_uses, or two records carry the same use_id (always a corruption — never legitimate).

This is the v0.9.6 behavior, preserved.

local-journal (CLI-side, workspace-aware)

Calls journal::find_use_for_action(grant_id, nonce_digest, max_uses_hint) against the workspace's <config>/journals/approval-use/. Asks the verify-time question — "does the recorded use's use_number stay within bounds?" — distinct from consume-time's "would the next use exceed?".

  • Pass: the journal has a record for this (grant_id, nonce_digest) and its use_number ≤ max_uses.
  • Fail: journal record exists but exceeds max_uses.
  • Warn: no journal in this workspace; falls back to package-local. Bare-package verification in someone's inbox doesn't error here.

included-checkpoint (offline)

Reads the package's embedded approvals/checkpoints/*.json. Recomputes each record_digest from canonical form and compares.

  • Pass: every checkpoint's stored digest matches the recompute.
  • Fail: any checkpoint was tampered after sealing.

A checkpoint is itself a Merkle commitment over a contiguous range of journal records. The Hub-signed variant (checkpoint_kind: hub-org) carries an embedded Ed25519 signature over the canonical signing bytes; that signature is what the hub-org row checks.

hub-org (consumer side, since v0.9.9)

A JournalCheckpoint with checkpoint_kind: hub-org carries five extra fields: hub_id, hub_public_key, hub_signature, signed_at, and covered_use_ids. The verifier emits replay-hub-org PASS only when every gate clears:

  1. Signature verifies. The Ed25519 signature decodes against the embedded public key over canonical_hub_signing_bytes() (every signed field except the signature itself).
  2. Coverage is explicit. Every use_id in the package appears in covered_use_ids. A checkpoint that verifies but doesn't cover a particular use cannot promote the row for that use.
  3. All required fields are populated. hub_id, hub_public_key, hub_signature, signed_at non-empty.

Anything short of all three: the row is (warning by default, fail under --strict). When no Hub-kind checkpoint is embedded at all, the row reports not checked (no Hub checkpoint in package) — absent evidence is reported as absent, never as a silent pass.

Out of scope for v0.9.9: the Hub server itself — the thing that signs checkpoints — lives in a separate release. v0.9.9 ships only the consumer-side verifier. Until you have a Hub signing checkpoints and embedding them in packages, the row will keep reading not checked.

The honesty rule, baked in: Treeship will never print "global single-use enforced" or "hub-org passed" without a real Hub checkpoint that signs cleanly AND covers every use. The check exists to fire when evidence exists; absent evidence stays explicit about what's missing.

Reading the report

treeship package inspect renders each level as a discrete line under the Approval Authority panel:

approval authority (1 use from 1 grant)

  human://piyush approved agent://deployer  (deploy.production)
    grant_id:    art_2a325283550936d0c32a15ba
    subject:     env://production      max_uses: 1      uses recorded: 1
    use 1/1  use_id=use_cf0cb9fea3540e92
    ✓ package-local        no duplicate use inside package
    ✓ local-journal        local Approval Use Journal passed, use 1/1
    - included-checkpoint  no journal checkpoint included in package
    - hub-org              not checked (no Hub checkpoint in package)

When the package embeds a Hub-signed checkpoint that covers each use, the bottom two rows promote:

    ✓ package-local        no duplicate use inside package
    ✓ local-journal        local Approval Use Journal passed, use 1/1
    ✓ included-checkpoint  cp_42 verified offline
    ✓ hub-org              use use_cf0cb… signed by hub://zerker-org

A means the level was actually checked and passed. A means it was checked and failed. A - means the level was not checked — usually because the evidence wasn't present, not because the check was skipped.

Strict mode

treeship package verify --strict promotes approval-evidence warnings to failures. Useful in CI:

treeship package verify --strict ./session.treeship
echo "exit code: $?"   # non-zero on any approval anomaly

Existing receipt-determinism and event-log warnings stay warnings. Only the replay-* and approval-use-integrity rows are promoted.

Decision Cards

The "Key decisions" section under package inspect includes a Replay-warning card when no verified Hub-signed checkpoint covers every use in the package:

⚠ Replay posture: no verified Hub coverage
    Verifiers without access to your workspace's local journal can
    only check package-local replay (duplicate uses inside this package).
    Hub-org replay is not asserted -- a global single-use guarantee
    requires a signed Hub checkpoint that covers every use_id in this
    package. v0.9.9 supports verifying such checkpoints when present;
    the Hub signer itself is out of scope for this release.
    evidence:
      approval uses:   1 (see approval authority panel above)
      hub checkpoints: 0 embedded (none)
      verify rows:     replay-package-local, replay-local-journal

When a Hub-signed checkpoint is embedded and verifies, the card stays silent — the Approval Authority panel's ✓ hub-org row already tells the story.

Every Decision Card carries evidence pointers (grant_id, approval_use_id, action_artifact_id, verify check rows). No LLM, no invented intent — the narrative is generated mechanically from the receipt.

See also