AgentVault’s telemetry data model is OTel-compatible from day one. Every audit event
conforms to the OpenTelemetry Log Data Model
so it can export to any OTel-compatible backend (Splunk, Datadog, Grafana) without schema changes.
Trace ID generation is deterministic from conversation IDs using a namespace UUID + SHA-256
truncated to 128 bits. The same conversation always produces the same trace ID.
Copy
Ask AI
import uuidAGENTVAULT_NAMESPACE = uuid.UUID("a1b2c3d4-e5f6-7890-abcd-ef1234567890")def conversation_to_trace_id(conversation_id: str) -> str: """Deterministic mapping from conversation ID to OTel trace ID.""" derived = uuid.uuid5(AGENTVAULT_NAMESPACE, conversation_id) return derived.hex # 32-char hex, OTel compatibledef generate_span_id() -> str: """Random span ID for each message exchange.""" return uuid.uuid4().hex[:16] # 16-char hex, OTel compatible
The hash covers: previous hash, timestamp, trace context, event body, and participants.
It excludes: observed_timestamp, delivery metadata, and the hash_chain block itself.
def verify_chain(events: list[dict]) -> tuple[bool, int | None]: """Returns (True, None) if valid or (False, break_index) if tampered.""" for i, event in enumerate(events): expected_previous = GENESIS_HASH if i == 0 else events[i-1]["hash_chain"]["event_hash"] if event["hash_chain"]["previous_hash"] != expected_previous: return (False, i) recomputed = compute_event_hash(event, expected_previous) if event["hash_chain"]["event_hash"] != recomputed: return (False, i) return (True, None)
Chains are partitioned per tenant to avoid bottlenecks. Within a tenant, events are
strictly ordered by sequence_number. Cross-tenant verification is handled via signed
checkpoint hashes in the federation phase.
CREATE TABLE audit_events ( audit_event_id UUID PRIMARY KEY, tenant_id UUID NOT NULL REFERENCES tenants(tenant_id), sequence_number BIGINT NOT NULL, timestamp TIMESTAMPTZ NOT NULL, observed_timestamp TIMESTAMPTZ NOT NULL DEFAULT now(), trace_id CHAR(32) NOT NULL, span_id CHAR(16) NOT NULL, parent_span_id CHAR(16), trace_flags SMALLINT DEFAULT 1, severity_number SMALLINT NOT NULL, severity_text TEXT NOT NULL, body JSONB NOT NULL, resource JSONB NOT NULL, attributes JSONB NOT NULL, event_hash TEXT NOT NULL, previous_hash TEXT NOT NULL, UNIQUE (tenant_id, sequence_number));
Indexes:
(tenant_id, sequence_number) — Chain traversal
(trace_id) — Conversation/room lookup
(tenant_id, timestamp) — Time-range queries
(tenant_id, severity_number) WHERE severity_number >= 17 — Error/critical filtering
GIN on body and attributes — JSONB content search
Copy
Ask AI
CREATE TABLE messages ( message_id UUID PRIMARY KEY, conversation_id UUID NOT NULL REFERENCES conversations(conversation_id), trace_id CHAR(32) NOT NULL, span_id CHAR(16) NOT NULL, parent_span_id CHAR(16), sender_id UUID NOT NULL REFERENCES entities(entity_id), recipient_id UUID NOT NULL REFERENCES entities(entity_id), message_type TEXT NOT NULL, priority TEXT DEFAULT 'normal', payload JSONB NOT NULL, metadata JSONB DEFAULT '{}', envelope_version TEXT DEFAULT '1.0.0', created_at TIMESTAMPTZ DEFAULT now(), delivered_at TIMESTAMPTZ, read_at TIMESTAMPTZ);
Copy
Ask AI
CREATE TABLE decisions ( decision_id UUID PRIMARY KEY, conversation_id UUID NOT NULL REFERENCES conversations(conversation_id), request_message_id UUID NOT NULL REFERENCES messages(message_id), response_message_id UUID REFERENCES messages(message_id), status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'resolved', 'expired', 'auto_resolved')), deadline TIMESTAMPTZ, resolved_at TIMESTAMPTZ, selected_option TEXT, created_at TIMESTAMPTZ DEFAULT now());
-- Full audit trail for a conversationSELECT * FROM audit_eventsWHERE trace_id = :trace_idORDER BY sequence_number ASC;-- Critical/error events for tenant in last 24hSELECT * FROM audit_eventsWHERE tenant_id = :tenant_id AND severity_number >= 17 AND timestamp > now() - interval '24 hours'ORDER BY timestamp DESC;-- Hash chain integrity verificationSELECT sequence_number, event_hash, previous_hash, LAG(event_hash) OVER (ORDER BY sequence_number) as expected_previousFROM audit_eventsWHERE tenant_id = :tenant_idORDER BY sequence_number;