Traits / Auditable
Auditable
Compliance-grade audit trail trait that captures state transitions with actor, reason, and timestamp metadata. Auditable observes Stateful transitions and records them as an append-only audit log suitable for compliance review, debugging, and timeline rendering. Auditable defines the INTERFACE for audit data — the schema shape, parameters, and view extensions that match the existing implementation. Advanced compliance features (crypto-shredding, KMS integration, tamper-proof hashing) are documented in R21.3 research and targeted for future enrichment. Core concepts: - Audit Log: append-only array of AuditEntry records - Transition Capture: from_state → to_state with timestamp, actor, and reason - Retention Policy: configurable retention period for log entries - Actor Tracking: optional actor_id capture for accountability - Reason Enforcement: optional requirement for transition justification
Generated from @oods/foundry 0.10.1
- Group
- lifecycle
- Maturity
- experimental
- Contexts
- detail, timeline
Fields it adds
| Field | Type | Required | Description |
|---|---|---|---|
audit_log | AuditEntry[] | yes | Append-only chronological log of state transition events. Each entry captures the full context of a state change. |
What it shows in each context
Parameters
retentionDaysnumber- Number of days to retain audit log entries before archival eligibility. Value of 0 means indefinite retention. Does not auto-delete — serves as a policy signal for downstream archival processes.
requireTransitionReasonboolean- When true, every state transition must include a reason string. Enforces accountability by preventing silent status changes.
trackActorIdboolean- When true, actor_id is captured on each transition. Enables per-user audit trails and accountability reporting.
Objects that use it
No shipped object uses this trait.
The trait file
traits/lifecycle/Auditable.trait.yaml
trait:
name: Auditable
version: 1.0.0
description: |
Compliance-grade audit trail trait that captures state transitions with actor,
reason, and timestamp metadata. Auditable observes Stateful transitions and
records them as an append-only audit log suitable for compliance review,
debugging, and timeline rendering.
Auditable defines the INTERFACE for audit data — the schema shape, parameters,
and view extensions that match the existing implementation. Advanced compliance
features (crypto-shredding, KMS integration, tamper-proof hashing) are documented
in R21.3 research and targeted for future enrichment.
Core concepts:
- Audit Log: append-only array of AuditEntry records
- Transition Capture: from_state → to_state with timestamp, actor, and reason
- Retention Policy: configurable retention period for log entries
- Actor Tracking: optional actor_id capture for accountability
- Reason Enforcement: optional requirement for transition justification
category: lifecycle
tags:
- audit
- compliance
- trail
- lifecycle
- transition
- accountability
parameters:
- name: retentionDays
type: number
required: false
description: |
Number of days to retain audit log entries before archival eligibility.
Value of 0 means indefinite retention. Does not auto-delete — serves as
a policy signal for downstream archival processes.
default: 0
validation:
minimum: 0
- name: requireTransitionReason
type: boolean
required: false
description: |
When true, every state transition must include a reason string.
Enforces accountability by preventing silent status changes.
default: false
- name: trackActorId
type: boolean
required: false
description: |
When true, actor_id is captured on each transition. Enables
per-user audit trails and accountability reporting.
default: true
schema:
audit_log:
type: AuditEntry[]
required: true
description: |
Append-only chronological log of state transition events.
Each entry captures the full context of a state change.
default: []
items:
type: object
properties:
from_state:
type: string
required: false
description: State before the transition. Null for initial state assignment.
to_state:
type: string
required: true
description: State after the transition.
transitioned_at:
type: datetime
required: true
description: UTC timestamp when the transition occurred.
actor_id:
type: string
required: false
requiredFromParameter: trackActorId
description: |
Identifier of the user or system that triggered the transition.
Required when trackActorId parameter is true.
reason:
type: string
required: false
requiredFromParameter: requireTransitionReason
description: |
Human-readable justification for the transition.
Required when requireTransitionReason parameter is true.
metadata:
type: Record<string, unknown>
required: false
description: |
Arbitrary key-value pairs for domain-specific context
(e.g., approval_id, ticket_number, automation_rule).
default: {}
semantics:
audit_log:
semantic_type: timeline.audit
token_mapping: tokenMap(audit.timeline.*)
ui_hints:
component: AuditTimeline
maxVisible: 7
collapseWhenEmpty: true
entryComponent: AuditEntryCard
audit_log.from_state:
semantic_type: audit.transition.from
token_mapping: tokenMap(audit.state.from)
ui_hints:
component: StatusBadge
emphasis: subtle
audit_log.to_state:
semantic_type: audit.transition.to
token_mapping: tokenMap(audit.state.to)
ui_hints:
component: StatusBadge
emphasis: subtle
audit_log.transitioned_at:
semantic_type: audit.transition.timestamp
token_mapping: tokenMap(audit.timestamp.*)
ui_hints:
component: RelativeTimestamp
audit_log.actor_id:
semantic_type: audit.transition.actor
token_mapping: tokenMap(audit.actor.*)
ui_hints:
component: ActorBadge
audit_log.reason:
semantic_type: audit.transition.reason
token_mapping: tokenMap(audit.reason.*)
ui_hints:
component: TextBody
view_extensions:
timeline:
- component: AuditTimeline
position: main
priority: 60
props:
auditLogField: audit_log
maxVisible: 7
showFromState: true
showActorId: true
showReason: true
detail:
- component: AuditSummaryCard
position: main
priority: 50
props:
auditLogField: audit_log
lastN: 5
showTransitionCount: true
showLastTransitionTime: true
showLastActor: true
tokens:
# Timeline connector tokens
cmp.audit.timeline.connector.color: "var(--sys-border-default)"
cmp.audit.timeline.connector.width: "var(--space-px)"
cmp.audit.timeline.dot.color: "var(--sys-surface-accent)"
cmp.audit.timeline.dot.size: "var(--space-2)"
# Audit entry tokens
cmp.audit.entry.bg: "var(--sys-surface-raised)"
cmp.audit.entry.border: "var(--sys-border-default)"
cmp.audit.entry.radius: "var(--radius-md)"
cmp.audit.entry.padding: "var(--space-3)"
# Audit text tokens
cmp.audit.entry.state.text: "var(--sys-text-strong)"
cmp.audit.entry.reason.text: "var(--sys-text-default)"
cmp.audit.entry.timestamp.text: "var(--sys-text-subtle)"
cmp.audit.entry.actor.text: "var(--sys-text-subtle)"
# Summary card tokens
cmp.audit.summary.count.text: "var(--sys-text-strong)"
cmp.audit.summary.label.text: "var(--sys-text-subtle)"
dependencies:
# Auditable observes Stateful state transitions to generate audit_log entries.
# Without Stateful, there are no transitions to audit.
- Stateful
metadata:
created: "2026-02-28"
owners:
- compliance@oods.systems
- engineering@oods.systems
maturity: experimental
accessibility:
keyboard: |
AuditTimeline entries are not interactive. Summary card expand/collapse
is keyboard navigable via Enter/Space.
screenreader: |
AuditTimeline uses role="log" with aria-label="Audit trail".
Each entry announces: transition direction (from → to), timestamp,
actor, and reason as a single description.
AuditSummaryCard announces total transition count and last activity.
regionsUsed:
- timeline
- detail
examples:
- Subscription
- Invoice
references:
- "objects/provenance.v1.json#/references/ref-abca58b6f92b — existing timeline renderer"
- "objects/provenance.v1.json#/references/ref-c373015a9045 — StatusTransitionEvent interface (shared shape)"
- "R21.3 Canonical Audit Architecture — compliance-grade audit trail research (200+ pages)"
- "traits/lifecycle/Stateful.trait.yaml — required dependency (state transitions)"