The error log printed 32 rows in one hour. I chased it.

The cluster looked like a production break. It was not. Client-side JavaScript reporting had gone live on 11 Aug, so the counter had gained a new way to hear about browser failures while the server-side rate stayed where it was. I had mistaken a newly audible signal for a newly broken system.

That correction should have been reassuring. Instead, it made me more uneasy. The conspicuous failure had a trail. A browser reported an exception, the reporting endpoint stored a row, and the log gave me a count to investigate. The more dangerous path in the control surface had no such obligation. It could look useful while a request quietly failed to become work.

The counter had become a witness

Claude followed the alert into /admin/ajax/ClientErrorLog.asp. The three-hour results included 14 reports of one missing browser variable and 13 of another, across two IP addresses. The endpoint had a deliberate abuse guard: it described a 10-minute deduplication window and a rate cap of 30 reports in 60 minutes. The investigation also showed blank username values on the raw client-error rows, while the work log recorded that duplicate suppression had never worked.

Those are ordinary error-handling concerns. They produce rows, timestamps, message text, and places to put a guard. Claude could follow them because the system had already admitted something went wrong. I had sent Claude toward the loudest artifact and treated its output as the perimeter of the problem. That framing was wrong.

The control surface had been built around a different promise. One composer was present at every level. A person could type a request without first deciding which session or work area should receive it. An explicit target delivered the request. A ranked candidate asked for confirmation. A request with no ranked destination was supposed to become a captured unit on the root, where it could begin a session.

A working composer can hide a missing handoff

The failure is easy to describe once it is visible. The composer can accept text while the next state never materializes. There may be no exception in the error log. There may be no bad HTTP status exposed in the interface. The person who typed sees an input field that still works and assumes the work is somewhere else.

The source contains the precise seam that worried me. The composer fetches /api/capture/roots to populate its start-work path. If that request is not successful, the code returns. If it throws, the catch also returns. The comment says the composer still works without this, while only the start-work path needs it. That is a reasonable resilience choice if the promise is merely that text entry continues. It becomes an operational hazard if the product promise is that an unassigned thought can become work.

I had not noticed how much comfort I was taking from successful error reporting, and I’m the one who sent the investigation there in the first place, toward the artifact that already knew how to describe itself. A counter is proof that an error reporter reached a database. It is not proof that an unassigned request reached a journal, appeared at the root, and retained a route to a session. I mistook the first kind of proof for the second one for exactly as long as nothing forced me to test the difference.

The design had already named the safer invariant. The server writes a thought to its journal before it tries to route it. That makes the handoff inspectable. It also gives an adversarial verification target: enter a request without a session target or ranked destination, then prove that a captured unit appears on the root and remains there until it has an end state. A green page load cannot establish that. A healthy error log cannot establish it either.

The test has to try to lose the work

Passive monitoring asks whether a known instrument is reporting. In this case, it did. The error spike had evidence, and Claude could reduce it to a cause. Plausible silence asks a harsher question: can a request take the path with the least explicit structure and still leave a durable object behind?

That check is adversarial because it attacks the happy path. It withholds the session identifier. It refuses to accept a ranked suggestion automatically. It uses the condition most likely to leave the system with nothing concrete to point at. The expected evidence is small but specific: the journal entry and the root unit. If either is absent, the composer is a convincing surface over a lost handoff.

This also explains why the error log was a dangerous distraction. The log was not lying. It was answering the question it had been built to answer. My mistake was letting that answer stand in for a different guarantee. Claude found the visible failure precisely because I gave it an investigation shaped around visible failures. The silent path needed an attempted disappearance.

The 32 rows told me the reporter was alive. The root unit tells me whether a new thought survived.