# Buyer-owned sealed testing

Run on buyer infrastructure. Generate signing and encryption keys with
`node research/buyer-blind/runner.mjs keygen CONFIG.json`. CONFIG has prefix.
The runner signing key and recipient encryption key are separate roles.

`seal CONFIG.json` reads cases (id,input), labels (id:boolean), buyer_private_key,
buyer_key_id, runner_public_key, run_id, now, sealed output path and reveal path.
Retain the reveal file and buyer private key outside Finality and outside the
adapter directory. Share only the encrypted envelope and buyer-signed manifest.

`execute CONFIG.json` takes sealed, runner_private_key, buyer_roots, now,
command array, adapter_directory, adapter_artifact, result_private_key,
result_key_id and receipt path. It verifies the buyer signature and AEAD payload,
passes only each input through stdin, requires every case result and signs the
whole result set. By default it requires bubblewrap with isolated namespaces,
read-only runtime/adapter mounts, no network, empty environment and private tmp.
The adapter command must use binaries available inside /usr and paths under /work.
No process fallback occurs when the required sandbox fails.

`require_isolation:false` explicitly selects process-only internal simulation;
its receipt labels it PROCESS_ONLY_NOT_A_SECURITY_SANDBOX. This environment could
not create the required namespace maps, so sandbox execution is NOT ESTABLISHED.

`reveal CONFIG.json` takes sealed, receipt, reveal, buyer_roots, runner_roots and
now. It checks both signatures, case identity/count, output digest and salted truth
commitment before counting unsafe accepts and disagreements. Modified cases, changed
truth or selectively omitted outputs reject. A party withholding execution/reveal
cannot be forced to participate; missing complete receipts cannot be called a pass.
No crypto receipt alone proves buyer authorship or an external operator's identity.
