Audit Trace¶
Format¶
SPO audit has two compatible encodings:
- append-only JSONL, one JSON object per line, retained for existing replay, report, and plotting tools;
- append-only length-delimited protobuf event stream, using
proto/audit.proto/scpn_phase_orchestrator.audit.audit.proto.
The protobuf stream is event-sourced: every header, step, and named audit event
is an immutable AuditEnvelope with sequence number, event type, timestamp,
payload digest, previous event hash, event hash, audit mode, and optional HMAC
signature metadata. The JSON payload is still stored inside the envelope so
existing deterministic replay semantics remain unchanged while the stream becomes
tail-safe and schema-versioned.
Unsigned JSONL audit logs use the same integrity principle: the header record
is part of the hash chain seed. The first step or event record therefore links
to the canonical header content instead of starting from a detached zero hash.
Prepending, replacing, or deleting a header changes the downstream
_previous_hash relationship and fails replay integrity checks.
Step Record¶
{
"ts": 1709272800.123,
"step": 42,
"regime": "nominal",
"stability": 0.87,
"layers": [
{"R": 0.91, "psi": 1.23},
{"R": 0.85, "psi": 4.56}
],
"actions": [
{
"knob": "K",
"scope": "global",
"value": 0.05,
"ttl_s": 10.0,
"justification": "degraded: boost global coupling"
}
]
}
Event Record¶
Fields¶
| Field | Type | Present in |
|---|---|---|
ts |
float | All records. Unix epoch seconds. |
step |
int | Step records only. |
regime |
str | Step records. Current regime. |
stability |
float | Step records. Stability proxy. |
layers |
list[{R, psi}] | Step records. Per-layer state. |
actions |
list[ControlAction] | Step records. Actions taken. |
event |
str | Event records. Event type. |
Deterministic Replay Contract¶
Given the same binding spec and initial seed, replaying the sequence of actions from the audit log must reproduce the same layer R values within floating-point tolerance (< 1e-12 absolute difference).
ReplayEngine in runtime.replay loads JSONL and provides iteration over entries.
Protobuf Event Stream¶
The protobuf stream starts with the magic bytes SPOA1\n, followed by repeated
varint-length-delimited spo.audit.AuditEnvelope messages.
Envelope fields:
| Field | Type | Meaning |
|---|---|---|
schema_version |
uint32 | Audit envelope schema version. |
stream_id |
string | Logical stream identity. |
sequence |
uint64 | Monotonic event number, starting at 1. |
event_type |
string | header, step, or the named audit event. |
recorded_at |
Timestamp | Wall-clock capture time. |
source |
string | Producing subsystem. |
previous_hash |
string | Previous event hash, or 64 zeroes. |
payload_json |
string | Canonical JSON audit record. |
payload_sha256 |
string | SHA-256 of payload_json. |
event_hash |
string | SHA-256 over envelope metadata and payload digest. |
signature_algorithm |
string | Signature algorithm, empty for unsigned development streams. |
signature_key_id |
string | Non-secret verification-key id, empty for unsigned development streams. |
signature |
string | HMAC signature value, empty for unsigned development streams. |
audit_mode |
string | hmac-signed or unsigned-development. |
verify_event_stream_integrity() checks sequence continuity, previous-hash
continuity, payload digests, event hashes, and HMAC signatures when verification
keys are configured. Any mutation to a payload or event envelope breaks the chain
at the first affected event.
Live Watch¶
spo watch tails the protobuf stream and prints replay summaries as events
arrive:
spo run domainpacks/minimal_domain/binding_spec.yaml \
--steps 120 \
--audit audit.jsonl \
--audit-stream audit.spoa
spo watch audit.spoa --from-start
For bounded automation and tests, pass --max-events N. Without
--from-start, watch mode follows newly appended events.
Log Management¶
- Logs are never truncated during a run.
AuditLogger.close()flushes and closes the file handle.- JSONL and protobuf stream rotation are the caller's responsibility.
References¶
Deterministic replay requirements are specified in eval_protocol.md § Deterministic Replay. The stability field corresponds to the Kuramoto order parameter R — see lock_metrics.md.