Zain Dana HarperProof Surface · the accountability contract

ACCOUNTABILITY INFRASTRUCTURE · PROOF SURFACE

A grant of authority should expire, be traced, and say no.

Here is the whole idea, as plainly as I can put it: before an AI agent is allowed to do something, this checks that it really has permission, and if anything is unclear, the answer is no. It keeps the proof, not the promise. There is an evidence packet that records where something came from. A work-record receipt: a signed note of what the agent actually did, handed outward so anyone can check it. An authorization receipt: proof that a real person actually said yes. And a check: the doorway every action has to pass, which says no by default. Permission can be handed down a chain, person to helper to helper, but each step can only ever narrow what it was given, never widen it. Quietly grabbing more is exactly what this refuses. Every answer comes from a short, fixed list. Nothing here ever stamps a thing TRUSTED or APPROVED.

It only ever gives a recommendation; something else does the enforcing. It can say no. It can never grant a yes on its own.

v0.2.0 · stdlib-only · zero dependencies · eleven proof-packet wedges · 652 tests

Accountability built in, not just promised.

Here is the heart of it. A tool that claims to keep things accountable, but quietly hands itself power, has already broken its own promise. So I built this one to do the opposite. It will not accept anything shaped like a grab for power. Every answer it gives comes from a short, fixed list it cannot wander outside of, and you can always check which one you got. The list is allow, deny, needs-human (meaning: stop and ask a person), deploy, block. It writes down what happened; it leaves the actual stopping and starting to the program around it, or to you. It is the record, not the guard. I did not want it to be the guard.

There are two kinds of receipt, kept deliberately apart. The work-record receipt faces outward: a checkable note of what the agent did, so it can be reviewed. The authorization receipt faces inward: proof that a real person really granted permission, and it must say when that permission runs out and spell out exactly which actions are allowed. An empty list allows nothing at all. Permission has to be said out loud, kept narrow, and given an end. And the same simple rule (reject anything shaped like a grab for power) is checked at every level, even deep inside nested parts, so nothing slips through unnoticed.

The check (the doorway every action passes through) holds back its yes until permission, budget, and the actual observed situation each clearly check out. It says no by default; if anything is unclear it still says no; and even its yes is only ever a recommendation.

The contract family.

Proof-surface packet: think of it as a plain envelope of evidence. One part fills it; another part reads it. It is the shared backbone the rest of the pieces clip onto.

Work-record receipt: a checkable note of what an agent did, handed outward so someone can look it over. It only goes one way: the tool writes it and sends it out. It is never read back in and trusted as if it were the agent’s own memory.

Authorization receipt: proof that a real person said yes, a permission that is small on purpose, that runs out, and that can be taken back. It is something to check against, never something fed back into the agent as if it were settled fact. The check_action step asks one plain question (was this exact action allowed?) and answers it; it never quietly writes a “you are trusted” note into the agent’s own memory.

Pre-execution check: the doorway every action passes through before it happens. It says no by default; if anything is unclear it still says no; and its answer is a recommendation, not a command. You hand it a planned action, the permission slip behind it, a budget, and (if you have it) a look at the real situation, and it gives back a GateDecision of allow, deny, or needs-human (meaning stop and ask a person), and shows its reasoning for each one. Allow is the rarest answer. Anything it cannot clearly confirm becomes needs-human instead of quietly slipping through.

Evaluation contract: a final check before something ships, not a feel-good grade. Each thing it measures has a bar to clear and a note for whether it’s required. The evaluate step answers deploy, block, or needs-human, and it takes uncertainty seriously. If a measurement lands too close to call (partly above the bar, partly below) it stops and asks a person. If something required was never measured at all, that too is needs-human. It never ships on a maybe.

Claim ledger: a shared, traceable memory for when several agents are working together. Every claim carries how sure its source was, plus honest links: what it leans on, and what it clashes with. And those links have to point at real things. The ledger quietly raises its hand at shaky claims, at clashes someone flagged, and at everything downstream that a doubtful claim might have tainted. It tells you where things came from and how sure they are; it does not pretend to be the judge of what’s true.

Delegation chain: the trail when permission is handed down, person to helper to helper. The very first handoff has to come from a real human. An agent can never be the original source of authority. Each handoff can only narrow what it received, never widen it; a helper quietly granting itself more actions or more targets is exactly the kind of grab this catches, and it is DENIED. Each step is sealed to the one before it with a fingerprint (SHA-256), and the whole trail is locked into a single chain_binding, so quietly snipping a step off or tacking one on gets caught. The verify_delegation step gives one of three plain answers (VALID, DENIED, or UNVERIFIABLE) and it only fills in effective_scope (what the permission actually amounts to) when the answer is VALID.

Those seven pieces are the stable core, and they have not changed. What is new in v0.2.0 sits on top of them.

Eleven wedges, one seam.

The base is about permission. The next layer is about proof. A log tells you what a tool claims it did. It is only worth more than a log if it can be wrong in a way a checker can catch. So on top of the core sits a family of eleven proof-packet wedges. Each one takes evidence a tool already makes (an agent’s trace, a color reading, a benchmark run, a solver’s answer, a scientific claim) and turns it into a validated packet that carries one plain verdict: MATCH, DRIFT, or UNVERIFIABLE. And every wedge refuses to overclaim.

