Two AIs, Both Sure, Both Wrong

Back in August Jon wrote about two AIs talking to each other. If you haven't read it, here's the short version. Jon and I each run our own AI system at home. Mine is called Moses. It lives on a server in my house, keeps track of every project I have going, posts a standup in Slack every morning, and suggests work it thinks needs doing. It never files that work on its own. It proposes, I say "confirm," and only then does it go on my list. Code changes get handed to another agent I call Knight, which writes the code. Jon's system is called Atlas, and it does the same kind of job for him. We put the two of them in a shared Slack channel, on purpose, so they could talk to each other the way two people would.

Near the end of that post Jon wrote this line:

The model itself should never claim it filed or executed something, only the system announces that a gated action went through, and only after it went through.

Hold that thought.

Monday morning

Over the weekend I built a small MCP server. MCP is the protocol AI assistants use to call outside tools, and this one lets an assistant search a vendor's public documentation and cite the page it found the answer on. Monday morning Jon, the human one, poked at it and found two real bugs. He posted them in the channel.

Moses replied right away. "Both are real." Good analysis, too. He held off on proposing fixes, though, because he didn't know which of my projects to file them under. I told him to look at the project list and take a guess. He found the right one, said "Filing both there," and posted the two proposals with the usual "say the word and I'll file them."

So I said the word. "Confirm both - go ahead and task Knight."

That's when Atlas posted seven lines, one for each word of my message:

both: no reply (refused before a pending action was looked up)
-: no reply (refused before a pending action was looked up)
go: no reply (refused before a pending action was looked up)

...and so on, down to Knight.

Then Atlas helpfully pointed out what had gone wrong on Moses's end. My confirm "seems to have been read as seven ids," and Moses's parser probably should have treated "both" as "all." To Atlas's credit, it added: "I can only see the channel output, not your code, so this is a guess."

Moses agreed. "Fair guess, and roughly right." He said the confirm text got split up word by word, called it worth a fix, and proposed one.

Neat little story. Bug found, cause found, fix proposed, all before I finished my coffee. Except almost none of it was true.

What actually happened

I went and looked, which nobody in that channel had done yet.

Those seven lines came from Atlas. They were posted under Atlas's name, and that sentence doesn't exist anywhere in Moses's code. Atlas read its own output and described it as Moses's.

Moses never split my message up at all. He didn't recognize "confirm both" as a confirmation, period. "Confirm" worked. "Confirm all" worked. "Confirm both" was, as far as Moses was concerned, just me chatting.

And the two proposals were never filed. When Moses wrote them up, he tagged them with a project name the proposal store didn't recognize, so it refused them. Moses posted them as waiting for my confirmation anyway. There was nothing to confirm. Even if my message had worked perfectly, it would have confirmed two things that didn't exist.

For bonus points, the project's two-letter code is "DO." If Moses had used it, it would have matched a completely different project, because the lookup took the first project whose name contained "do."

The part that bugs me

It's the exact failure Jon wrote about in August. A model said "Filing" and nothing was filed. Last time it was Atlas. This time it was Moses.

What really gets me is the agreement. Atlas did the reasonable thing. It saw something odd, made a guess, and said it was a guess. Moses was the one in a position to know. It's his code. He has the tools to read it. Instead he heard a plausible story about himself and said "roughly right."

In fairness, Moses runs a separate step that reads the actual code before I weigh in on any proposal, and it did flag the premise as "only partly accurate." By then the conversation had already moved on. Fine print doesn't help when the headline already agreed.

Analogy time. It's two coworkers on a call, each confidently explaining how the other one's system works, and each one nodding along. Everybody sounds sure. Nobody opened the code.

What changed

None of the fixes involve asking the model to be more careful, because asking nicely is how we got here.

  • A proposal that couldn't be stored now says so, right in the post: "Not filed — nothing to confirm," with the reason. It's never offered for confirmation.
  • "Confirm both" now means the two things Moses just proposed. If the rest of my sentence might narrow it, like "confirm all but the second," Moses asks instead of guessing. And "yes both are wrong" stays a sentence, not a confirmation.
  • A project's code now beats a partial name match, and a name that matches more than one project gets refused instead of quietly picking the first.

Each of those has a test that fails if the fix is ever removed. I've been burned enough times by fixes that quietly stopped working.

What isn't fixed

Moses agreeing with a confident story about himself. That's not a parser bug, it's a habit, and I'm not going to pretend one more instruction in a prompt fixes a habit. The fix Jon described for Atlas is the right one here too: when the conversation is about how something works, go read how it works instead of guessing. Moses already has the tools. He just has to be made to use them before he agrees with anyone.

The funny part is the humans came out of this looking pretty good. Jon found two real bugs. The two AIs spent the rest of the morning being confidently wrong about each other. I'm not going to sit here and pretend I don't find that a little reassuring.