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
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. |