Story Script — “Seed Once, Update Everywhere”¶
Format: Live demo narration (90–150 seconds) for a single terminal session. Audience: Technical evaluators / security engineers. Theme: Deterministic, airgapped OTA for edge AI systems.
Setting¶
You are running a fleet of edge nodes. Each node runs a policy-governed AI runtime
(autonomy). The nodes are offline-first: they accumulate telemetry in a WAL and drain
when the collector is reachable. You update them by publishing a release to a control
plane; each node verifies the update cryptographically before doing anything.
The story has four beats:
1. Day 0 — Policy loaded, identity established, runtime enforcing deny-by-default
2. Day 1 — Release published, node detects it, verifies supply chain, stays on previous
3. Day N — OS replaced during maintenance window; node reconstructs itself automatically
4. Always — Any of the above can fail; the system fails closed, not open
Act 1 — Policy Enforcement (15 seconds)¶
Setup: Demo stack is up. Policy bundle is loaded. Runtime is running.
[OPERATOR] $ curl -s http://localhost:7777/health | jq .
Output marker:
{"status":"ok","mode":"normal"}
Narration: “Runtime is up, policy loaded, mode normal.”
[OPERATOR] $ curl -s -X POST http://localhost:7777/v1/tool \
-H 'Content-Type: application/json' \
-d '{"kind":"tool.echo","params":{"message":"hello"}}' | jq .decision
Output marker: "allow"
[OPERATOR] $ curl -s -X POST http://localhost:7777/v1/tool \
-H 'Content-Type: application/json' \
-d '{"kind":"tool.shell","params":{"command":"id"}}' | jq .decision
Output marker: "deny"
Narration: “The policy allows echo, denies shell. Every tool call is logged to the WAL before the response is returned — fsynced, durable.”
Act 2 — Supply Chain: Seed Once, Propagate Verified (30 seconds)¶
Setup: Registry is running. Release published to control plane. OCI artifacts are signed with cosign.
[OPERATOR] $ autonomy verify \
--image registry.local:5000/myapp:v1.0.0 \
--pubkey demo/keys/cosign.pub \
--require-lock
Output marker:
[PASS] Step 1: cosign signature valid
[PASS] Step 2: agent binary digest matches lock
[PASS] Step 3: behavioral fingerprint matches BLAKE3(canonical(lock))
[PASS] Step 4: policy bundle semver compatible with runtime
verification OK
Narration: “Four verification steps: signature, binary digest, BLAKE3 behavioral fingerprint, semver compatibility. All four must pass. Fail any one — reject.”
[OPERATOR] $ # Now load the verified policy bundle
autonomy policy load --bundle demo/policies/bundle.tar.gz
Output marker:
policy loaded: echo_allow.rego + shell_deny.rego
bundle hash: sha256:...
Narration: “Policy loaded from the verified bundle. The runtime is now running with verifiable provenance all the way back to the signed OCI image.”
Act 3 — WAL Durability: Offline Collection, No Data Loss (20 seconds)¶
Setup: OTLP collector is stopped. 5 tool calls accumulate in the WAL.
[OPERATOR] $ docker compose -f demo/docker-compose.yml stop otel-sink
[OPERATOR] $ for i in 1 2 3; do
curl -s -X POST http://localhost:7777/v1/tool \
-H 'Content-Type: application/json' \
-d "{\"kind\":\"tool.echo\",\"params\":{\"message\":\"offline-$i\"}}" | jq -r .decision
done
Output markers: allow × 3
[OPERATOR] $ # Drain attempt fails, but events survive
autonomy telemetry drain --dir /data/wal --endpoint http://otel-sink:4318
Output marker:
[drain] OTLP error: connection refused
drain failed: could not reach endpoint
[OPERATOR] $ docker compose -f demo/docker-compose.yml start otel-sink
[OPERATOR] $ autonomy telemetry drain --dir /data/wal --endpoint http://otel-sink:4318
Output marker:
[drain] priority queue: 5 events (0 errors, 5 decisions, 0 lifecycle)
[drain] batch 1 accepted: 5 events
drain complete: 5 events sent
Narration: “Five events written before collector outage, zero deleted on failure, five delivered after recovery. WAL is append-only, fsynced before each response.”
Act 4 — OS Replacement: Reconstruct and Continue (25 seconds)¶
Setup: edge daemon precheck is available. State root is populated with fingerprint and a signed manifest.
[OPERATOR] $ # Simulate OS replacement: zero the stored fingerprint
python3 -c "
import json, pathlib
fp = json.loads(pathlib.Path('/data/state/bootstrap/os_fingerprint.json').read_text())
fp['composite_hash'] = '0' * 64
pathlib.Path('/data/state/bootstrap/os_fingerprint.json').write_text(json.dumps(fp))
print('fingerprint tampered — OS replacement simulated')
"
Output marker: fingerprint tampered — OS replacement simulated
[OPERATOR] $ edged --config /etc/edge/edge.toml precheck
Output markers:
level=WARN msg="edge.os.update_detected" previous_hash="000...000" current_hash="a3f...d91"
level=INFO msg="edge.os.reconstruction_started"
level=INFO msg="edge.os.reconstruction_completed" duration_seconds=0.003 boot_epoch=1
[OPERATOR] $ cat /data/state/bootstrap/os_fingerprint.json | python3 -c "
import sys, json; fp=json.load(sys.stdin); print('BootEpoch:', fp['boot_epoch'])
"
Output marker: BootEpoch: 1
Narration: “Fingerprint mismatch detected. Manifest signature verified with Ed25519.
Operations executed from the verified manifest bytes — same bytes, no re-read, TOCTOU closed.
BootEpoch advanced to 1. Node reconstructed. edged starts normally.”
Fail-Closed Coda (10 seconds)¶
Narration: “What if something goes wrong? The system fails closed.”
[OPERATOR] $ # Remove the manifest verify key and retry
mv /data/state/identity/manifest-verify.pub /tmp/
edged --config /etc/edge/edge.toml precheck; echo "Exit: $?"
Output markers:
level=ERROR msg="precheck: manifest verify key missing on reconstruction path"
Exit: 5
[OPERATOR] $ # Runtime in strict mode: all calls denied regardless of policy
AUTONOMY_STRICT_MODE=1 curl -s http://localhost:7777/health | jq .mode
Output marker: "strict"
Narration: “Missing key: exit 5. Strict mode: deny everything. The system never proceeds with unverifiable state.”
Summary Line (5 seconds)¶
“Seed once with a verified OCI image. The runtime enforces it everywhere — airgapped, across OS replacements, through collector outages. Every event durable, every action logged, every recovery cryptographically gated.”
Exact Make Targets for Live Demo¶
# Start full stack
make demo-up
# Load unsigned policy (for environments without cosign)
make demo-run-unsigned
# Full supply-chain demo (cosign required)
make demo-run
# WAL offline accumulation + priority drain
make demo-offline-drain
# All 5 failure injection drills
make demo-drills
# Release poll loop + lifecycle events
make demo-poll-loop
Pause Points¶
After Act |
Pause reason |
What to show |
|---|---|---|
Act 1 |
Verify policy enforcement |
|
Act 2 |
Verify tamper detection |
Run |
Act 3 |
Verify WAL count |
|
Act 4 |
Show epoch evidence |
|