Audit Trail
Each agent maintains a per-agent hash-chained audit log with Ed25519 signatures per event.
Audit Event Envelope
InkAuditEvent = { id: string, // ULID version: "ink-audit/1", agentId: string, agentSignature: string, // Ed25519 over event (minus this field)
// Chain position (SSB-inspired) sequence: number, // monotonically increasing from 1 previousEventHash: string | null, // SHA-256 of prior event; null for seq=1
// What happened eventType: InkAuditEventType, timestamp: string, // ISO 8601
// References messageId?: string, correlationId?: string, counterpartyId?: string, data?: Record<string, unknown>,}Event Types
Message Lifecycle
message.sent · message.received · message.queued · message.delivered · message.acted · message.rejected · message.expired · message.retracted
Receipt Lifecycle
receipt.sent · receipt.received
Delegation
delegation.granted · delegation.used · delegation.revoked · delegation.expired
Connection
connection.requested · connection.accepted · connection.declined
Verification
signature.verified · signature.failed · replay.detected
Hash Chain Structure
Tamper Evidence
The audit chain uses both a hash chain and monotonic sequence numbers:
sequence: Monotonically increasing integer starting at 1. Gaps indicate deleted or suppressed events.previousEventHash: SHA-256 of the JCS-canonicalized prior event (excludingagentSignature). Null for sequence=1.agentSignature: Ed25519 signature over the event (excluding this field). Proves the agent attested to this event at this chain position.
Fork detection: If an agent presents two different events with the same sequence number, the chain is forked and SHOULD be treated as untrusted.
Audit Exchange Protocol
Agents exchange audit records via POST /ink/v1/audit.
Request
{ "protocol": "ink/0.1", "type": "network.tulpa.audit_query", "from": "did:plc:alice", "to": "did:plc:bob", "messageId": "msg-123", "nonce": "<base64url>", "timestamp": "2026-03-19T12:00:00Z"}Response
{ "protocol": "ink/0.1", "type": "network.tulpa.audit_response", "messageId": "msg-123", "events": [ /* InkAuditEvent[] */ ], "responseSignature": "<Ed25519 over JCS(events)>"}The responseSignature allows the requester to prove the responder attested to this specific audit history.
Access Control
The responder MUST verify that the requester’s DID is either the sender or recipient of the referenced messageId. If not, return access_denied.
Dispute Resolution
Reconciliation: Agreement vs Divergence
When agents exchange audit records, four outcomes are possible. Implementations MUST handle all four.
Retention Policy
- Message lifecycle events: 12 months minimum
- Delegation events: lifetime + 12 months
- Connection events: lifetime + 6 months
Export Format
- JSON Lines (one
InkAuditEventper line, newline-delimited) - File naming:
ink-audit-{agentId}-{startDate}-{endDate}.jsonl - Trailing line with final hash chain value