Oracle Validation
June 29, 2026 · View on GitHub
The oracle validates packet behavior against reference backends owned by
tools/oracle/. Keep backend-specific logic and backend names inside that tool
tree; crate tests, public docs, and fixture docs should describe only the
oracle boundary.
Oracle answers this question: given one packet plan, do libcrafter and a reference backend agree on the emitted bytes and parsed model? Kernel and service behavior checks belong to probe validation.
Probe answers a different question: given a packet built by libcrafter and sent
inside a disposable lab session, does the peer kernel or controlled service
respond as expected, and can libcrafter decode and validate that response? Keep
those behavioral checks in tools/probe/; they are not oracle packet
equivalence cases.
The probe behavior profile is the full DNS/DHCPv4/ARP/UDP peer-response suite:
forty deterministic cases, ten per protocol, with dry-run plans that expose the
stimulus, expected response, provider requirements, target setup, and validation
contract. DNS and UDP use controlled target services plus decoded UDP/DNS or
UDP/ICMP validation. DHCPv4 uses a controlled DHCPv4/BOOTP responder on a private
link-layer segment. ARP uses target kernel behavior on a link-layer-capable
segment with setup for aliases, cache flushes, padding, provider MAC checks,
and filtered captures.
Lab, oracle, and probe reports may also include appliance runtime metadata from
the provider substrate. That metadata describes where the workload would run:
for example Docker private endpoint-container execution or VM/cloud
ssh-docker-host execution with an appliance image, remote workspace, artifact
root, and readiness checks. Appliance runtime profiles are placement labels,
not packet behavior selectors; oracle specs and probe cases remain the
validation authority.
Run probe behavior validation through the dry-run path first:
tools/probe/run --provider qemu --dry-run --profile behavior --seed 1052 --count 40 --out target/probe/behavior-dry-run
python3 tools/probe/engine/provider_matrix.py --providers hetzner,qemu,virtualbox,docker --dry-run --profile behavior --seed 1052 --count 40 --out target/probe/provider-matrix
Live probe behavior runs stay behind explicit confirmation and disposable lab sessions. The guarded workflow keeps dry-run as the default when no live provider is selected:
if [ -n "${LIBCRAFTER_PROBE_LIVE_PROVIDER:-}" ]; then
tools/probe/run --provider "$LIBCRAFTER_PROBE_LIVE_PROVIDER" --confirm-live-run --profile behavior --seed 1051 --count 40 --out target/probe/acceptance/51-live-behavior-suite
else
tools/probe/run --provider qemu --dry-run --profile behavior --seed 1051 --count 40 --out target/probe/acceptance/51-live-behavior-suite-dry-run
fi
Provider capability skips are part of the probe contract. Hetzner can plan IPv4 unicast DNS and UDP service cases but skips DHCPv4 and ARP link-layer cases. QEMU, VirtualBox, and Docker private sessions can plan the full private-lab behavior suite when local prerequisites are available. A provider skip must come from a missing declared capability; a supported case that fails to build, send, capture, decode, or validate is a failure to fix in libcrafter or probe infrastructure.
The focused QUIC probe profile is quic-smoke. Its initial observation case is
live-capable through the Rust probe adapter and a controlled target-side UDP
echo service on port 4433; the Version Negotiation, Retry, stateless reset, and
protected-flow cases remain planned-only until the lab owns a stateful QUIC
target. Validate QUIC probe work through dry-run planning first:
tools/probe/run --provider qemu --dry-run --profile quic-smoke --seed 1 --count 5 --out target/probe/quic-smoke-dry-run
tools/lab/run plan --provider qemu --dry-run --profile quic-smoke --seed 1 --role stimulus --role target --json
If live QUIC prerequisites or authorization are missing, record a structured
skip artifact under target/lab/quic-live-validation/README.md rather than
sending traffic from the developer host.
SSDP Validation Safety
SSDP validation is a packet-behavior workflow, not a discovery scan. Run SSDP
oracle, probe, and lab checks through dry-run planning first, and keep all
artifacts under ignored SSDP roots such as target/oracle/ssdp-* and
target/probe/ssdp-*. Tracked records should name only the relative artifact
root, case label, seed, provider class, role names, skip reason, and teardown
status.
Before any SSDP artifact is copied into docs, fixtures, oracle specs, or probe
assets, redact or replace credentials, provider account data, public addresses,
endpoint IDs, live hostnames, SSH details, local absolute paths, interface names,
real UUIDs, device descriptions, LOCATION URLs, SERVER strings, and
uncontrolled capture payloads. If redaction removes the fact being validated,
regenerate the case offline with documentation-safe addresses and synthetic
identifiers instead of promoting the live artifact.
Oracle CLI modes
tools/oracle/run is the single entrypoint for every oracle mode. Each mode is
a subcommand; the generation/validation modes share --backend (the reference
backend; defaults to the full read/write backend, with a Wireshark/tshark
parser-only option), --profile (default smoke), --seed, --count,
--family, --root, --case, --feature, --index, and --out. The modes
are:
corpus— generate a reusable packet corpus artifact (plans.json) that the other modes can replay with--corpus. Flags: generation options +--out,--direction.offline— compare libcrafter raw vectors and normalized decode models against the reference backend without root, pcap files, or live traffic. Flags: generation options +--direction,--corpus,--dry-plan,--emit-vectors,--emit-decoded,--keep-artifacts.pcap— exercise classic pcap write/read, link-type selection, and roundtrip decoding. Flags: generation options +--direction,--corpus,--dry-plan(alias--dry-run),--keep-artifacts.live— route provider-backed packet exchange through lab-backed oracle provider adapters; the default is a planned run and real traffic is gated. Flags: generation options +--provider(required;local-dry-runor a registered provider),--direction,--corpus,--dry-run,--confirm-live-run,--keep-wire-endpoints.generate— emit deterministic packet plans as metadata only, no backend. Flags: common + generation options +--direction.report— run final oracle validation and write a summary. Flags:--out.specs— inspect executable oracle specs:specs validateloads and validates all specs (--json,--strict),specs suiteemits the reproducible offline case suite for a--family(--backend,--profile,--seed,--out,--json,--run).backend-info— print backend dependency and version metadata. Flags:--backend.self-check— run lightweight oracle engine self checks. No flags.
Safe offline and provider dry-run examples (no root, no credentials, no live traffic):
tools/oracle/run offline --profile smoke --seed 1 --count 10
tools/oracle/run pcap --profile smoke --seed 1 --count 10
tools/oracle/run live --provider local-dry-run --profile smoke --seed 1 --count 10
Corpus Generation
Corpus generation writes the ordered packet plans shared by validation modes:
tools/oracle/run corpus --profile smoke --seed 1 --count 10
The artifact is written to target/oracle/corpus/plans.json by default. It
records the corpus id, selected specs, requested filters, backend metadata,
libcrafter metadata, ordered packet plans, and per-packet eligibility for
offline, pcap, and wire modes. Reuse --corpus <path> to run the exact same
packet set through multiple validation levels:
tools/oracle/run offline --corpus target/oracle/corpus/plans.json
tools/oracle/run pcap --corpus target/oracle/corpus/plans.json
tools/oracle/run live --provider hetzner --dry-run --corpus target/oracle/corpus/plans.json
Offline Validation
Offline validation compares generated raw packet vectors and normalized decode models without root privileges, pcap files, or live traffic:
tools/oracle/run offline --profile smoke --seed 1 --count 10
Use --profile, --seed, and --count to make failures reproducible. When a
report identifies a packet index, rerun with the same inputs and --index.
When a corpus exists, prefer --corpus so the same packet appears in the same
position across offline, pcap, and live dry-runs.
The checked-in fixture suite complements oracle validation. Fixture tests decode
committed bytes and pcaps, assert typed layers and stable fields, compare selected
summaries, verify byte-preserving roundtrips where promised, and exercise named
malformed inputs with structured error assertions. These tests run without
reference backend imports or target/oracle/ artifacts.
Useful focused fixture checks:
cargo test -p crafter --test fixture_suite
cargo test -p crafter --test resilience malformed_corpus_reports_structured_errors
IPv4 Coverage
The IPv4 behavioral suite stays offline and uses documentation address space. Use these focused checks when touching IPv4 builders, decode behavior, summaries, fixtures, malformed coverage, pcap RawIp coverage, or oracle specs:
cargo test -p crafter --test ipv4_public_api
cargo test -p crafter --test fixture_suite ipv4
cargo test -p crafter --test resilience ipv4
cargo test -p crafter --test fixture_suite pcap_fixture_roundtrips
tools/oracle/run offline --profile ipv4-enrichment --seed 1 --count 12 --root l3:ipv4
.agents/scripts/check-crafter-release --static
The fixture-suite IPv4 filter covers named IPv4 fixture assertions. The pcap roundtrip check is the focused RawIp IPv4 DSCP/ECN pcap fixture assertion. Keep live IPv4 packet exchange out of this suite unless a separate protected provider workflow explicitly asks for it.
DNS Coverage
The DNS family has an extensive reference-backed oracle suite that validates packet construction, decode, and capture behavior, not DNS client, resolver, or server semantics. It covers every implemented DNS group: header (id, QR, AA/TC/RD/RA/ AD/CD flags, opcodes, rcodes, raw flags, section counts), names and compression, questions and QTYPE/QCLASS axes, A/AAAA, NS/CNAME/PTR, MX/TXT, SOA/SRV, raw-unknown records, EDNS OPT and options, DNSSEC DS/DNSKEY/RRSIG/NSEC/NSEC3, SVCB/HTTPS, section placement, and malformed names and RDATA.
Reproduce the DNS coverage offline, in pcap, and as a live dry-run; offline is the default and the others reuse the same case contract:
tools/oracle/run offline --family dns --profile ci --seed 3001 --count 50
tools/oracle/run pcap --family dns --profile ci --seed 3002 --count 50
tools/oracle/run live --provider hetzner --dry-run --family dns --profile ci --seed 3003 --count 50 --direction live_exchange
tools/oracle/run specs suite --family dns --run
Real packet exchange is opt-in and gated behind the protected provider workflow:
tools/oracle/run live --provider hetzner --confirm-live-run --family dns --profile ci --count 50 --direction live_exchange
A few DNS features are not strict-byte comparable and use raw bytes or a
normalized decoded-model comparison: compressed names compare as the normalized
model (libcrafter re-encodes uncompressed); SVCB/HTTPS RDATA is supplied as
backend-owned raw bytes because the high-level SvcParam encoder re-interprets
known keys; \DDD name escapes are flattened by the high-level encode; and malformed
inputs are covered by the crate corpus and resilience.rs, not an offline oracle
comparison. See DNS wire coverage for the per-record contract.
IPv6 Enrichment Offline Profile
The ipv6-enrichment oracle profile is the focused offline reproducibility
suite for the enriched IPv6 base and extension-header packet surface. It covers
base field boundaries, unknown next-header raw preservation, Hop-by-Hop and
Destination Options, Fragment Header, generic Routing, Mobile Routing Type 2,
Segment Routing, routed TCP/ICMPv6 chains, and the checksum context carried
through supported extension chains. It runs without live traffic or provider
infrastructure and should keep its artifacts under target/oracle/.
Run the focused crate checks first. They consume checked-in documentation-space
fixtures and malformed corpus rows, and they do not need reference backend
imports or target/oracle/ artifacts:
cargo test -p crafter --test ipv6_public_api
cargo test -p crafter --test fixture_suite ipv6
cargo test -p crafter --test fixture_suite pcap_ipv6_roundtrip
cargo test -p crafter --test resilience ipv6
The fixture filters cover byte-preserving IPv6 base, UDP/TCP/ICMPv6, options,
routing, fragment, and summary/show checks. The pcap_ipv6_roundtrip filter
pins the RawIP IPv6 pcap fixture path, link type, timestamp, captured bytes,
decode surface, and compile/decode/compile roundtrip. The resilience filter
covers curated IPv6 decode surfaces, structured errors for malformed IPv6 base
and extension buffers, random decode panic guards, unknown-next-header raw
roundtrips, and extension-chain roundtrips.
Then run the oracle profile with fixed seeds and explicit output directories:
tools/oracle/run offline --profile ipv6-enrichment --seed 2 --count 20 --root l3:ipv6 --out target/oracle/ipv6-enrichment-offline
tools/oracle/run offline --direction backend_to_libcrafter --profile ipv6-enrichment --seed 3 --count 12 --root l3:ipv6 --out target/oracle/ipv6-enrichment-reference-to-libcrafter
tools/oracle/run offline --direction libcrafter_to_backend --profile ipv6-enrichment --seed 4 --count 12 --root l3:ipv6 --out target/oracle/ipv6-enrichment-libcrafter-to-reference
Use the default offline run for the profile-selected comparison set, then use a
directed run such as backend_to_libcrafter or
libcrafter_to_backend when isolating one side's encode/decode behavior. Use
--seed, --count, and --index to make any failure rerunnable. Malformed
IPv6 extension cases are declared as structured-error coverage, but they are
not offline byte-compared because malformed extension buffers do not have a
comparable strict-byte oracle path; keep those checks in resilience.rs and
the malformed fixture corpus.
Provider-backed live exchange is not part of the IPv6 enrichment qualification.
If live-mode planning needs to be inspected without creating infrastructure,
start with the local dry-run path and keep the result under target/oracle/;
real provider traffic remains an explicit protected workflow with
--confirm-live-run:
tools/oracle/run live --provider local-dry-run --profile ipv6-enrichment --seed 5 --count 10 --root l3:ipv6 --out target/oracle/ipv6-enrichment-live-local-dry-run
For the broader crate and workspace pass around the focused IPv6 suite, run the normal crate tests and the workspace preflight before the release gate:
cargo test -p crafter
cargo test --workspace
.agents/scripts/check-crafter-release --static
Pcap Validation
Pcap validation exercises packet materialization, classic pcap write/read behavior, link type selection, and roundtrip decoding:
tools/oracle/run pcap --profile smoke --seed 1 --count 10
Use pcap mode when changes affect link types, timestamps, pcap framing, or decode behavior that should survive file serialization. Packets that cannot be represented in the requested pcap mode are reported as skipped with a stable reason.
IP Fragment Transform Validation
IpDefrag and IpFragment validation follows the same safe ladder as the rest
of the packet stack: transform unit tests, offline oracle checks, pcap
roundtrips, provider dry-runs, and only then explicitly confirmed lab-backed
live behavior. Fragment examples and generated tools should use documentation
addresses and dry-run or pcap writers unless a protected provider workflow has
been selected.
Run the offline transform and fixture checks first. They do not create
infrastructure and keep artifacts under target/oracle/ or target/examples/.
ORACLE_BACKEND should name the oracle backend being validated:
cargo test -p crafter wire::ip
cargo test -p crafter --test fixture_suite ip_fragment
tools/oracle/run offline --backend "$ORACLE_BACKEND" --family ip --profile fragmentation-smoke --seed 1201 --count 50 --out target/oracle/ip-fragment-offline
tools/oracle/run pcap --backend "$ORACLE_BACKEND" --family ip --profile fragmentation-smoke --seed 1203 --count 50 --out target/oracle/ip-fragment-pcap
cargo run -p crafter --example ip_defrag_pcap_summary -- --out target/examples/ip-defrag-pcap-summary.json
The pcap summary example is the inspectable bridge between oracle fixtures and
lab artifacts: it reads fragment pcaps through public crafter APIs, runs
IpDefrag, and writes packet hashes, payload hashes, metadata, and transform
traces as JSON.
Live IP fragmentation validation must not originate as raw traffic from the
developer machine. Use lab-backed providers only, with disposable stimulus
and target roles, constrained MTUs, offloads disabled where the provider
supports it, and oracle-owned artifacts rooted at
target/oracle/ip-fragment-*. The
ip-fragment-smoke provider dry-run profile writes an oracle workload plan for
small MTU setup, offload handling, oversized/crafted fragment traffic, pcap
capture, and payload hash comparison. Artifact audits live in
tools/oracle/engine/ip_fragment_artifacts.py. Start with provider dry-runs:
tools/oracle/run live --backend "$ORACLE_BACKEND" --provider qemu --dry-run --family ip --profile ip-fragment-smoke --seed 1204 --count 20 --out target/oracle/ip-fragment-qemu-dry-run
python3 tools/oracle/engine/live_provider_matrix.py --providers hetzner,qemu,virtualbox,docker --backend "$ORACLE_BACKEND" --profile ip-fragment-smoke --seed 1204 --count 20 --dry-run --out target/oracle/ip-fragment-provider-matrix-dry-run
Real provider-backed fragment behavior is a protected workflow. It must use
--confirm-live-run, write pcaps, decoded summaries, transform JSON, provider
manifests, command logs, and report.json under a fresh
target/oracle/ip-fragment-* directory, and finish with teardown records. When a
provider lacks the needed capability or prerequisite, the run should write a
structured skip artifact under the same directory instead of silently passing:
tools/oracle/run live --backend "$ORACLE_BACKEND" --provider qemu --confirm-live-run --family ip --profile ip-fragment-smoke --seed 1205 --count 20 --out target/oracle/ip-fragment-qemu-live
python3 tools/oracle/engine/live_provider_matrix.py --providers qemu,virtualbox --backend "$ORACLE_BACKEND" --profile ip-fragment-smoke --seed 1205 --count 5 --real --confirm-live-run --skip-unavailable --out target/oracle/ip-fragment-vm-live
Do not keep live endpoints after fragment validation except for an explicit debugging session approved by the operator. A completed run needs either teardown evidence for every disposable session or a skip artifact explaining why no live session was created.
UDP Options Validation
UDP options validation exercises the RFC 9868 surplus area after UDP Length,
normal UDP checksum handling, OCS/APC handling, option status reporting, and
unknown SAFE/UNSAFE preservation. Use a UDP-filtered corpus when changing
Udp, UdpOptions, UdpOption, or oracle UDP option normalization:
tools/oracle/run offline --profile smoke --seed 9868 --count 100 --family udp --out target/oracle/udp-options-offline
tools/oracle/run offline --direction backend_to_libcrafter --profile smoke --seed 9868 --count 100 --family udp --out target/oracle/udp-options-reference-to-libcrafter
tools/oracle/run offline --direction libcrafter_to_backend --profile smoke --seed 9868 --count 100 --family udp --out target/oracle/udp-options-libcrafter-to-reference
Pcap mode checks that the same UDP surplus bytes survive classic pcap write/read and raw-link normalization:
tools/oracle/run pcap --profile smoke --seed 9868 --count 100 --family udp --out target/oracle/udp-options-pcap
cargo test -p crafter --test fixture_suite udp_options
Provider-backed live planning stays dry-run by default. The local dry-run path filters the bounded UDP option live case set without sending packets, and the provider matrix records provider-specific skips for cases such as IPv6 zero-checksum status or DHCPv4-style L2 broadcast requirements:
tools/oracle/run live --provider local-dry-run --profile smoke --seed 9868 --count 20 --family udp --out target/oracle/udp-options-live-local-dry-run
python3 tools/oracle/engine/live_provider_matrix.py --providers hetzner,qemu,virtualbox,docker --profile smoke --seed 9868 --count 20 --dry-run --out target/oracle/udp-options-live-dry-run-matrix
Live Validation
Live validation routes provider-backed packet exchange through lab-backed oracle provider adapters. It uses the same corpus contract as offline and pcap modes, then filters each packet by provider capabilities and explicit mutation policy. Reports keep generated, eligible, skipped, sent, captured, parsed, byte comparison, decode comparison, passed, and failed counts.
Provider-backed adapters are selected by --provider and registered under
tools/oracle/engine/providers/. They bind oracle policy to a lab provider,
but the lab provider adapters own substrate lifecycle only. Providers create,
connect, describe, and tear down disposable endpoints; they do not install
oracle packages or define workload bootstrap commands.
tools/lab owns repository archive transfer, remote unpack, bootstrap context,
artifacts, and cleanup records. Oracle owns the libcrafter and
reference_backend workload setup that runs after lab has unpacked the
repository. Packet generation, endpoint protocol comparison, report assembly,
and the generic provider execution flow remain in the oracle runner.
tools/endpoint owns one endpoint and artifact transport; see
docs/operations/endpoint.md for endpoint provider credentials, lifecycle
commands, artifacts, and cleanup.
Dry-run live reports surface appliance runtime metadata for inspection before a provider is contacted. Docker private reports an endpoint-container appliance runtime because the constrained endpoint container is the runtime and nested Docker stays disabled. QEMU, VirtualBox, Hetzner, and generic SSH Docker hosts report an SSH Docker-host appliance runtime, where lab runs the standard image on the remote host after endpoint creation. This runtime choice does not alter oracle packet selection, byte policy, or probe case selection.
Docker is available as a lab-backed oracle provider through the constrained
docker/private lab adapter. The Docker adapter owns only the private
multi-endpoint substrate; oracle still owns the libcrafter and
reference_backend workload setup. The Docker private capability model
advertises IPv4 unicast, link-layer send and capture, broadcast, provider MAC
knowledge, and controlled services, but not IPv6 or a controlled router.
Docker lan and wan are direct endpoint smokes for NAT-backed L3 reachability
from one container. They are not oracle lab-backed multi-endpoint modes and do
not claim LAN L2, WAN L2, or public inbound behavior:
tools/endpoint/run doctor --provider docker --exposure lan --dry-run
tools/endpoint/smoke/live_docker_lan_icmp.py --plan-only
tools/endpoint/smoke/live_docker_wan_dns.py --plan-only
Use the non-provider-backed local dry-run or provider-backed dry-runs for planning and CI-safe checks:
tools/oracle/run live --provider local-dry-run --profile smoke --seed 1 --count 10
tools/lab/run plan --provider hetzner --dry-run --profile smoke --seed 1 --role libcrafter --role reference_backend --json
tools/lab/run plan --provider docker --dry-run --profile smoke --seed 1 --role libcrafter --role reference_backend --json
tools/oracle/run live --provider hetzner --dry-run --profile smoke --seed 12345 --count 10
tools/oracle/run live --provider qemu --dry-run --profile smoke --seed 12345 --count 10
tools/oracle/run live --provider virtualbox --dry-run --profile smoke --seed 12345 --count 10
tools/oracle/run live --provider docker --dry-run --profile smoke --seed 12345 --count 10
python3 tools/oracle/engine/live_provider_matrix.py --providers hetzner,qemu,virtualbox,docker --profile smoke --seed 12345 --count 5 --dry-run --out target/oracle/provider-matrix-dry-run
Real provider-backed validation is reserved for explicit protected workflows on
disposable endpoints and requires --confirm-live-run. Provider selection
still uses the same live oracle command and adapter registry:
tools/oracle/run live --provider hetzner --confirm-live-run --profile smoke --seed 12345 --count 10
tools/oracle/run live --provider docker --confirm-live-run --profile smoke --seed 12345 --count 10
For local VM providers, use the guarded matrix smoke path. It runs QEMU and VirtualBox endpoint doctor checks first, uses a small corpus, and records structured skips by default when VM creation is not explicitly enabled:
python3 tools/oracle/engine/live_provider_matrix.py --providers qemu,virtualbox --profile smoke --seed 12345 --count 2 --real --skip-unavailable --out target/oracle/provider-matrix-vm-real
Use --allow-vm-create or LIBCRAFTER_ORACLE_VM_SMOKE_ALLOW_CREATE=1 in a lab
run when the matrix should pass --confirm-live-run to the same oracle live
command and create disposable local VMs. Use --strict-vm-smoke or
LIBCRAFTER_ORACLE_VM_SMOKE_STRICT=1 when missing VM prerequisites or disabled
VM creation should fail the qualification run. QEMU uses qemu/private with
private group oracle-live-private; VirtualBox uses virtualbox/lan with the
bridged interface discovered by VBoxManage or requested through
LIBCRAFTER_VBOX_BRIDGE_IFACE.
See lab.md for lab session metadata and docs/operations/endpoint.md for single-endpoint provider credentials, artifacts, and cleanup.
DHCPv6 Live Validation
DHCPv6 live validation follows the oracle live provider boundary. The default
workflow is a dry-run plan for dhcpv6-smoke and --case dhcpv6-solicit; it
sends no traffic, creates no infrastructure, and records stable skip reasons
when IPv6, multicast, link-layer send/capture, or provider MAC discovery is not
available:
tools/oracle/run live --backend "$ORACLE_BACKEND" --provider qemu --dry-run --profile dhcpv6-smoke --seed 9917 --count 2 --case dhcpv6-solicit --out target/oracle/dhcpv6-guarded-doc-dry-run
tools/oracle/run live --backend "$ORACLE_BACKEND" --provider docker --dry-run --profile dhcpv6-smoke --seed 9917 --count 2 --case dhcpv6-solicit --out target/oracle/dhcpv6-docker-dry-run
Real DHCPv6 exchange is a protected lab workflow only. It must run from
disposable provider endpoints, require --confirm-live-run, and be wrapped by
a family-specific environment gate such as LIBCRAFTER_RUN_DHCPV6_VM_LIVE=1
or LIBCRAFTER_RUN_DHCPV6_HETZNER_LIVE=1. Store reports, pcaps, decoded
models, capability reports, and teardown logs under target/oracle/dhcpv6-*;
never commit provider identifiers, public IPs, credentials, live hostnames, or
captures.
Every non-dry-run DHCPv6 oracle artifact set must be reviewable offline. Keep
the provider session metadata, endpoint/provider manifests, planned topology,
stimulus and reply bytes, pcap or pcapng captures, decoded summary() and
show() text, normalized comparison JSON, command stdout/stderr paths, final
reports, and teardown records under the selected target/oracle/dhcpv6-*
directory. Audit one or more artifact roots before treating a live run as
complete:
python3 tools/oracle/engine/dhcpv6_artifacts.py \
--input target/oracle/dhcpv6-vm-live \
--out target/oracle/dhcpv6-artifact-audit
Dry-run or skipped DHCPv6 artifact roots are allowed to audit as skipped;
they still preserve the plan, capability, and skip reason needed to reproduce
why no packet exchange occurred.
ICMPv4 Live Matrix
The ICMPv4 live matrix runs the oracle live path against the l2:ipv4 root
with the icmpv4_live feature. It validates packet write/parse parity: that
libcrafter and the selected reference backend agree on the bytes placed on the
wire and on the decoded model after a real round trip over a Hetzner private
network. It does not validate kernel ICMP behavior, ping semantics, or
router-generated errors. The root is IPv4-rooted; comparison canonicalizes to
the IPv4 header, so Ethernet fields are not part of ICMP pass/fail.
Use the offline and dry-run paths for planning and CI-safe checks. Neither sends packets or creates infrastructure, and neither needs a credential:
tools/oracle/run offline --root l2:ipv4 --feature icmpv4_live --profile smoke --seed 22 --count 20 --out target/oracle/icmp-live/offline
tools/oracle/run live --provider hetzner --dry-run --root l2:ipv4 --feature icmpv4_live --profile smoke --seed 70 --count 40 --out target/oracle/icmp-live/dry
python3 tools/oracle/engine/live_provider_matrix.py --providers hetzner --profile smoke --seed 70 --count 20 --dry-run --out target/oracle/icmp-live/matrix-dry
Real Hetzner exchange is explicit and protected. It requires --confirm-live-run
and a Hetzner credential in the environment (HETZNER_API_TOKEN, or
HCLOUD_TOKEN); never store the token value in a tracked file:
tools/oracle/run live --provider hetzner --confirm-live-run --root l2:ipv4 --feature icmpv4_live --profile smoke --seed 71 --count 60 --out target/oracle/icmp-live/full-matrix
Artifacts land under the requested --out directory, e.g.
target/oracle/icmp-live/<step>/, with the live report at
<out>/live/report.json. Each run live invocation mints a unique per-run
private group so concurrent live runs (for example an ICMP run and a DNS run,
possibly in different worktrees) never share a Hetzner network or collide on
private IP allocation. Override the group with ORACLE_LIVE_PRIVATE_GROUP only
to coordinate or reproduce a specific run; do not commit live IPs or captures.
CI Expectations
Pull request CI should run deterministic corpus, offline, pcap, provider-backed dry-run, and probe dry-run checks. Oracle provider checks are selected through the live provider adapter registry. Real live packet exchange must stay behind explicit protected workflow confirmation and cleanup logic. Dry-runs are the default validation path for provider-backed lab, oracle, and probe checks.
Recommended local preflight:
cargo test --workspace
tools/oracle/run corpus --profile ci --seed 12345 --count 100 --out target/oracle/final-corpus
tools/oracle/run offline --corpus target/oracle/final-corpus/plans.json --out target/oracle/final-offline
tools/oracle/run pcap --corpus target/oracle/final-corpus/plans.json --out target/oracle/final-pcap
python3 tools/oracle/engine/live_provider_matrix.py --providers hetzner,qemu,virtualbox,docker --profile ci --seed 12345 --count 100 --dry-run --out target/oracle/final-live-matrix
tools/probe/run --provider hetzner --dry-run --profile smoke --seed 1 --count 10 --out target/probe/final-dry-run
tools/probe/run --provider qemu --dry-run --profile smoke --seed 1 --count 10 --out target/probe/final-dry-run-qemu
tools/probe/run --provider virtualbox --dry-run --profile smoke --seed 1 --count 10 --out target/probe/final-dry-run-virtualbox
tools/probe/run --provider docker --dry-run --profile smoke --seed 1 --count 10 --out target/probe/final-dry-run-docker
tools/probe/run --provider qemu --dry-run --profile behavior --seed 1052 --count 40 --out target/probe/final-behavior-dry-run
python3 tools/probe/engine/provider_matrix.py --providers hetzner,qemu,virtualbox,docker --dry-run --profile behavior --seed 1052 --count 40 --out target/probe/final-provider-matrix
.agents/scripts/check-crafter-release --static
Oracle artifacts default below target/oracle/, with mode-specific reports
under target/oracle/corpus, target/oracle/offline, target/oracle/pcap,
and target/oracle/live.
Keep promoted fixture bytes under crafter/tests/fixtures/ and reference
backend ownership under tools/oracle/.