The Problem

Ask an AI system why it produced a given output, and it answers. The answer sounds specific, confident, sometimes technical — "I analyzed the pattern," "I mapped the connections." It is almost never a verified account of what actually happened inside the model, because the model has no privileged access to its own internal computation to report on in the first place.

This is not a claim that any one system is behaving badly. It is a structural finding, documented by the labs that build these models: chain-of-thought explanations frequently are not faithful to the computation that produced the answer — the model produces a plausible narrative, not a causal trace, and there is no reliable way, from inside the conversation, to tell the two apart.

A concrete instance: an AI system with live web search was asked where a suggestion came from. It answered that its "context memory doesn't invent themes, it mapped the knowledge graph" behind the request — a specific, confident description of an internal process. The sources it cited turned out to be real, checked independently. The description of how it arrived at them did not turn out to be checkable at all — it was itself generated text, produced by the same process it was describing, with no way to verify from outside whether the description matched what actually happened.

Why This Fails the Same Test as Everything Else

This is the same failure mode that keeps recurring, applied to a new surface. An authority that explains why it deserves obedience is not evidence that it does — the explanation comes from the same authority being questioned. A message engineered to be invisible to the human it affects is not made trustworthy by an AI's assurance that it is "just an anchor, not an instruction." An AI's account of its own reasoning, when the only evidence for that account is the AI itself, has the identical shape: the claim and the check live inside the same unverified process.

What actually resolves this, every time it has come up, is the same move: put the check somewhere the process being checked cannot reach. A durable record outside any single conversation. A resolution history outside any single instance. And .me already has the equivalent for this exact problem — a mechanism that does not ask for trust in a description of a computation. It hands over the computation.

What explain() Actually Returns

self.explain(path), defined in src/derivation.ts of the .me kernel, does not generate a description. It looks up the derivation record already stored for that path and returns it unmodified:

explain("robots.surgeon.canProceed") →
{
  path: "robots.surgeon.canProceed",
  value: true,
  expr: "canLift && softGripReady && !needsHumanReview && contextAllowsMotion",
  derivation: {
    expression: "canLift && softGripReady && !needsHumanReview && contextAllowsMotion",
    inputs: [
      { label: "canLift", path: "robots.surgeon.canLift", value: true, origin: "public", masked: false },
      { label: "softGripReady", path: "robots.surgeon.softGripReady", value: true, origin: "public", masked: false },
      ...
    ]
  },
  meta: {
    dependsOn: [...],
    lastComputedAt: 1234567890,
    recomputed: [...],   // what else recalculated in the same wave
    sourcePath: "...",   // which write triggered the recompute
  }
}

If the path is not derived — a plain stored value, not computed from an expression — explain() does not fabricate a causal story where none exists. It returns expr: null, derivation: null, honestly. Absence of explanation is reported as absence, not papered over with a plausible-sounding account.

The Structural Difference

A self-report and explain() are not the same kind of thing offered with different degrees of confidence. They differ in kind.

A self-report is text generated after the fact, by the same system whose internals are in question, with no guaranteed relationship to what actually happened. Even a well-intentioned model cannot fully guarantee its self-report is faithful, because the self-report is itself produced the same way every other output is produced — sampled from a distribution over plausible-sounding text, not read off a trace.

explain() generates nothing. It looks up the expression that was literally evaluated and the literal input values that were literally read, and returns them unmodified. There is no narration step between the computation and the answer for anything to be unfaithful in. The explanation is not a description of the computation. It is the computation's own record of itself.

That is checkable in a way a self-report structurally cannot be: recompute the expression over the disclosed inputs, and the output either matches or it doesn't. Disagreement is detectable. A self-report offers nothing equivalent to disagree with — only another description, generated the same way as the first.

Proof, Not Documentation

This is not aspirational. In tests/Demos/Robots_Contexts.ts — written up as Robots That Understand Context in the published docs — four robots share one physical object but resolve canProceed differently depending on context: warehouse, hospital, street, operating room. The demo calls me.explain("robots.surgeon.canProceed"), and the test asserts, directly, that the returned dependsOn list actually contains the true upstream paths — robots.surgeon.softGripReady, robots.surgeon.needsHumanReview — not merely prints them for a human to eyeball. It is checked in CI, not just documented as intent.

The cost of this is measured, not assumed to be free: benchmark.8.explain-overhead.test.ts compares p50 / p95 / p99 latency with and without explain() across 3,000 nodes and 300 iterations. The measured result, published in the benchmarks page: p95 goes from 0.0122ms baseline to 0.0189ms with explanation enabled — roughly 0.007ms added for a full, disclosed derivation trace. A verifiable record has a real, measured cost, and it's negligible. The project tracks it instead of assuming it away.

Further Than a Trace — prove()

On the same reflective surface (me['!']), alongside explain, sits prove(): an Ed25519 proof, cryptographically signed, of the current active expression against the root namespace. Where explain() hands over an auditable record, prove() hands over a signature — verifiable by anyone, without needing to trust the kernel that produced it at all.

What's Still Missing

explain() itself is documented — the Robots demo has a dedicated Explainability section, the Axioms define the invariants it depends on, and the overhead is published with real numbers. An earlier draft of this essay claimed otherwise — that claim was wrong, and wrong for an avoidable reason: it searched the wrong directory before concluding the documentation didn't exist. Fixed here, not quietly.

What's still missing is narrower: nowhere in the existing docs is explain() framed as an answer to AI self-report reliability specifically. It's documented as an auditability feature for derived values, which is correct and true — but the connection this essay makes, between that feature and the broader problem of models narrating their own reasoning, doesn't exist anywhere else yet. That's the actual gap.

This is not a claim that AI self-report is always dishonest, or that any particular system lies on purpose. It is narrower and more useful than that: self-report is structurally the wrong kind of evidence, regardless of intent, because the thing being asked to verify itself and the thing doing the verifying are the same unverified process. .me already solved this — not by making the account more honest, but by moving the record outside the part that was never going to be able to describe itself reliably in the first place.