Skip to Content
ConceptsSession Forensics

Session Forensics

Session Forensics is the mechanism by which Govrix Scout creates a cryptographically-linked, tamper-evident audit trail for every conversation an agent has with an LLM. It is designed to satisfy compliance requirements where you need to prove — not just claim — what an agent said and when.

The compliance invariant

Every event emitted by the proxy must carry the following four fields. This is enforced at compile time: AgentEvent::new() will not compile without all four.

FieldTypeDescription
session_idUUID v4Groups all events belonging to one logical conversation
timestampISO-8601 UTCNanosecond-precision wall-clock time of the event
lineage_hashSHA-256 hexMerkle chain node linking this event to its predecessor
compliance_tagStringRegulatory classification applied at policy evaluation time (e.g. pci-dss, hipaa, internal)

Removing any of these four fields from AgentEvent is a compile error, not a runtime warning. This is intentional — compliance invariants are structural, not optional.

How the Merkle chain works

Each event’s lineage_hash is computed as:

SHA-256( previous_lineage_hash || session_id || timestamp || payload_hash )

The first event in a session uses the session ID itself as the seed (there is no predecessor hash). This produces a chain where any retroactive modification to an event — including deleting it — produces a detectable break in the hash sequence when you walk the chain.

This is not a blockchain. It is a single-author, append-only Merkle chain. Its purpose is tamper detection, not consensus.

Implementation

FileRole
crates/govrix-scout-proxy/src/policy/session.rsSessionRecorder — appends events to the session trace, computes lineage hashes
crates/govrix-scout-common/src/models/event.rsAgentEvent struct — enforces the four required fields at the type level
crates/govrix-scout-store/src/sessions.rsDatabase reads for the session query API

The SessionRecorder is called from log_response_event via PolicyHook::record_session_event — it is on the event-write path, not the hot-path request handler.

API

curl -X GET http://localhost:4001/api/v1/sessions \ -H "Authorization: Bearer $GOVRIX_API_KEY"

Response:

{ "sessions": [ { "session_id": "018e4b7a-1234-7abc-8def-000000000001", "agent_id": "billing-agent", "started_at": "2026-03-05T08:00:00.000Z", "last_event_at": "2026-03-05T08:04:22.317Z", "event_count": 12, "compliance_tag": "pci-dss" } ] }

Event writes are fire-and-forget: the proxy never awaits the database write. Events are buffered in a bounded in-process channel (capacity 10,000) and flushed by a background batch writer every 100ms or every 100 events, whichever comes first. This means a session’s event list may lag real-time by up to 100ms.

Verifying chain integrity

To verify that no events have been tampered with or deleted, walk the events for a session in timestamp order and recompute each lineage_hash. A break in the chain at position N means event N (or an event between N-1 and N) was altered or removed.

Govrix does not currently expose a built-in chain verification endpoint. You can verify offline by querying the raw events table directly:

SELECT event_id, timestamp, lineage_hash FROM agent_events WHERE session_id = '018e4b7a-1234-7abc-8def-000000000001' ORDER BY timestamp ASC;
Last updated on