Skip to main content
A proof artifact has one content digest. An accepted-result record binds a review outcome to that proof and the bytes it covered. An approval record binds a stored action decision to the same kind of exact subject.

Run the example

From an Obversa checkout, run:
The report shows that two accepted-result records cite one proof digest, stored state survives reopening, and changed workspace-anchor or output bytes return to wait:

Source

The example runs without a bound workspace. Its /workspace anchor is illustrative caller-supplied data used to show digest matching; it was not captured from a real checkout.
The clean-consumer check compiles and runs this exact source from the packed package with TypeScript 6 and TypeScript 7.

One proof artifact

writeProofArtifact stores the stable JSON bytes of one proof packet. Its reference contains the content digest, byte length, media type, and proof-packet purpose. Reordered object fields produce the same bytes and digest. Changed proof data produces another digest. The caller chooses the packet fields and proof scope. This helper does not check how a proof was produced.

Accepted results

createAcceptedResultRecord stores a result only when the graph matches the stored run plan and the run contains exactly one dispatch for that position, followed by a completed event with the same node and result. Missing, failed, or conflicting completions are refused with INVALID_STORED_VALUE. The record binds the result to input hashes, proof scope and artifact, graph definition and type version, workspace anchor, and caller-supplied reviewer identity. The reviewer fingerprint is the digest of that supplied identity. Accepted results require a caller-supplied WorkspaceAnchor; they have no null representation for an absent workspace, even when the stored run has workspaceBinding: null. Approval subjects can use workspaceAnchor: null. The WorkspaceAnchor type names the workspace root, repository identity, HEAD revision, content fingerprint, capture scope, and file states, with schemaVersion: 1. A null scope means the whole worktree. Accepted-result and approval validators check that a supplied anchor is a JSON object and bind its bytes into the record digest. They do not validate those fields, compare the anchor with the run’s workspace binding, or verify the checkout. For a real workspace, the caller must use an anchor captured by its workspace provider and verify it before reusing a result or acting on approval. Writing the same complete record again at the same position does nothing. Writing a different binding for the same completed result at that position returns REVISION_CONFLICT. resolveAcceptedResult returns accepted only while the stored graph, completed node result, and all bound values still match. Otherwise it returns wait. Accepted-result storage is called by the host. The graph executor does not store these records by itself. The host can use createProofCache to share declared read-only evidence and resolve stored results against that evidence.

Read-only proof cache

createProofCache creates a cache for one host process and one stored run. Its packet(jobId) method returns a bounded proof packet, source hashes, proof scope, and an immutable artifact reference. Fresh workers can receive the same packet from the host without reading unchanged source data again. Declare each source by ID. Its revision() method returns an authoritative content revision. Its read(expectedRevision, maxBytes) method returns complete JSON or text for that revision within the byte limit. The source adapter must advance its revision whenever its content changes. The cache checks revisions before and after capture and hashes the captured content. It refuses an oversized packet or a capture that races a source change. It does not truncate source data. Declare each proof job’s source IDs, proof scope, and read-only or effectful mode. Only declared read-only jobs can request packets or stored results. The cache executes no job. The adapter’s source declarations and revision behavior are part of the host’s trusted code. The node’s retrySafe setting governs crash recovery; it does not declare a job read-only. Concurrent packet requests share source reads. A changed source invalidates only packets that depend on it. Unchanged dependencies keep their captured content. The cache keeps the latest entry for each declared source and job. Restarting the host creates a cold cache. Stored proof artifacts and accepted-result records remain in run storage. resolveAccepted(jobId, position, current) derives the source hashes, proof scope, and artifact from the current packet. Supply the current graph, verified workspace anchor, and reviewer identity. Each call uses resolveAcceptedResult to check the stored completion and acceptance again. Read record.result only when the returned kind is accepted. A wait result requires fresh proof or a decision by the host. A changed binding needs a newly completed proof position; it cannot replace the acceptance already stored for an earlier completion. Reviewers can share evidence while retaining separate accepted answers. A different reviewer identity does not inherit another reviewer’s result. The cache does not execute missing proof work or create completion records. From a checkout, run the cache example:
The program in examples/packages/proof-cache.ts checks a captured timeout configuration with a deterministic review node. It uses a real Git workspace anchor and two in-memory sources that own their revision counters. Two packet requests share the same artifact. Changing the configuration reads it again, preserves the independent policy packet, and refuses the stored review. The report is:
The clean-consumer check compiles and runs this program from the packed runtime with TypeScript 6 and TypeScript 7. It checks the report against the documented output.

Approval

createApprovalCallbackGate puts the subject digest into the callback request before its identity is created. StoredCallbackClient.post stores that exact subject with the request. Its submit method stores the callback answer and approval record in one event batch. The approval subject covers input artifact hashes, proof scope and artifact, proposed output bytes, effective permissions, and a workspace anchor or null. The record also binds the stored run plan, graph, caller-supplied actor, router path, and action decision. Each effective permission in the subject must match one permission admitted by the stored run plan. Its name and JSON scope must match exactly. Object key order does not matter. The subject may use a subset of the admitted permissions. post throws ApprovalSubjectError with SUBJECT_MISMATCH for a permission outside the stored plan. submit returns the typed invalid result if its stored subject is outside that plan. resolveApproval returns wait in the same case. resolveApproval returns the stored decision only while the current request and subject match the record. It returns wait after any covered byte changes. The host owns every effect after approval. These approval APIs do not make a backup, apply output, read the effect back, reconcile an uncertain effect, or merge files.

Stored identities

Accepted-result records store the complete supplied reviewerIdentity JSON object alongside its fingerprint. Approval records store the complete supplied actor JSON object. A fingerprint does not hide the identity fields. These APIs check JSON object shape; they do not authenticate the identity or recognize credentials by field name. Supply only non-secret identifiers and review settings. Keep passwords, tokens, cookies, and private keys out of both objects. The local event store rejects a write with KNOWN_SECRET when an identity contains a value from its configured knownSecrets, including nested values and object keys. The caller must configure those secret values in the live storage options and exclude credentials that are not in that list. A rejected approval write stores neither the callback answer nor its approval record.