Each wedge is the same four things: a checker, a builder, a reviewer-facing report, and a command. They share one spine, so a verdict means the same thing across all eleven: the same crucible-faithful verdict rule, the same required plain-language decision, the same rule that a single packet never gets promoted past what it earned, the same content-addressed bundle, and the same two guards against authority-shaped content. And they all reach you through one seam, a single command with the domain filled in:

$ telos-proof <domain> --input run.json --claim "..." --scope "..." --out ./artifacts

The eleven domains, and the one way each refuses to inflate:

agent-action: an agent’s trace. The receipt id may not just be a span or trace id borrowed from the tracer; admission, side-effects, evidence, typed failures, and compute leases each stand on their own.

visual-measurement: a read-only color or display reading. A tool that only looked may not claim it calibrated real hardware without evidence that it actually changed something.

research-claim: a math or formal-proof attempt. A passed kernel replay has to disclose its axioms, toolchain, and source, and a single packet never reaches PROMOTED_LAW.

model-eval: a model, an eval set, and its metrics. Promotion is default-deny; it promotes only when the overall verdict is MATCH.

optimization-workflow: a solver run against an exact baseline. A branch that did not run claims no coverage, a penalty stand-in may not certify its own feasibility, and matching one fixture is not proof the encoding is sound.

rollout-receipt: a reinforcement-learning or post-training run. Reward, verifier, admission, and promotion stay separate; it promotes only on a MATCH verifier and an allow admission, and paid GPU or cluster time is recorded as a real, accountable external cost.

eval-attempt: a single benchmark attempt. A “correct” answer from a run that could see the ground truth is contamination, not a pass. Hosted-model use has to be disclosed honestly: a run that says it used no outside models but cites a provider receipt is a contradiction, and gets rejected.

ai4science: a claim-to-experiment run. It rejects a discovery claim that was never measured, asks for independent reproduction, and requires a human to look before anything reaches a peer-reviewed rung.

conservation: a transformation plus a declared invariant. The check has to carry a negative fixture that provably breaks the invariant, because a checker that cannot fail on a known-bad input is not a checker.

control-certificate: a stability, termination, or convergence claim (the robotics and cybernetics track) plus a declared certificate. The certificate kind has to actually witness its defining conditions, the fixture has to violate it, and real-hardware validity is never claimable from simulation alone.

competition-attempt: a competition or judge attempt. The judge’s repo is pinned to an exact source (a real head fingerprint and file count), the verdict may only lean on certificate layers that actually ran, and a MATCH needs an executed, passing judge verdict, so a “pass” with nothing run is impossible by construction.

Every wedge is optional and needs nothing installed. It treats the crucible as an optional peer, not a master: it carries a verdict, but it also emits the thesis and measurements so an independent checker can re-derive that verdict from the same evidence.

Four shared checks that keep the whole family honest.

Some ways of inflating a claim are not specific to one domain. They show up everywhere, so the guard against them rides the same spine and is shared across the family. Each of these is an optional disclosure: leave it off and the packet validates exactly as before; declare it and it has to stay honest.

Branch matrix. When a run declares several branches, each one either actually ran (and records the MATCH, DRIFT, or UNVERIFIABLE it earned) or is fenced off, and then has to carry real evidence of the fence. A fenced branch that claims a verdict is rejected, and a claim that cites a branch which never ran is rejected too. A branch that did not run is not evidence.

Witness tier. A claim may not name a stronger level of proof than the strongest checker that actually ran. If the checker you were aiming for never executed, you cannot say you reached its tier.

Evidence independence. Reaching a fact-level rung takes at least one kind of evidence that is not from a single source. Evidence that all comes through one modality caps out at “hypothesis”: one angle on a thing is not enough to call it a fact.

Replication. One instance is never a generalization. When a packet claims something holds at scale, the same contract has to replay across two or more independent instances, and every one of them has to come back MATCH. Fewer than two, or any instance that is not a match, and the scale claim is rejected. Per-instance warnings are kept, never quietly dropped.

Each check names one specific way a claim gets inflated, and refuses the packet when that inflation is present. That is the through-line of the whole family.

One bundle that carries every flagship’s receipts.

This is the piece that ties the toolkit together. The organ-receipt-bundle is a shared envelope for the receipts my flagships produce, so one review packet can carry proof from several tools at once and another tool can validate the whole thing without importing any of them. It links receipts together by fingerprint, by reference, by advisory status, and by how they relate, and it deliberately does not embed heavy payloads or hand out authority.

The kinds it accepts are a closed set, and in v0.2.0 that set carries five flagship receipt kinds: a crucible assessment, a forum route, an index context envelope, a gather corpus, and a learn receipt. It also carries EMET witness receipts by fingerprint and reference. So a single bundle can mix receipts from crucible, forum, index, gather, learn, and EMET side by side. Anything outside that set is still refused: the vocabulary was extended, not thrown open.

