run_circuit_fixture stands up an isolated docker N-hop nested-SSH chain, pipes a
seed-deterministic self-generated payload through it, verifies end-to-end
delivery, captures + checksums a per-hop pcap, emits R3 events, and always tears
the circuit down. Containment is load-bearing: assert_isolated refuses
local/unknown engines up front, every hop is built through the ForwarderPlan
guard, only our own fixture bytes move between our own containers, and the runner
is wired for docker only (multipass e2e refused, not faked). Adds the sor-hop
fixture image (alpine + sshd + tcpdump, lab-relay only) and a docker-gated
acceptance test that skips where no daemon/image is present. Instrument-validation
gate item 1 GREEN: live 3-hop delivery verified, 3 distinct hops, pcaps checksum.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Land only the containment-refusal half of R4: the guard every SOR forwarder
must pass before it does anything — assert engine != local, or refuse. It moves
no traffic, opens no socket, spawns no engine, and builds no SSH chain.
- forwarder.py: assert_isolated (raises on local and on any engine off the
manifest allow-list), isolation_prefix (docker/multipass exec argv, no host
path), ForwarderPlan (construction IS the gate — no plan for local/unknown/
no-container). Allow-list imported from provenance so forwarder and manifest
cannot disagree about what counts as isolated.
- There is no code path in this module that returns an exec prefix for the host;
containment is structural, not a runtime flag.
The traffic-moving half of R4 (gate item 1: 3-hop self-traffic e2e delivery +
per-hop pcaps across the grid) is deliberately NOT implemented — HELD for a live
isolated engine + grid. This guard is fully verifiable offline.
Acceptance (gate item 5) green: local/unknown/no-container refused; isolated
engine accepted with the correct isolation prefix. Python forwarder suite 12
passed; full SOR Python suite 49 passed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>