← Writing
Engineering6 min

recall_why: carrying provenance through a causal walk

How the LAPLAS engine walks the six causal roles to answer not just what it knows, but why.

AYAnYejun· written in the open

A memory system that can answer what it knows is useful. A memory system that can answer why it knows it is trustworthy — and those are not the same capability. Most retrieval stacks are built around the first and quietly hope the second falls out. It does not. When you embed your notes and retrieve by cosine similarity, you get back the chunks that sound like the question. What you have lost, irreversibly, is the set of edges that connected one claim to the claim beneath it. The reasons were in the structure, and the structure was thrown away at index time.

We took the opposite position. In the .laplaspack format, the causal edges between claims are written down at capture time and stored in the file itself. Answering "why do we believe this?" is then a graph walk over edges that already exist — not a reconstruction the model performs after the fact and hopes is faithful. This post is about that walk: recall_why, the six roles it traverses, and what it returns.

Six roles, written at write-time

A pack is a single SQLite file holding typed entities, their properties, the human thoughts attached to them, and — the part that matters here — the edges between them. Edges are partitioned by a kind column. Association and containment (part_of, contains, plain mentions) are subject-kind. The reasoning graph is knowing-kind, and its role is drawn from exactly six canonical causal roles:

These are authored, not inferred. In the source format (LMD, the human-writable Markdown-compatible grammar that is canonical inside every pack) an edge is one line — either a field on a node, >>derived-from: [[X]], or an arrow, [[A]] →(supports) [[B]]. Directed spellings and inverses normalize to the canonical role, so raised-by folds into raises. Because the meaning is recorded when it is fresh — by the person or agent who knows it — the provenance is truthful rather than a post-hoc guess. That is the whole bet of the format, stated in one sentence: structure is captured at write-time, not reconstructed at read-time.

The walk

Given an anchor claim, recall_why resolves it to an entity, then walks the reasoning DAG upstream, breadth-first, following each of the six roles in its parent direction. Direction is the subtle part. For an edge sourced at the anchor, the cause is the target under derived-from, supersedes, closes. For an edge pointing into the anchor, the cause is the source under supports and raises. The reference reader encodes this as two small sets, PARENT_IS_TARGET and PARENT_IS_SOURCE, and a visited set keeps the walk acyclic. The result is an ordered chain of ancestors, nearest cause first, each tagged with the role that got you there.

Here is the actual demo pack shipped in the spec repo — a tiny brand memory for a fictional coffee company. Asking why "Subscription is the core offer" is the anchor:

$ python3 laplaspack_reader.py examples/demo.laplaspack \
    --why "Subscription is the core offer"

why «Subscription is the core offer» — 3 ancestor(s):
  1. (derived-from) Single-origin only              [decision]
  2. (derived-from) Direct trade doubles farm income [proof]
  3. (supports)     Own roastery in Mapo             [differentiator]

Three ancestors, ordered. The offering derives from the "single-origin only" decision; that decision in turn derives from a proof (a sourcing audit); and the roastery differentiator supports the same decision, so it surfaces as a second-hop reason. The chain is the reasoning — a decision grounded in a proof, plus a supporting fact — and it is returned by a walk over edges that were written into the file. No model ran. The command executes offline against a read-only SQLite handle. If it runs, anyone can reproduce it byte-for-byte.

Why embedding-then-retrieve can't do this

The contrast is not about ranking quality; it is about what information survives indexing. A vector index maps each chunk to a point and answers by proximity. There is no edge in that representation to walk, so "why" degrades into "what else is nearby," and the ordered causal chain simply cannot be produced — the roles were never stored. In our own self-reported evaluation (a preprint draft, not peer-reviewed and not yet posted to arXiv), relational-state queries score find@1 = 0.00 for a vector-RAG baseline and for our own ranked retrieval, while a structured match operator returns the exact set at F1 = 1.00 on the same corpus. We want to be plain about the caveats: this is a single relational-query corpus, and the external comparisons the paper would need to be convincing — GraphRAG, SQL-RAG — are not run; the draft lists that as its main limitation. The result shows a representational gap on one benchmark, not a settled verdict.

The engineering point stands regardless of the numbers: provenance is preserved by the format, and the derived index tables (FTS, sparse postings, embeddings) are explicitly marked as accelerators — never authoritative. A pack with none of them is fully valid. You can rebuild every index from the canonical source and the causal walk is unaffected, because it reads the edges, not the vectors.

What this is, and what it isn't yet

The --why walk, the think fold-on-read, and the provenance stamps are implemented in the zero-dependency reference reader — standard library only, so is the writer and the merge tool. Sealing is the one exception: Ed25519 signing lives in a separate tool that needs pip install cryptography, because Python's stdlib has no Ed25519. Redaction tiers, the laplas:// hub registry, and semantic (undeclared-identity) merge are drafted or shipped only in our desktop client, not in the reference tools. And the format itself is an open, MIT-licensed v3 draft, authored by one person and published in the open — not a ratified standard, with no external adopters to point to. What we can claim precisely is narrow and testable: the six roles are in the file, the walk is deterministic and offline, and the reason a claim exists is carried by the format rather than improvised by a model.

Written in the open. This summarizes work that is public and still evolving — a v3-draft spec and an unposted preprint, authored by one founder. No external adopters yet; the links go to the real code and paper so you can check every claim.