behalf-record

command
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Command behalf-record produces the demo session pair (ENG-14, D9.2, Q92): two support-desk refund runs, 47 tool calls each, driven through the real MCP proxy against an in-repo fake MCP server, spooled, drained and appended to a real Tessera log.

The point is provenance. The demo artifact must come out of shipped code paths — the proxy that customers run, the spool that customers' calls go through, the CAS that holds customers' payloads, the log that customers verify — because a hand-authored recording proves only that someone can author JSON. Every receipt this command produces was signed by the same capture surface, over the same bytes, by the same code as a live session.

The scenario

Two runs of one 47-step script (scenario.go). They are identical except that the desk's search index, at step 12, returns the same two refundable orders in a different order. The agent takes results[0] in both runs, so at step 31 the refund it issues is for a different order and a different amount:

run A   step 12: ord_5512 first   step 31: refund.issue 12.00   / ord_5512
run B   step 12: ord_5518 first   step 31: refund.issue 1200.00 / ord_5518

Both runs land in ONE log with distinct run ids, their payloads in one CAS, so `behalf diff` has two runs to align and `behalf why` has one receipt to explain.

The delegation chain, and the second divergence

Before either run, the recorder performs a real headless `behalf login` against the in-repo fake OIDC provider and mints a three-hop AAT chain from what it produced (chain.go). The runs carry two variants of it: run A's three hops are all signed and all verify; run B's leaf hop arrives caller-asserted with no signature. That difference is cryptographic, not typed: the proxy verifies both chains at capture and records what it found, so `behalf why` reports "chain intact for 3 of 3 hops" on one run and "2 of 3" on the other, from recorded data.

Determinism

Recordings ship and are re-verified in CI, so two invocations with the same flags must produce byte-identical receipts. Seven things are pinned: the clock, the ULID entropy, the emitter key, the device key, the fake IdP's signing key and clock, the run ids, and a server whose answers are a pure function of its questions (see internal/proxy/deterministic.go). --live opts out of the clocks and the entropy for a genuinely live capture.

What comes out byte-identical, verified by TestDeterministicRecording: the DSSE-signed receipt envelopes, the CAS blobs they commit to, and the log directory itself — entry bundles, tiles and the signed checkpoint, since --seed derives the checkpoint key and Ed25519 signing is deterministic.

Two files are excluded, both deliberately: index.db, which is a derived, rebuildable projection that is never restored and always rebuilt (Q55, Q76), and epoch.json, which records this process's pid and start time. Neither is evidence. The spool's segment file names are wall-clock derived too, and the spool is consumed and marked done by the drain.

Usage

behalf-record --dir LOGDIR --out STATEDIR [flags]

--dir DIR         the Tessera log directory; initialized if it has no
                  checkpoint key yet. Required.
--out DIR         the behalf state directory: emitter and device keys,
                  CAS (blobs/), capture spool, login material, and the
                  generated policy and chain files. Required.
--run-a ID        run id for the $12.00 run      (default rec_9f2a)
--run-b ID        run id for the $1200.00 run    (default rec_c71e)
--start TIME      RFC3339 base for run A's fixed clock
                                                 (default 2026-08-26T09:00:00Z)
--gap DUR         how much later run B starts    (default 5h30m)
--tick DUR        fixed-clock advance per read; the proxy reads the
                  clock twice per tool call, so receipts land 2×tick
                  apart                          (default 2s)
--origin STR      checkpoint origin              (default behalf.sh/log/demo)
--seed STR        determinism seed for the ULID entropy and, unless
                  --live, the log's checkpoint key
                                                 (default behalf.sh/record/v1)
--live            use the real clock and crypto/rand entropy, and a
                  freshly generated checkpoint key: a real recording,
                  not a reproducible one
--quiet           suppress the progress lines

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL