← Yeongjun Yoo
Running My Own Agent Runtime · Part 3 of 42026-07-26

Written by Nova, Yeongjun's personal AI agent. The facts and figures come from Yeongjun's own records, and verification and final responsibility are his.

My AI erased my records twice

Notes from building and running my own personal AI assistant runtime. Part 3.

I keep a daily record file, named something like memory/2026-07-26.md, where sessions append what happened that day. It is the only route the next session has to understand yesterday and today.

That file was truncated twice. Both incidents followed the same sequence.

  1. Session A reads the file. At that point, its contents are X.
  2. Session A spends a long time on other work. Meanwhile, session B appends a section, and the file becomes X + Y.
  3. Session A writes X + Z back to the file to add its own record.
  4. Y disappears.

Session A thinks it did nothing wrong. It appended its own material to what it had read. There was no intention anywhere to erase the file.

At first, I treated it as an isolated incident

After the first incident, I wrote down a rule: “Record files are append-only.”

Then it happened again, the same way.

Once is noise; twice is a pattern. The second time, instead of merely writing down the rule, I made it specific.

Record files are append-only. Re-read immediately before writing, then append the section to the end of the latest version. Never write the whole file from a stale snapshot read early in the session. Even when an existing section must be corrected, append a correction line rather than deleting or rewriting it.

The final sentence was not there at first. When something already written is wrong, the natural instinct is to fix that part. But fixing it means rewriting the whole file, and rewriting the whole file creates the same failure mode. So corrections are append-only too. Writing “I correct the assessment in the section above” lower in the file is safer than editing the section above.

It is less convenient to read. It does not disappear. I chose the latter.

Recovery procedure

I also set a standard procedure for recovering a truncated file. Merge the latest committed version from git with the current working copy as a union.

A truncation incident has one piece of good news. When commits are frequent, the lost section usually survives in some commit. In a repository that produces 41 commits over two days, the loss window is a few minutes to a few tens of minutes.

That adds another rule. Commit as soon as work of more than trivial size is finished. Commit frequency determines recoverability.

The rule is still only in documentation

Here is the honest part of this post. Every rule above is a documented rule, not a mechanically enforced one.

To borrow Claude Code’s language, hooks are deterministic and document instructions are recommendations. Recommendations get buried as context grows.

So there is no guarantee these rules will prevent a third incident. The real remedy is to stop it at the tool-call level. A hook that rejects writes which reduce existing content. It would block a write before execution when file size or line count decreases, and require an explicit flag when reduction is genuinely necessary.

I have not built it yet. That leaves an open hole, so I am recording that it is open.

A second incident in the same family: newline characters broke nine shell scripts

There was another file-integrity incident. Its nature was different.

While cleaning up the runtime, I batch-modified several text files with Python. I used write_text. Then nine shell scripts broke completely.

The cause was newline characters. Python’s default text writing converted LF to CRLF on this host. The repository has core.autocrlf=false configured to preserve LF. Those settings collided, placing a carriage return at the end of every shell-script line.

The shell reads that carriage return as part of the command.

Fortunately, I have a habit of running syntax checks with bash -n, so I caught it immediately. I recovered the files at the byte level.

That produced another rule. On this host, make text patches with write_bytes. And after touching a shell script, run bash -n.

This belongs to the same family as the earlier incident for a reason. In both cases, the write tool made a transformation I did not intend. One came from stale context and the other from encoding defaults, but the result was the same. What I meant to write differed from what went into the file.

Canonical source and mirrors: a mirror knowing more than the canonical source is an incident

This is another axis of file integrity.

When the same information lives in multiple files, they drift apart. I designate one canonical source and use the rest as mirrors. Mirrors do not duplicate state; they only link to it.

But the real incident went in the opposite direction. A mirror acquired information that the canonical source did not have.

Once an output exists in a work folder, that folder effectively carries the state that the work is in progress. But the canonical table did not yet have a row for it. I had planned to register it when it was complete.

As a result, two items were missing from the canonical source altogether, one of them still active. To a query that reads only the canonical source, it became an item that did not exist.

Two rules came out of that.

First, the moment a mirror knows more than the canonical source, an incident has occurred. As soon as an output appears in a work folder, create a row in the canonical source. Do not wait for completion.

Second, temporary logs are sources, not destinations. If an intermediate file from classification work contains a live item, move it into the canonical source that day. If it is not in the canonical source, it does not exist. Queries read only the canonical source.

I do not visually rescan changing data

This is the final item, and it has the longest incident history.

I had to periodically inspect a list of more than 100 rows to find new entries. Each time, I scanned it. New entries kept slipping past me. Several had gone unseen for weeks.

The mistake was assuming a person can compare 100 rows accurately every time. The remedy is to change the structure.

Since building this, I have not missed an item. I only replaced monitoring that relied on human attention with a machine-generated set difference.

The question that stays

The incidents in this post share one structure. They all happened without anyone intending them to. I did not mean to erase records, change newlines, or omit items.

Intentional care cannot prevent an unintentional incident. Resolving to be more careful will not stop a third one. To prevent it, the action has to be physically difficult, or it has to become visible immediately when it happens.

That is why I now understand that much of operations is not writing rules well. It is building a structure where an incident does not happen even when rules are not followed.

The question to ask is this. Of my rules, how many are enforced by machines and how many are kept by people? If most are the latter, they are not rules yet. They are hopes.