Every fasten audit row carries an actor_kind field. Its four values name the class of thing that emitted the row. A fatigued human approver is audited with the same primitive as a hallucinating model. This page explains why one enum, not four separate audit systems, and how membrane uses it for suppressed-claim provenance.
| Value | Represents | actor field carries |
|---|---|---|
user | A human whose action produced the row (approval, override, manual review). | The user id (e.g. u_04217). |
agent | An AI model that produced the row (belief update, tool call, response emission). | The model id or agent id (e.g. credit-triage-v3). |
service | A running program that produced the row (a microservice writing durable state). | The service id (e.g. payments-processor). |
schedule | A scheduled job that produced the row (nightly reconciliation, retry sweep). | The scheduler id and job name (e.g. cron:eod-close). |
actor_kind = "user")emit(
code="LOAN_APPROVED",
target="acct_042",
actor="u_04217", # the approver's id
actor_kind="user",
detail={"amount_cents": 500000, "override_reason": "long-standing customer"},
)
The row records that a human with id u_04217 approved the loan for acct_042. The detail.override_reason is queryable evidence. If a supervisor asks later "who override-approved this loan and what did they cite," the row is the answer.
actor_kind = "agent")emit(
code="BELIEF_UPDATED",
target="acct_042",
actor="credit-triage-v3",
actor_kind="agent",
detail={"field": "risk_tier", "value": "low", "confidence": 0.62},
)
The model updated its belief about acct_042's risk tier. Membrane checks this against the system of record and suppresses the claim if it disagrees, but the attempted write is recorded, with actor_kind = "agent". When a regulator asks "did any AI decision touch this account," the query is ?target=acct_042&actor_kind=agent.
actor_kind = "service")emit(
code="PAYMENT_CAPTURED",
target="pay_01H9F2K7ZZ",
actor="payments-processor",
actor_kind="service",
detail={"amount_cents": 1299, "currency": "USD"},
)
A backend service captured a payment. No human in the loop; no AI in the loop. Ordinary automated commitment.
actor_kind = "schedule")emit(
code="EOD_RECONCILED",
target="ledger:2026-08-14",
actor="cron:eod-close",
actor_kind="schedule",
detail={"tx_count": 18294, "delta_cents": 0},
)
The end-of-day reconciliation job closed the ledger cleanly. When something drifts, an operator queries ?actor=cron:eod-close for the sequence of scheduled runs.
The alternative is separate tables (or worse, separate products) for user audit, agent audit, service audit, scheduler audit. Compliance teams end up with four query surfaces, four retention policies, four export formats, and no single answer to "who touched entity X in the last 30 days." The union query is the compliance officer's nightmare because it has to be repeated for every question.
One primitive on one substrate collapses all four into a single predicate. The query is one WHERE clause. Cross-actor invariants ("show me every entity where an AI decision preceded a human override within one hour") are one JOIN.
Membrane's source-authority ranking assigns different trust levels by actor_kind:
system_of_record (typically actor_kind = "service" from the authoritative writer): highest authority.user input (e.g. a compliance officer's manual override): high authority, sometimes above system-of-record when the policy says so.agent emissions (LLM inference): low authority by default. A claim from actor_kind = "agent" that conflicts with the system of record is suppressed and recorded in the suppressed-alternative ledger rather than merged.schedule writes are ordinary automated commitment; treated like service.The OWASP LLM Top 10 · engineer's catalog shows this in the LLM01 (prompt injection) and LLM05 (improper output handling) sections: source-authority + actor_kind is why an injected instruction never commits to system state, only to the suppressed ledger.
Model provenance (P2-33) extends actor_kind = "agent" rows with three optional fields: model_id, model_version, prompt_hash. An auditor can then answer "which model version, on which prompt, produced this belief?" without a separate provenance store.
The audit substrate for distributed systems, and the belief layer for the AI agents on top of them.