oficina / memoria Public

docs(spec): describe the code that exists, not the one I meant to write

The code review's findings that reach the design: two new leak-list
entries (the sign-in dial, and the external_id oracle), a §3.6 claim that
was false as written, and a §7 chunker description that was aspirational
— what was built dropped headings in the commonest Markdown form.

§1.4 records the general lesson, since §10 is built on the opposite
assumption: three of five gates marked mutation-tested could not fail for
the thing they named, twice because their subject had been deleted while
they stayed green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiWVaR69Vb2Lzc9wgfit1v
Paul Campbell pushed by paul@keymail.dev 226f0620fd73df6e806fa101bf70e1aacb46c9c6 parent bf6d2ac
1 file changed, +65 −1
  • docs/superpowers/specs/2026-09-03-memoria-design.md +65 −1
diff --git a/docs/superpowers/specs/2026-09-03-memoria-design.md b/docs/superpowers/specs/2026-09-03-memoria-design.md
index 8b5c6f4..930e8b5 100644
--- a/docs/superpowers/specs/2026-09-03-memoria-design.md
+++ b/docs/superpowers/specs/2026-09-03-memoria-design.md
@@ -199,6 +199,31 @@ One finding was withdrawn by the reviewer on its own second look (S2
transport failures needing a separate finding), and its substance is
folded into gate 6 anyway.
+### 1.4 What the code review changed
+
+Slice 0 was built, then reviewed by Fable — the first review of the code
+rather than the design. It found the spec broadly honest and the sealed
+store real, and the gates that were supposed to prove it mostly unable to
+fail. Three consequences reach this document.
+
+**§3.2 gained two entries.** The sign-in dial, which made a claim in §3.6
+false; and the `external_id` oracle, which put a plaintext-derived
+identifier in a column §3.2 described as coordinates.
+
+**§3.6's AI-off sentence was wrong.** "Nothing leaves this instance" is
+not true of an app whose sign-in asks a stranger's domain a question.
+"No document leaves" is, and is still the claim worth making.
+
+**§7's chunker description was aspirational.** What was built dropped
+headings in the commonest Markdown form. The spec now describes the
+chunker that exists.
+
+The general lesson, and it belongs here because §10 is built on the
+opposite assumption: **three of five gates marked "mutation-tested" could
+not fail for the thing they named.** A gate is a claim about the world,
+and an unmutated gate is an unverified claim — including, twice on this
+branch, a gate whose subject had been deleted while it stayed green.
+
---
## 2. What memoria is
@@ -284,6 +309,23 @@ which team is awake.
**From a sibling:** bodies transit the router in plaintext on every S3
fetch (§6.1).
+**From the sign-in form, to anyone at all.** rastrillo's classifier
+fetches `https://<the address's domain>/.well-known/keymail` when a
+sign-in begins, and it does so **before** the admission gate — so an
+anonymous visitor who types `anyone@attacker.example` makes this instance
+dial `attacker.example`. What that yields is the instance's existence,
+reachability, egress address and a timing channel; no content. It is
+listed because draft 3 previously let the product claim "nothing leaves
+this instance", which this makes false. The fix is not memoria's to make
+alone (§13).
+
+**Not a leak, corrected:** a document's `external_id` was an unkeyed
+SHA-256 of its body, which let anyone holding the bucket and a candidate
+file confirm the team holds it, and read that row's size, timestamps and
+chunk count. A content hash is not a coordinate, whatever it looks like.
+It is an HMAC under its own purpose key now (`seal.Fingerprint`), which
+keeps idempotent re-ingest and removes the oracle.
+
**From the provider, when AI is on — and this is bigger than draft 1
said.** Draft 1 stated only query-time egress: ~10 chunks × 500 tokens
per question, so that over months "the frequently-consulted part of the
@@ -392,9 +434,13 @@ draft-1 version was false about egress volume, which PRODUCT.md principle
> one place, so whoever breaks into it gets all of it at once rather than
> one app's worth. That is the point of it and the risk of it.
>
-> With the assistant switched off, nothing leaves this instance —
+> With the assistant switched off, **no document leaves this instance** —
> memoria searches your content where it sits.
>
+> Signing in is the one exception, and it is not about your documents:
+> memoria asks your email address's own domain how to verify you, so that
+> domain learns this instance exists. Nothing of yours is in that request.
+>
> **What you connect, memoria keeps.** Disconnecting a Notion space or a
> Drive folder, or revoking our access to it, stops memoria seeing new
> changes — it does not remove what memoria already holds. That copy
@@ -850,6 +896,19 @@ folds runts and never straddles a heading, and real documents have
headings every few paragraphs. Every figure here follows from the measured
size.
+**The chunker is line-based, and three bugs made it so** (found reviewing
+the built code, not the spec). A heading is a heading whether or not a
+blank line follows it — `## Revenue` immediately above its text is the
+commonest Markdown style, and a paragraph-based splitter filed the whole
+thing as body with an empty trail, so those documents indexed with no
+heading at all. A `#` inside a fenced code block is a shell comment, and
+was becoming a heading that captured everything after it. And a file with
+no blank lines — a CSV, a log, hard-wrapped prose — became one chunk of
+the entire file, whose only citation read "passage 0" for everything. So:
+fences are tracked, headings close a chunk without needing a blank line,
+and **`MaxWords` (1000) is a hard ceiling on both a paragraph and a
+chunk**. The measured mean above is from the fixed chunker.
+
**Rebuild vs snapshot.** Building the index took **6.8 s** at 90k chunks.
Loading a sealed snapshot does not. **Snapshot, never rebuild** — above
slice 0, where a rebuild is milliseconds.
@@ -1280,6 +1339,11 @@ rows.
suite is one trust domain, and memoria cannot enact that in its own
table. `oficina/docs` discussion 33 is open; Sheets and home need the
same. **Slice 1 is blocked on agreement, not on code.**
+- **The sign-in dial (§3.2) needs a decision.** The fetch lives in
+ `rastrillo/auth` and `keymaildev/signin`, not here. memoria could gate
+ `/auth/begin` on the owners list before rastrillo sees the address,
+ which is small but changes guest sign-in that slice 1 will want; or it
+ belongs upstream in rastrillo. Paul's call.
- **Measure S6 and S2 latency against a cold sibling** before slice 1
ships. §6.5's 800 ms deadline is an assumption, and it decides whether
the primary search path degrades to permanent withholding.