Skip to content
← Posts

Toward an audit log your agent cannot lie to

I built an event-sourced system to SEC guidelines that could reconstruct any account's state at any moment. It is the exact primitive agent memory is missing.

5 min read

The requirement, stated the way a regulator states it, is not complicated. Reconstruct the complete state of any agent's account at any point in time. Not from a backup you hope you kept. By construction. If you cannot replay the events, you do not have the state. You have a guess with a timestamp.

That is what we built at Life Happens. A ground-up rewrite of the agent-facing Laravel SaaS, driven by SEC compliance as client organizations got larger, event-sourced so a complete account could be rebuilt at any moment, designed to those guidelines such that FINRA requirements were covered by construction. The platform connected across hundreds of carriers. New York Life, State Farm, and Nationwide were among the integrations. I am not going to describe the data model. I am not going to name tables, and I am not going to pretend that system is something I can publish. The receipt is the constraint, not the schema.

What the constraint forces is simple and expensive. You stop treating the current row as the truth. The truth is the sequence of things that happened. Current state is a projection you can throw away and rebuild. That costs storage, and it costs discipline, because every shortcut that writes "the answer" without writing "the event" is a hole you will not see until someone asks for last March. I do not have a clean number for that cost. I have the reason we paid it. A reconstruction requirement does not negotiate with your preference for a simpler table.

Most agent memory is the simpler table.

Summaries. Compaction. A rewritten file that replaced the file before it. A vector store that holds whatever the latest embedding pass decided was nearby. Auto-compaction is vendor-authored summarization of your own work. Each of those keeps a latest state. An update can erase the record of how the agent reached it. You cannot audit a decision you cannot replay.

I do not need a hypothetical to know what that looks like in practice. I have an estate of scheduled agents. On August 12, 2026, I audited it.

The scheduler's lastRunAt records an attempt, not a success. Twenty-four tasks. Twenty-two enabled. About 41 invocations a day. Zero of the 24 had an expiry. Five of the 24 named the credentials they use. research-gap-monitor reported healthy for six days while writing no output. The newest report on disk was GAP-REPORT-2026-08-07.md. Every field the inventory exposed said the task was fine. It is the monitor. Its job is noticing staleness in other work. It was stale, and it was watching moto-finder, which had been dead 49 days.

That is what agent memory looks like when you confuse a timestamp with an audit log. The system can tell you that something ran. It cannot tell you what happened, and it cannot reconstruct the state of the estate on August 7 versus August 12 except by me opening directories by hand. A lastRunAt is a current row. It is not an event.

The mapping I want, and do not yet have, is the one the rewrite taught me. Events are the agent's actions. Projections are its beliefs. You keep the actions. You rebuild the beliefs when you need to know what it thought, or what the world looked like, at a time that is no longer current. Replay is what makes a post-mortem possible. It is what makes an eval possible against real history instead of a story. It is what makes blame land somewhere, which sounds punitive until you have tried to debug a system that only remembers the ending.

I have to say the next sentence before the mapping gets too tidy.

Replay is not reproduction when the model is non-deterministic. If I keep every prompt, every tool call, and every output, I can reconstruct what happened. I cannot run the same events forward and expect the same next token. That is a real limit. Event sourcing in a ledger of account changes assumes the events are the facts and the projection is derived. Agent traces are facts about a run. They are not a recipe that will bake the same loaf. Anyone who claims they have "reproducible agents" because they logged the conversation is claiming more than the math allows. What you can claim is reconstructable history. What you cannot claim is that history will happen again.

Storage objections are fair and, in my own estate, unanswered. I do not have a dollar figure for 41 invocations a day. The August audit could not answer what the estate costs. Keeping events is not free. Keeping only the latest state is cheaper right up until you need last Tuesday and the summary already ate it. I am not going to pretend I have the cost model. I have the failure mode.

The other limit is institutional. The Life Happens system existed because a regulator could ask, and because a carrier could ask, and because a member's account is not a demo. I will not imply that work can be open-sourced, and I will not use it as a product teaser. It taught me a primitive. The primitive is: keep what happened, rebuild what is true.

I am still working out what that primitive looks like when the actor is a model. An account event has a type you designed. An agent event is messier. Some of it is a tool call you can name. Some of it is a paragraph the model wrote and then compacted away. I do not yet know the smallest set of events that would let me reconstruct a run well enough to say why a monitor was silent for six days without opening the directory. I know a timestamp will not do it. I am still figuring out the log I would trust when the thing writing to it cannot be trusted to remember, or to tell the truth about what it remembers.

Related: Event sourcing, Comprehension debt, Verification