Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

Prepared verifier loaders

A prepared verifier executes runner material captured by its host before task mutation. Its execution receipt identifies that baseline. An ordinary command's exit code alone doesn't establish verifier identity.

This reference covers harn_vm::verifier_provenance and its prepared-run authority integration.

Host declaration#

RunIntent.verifier_loaders contains VerifierLoaderSpec values. HostFacts.admitted_verifier_loaders must contain the exact same declarations. Neither a serialized intent nor a model-supplied digest can create native verifier authority.

LoaderRust configurationCaptured material
python_sourceIsolatedPythonSourceVerifierInterpreter and entrypoint source
python_moduleIsolatedPythonModuleVerifierInterpreter, module or package source, and declared source dependencies

Both configurations require id, interpreter, workspace, and args. Interpreter, source, workspace, and search-root paths must already be canonical and absolute. id must be nonempty.

The source loader requires source. The module loader requires module and ordered search_roots. Its optional dependencies lists additional module or package names to capture from those roots. Dependencies default to an empty list. Capturing a package includes its Python source submodules.

invocation_args() supplies the exact admitted invocation, including -I -S. Use the configured interpreter and workspace with those arguments. A changed invocation doesn't inherit the verifier's authority.

Preparation reads files without importing them or running startup hooks. The first measurement for each exact declaration belongs to its PreparedRun. Repeated preparation retains that measurement, including measured absence. An attached PreparedSession retains the same native material across turns. After process restart, attaching a serialized verifier lease refuses rather than recapturing changed files.

Python loader contract#

Prepared Python execution is isolated. Ambient PYTHONPATH, user-site directories, startup hooks, bytecode caches, and automatic plugin discovery don't select its runner. Module search roots are explicit host configuration. They don't grant filesystem access to child processes.

The source loader registers a separate __main__ module. The module loader preserves package initialization, relative imports, __package__, __spec__, and the selected entrypoint's __file__. Package initialization must reach the declared __main__ entrypoint before execution can earn a receipt.

Native extensions, bytecode-only modules, namespace packages, and symlinked module material aren't supported by this source-loader backend. Modules that overlap the trusted Python bootstrap are refused. A runner's package data and test inputs remain ordinary filesystem reads under the process policy.

The interpreter and its installed standard library are host-admitted runtime material. This contract doesn't attest a malicious interpreter or every library the runner may load. Python-level audit hooks aren't a substitute for that boundary; Python documents that malicious code can bypass them. See Python auditing.

Observations and execution receipts#

PreparedVerifier::observe_workspace() returns a typed observation of the original filesystem locations:

DispositionMeaning
unchangedMeasured locations still match their baseline
changedMaterial differs, including a new earlier search candidate
absentMaterial present in the baseline is now missing, or capture measured absence
unmeasuredFilesystem access, platform support, or loader behavior prevented measurement
refusedThe declaration or host authority wasn't admitted

A workspace observation doesn't prove what a later child loaded. Prepared execution consumes the captured interpreter and source through private native descriptors. Replacing or deleting the original files can't replace those bytes.

Normal completion returns verifier_receipt through harness.process execution and hostlib process completion. It contains verifier_id, baseline_sha256, and executed_material.disposition: "unchanged". The baseline digest includes the exact declaration and captured material identities.

An execution receipt establishes runner identity, not test success. A verifier pass also requires the observed successful terminal status. Failure to reach the declared entrypoint refuses completion, including when the process exits zero. Cancellation and timeout don't publish a verifier receipt.

The workspace may report changed while a child executes the original captured baseline. In that case, only the original runner can earn verification. Tests can fail, be repaired, and pass without replacing the runner.

Platform and resource limits#

Pinned execution currently requires Linux. Other platforms return an explicit unmeasured disposition. Strict native runtime attestation remains unmeasured. Ordinary process execution keeps its existing behavior and gains no verifier qualification merely from executable presence.

Capture ceilings live in the backend's policy.toml: 64 MiB per interpreter, 1 MiB per source file, 1,024 source modules, and 16 MiB per encoded bundle. Exceeding a ceiling refuses preparation.

CommandPlan.literal_argv supplies static invocation facts for inspection. Only CommandPlan.argv authorizes shell-to-argv conversion. Startup-dependent or dynamic shell behavior remains explicitly unmeasured.