ADR-0003: Audit/v1 Stream Design¶
Status: Accepted (2026-05-17)
Author: Operator
Context¶
The policy/v1 gate (PR #9) evaluates Allow/Deny/Prompt decisions for networked sinks. Operators require visibility into these decisions for compliance verification and debugging. Prior to this work, no structured audit logging mechanism existed.
Problem Statement¶
- Policy enforcement happens silently; operators cannot verify what decisions were made or why.
- Compliance auditors cannot demonstrate to external parties that policy is working as intended.
- Debugging policy bugs requires source-level tracing; post-hoc log analysis is not possible.
Decision¶
Implement an append-only JSONL audit stream at ~/.vox/audit.jsonl with the following properties:
Storage & Permissions¶
- Location:
~/.vox/audit.jsonl(relative to user home, not project root) - Mode: 0600 (read/write for owner only)
- Format: JSONL (one JSON object per line)
- Thread-safe writes via mutex
Schema¶
{
"timestamp": "2026-05-17T14:32:18Z",
"kind": "policy_decision",
"sink": "llm-anthropic",
"verdict": "allowed",
"reason": "",
"mode": "selective"
}
Field value reference:
- kind: always "policy_decision" in v1
- verdict: "allowed" or "denied"
- reason: denial reason constant ("air-gap-mode", "explicit-deny", "consent-declined", "headless-prompt-required") or "" when allowed
- mode: active policy mode ("air-gap", "permissive", "selective")
Schema versioning: future changes are gated via a schema_version field (1 reserved for baseline; migration tooling tracked in bd blackrim-vox-1vb).
Rotation Policy¶
- Size: 16 MB per file (rotates to
audit-<RFC3339-timestamp>-<ns>.jsonl) - Age: 30 days (archives older than 30 days)
- Retention: Keep 5 most recent files
- Deletion beyond retention is silent (no backup/trash)
Default Behavior¶
- NullStream (no-op) is the default when no sink is configured
- Preserves existing test behavior (no audit side effects in tests unless explicitly enabled)
- Can be toggled on/off via config flag
[audit] enabled = true|false
Consequences¶
Positive¶
- Operators can query audit trail:
vox audit tail,grep verdict=deny audit.jsonl, etc. - Compliance auditors can demonstrate policy enforcement post-hoc (non-repudiation).
- Disk growth is bounded by rotation; no unbounded file growth.
- Schema versioning allows future extensions without breaking existing deployments.
Risks & Mitigations¶
- Disk space: Rotation + retention bounds the footprint. On typical usage (~10 decisions/hour), 5 files of 16 MB each absorbs ~750 days of logs.
- Performance: Mutex + append is O(1); serialization latency is <1 ms per entry. Negligible impact on policy evaluation (~40 ms baseline).
- Schema changes: Breaking changes require migration tooling. Plan:
vox audit migratesubcommand for bulk rewriting old entries (filed as bddbl). - Privacy: Home directory storage is per-user; shared systems see separate audit trails per user (no cross-user data).
Alternatives Considered¶
Syslog / Journald¶
Rejected. Platform-specific (Linux journald, macOS log, BSD syslog). Vox targets Linux, macOS, and Windows; syslog adds platform abstraction overhead. Also makes grepping from CI/CD pipelines harder (must use platform-specific query tools). Local file is simpler and more portable.
Prometheus Events / Metrics¶
Rejected. Prometheus is a metrics scraper, not an event log. Cannot preserve historical decisions (point-in-time gauge overwrite). Overkill for a CLI tool without infrastructure assumptions.
Structured Database (SQLite)¶
Rejected. Adds a runtime dependency and complexity for write-heavy, read-light workload. JSONL + grep is sufficient and easier to ship as a single-binary tool. Database migrations introduce failure modes (locked DB, schema mismatch across binary versions).
Cloud Audit Sinks (CloudTrail, GCP Logging, etc.)¶
Rejected. Out of scope for vox 1.x; adds dependency on cloud provider choice. Local audit trail is a prerequisite. Cloud sinks can be layered on top later (via log-shipping tooling).
Unresolved Questions¶
-
Aggregation across runs: For high-volume sinks, a single audit file across many policy decisions may grow quickly. Long-term archival strategy (S3, log-shipping) is deferred to a future enhancement.
-
Decryption/signing: Audit entries are stored as plaintext. HMAC signing for tamper detection is tracked as
blackrim-vox-2rf(post-1.0). -
Structured query API:
vox audit tailand grep are sufficient for MVP. A structured query interface (e.g.,vox audit query --since 7d --verdict deny) is deferred.
Related Issues¶
- blackrim-vox-457 (this ADR)
- blackrim-vox-1vb (schema migration tooling)
- dbl (
vox audit migratesubcommand) - blackrim-vox-2rf (HMAC signing)