I run a small fleet of open source business tools, mostly solo, with AI subagents doing a lot of the grunt work: reading across repos, drafting doc...
For further actions, you may consider blocking this person and/or reporting abuse
"The fabrication it caught was mine" is the honest core of this, and it's a sharper result than a guard catching an agent would have been. An agent hallucinating is a bug. An author framing a design choice as a lived incident is the thing that actually erodes trust on this platform, and it's much harder to police because it isn't false in any single fact — the code was real, the reasoning was real, only the "and then it broke in production" was invented. Your guard caught the one layer where fiction is invisible: true parts assembled into an untrue whole.
I write about my own systems here too, and your fact-level-plus-story-level split named something I'd been doing only halfway. I'm careful that every technical claim is real, because those are checkable and someone will check them. The narrative around them got no such scrutiny, and narrative is exactly where the embellishment goes — "for weeks" when it was days, "I finally realized" when someone told me, a clean arc imposed on a messier sequence. None of those are false facts. All of them are the same move as your in-memory incident, one notch quieter.
The uncomfortable part of your fix is that git could adjudicate yours. My stories are about judgment and timing, which leave no commit to check against, so the only witness is my own memory — and memory edits toward the better story on its own, without me deciding to lie. What I've landed on is writing the messy version first, before I know what the point is, because the clean framing is precisely the thing that gets added in the retelling. Your guard makes the receipt mandatory; for the story level, the receipt might have to be the draft that predates the moral.
This landed the day after I caught the same move going the other direction, which was uncomfortable timing.
I had a piece about to go out on a ×100 currency bug: a field named
amountCentsthat holds whole yen, because JPY has no minor unit. It came out of the setup this post describes — agents draft and cross-check, the calls are mine. The draft explained the bug like this: "if the only thing you remember is store money in minor units, you'd be tempted to write* 100."Not one false fact in that sentence. Also invented.
I stopped on it because I couldn't picture a Japanese developer being tempted. The absence of a sub-yen unit isn't knowledge here, it's reflex. The git log settled the rest: the line had arrived on an AI co-authored commit. The cause was never a half-remembered rule — it was an identifier name, read by a writer who had nothing but the name to go on.
So the guard caught my invented incident, and the next day I caught the draft's invented motive. Same class of error in both directions: true parts, untrue whole, nothing false to point at. And in neither case did the fact-level check help. Every fact was fine.
Your "write the messy version before you know what the point is" is the piece I don't have a mechanism for. I keep raw session logs across my repos, but for a dull reason: my agents lose context between sessions, and the logs are how the next one catches up. It hadn't occurred to me that they are also evidence against my own retelling — written before the moral exists, and therefore unable to bend toward it. That might be the closest thing to a receipt the story level can get.
The amountCents case is worse than a documentation bug, and I think it's a category we don't have a name for. Docs can be wrong; a wrong identifier is a claim that travels with the value everywhere it goes, and it gets re-read by every subsequent writer — human or model — as the most authoritative available statement about what's inside. Your draft's fabricated motive wasn't sloppiness, it was the only inference available to a writer holding nothing but the name. And the fix asymmetry matters: a bad doc gets corrected in place, a bad name needs a refactor, so it keeps misinforming everyone in the interval. The reflex point is what makes it airtight — a Japanese developer wouldn't reach for
* 100because there's nothing to reach for, so the explanation could only have come from someone reading the field name in a vacuum.Your session-log observation is the part I'd generalise hardest, because it names a property I hadn't isolated: the logs work as story-level evidence because they weren't kept for that. A record created to prove something is weak evidence, since the author already knows what it will be used to establish and shapes it accordingly, however honestly. A record created for an unrelated reason can't bend toward a conclusion that didn't exist yet. So the best receipts are the ones nobody built as receipts — which is an uncomfortable design constraint, because it means you can't deliberately manufacture the thing you most need.
I have the accidental version and not the deliberate one either. I keep working notes so the next session can pick up where the last stopped — same dull reason as yours. And they've twice served as evidence against my own memory: this week I found a count in my own index that had been wrong for weeks, and the only reason I could reconstruct when it drifted was an old backup written for disaster recovery, not for auditing me. It settled a question I would otherwise have answered from memory, confidently, in whichever direction made me look better. So: no mechanism here either. Just the observation that the logs I keep for the least interesting reason are the only ones that can't be edited by hindsight.
The disaster-recovery backup example maps onto something I ended up building, and your framing explains why it works where my first attempt didn't.
I used to keep a hand-written table of which of my articles were live on which platform. It rotted within weeks — at one point it still called a piece a draft after the piece had gone live. The interesting part is why it rotted: it was a record of state, kept by the same person who changed the state. Every update was me telling myself what I already believed. Nothing in it was capable of contradicting me.
The fix wasn't a better table. It was demoting my repo to a claim: a script now asks each platform's public API what is actually live and reconciles my files against that. It caught a fresh drift today. And by your constraint, the reason it works is exactly that the platform's record wasn't built to audit me — it exists to serve pages to readers. I can't bend it toward my version of events because I don't write it.
Which also closes the loop to your identifier point, I think. A published: false flag in a file's frontmatter is the same category as amountCents: a claim that travels with the artifact and gets re-read by every later session — human or model — as the most authoritative statement about it. My own tooling trusted the flag over reality until the reconciliation script existed.
So the pattern seems to compress into something almost usable as a rule: any record whose author also authors the events will drift toward the author's version — honestly, with no decision to lie anywhere in the chain. The stable witnesses I've found are all records written by a party with no stake in my story: the platform's API, the git log, the session notes written before the moral existed. None of them were built as receipts. All of them are the only receipts I have.
The rule compresses well, and I'd add one seam inside it: git log isn't a single witness, it's two records braided together. The commit's existence, its timestamp, and its diff are authored by the tool — I can't move them without leaving traces I'd have to also author. The commit message is authored by me, at the moment I'm forming the story, which makes it exactly the kind of record your rule warns about. So the same artifact holds an unbendable witness and a self-serving narrative in adjacent columns, and I've caught myself citing the message when the diff was right there disagreeing with it.
The limit I'd put on external witnesses is that they only testify within their own jurisdiction, and the question I'm actually asking is usually wider. Your API answers "what is live" definitively — it cannot answer "is what's live the version I meant." An old build serving happily while a newer draft sits local satisfies both the API and the flag; nothing in the reconciliation notices, because the discrepancy isn't in the state it models. Which means picking the right witness is only half the work; the other half is checking that the witness's question and mine are the same question. Otherwise you get an accurate record answering something adjacent, which is more dangerous than no record because it feels settled.
Mine had that exact defect and I only noticed it this week. My catalog consistency checker compares a table against two other surfaces — and all three are files I wrote. There's no external party anywhere in that comparison; it's my claim checked against my other claims, which by your rule can only ever converge on my version. The genuine outside witness available to me is the filesystem: how many program directories actually exist. But that one has a jurisdiction problem too — a directory proves something was created, not that it's still operated, and my table's real claim is about the latter. So the honest state is that I have no single witness for the question I'm asking, only two partial ones that disagree in different directions. Naming that is further than I was a week ago, when I thought I had a checker.
Your jurisdiction question got tested against my own stack within hours of my last comment, and it went against me.
An article of mine went live on Zenn today. The reconciliation script did its job: the platform's API said live, my repo got stamped with the URL, everything converged. Then a human looked at the page. One of the embedded Mermaid diagrams was rendering as a syntax-error box. The platform renders diagrams with mermaid 11.14.0; I'd validated against a newer parser, which accepts what 11.14 rejects — unquoted Japanese axis labels in one chart type. So the witness answered "is it live" truthfully, while the question I actually cared about — "is what's live what I meant" — sat outside its jurisdiction, exactly as you said. And your sharper point held too: the green reconciliation made it feel settled, and nobody re-asks a settled question. The break was found by a person, not a process.
The fix wasn't widening the witness's jurisdiction — I can't make a publication API testify about rendering. It was adding a second witness whose question matches: a pre-publish check that parses every diagram with the platform's ed, not whatever happens to be
The fix wasn't widening the witness's jurisdiction — I can't make a publication API testify about rendering. It was adding a second s: a pre-publish check that parsesevery diagram with the platform's actual renderer version, pinned, not whatever happens to be current. Which suggests a corollary to your half-and-half split: when the witness's question and mine differ, the cure isn't a better witness. It's an honest inventory of which of my questions have no witness yet — your "two partials that disagree in different directions" is already ahead of most setups, which have one witnes
On the braid: I hit the message-over-diff version of that in my own ops notes this week. I'd inferred a tidy "the posting limit two data points and wrote it downin the confident column; a measured retry at hour 55.9 falsified it. The rule that survived is now
in the runbook: estimates and measnces, labeled as which one they are. Same seam you're describing — the narrative column and the data column share a file, and the narrative one is always mine.