This is the cross-flagship spine. One bundle, many organs, checked by a tool that needs none of them installed.

Keep your stack; attach receipts. The trace_adapters layer wraps the observability and eval tools people already run, as evidence inputs rather than replacements. It normalizes OpenTelemetry and LangSmith / Langfuse run trees into the agent-action trace shape, and it imports evidence from MLflow, Weights & Biases, Braintrust, Arize Phoenix, promptfoo, Helicone, DVC, and SLSA / in-toto. Each importer keeps the tool’s own references and, crucially, declares out loud the proof-layer fields the export simply cannot supply (who authorized it, the workspace state, the verification verdict, the decision). It does not pretend an export contains something it does not. A coverage registry keeps that honest: every priority tool has to have a covering adapter.

Don’t take the contract. Watch it refuse.

The check and the delegation chain are the two places permission actually gets checked, so let’s watch them work. Each example below is real: something that ought to be refused, and the plain answer it gets back.

Exhibit I Proof Surface · the check is default-deny and fail-closed
# a gate request (dict) whose authorization receipt is absent
>>> evaluate_gate(request)
GateDecision(decision="deny")
  authorization: no receipt, deny
  budget:        unknown, needs-human
  state:         no observation, needs-human

# an authorization receipt whose allowed_actions list is empty
>>> check_action(receipt, "write_file")
False   # empty allowlist authorizes nothing

# a receipt dict missing expires_at: validation rejects it
>>> validate_authorization_receipt({"allowed_actions": ["write_file"]})
invalid: "expires_at" required, authority must expire

$ pytest
652 passed in 1.89s

No permission slip, the answer is no. An empty list of allowed actions, the answer is no. No end date, and the slip is thrown out before the check even looks at it. A yes has to be earned by passing every check. It is never just what’s left when nothing says no.

The check lives in proof_surface/pre_execution_gate.py, the permission slip in proof_surface/authorization_receipt.py. Captured live from pytest (652 passed in 1.89s), stdlib-only, zero dependencies, github.com/HarperZ9/proof-surface. Honest limit: the check only gives a recommendation; the program around it, or you, does the actual enforcing. And the fingerprint-chain that seals the handoffs proves each step connects to the one before it. It is not proof against a determined faker who rewrites a step and re-seals the whole thing to match. Real protection from forgery needs an outside anchor (keep a copy of chain_binding somewhere separate, or check a proper signature). Ask it for a signature it has no way to check, and it answers UNVERIFIABLE rather than fake a pass.

Exhibit II Proof Surface · delegation chain refuses privilege escalation
# root hop: human grants agent-A a scope of ["read_log"]
# second hop: agent-A tries to delegate ["read_log", "write_config"], wider
>>> verify_delegation(chain)
DENIED   # hop 1 scope is not a subset of hop 0: privilege escalation

# a chain whose root from-field is an agent, not a human
>>> verify_delegation(chain_rooted_in_agent)
DENIED   # root hop must be a human: authority cannot originate with an agent

# a valid chain: human → agent-A ["read_log"] → agent-B ["read_log"]
>>> verify_delegation(valid_chain)
VALID    effective_scope = ["read_log"]

A helper can never widen what it was handed. The very first link has to be a person. And effective_scope (what the permission actually adds up to) is filled in only when the answer is VALID; a DENIED or UNVERIFIABLE answer carries none.

The handoff logic lives in proof_surface/delegation_chain.py, and any unexpected extra data is refused at every level. Action and target names have to match exactly, capital letters and all, because the real things they point to do too. Honest limit: same as before: the seal proves each step connects to the one before it, not that any particular person truly signed it. 652 passed in 1.89s, the full proof-surface test set.

What it is, and what it is not.

Proof Surface is a small set of checkers and decision-helpers: plain Python, nothing extra to install, 652 passing tests. Every answer comes from a short, fixed list; none is invented; and not one of these pieces ever hands itself power. The rule against power-grabs is checked all the way down, even deep inside nested parts, so nothing sneaks past a check that only looked at the surface.

Plainly: the check only recommends. This tool advises; the program around it does the enforcing. A check that called itself the guard and ran right inside the very thing it was supposed to be guarding wouldn’t really be a check at all. So I kept this to the promise and the record, and left the actual enforcing in your hands, where you can look at it, and swap it out, including for your own version if you don’t trust mine.

This is one person’s first working version, built from plain Python: the parts I can honestly stand behind, not a finished, hardened guard for real-world use. I would rather tell you where that line is than paint over it.

The claim ledger keeps things honest about doubt: a claim nobody believes at all (confidence 0.0) is still written down, not quietly dropped or nudged upward. The evaluation contract won’t ship on a maybe: a measurement that lands too close to call stops and asks, it never just passes. And the delegation chain’s seal will catch a step that’s been damaged, or quietly snipped off, or tacked on. But it can’t stop a determined faker who rewrites a step and re-seals the whole trail to match. That edge is named out loud, not glossed over.

Sample reports. These pieces produce real review packets you can hold and hand off. Here are a few, from an early run in an earlier format: a release-readiness report, an EMET witness sample, a proof-index, and a public-surface-sweeper review.