oficina / memoria Public

🤖 review: the merge review, and the rule about how to review a merge

Fable on the whole branch after the merge: REQUEST CHANGES, 8 MAJOR, 4
MINOR, all applied. §1.11 records it. Every MAJOR was in something the
merge did not open — §1.10's lesson for the fifth time, which is why it is
now a rule in AGENTS.md and not an observation.

The new lesson is about reviewing rather than writing, and it belongs in
AGENTS.md too: REVIEW A MERGE AGAINST BOTH PARENTS, NEVER AGAINST THE
RESULT. This pass found more than the four before it combined, and it found
it by diffing the merge against each side rather than reading what came
out. Reading the output cannot tell you what is missing, and a merge is the
one change whose defects are all absences.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev aecdfb02038181608d25e7ef831c5c4ebe994ba0 parent db7665a
2 files changed, +60 −3
  • AGENTS.md +8 −2
  • docs/superpowers/specs/2026-09-03-memoria-design.md +52 −1
diff --git a/AGENTS.md b/AGENTS.md
index c5cc1f4..0b64747 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -7,7 +7,7 @@ wins. Where it disagrees with the design spec, the spec wins and this file
is wrong — fix it in the same commit.
**The design:** `docs/superpowers/specs/2026-09-03-memoria-design.md`. Its
-§1 is the settled-decisions table, §1.2–§1.10 record what nine independent
+§1 is the settled-decisions table, §1.2–§1.11 record what ten independent
reviews changed. Don't relitigate a settled decision in a drive-by.
---
@@ -144,7 +144,7 @@ so; it never renders as a confident zero.
Every spec and every branch is reviewed by a model that did not write it,
before it is approved or merged, and the reviewing model is recorded.
-**Thirteen passes so far, on two strands that ran in parallel and are
+**Fourteen passes so far, on two strands that ran in parallel and are
counted together here because they are one project.** Spec drafts 1–3 by
GPT Sol and Fable; draft 4 by Fable 5.1; draft 5 by a reviewer **whose
attribution is disputed** — it named itself as the model that wrote the
@@ -174,6 +174,12 @@ When you retire something, grep for it by name — the sections you did not
open are where an adoption commit goes wrong, because a rewritten section
has been read twice and an untouched dependant never.
+**Review a merge against both parents, never against the result.** The
+merge review found more than the four passes before it combined, and it
+found it by diffing the merge against each side rather than reading what
+came out. Reading the output cannot tell you what is missing, and a merge
+is the one change whose defects are all absences (§1.11).
+
**And a reviewer's self-reported model id is not evidence.** Record what
was dispatched and what came back, and record the disagreement when they
differ — twice now they have.
diff --git a/docs/superpowers/specs/2026-09-03-memoria-design.md b/docs/superpowers/specs/2026-09-03-memoria-design.md
index 60f6ccb..5ce68e2 100644
--- a/docs/superpowers/specs/2026-09-03-memoria-design.md
+++ b/docs/superpowers/specs/2026-09-03-memoria-design.md
@@ -38,7 +38,7 @@ draft they reviewed; all drafts were written by Opus.
| 3, §8.4 and decisions 13–14 | Fable | REQUEST CHANGES — 5 MAJOR, 4 MINOR, 1 NIT. All applied. It found §8.4's central argument resting on a misreading of §6.5 and §4.1; §1.8 records what it changed |
| 3, gate 17 + live-key verification | Fable | REQUEST CHANGES — 3 MAJOR, 4 MINOR, 3 NIT. All applied. **It mutation-tested gate 17 itself** and found five idioms the gate blessed, including one that served a declared path outside the session gate; §1.9 records what it changed |
| 3, suite doctrine adoption (A.4) | Fable | **REQUEST CHANGES — 1 BLOCKER, 9 MAJOR, 3 MINOR, 1 NIT.** All applied. The blocker: §4.1 adopted a custody intersection that was not the doctrine's, could not fail, and left the leak it claimed to close. §1.10 records what it changed |
-| slice 1's S2 client, gate 33, gate 21, the merge | — **not yet reviewed** | Owed before this branch merges |
+| slice 1's S2 client, gates 33 and 21, the merge | Fable | **REQUEST CHANGES — 8 MAJOR, 4 MINOR.** All applied. It found a conflict marker committed into `.gitignore` (which `make ci` cannot see), an egress exemption paid by a test that did not exist, "one predicate" untrue of production, `S7` reintroduced by the merge into the sections that retire it, and four green mutations in the sibling client — including a silent value that rendered a count. §1.11 records it |
§1.2 records what the draft-1 reviews changed, §1.3 what the draft-2
review changed, §1.4 what the review of the built code changed, §1.5 what
@@ -610,6 +610,57 @@ claim was unverifiable *as written*, and §13 now says which ref the hashes
are on and how they were checked. A citation that only resolves for
whoever wrote it is not a citation.
+### 1.11 What the merge review changed
+
+The branch merged eighteen commits of `main` — the Notion connector,
+multi-file drop, draft 5 — and was then reviewed as a whole. REQUEST
+CHANGES, eight MAJOR. **Every one of them was in something the merge did
+not open**, which is §1.10's lesson arriving for the fifth time and the
+reason it is now a rule in AGENTS.md rather than an observation.
+
+**Three were guards that could not have worked.**
+
+`.gitignore` was committed **with conflict markers in it**, and `make ci`
+was green throughout, because git parses the marker lines as harmless
+patterns. A broken file that no gate in this repository can read.
+
+The egress gate's sibling exemption cited
+`sibling.TestClientRefusesHostsOutsideTheTeam` as the runtime guard paying
+for it. There was no such test. Every test in the package built its own
+`&http.Client{}`, so nothing exercised `suite.NewSiblingClient` and a
+constructor returning a client with no team check and no redirect refusal
+would have stayed green. AGENTS.md's second named failure — a gate naming a
+test that is not there — inside the comment claiming the payment.
+
+And "one predicate" was not true of production: `main.go` passed
+`Admits(cfg.Owners)` to `NewAuth` and separately called
+`SetOwners(cfg.Owners)`, two closures over two copies of one rule, while
+`handlers.go` asserted there was "no second value to disagree with". The
+fix is not a gate: `Admits` is deleted and `app.Admit` is a method on the
+one list, so there is nothing to build twice.
+
+**Four more were mutations the author had not thought of**, found in the
+sibling client after five author-chosen ones had all gone red. The worst
+rendered a *count* for `NOT_VISIBLE` — the one value that must be silent —
+telling a reader how many things they may not see. The most instructive
+bounded the deadline against itself, so `Deadline = 30s` passed and a page
+could hang for half a minute with the suite green. **A test that measures a
+constant against itself measures nothing.**
+
+**And the rest were the merge's own seams.** `S7` came back into §4.3 and
+decision 11 from a branch written before ruling 4. §2 contradicted itself
+four lines apart. §13 carried two lists arguing — an item truncated
+mid-sentence, the same question live in one copy and struck in another, a
+header counting four items of which two were dead. Twelve gate citations
+pointed at the wrong gates after the renumbering, one sentence naming the
+same gate under two numbers.
+
+**The lesson that is new**, and it is about reviewing rather than writing:
+this pass found more than the four before it combined, and it found it by
+comparing the merge against *both parents* rather than reading the result.
+A merge is the one change where reading the output cannot tell you what is
+missing.
+
---
## 2. What memoria is