diff --git a/Makefile b/Makefile index 5f86a3c..1a99aee 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,7 @@ validate-cli: $(PYCLI) steer preflight --sourceset gpt2-small.res-jb --pretty >/tmp/agent-machine-pycli-steer-preflight.json $(BOOTSTRAP_CLI) steer preflight --sourceset gpt2-small.res-jb --pretty >/tmp/agent-machine-bootstrap-steer-preflight.json $(PYCLI) steer resolve-artifacts --sourceset gpt2-small.res-jb --local-dir /tmp/agent-machine-steering-artifacts --receipt-out /tmp/agent-machine-steering-artifact-receipt.json --dry-run --pretty >/tmp/agent-machine-pycli-artifact-receipt.json + $(PYTHON) scripts/verify-steering-receipt.py examples/steering-artifact-receipts/gpt2-small-res-jb.missing.steering-artifact-receipt.json --expect-status not_configured --pretty >/tmp/agent-machine-steering-load-preflight.json $(PYTHON) scripts/verify-steering-receipt.py examples/steering-artifact-receipts/gpt2-small-res-jb.missing.steering-artifact-receipt.json --expect-status not_configured --pretty >/tmp/agent-machine-steering-verify-preflight.json $(PYTHON) scripts/load-steering-receipt.py examples/steering-artifact-receipts/synthetic.available.steering-artifact-receipt.json --attempt-load --pretty >/tmp/agent-machine-steering-synthetic-load.json $(PYTHON) scripts/run-mock-steering.py /tmp/agent-machine-steer-request.json --pretty >/tmp/agent-machine-mock-steering.json diff --git a/docs/steering-loader.md b/docs/steering-loader.md index b235d4a..91ee4f9 100644 --- a/docs/steering-loader.md +++ b/docs/steering-loader.md @@ -1,5 +1,12 @@ # Steering Receipt Loader +Status: receipt verification tranche for local steering work. + +## Purpose + +Before any local steering runtime may load model or SAE files, Agent Machine must verify that every artifact referenced by a `SteeringArtifactReceipt` exists locally and matches the receipt's SHA-256 digest. + +This document describes the fail-closed loader preflight. It does not claim applied steering. Status: receipt verification and CI-safe synthetic loading tranche for local steering work. ## Purpose @@ -19,6 +26,9 @@ scripts/verify-steering-receipt.py \ The fixture paths intentionally do not exist. The expected result is `status: not_configured`, with missing-file diagnostics for each absent artifact. +## Runtime rule + +A future runtime loader must not attempt to load GPT-2 Small or the residual-stream SAE until: ## CI-safe load command ```bash @@ -44,6 +54,17 @@ A future runtime loader must not attempt to use GPT-2 Small or the residual-stre If any check fails, the runtime must fail closed and return a non-applied posture. +## Boundary + +This tranche verifies receipt integrity only. It does not: + +- load GPT-2 Small into memory +- load the SAE into memory +- run inference +- inject activations +- return `status: applied` + +The next implementation tranche may add optional runtime loading after this digest gate succeeds. ## Operator runtime imports The loader contains an optional runtime-import path for operator machines after a complete artifact receipt exists. Optional runtime dependencies are not part of normal validation and must remain outside the default bootstrap path. diff --git a/src/agent_machine/steering_loader.py b/src/agent_machine/steering_loader.py index e806724..9717f3d 100644 --- a/src/agent_machine/steering_loader.py +++ b/src/agent_machine/steering_loader.py @@ -1,3 +1,8 @@ +"""Receipt-backed local artifact verification for steering runtime. + +This module verifies a SteeringArtifactReceipt before any runtime may use the +referenced files. It is deliberately fail-closed: absent files or digest mismatch +produce a not_configured result rather than a runtime claim. """Receipt-backed local artifact verification and loading gate. This module verifies a SteeringArtifactReceipt immediately before any runtime use @@ -83,8 +88,6 @@ def load(self, receipt_path: Path, *, allow_runtime_imports: bool = False) -> di } return load_runtime_artifacts(receipt, model_files, sae_files, Path(receipt_path), verified) - - def verify_receipt_files(receipt_path: Path) -> dict[str, Any]: """Verify receipt local paths and SHA-256 digests without loading artifacts.""" receipt_path = Path(receipt_path) @@ -208,8 +211,6 @@ def common_parent(paths: list[Path]) -> Path | None: return None common = common.parent return common - - def sha256_file(path: Path) -> str: hasher = hashlib.sha256() with path.open("rb") as handle: