Audit Event Schema¶
Purpose: Define all audit event types with payload schemas for sequence mapping and validation.
Base Event Schema¶
All events extend this base:
interface BaseAuditEvent {
id: string; // UUID
sequence: number; // Monotonic, no gaps
timestamp: string; // ISO 8601
previousHash: string; // Hash of previous event
hash: string; // Hash of this event (excluding hash field)
signature: string; // Service key signature
// Context
type: EventType; // Event type (see below)
resourceType: 'vault' | 'document' | 'trigger' | 'access_grant';
resourceId: string; // UUID of affected resource
// Attribution
actor: {
type: 'user' | 'system' | 'trigger' | 'executor';
id: string; // User ID or 'system'
ip?: string; // Client IP if user-initiated
};
}
Event Types by Category¶
Trigger Lifecycle Events¶
trigger_created¶
{
type: 'trigger_created',
resourceType: 'trigger',
resourceId: string,
payload: {
vaultId: string,
triggerType: 'dead_man_switch' | 'scheduled' | 'death_verification',
config: {
checkInInterval?: number, // ms
gracePeriod?: number, // ms
challengeWindow?: number, // ms
abortWindow?: number, // ms
scheduledDate?: string, // ISO 8601
},
initialState: 'draft',
}
}
trigger_armed¶
{
type: 'trigger_armed',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'draft',
newState: 'armed',
nextCheckInDue: string, // ISO 8601
executorId: string,
}
}
trigger_updated¶
{
type: 'trigger_updated',
resourceType: 'trigger',
resourceId: string,
payload: {
updatedFields: string[], // ['checkInInterval', 'gracePeriod', etc.]
previousConfig: object, // Snapshot of changed fields before
newConfig: object, // Snapshot of changed fields after
updatedBy: string, // User ID
}
}
trigger_disarmed¶
{
type: 'trigger_disarmed',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'armed',
newState: 'draft',
disarmedBy: string, // User ID
reason?: string, // Optional user-provided reason
}
}
check_in_recorded¶
{
type: 'check_in_recorded',
resourceType: 'trigger',
resourceId: string,
payload: {
checkInMethod: 'web' | 'email_link' | 'sms' | 'app',
previousCheckIn: string | null, // ISO 8601
nextCheckInDue: string, // ISO 8601
signalCount: 0, // Reset to 0
}
}
check_in_missed¶
{
type: 'check_in_missed',
resourceType: 'trigger',
resourceId: string,
payload: {
expectedBy: string, // ISO 8601
missedAt: string, // ISO 8601
signalCount: number, // Incremented (1)
triggerState: 'armed', // Still armed, not triggered yet
}
}
reminder_sent¶
{
type: 'reminder_sent',
resourceType: 'trigger',
resourceId: string,
payload: {
channel: 'email' | 'sms' | 'push',
recipient: string, // Masked email/phone
reminderType: 'check_in_reminder' | 'challenge_notification' | 'final_warning',
expiresAt: string, // ISO 8601 (when reminder link expires)
}
}
reminder_acknowledged¶
{
type: 'reminder_acknowledged',
resourceType: 'trigger',
resourceId: string,
payload: {
channel: 'email' | 'sms' | 'push',
acknowledgedAt: string, // ISO 8601
signalCount: 0, // Reset
triggerState: 'armed', // Back to normal armed state
}
}
reminder_unacknowledged¶
{
type: 'reminder_unacknowledged',
resourceType: 'trigger',
resourceId: string,
payload: {
channel: 'email' | 'sms' | 'push',
sentAt: string, // ISO 8601
expiredAt: string, // ISO 8601
signalCount: number, // Incremented (2)
}
}
secondary_signal_confirmed¶
{
type: 'secondary_signal_confirmed',
resourceType: 'trigger',
resourceId: string,
payload: {
signalType: 'sms_failed' | 'contact_confirmed' | 'email_bounced',
signalCount: number, // Current count (2+)
details: string, // Human-readable description
}
}
trigger_fired¶
{
type: 'trigger_fired',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'armed',
newState: 'triggered',
signalCount: number, // Must be >= 2
signals: string[], // List of signal types that fired
challengeWindowEnds: string, // ISO 8601
}
}
challenge_window_started¶
{
type: 'challenge_window_started',
resourceType: 'trigger',
resourceId: string,
payload: {
windowDuration: number, // ms
expiresAt: string, // ISO 8601
notificationsSent: string[], // ['email', 'sms']
}
}
challenge_window_elapsed¶
{
type: 'challenge_window_elapsed',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'triggered',
newState: 'pending_execution',
startedAt: string, // ISO 8601
elapsedAt: string, // ISO 8601
abortWindowEnds: string, // ISO 8601
}
}
abort_requested¶
{
type: 'abort_requested',
resourceType: 'trigger',
resourceId: string,
payload: {
requestedBy: string, // User ID
requestMethod: 'web' | 'email_link' | 'sms' | 'support_call',
previousState: 'armed' | 'triggered' | 'pending_execution',
verificationMethod: 'password' | 'mfa' | 'security_questions',
}
}
trigger_aborted¶
{
type: 'trigger_aborted',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'armed' | 'triggered' | 'pending_execution',
newState: 'aborted',
abortedBy: string, // User ID
reason: string, // User-provided or system
}
}
execution_started¶
{
type: 'execution_started',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'pending_execution',
newState: 'executing',
documentsToRelease: string[], // Document IDs
executorId: string,
}
}
access_granted¶
{
type: 'access_granted',
resourceType: 'trigger',
resourceId: string,
payload: {
executorId: string,
documentIds: string[],
accessType: 'download' | 'view',
expiresAt: string, // ISO 8601 (link expiry)
}
}
executor_notified¶
{
type: 'executor_notified',
resourceType: 'trigger',
resourceId: string,
payload: {
executorId: string,
channel: 'email' | 'sms',
recipient: string, // Masked
includesAccessLink: boolean,
}
}
execution_completed¶
{
type: 'execution_completed',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'executing',
newState: 'released',
documentsReleased: number,
executorAccessGranted: boolean,
}
}
trigger_released¶
{
type: 'trigger_released',
resourceType: 'trigger',
resourceId: string,
payload: {
releasedAt: string, // ISO 8601
reversalWindowEnds: string, // ISO 8601 (7 days)
accessLinkExpiry: string, // ISO 8601
}
}
trigger_finalized¶
{
type: 'trigger_finalized',
resourceType: 'trigger',
resourceId: string,
payload: {
previousState: 'released',
newState: 'finalized',
finalizedAt: string, // ISO 8601
reversalWindowElapsed: boolean,
archiveLocation?: string, // If archived
}
}
Document Events¶
document_uploaded¶
{
type: 'document_uploaded',
resourceType: 'document',
resourceId: string,
payload: {
vaultId: string,
encryptionClass: 'A' | 'B' | 'C',
filename: string, // Original filename (Class A metadata)
mimeType: string,
sizeBytes: number,
checksumSha256: string, // Of ciphertext
clientEncrypted: boolean, // true for B/C
}
}
document_downloaded¶
{
type: 'document_downloaded',
resourceType: 'document',
resourceId: string,
payload: {
downloadedBy: string, // User ID or executor ID
downloadType: 'owner_access' | 'executor_access' | 'recovery_access',
triggerId?: string, // If executor access
contentDelivered: 'ciphertext' | 'plaintext', // C = always ciphertext
}
}
document_deleted¶
{
type: 'document_deleted',
resourceType: 'document',
resourceId: string,
payload: {
vaultId: string,
deletedBy: string, // User ID
reason?: string,
softDelete: boolean, // Tombstone vs permanent
}
}
document_version_created¶
{
type: 'document_version_created',
resourceType: 'document',
resourceId: string,
payload: {
vaultId: string,
versionNumber: number, // Sequential version
previousVersionId: string | null,
encryptionClass: 'A' | 'B' | 'C',
sizeBytes: number,
checksumSha256: string, // Of new ciphertext
changeType: 'update' | 'restore',
}
}
Vault Events¶
vault_created¶
{
type: 'vault_created',
resourceType: 'vault',
resourceId: string,
payload: {
ownerId: string,
vaultType: 'witness' | 'estate' | 'exit' | 'legacy',
defaultEncryptionClass: 'B' | 'C',
}
}
executor_assigned¶
{
type: 'executor_assigned',
resourceType: 'vault',
resourceId: string,
payload: {
executorId: string,
executorEmail: string, // Masked
assignedBy: string, // User ID
permissions: string[], // ['download', 'view_metadata']
notificationSent: boolean,
}
}
executor_removed¶
{
type: 'executor_removed',
resourceType: 'vault',
resourceId: string,
payload: {
executorId: string,
removedBy: string, // User ID
reason?: string,
}
}
vault_updated¶
{
type: 'vault_updated',
resourceType: 'vault',
resourceId: string,
payload: {
updatedFields: string[], // ['name', 'defaultEncryptionClass', etc.]
previousValues: object, // Snapshot before
newValues: object, // Snapshot after
updatedBy: string, // User ID
}
}
vault_deleted¶
{
type: 'vault_deleted',
resourceType: 'vault',
resourceId: string,
payload: {
deletedBy: string, // User ID
documentCount: number, // Documents affected
triggerCount: number, // Triggers affected
softDelete: boolean, // Tombstone vs permanent
retentionDays?: number, // Days before permanent deletion
}
}
Encryption Events¶
master_key_unwrapped¶
Vault-level event: Logged when master key is retrieved for trigger execution
This event is logged BEFORE any document decryption occurs. It records how and why the vault's master key was obtained.
{
type: 'master_key_unwrapped',
resourceType: 'vault',
resourceId: string, // Vault ID
payload: {
triggerId: string, // Trigger that initiated unwrap
keySource: 'server_escrow' | 'quorum_shares' | 'user_password',
// Phase 0.5: always 'server_escrow'
// Phase 1+: 'quorum_shares' if M-of-N recovery used
escrowMethod: 'sealed_secret' | 'hsm' | 'shamir_combine',
sharesUsed?: number, // Only for quorum mode
sharesRequired?: number, // Only for quorum mode
}
}
class_b_decryption¶
Document-level event: Logged for EACH document decrypted
CRITICAL: Must only appear inside trigger execution handler, AFTER master_key_unwrapped.
{
type: 'class_b_decryption',
resourceType: 'document',
resourceId: string, // Document ID
payload: {
triggerId: string, // REQUIRED
vaultId: string, // Parent vault
reason: 'trigger_execution', // Only valid reason
jurisdiction: {
country: string,
state?: string,
legalNotes?: string,
},
decryptedFor: 'executor_delivery' | 'pdf_generation',
keySource: 'server_escrow' | 'quorum_shares', // Must match master_key_unwrapped
}
}
Expected sequence for Class B release:
1. master_key_unwrapped (vault-level, once)
2. class_b_decryption (document-level, per document)
3. class_b_decryption (document-level, per document)
...
class_c_document_released¶
Note: No content fields - ciphertext delivery only
{
type: 'class_c_document_released',
resourceType: 'document',
resourceId: string,
payload: {
triggerId: string,
executorId: string,
deliveryMethod: 'download_link',
contentType: 'ciphertext_only', // Always ciphertext
accessLinkExpiry: string, // ISO 8601
// NO content, NO decryption key, NO plaintext reference
}
}
encryption_class_violation_attempt¶
Security event - always logged, always blocked
{
type: 'encryption_class_violation_attempt',
resourceType: 'document',
resourceId: string,
payload: {
encryptionClass: 'A' | 'B' | 'C',
attemptedOperation: string, // e.g., 'decrypt', 'generatePDF'
blockedBy: 'middleware' | 'runtime_check',
codeLocation: string, // File:line for debugging
severity: 'critical',
}
}
Access Events¶
access_link_generated¶
{
type: 'access_link_generated',
resourceType: 'document',
resourceId: string,
payload: {
linkId: string, // UUID
generatedFor: string, // Executor ID
expiresAt: string, // ISO 8601
maxUses: number, // Usually 1
documentsIncluded: string[], // Document IDs
}
}
access_link_used¶
{
type: 'access_link_used',
resourceType: 'document',
resourceId: string,
payload: {
linkId: string,
usedBy: string, // Executor ID
usedAt: string, // ISO 8601
remainingUses: number,
downloadedDocuments: string[],
}
}
access_denied¶
{
type: 'access_denied',
resourceType: 'document',
resourceId: string,
payload: {
attemptedBy: string, // User/executor ID
reason: 'not_released' | 'link_expired' | 'unauthorized' | 'max_uses_exceeded',
triggerState?: string, // Current trigger state
}
}
access_link_expired¶
{
type: 'access_link_expired',
resourceType: 'document',
resourceId: string,
payload: {
linkId: string, // UUID
generatedFor: string, // Executor ID
generatedAt: string, // ISO 8601
expiredAt: string, // ISO 8601
wasUsed: boolean, // Whether link was ever used
usageCount: number, // Times used before expiry
}
}
Recovery Events¶
recovery_requested¶
{
type: 'recovery_requested',
resourceType: 'vault',
resourceId: string,
payload: {
requestedBy: string, // User ID or system
recoveryType: 'password_lost' | 'executor_recovery',
contactsNotified: number, // M-of-N contacts
threshold: number, // Required shares
expiresAt: string, // ISO 8601
}
}
recovery_share_submitted¶
{
type: 'recovery_share_submitted',
resourceType: 'vault',
resourceId: string,
payload: {
recoveryRequestId: string,
submittedBy: string, // Contact ID
shareIndex: number, // Which share (1-N)
sharesCollected: number, // Current count
thresholdMet: boolean,
}
}
recovery_completed¶
{
type: 'recovery_completed',
resourceType: 'vault',
resourceId: string,
payload: {
recoveryRequestId: string,
completedAt: string, // ISO 8601
sharesUsed: number,
newKeyWrapped: boolean, // User set new password
}
}
recovery_cancelled¶
{
type: 'recovery_cancelled',
resourceType: 'vault',
resourceId: string,
payload: {
recoveryRequestId: string,
cancelledBy: string, // User ID, contact ID, or 'system'
cancelledAt: string, // ISO 8601
reason: 'user_request' | 'timeout' | 'owner_login' | 'suspicious_activity',
sharesCollectedAtCancellation: number,
}
}
Expected Event Sequences¶
North Star Test: Happy Path (Steps 1-5)¶
1. Setup:
vault_created
document_uploaded
executor_assigned
trigger_created
trigger_armed
2. Check-in Missed:
check_in_missed
reminder_sent
3. Reminder Ignored:
reminder_unacknowledged
trigger_fired
challenge_window_started
reminder_sent (challenge notification)
4. Challenge Window Passes:
challenge_window_elapsed
reminder_sent (final warning)
5. Execution:
execution_started
[master_key_unwrapped + class_b_decryption] OR [class_c_document_released] // Based on class
access_granted
access_link_generated
executor_notified
execution_completed
trigger_released
North Star Test: Abort Path (Step 6)¶
1-3. (Same as happy path through trigger_fired)
4. User Aborts:
abort_requested
trigger_aborted
(No execution_started, no access_granted, no executor_notified)
Class C vs Class B Divergence (Step 5)¶
Class B:
execution_started
master_key_unwrapped (keySource: server_escrow, escrowMethod: sealed_secret)
class_b_decryption (reason: trigger_execution, keySource: server_escrow) // Per document
access_granted
access_link_generated
executor_notified
execution_completed
Class C:
execution_started
class_c_document_released (contentType: ciphertext_only)
access_granted
access_link_generated
executor_notified
execution_completed
Key difference: Class C has NO class_b_decryption event. If one appears for a Class C document, the test fails.
This schema defines all audit events. Use for sequence assertions in integration tests.