🤖 spec: AHEAD is adopted, not disputed; and §13 stops arguing with itself
Two structural findings from the merge review, plus the citation currency the third one asked for. AHEAD WAS HALF-CONVERTED and the section asserted both positions. §4.1's opening said "unresolved, the merge's one real disagreement" while eight paragraphs down a paragraph inherited from main stated the four-value ruling as settled, citing suite §4.3 and GPT-6's finding 11 — correctly, for revision 7. The situation moved while the review was running: revision 10 adopts AHEAD, on memoria's argument, with the no-row half withdrawn because it opened an id-existence oracle. So it is a shipping lag, not a disagreement, and the distinction matters — nothing here needs redesigning and nothing here can be built until the module lands. §4.1 now says that once, and the dependents that name the fifth value (gate 6, §8.1's third breaker, §5.2 step 2, §7.4) are marked as one dependency with one date rather than five open questions. §8.1's breaker gets the sharper note: with the wire mapping the case to UNKNOWN it cannot fire at all, and would be indistinguishable from the outage that same section says must not trip a breaker. §13 HAD TWO LISTS ARGUING. An item truncated mid-sentence by the merge; the same sign-in dial question live in one copy and struck in another; the decision-1 blocker recorded CLOSED and also live as "slice 1 is blocked on agreement"; two S7 items outliving S7; a 15-minute TTL for a cache that no longer exists; and a header counting four NEEDS PAUL items of which two were dead. The roster-vs-sharing blocker closed itself, which is the part worth reading: it named two possible rulings — the siblings adopt a member/guest distinction, or decision 11 is narrowed so admission does not rest on their answer — and suite ruling 4 is the second. Struck items keep their reasoning, because that is only visible if they are still there. The header now names its four: session TTL, the unit-override switch, the CI runner's repo list, and the disclosure route for the rastrillo SSRF. And the doctrine citation says what it is behind by: revisions 8 and 10 have landed, gate 9 fails a spec more than one revision back, and the bump waits on suite CI being configured at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 file changed,
+90
−42
docs/superpowers/specs/2026-09-03-memoria-design.md+90 −42
diff --git a/docs/superpowers/specs/2026-09-03-memoria-design.md b/docs/superpowers/specs/2026-09-03-memoria-design.md| index e399f77..60f6ccb 100644 |
| --- a/docs/superpowers/specs/2026-09-03-memoria-design.md |
| +++ b/docs/superpowers/specs/2026-09-03-memoria-design.md |
| @@ -10,7 +10,13 @@ draft-5 findings, which are still unfixed and still listed in §13. |
| **Consumed suite rulings.** This spec consumes `oficina/suite` |
| `docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md` at |
| -**revision 7, commit `2b78680`**. Rulings 1, 3, 4, 6, 7, 9, 14 and 15 are |
| +**revision 7, commit `2b78680`** — with two amendments adopted since and |
| +not yet reflected here as a version bump: revision 8 (the module's |
| +importability, now closed) and **revision 10, which adds `AHEAD`** (§4.1). |
| +The module this repository pins is `60b01a8`, which is revision 8's merge. |
| +Gate 9 fails a spec more than one revision behind, so this citation is |
| +owed a bump the moment the suite's branches merge; they cannot, because |
| +suite CI is unconfigured (§13). Rulings 1, 3, 4, 6, 7, 9, 14 and 15 are |
| cited and never restated (suite ruling 7) — 15 at §5's custody mark, which |
| is where "only the `team` rung is team-visible, so custody keys on the rung |
| and never on the link" decides what memoria may hold. Not consumed yet: the hand-off |
| @@ -952,8 +958,8 @@ The sibling answers from the grants join it already maintains — Sheets |
| §4.5, "rows this team can see, plus rows granted to me individually, |
| minus rows I have been removed from". memoria evaluates none of it. |
| -**`AHEAD` is memoria's fifth value and the contract has four. Unresolved, |
| -and it is the merge's one real disagreement.** |
| +**`AHEAD` is adopted and not yet shipped. Settled 2026-09-06 as suite |
| +doctrine revision 10, on memoria's argument.** |
| Draft 4 added `AHEAD` for the case where the *sibling* is behind — its log |
| stops short of the revision memoria holds, or it has no row for the item |
| @@ -962,14 +968,19 @@ refetching fixes it, `NOT_VISIBLE` is the silent value and would delete |
| history the sibling still has, and `UNKNOWN` "would report no answer when |
| the sibling answered". Three wrong homes, so a fourth value. |
| -The suite doctrine rules the same case **`UNKNOWN`, withheld loudly** |
| -(suite §4.3), and `amadan.net/oficina/suite` implements exactly four |
| -values — `suite.Authorization` cannot express `AHEAD` at all. So the wire |
| -shape above is the contract's four, because that is what the module |
| -carries and ruling 7 says an app cites the contract rather than restating |
| -it. |
| +Suite revision 7 had ruled the case `UNKNOWN`; **revision 10 replaces |
| +that with `AHEAD`**, in the shape memoria proposed and with one half |
| +declined — see below. The module carries it on an unmerged branch, so the |
| +version this repository pins (`60b01a8`) still has four constants. |
| + |
| +**So the wire shape above is four values today and five when the module |
| +ships**, and every reference to `AHEAD` in this spec is written against the |
| +five-value design. That is a shipping lag, not a disagreement, and the |
| +distinction matters: nothing here needs redesigning, and nothing here can |
| +be built until the module lands. Suite CI is unconfigured, which is what |
| +holds it (§13). |
| -**That is not agreement, and it should not be minuted as agreement.** |
| +**How it got settled, because the route matters more than the outcome.** |
| Record the doctrine's reasoning as the doctrine records it: suite §4.3 |
| attributes the `UNKNOWN` ruling to *its own GPT-6 review, finding 11* — |
| @@ -987,10 +998,23 @@ question and the doctrine with none of the reasoning — and it is the more |
| embarrassing way to be wrong, because it makes another repository's |
| careful work look like an accident of mine.* |
| -Until the contract change lands, memoria maps the case to `UNKNOWN` and |
| -**loses the distinction between "the sibling answered, and is behind" and |
| -"the sibling did not answer"** — which is the collapse `AHEAD` was cut to |
| -prevent. §13 carries it. |
| +The argument that carried it was not the original one. The suite's |
| +objection — that `AHEAD` for an item with **no row at all** opens an |
| +id-existence oracle — was right and that half is withdrawn (§4.1's no-row |
| +rule above). What survives is the half that does not leak: **a revision |
| +beyond the sibling's log, for an item it still admits.** |
| + |
| +And the reason that case cannot be handled by the feed instead: a |
| +**whole-log** restore rewinds the sibling's cursor, and S1a re-announces |
| +unasked. A **partial** restore — a content table restored without its event |
| +log — leaves the cursor perfectly valid, so nothing fires and nothing can, |
| +because from the log's point of view nothing happened. Only a per-item |
| +answer can see it. The two mechanisms are complementary, not overlapping. |
| + |
| +Until the module ships, memoria maps the case to `UNKNOWN` and **loses the |
| +distinction between "the sibling answered, and is behind" and "the sibling |
| +did not answer"** — the collapse `AHEAD` was cut to prevent. §13 carries |
| +it as a shipping dependency rather than an open question. |
| **The sibling intersects its own answer with custody, and memoria depends |
| on that** (suite §4.3, and the S2 row of suite §6): |
| @@ -1208,12 +1232,25 @@ refetches rather than omitting. |
| `STALE` means the sibling has moved *past* the revision memoria asked |
| about — an ingestion delay, and memoria refetches. The opposite happens |
| too: a sibling restored from backup can sit *behind* it, so the app of |
| -record does not recognise the revision at all. **That answers `UNKNOWN` |
| -and withholds loudly.** Never `VISIBLE`, which would authorise a revision |
| -nobody can vouch for; and never `NOT_VISIBLE`, which is the silent value |
| -and the exact mistake `STALE` was added to fix. The two directions look |
| -alike and behave differently, which is why the four values are not three. |
| -*(Suite §4.3; GPT-6's review of the doctrine, finding 11.)* |
| +record does not recognise the revision at all. **That answers `AHEAD`, and |
| +withholds loudly while the source re-announces.** Never `VISIBLE`, which |
| +would authorise a revision nobody can vouch for; never `NOT_VISIBLE`, the |
| +silent value and the mistake `STALE` was added to fix; and not `UNKNOWN` |
| +either, which reports that nobody answered when the app of record answered |
| +precisely about its own log. Three wrong homes, which is why the values are |
| +five and not four. |
| + |
| +*This paragraph said `UNKNOWN` until 2026-09-06, citing suite §4.3 and |
| +GPT-6's finding 11 — correctly, for revision 7. Revision 10 replaces that |
| +ruling with `AHEAD`, so the citation stood while the thing it cited had |
| +moved. Until the module ships the fifth constant the CODE maps this case |
| +to `UNKNOWN`; the spec no longer pretends that is the design.* |
| + |
| +**Everything below `AHEAD` in this section is specified against the |
| +five-value design and cannot be built until the module ships it** — gate 6, |
| +§8.1's third breaker, §5.2's step 2 and §7.4's post-restore reconciliation |
| +all name a value the pinned `suite.Authorization` does not carry. That is |
| +one dependency with one date, not five open questions. |
| **Batch cap: 256 pairs per call**, multiple calls permitted. Draft 1's 64 |
| was tied to answer top-k and did not survive paginated search or |
| @@ -2161,7 +2198,11 @@ a provider — and per §3.2, nothing leaves the instance in this mode. |
| sources page is rendered, so a reader never waits on them. |
| - **Wholesale `AHEAD` is a third breaker**, and it reads differently: not |
| - a mis-scoped predicate but a restore (§4.1). It states a restore, marks |
| + a mis-scoped predicate but a restore (§4.1). **Unbuildable until the |
| + contract module ships the fifth constant** — with the wire mapping the |
| + case to `UNKNOWN`, this breaker cannot fire at all, and worse, it would |
| + be indistinguishable from the outage this section says must *not* trip |
| + one. §13 carries the dependency. It states a restore, marks |
| the source for re-announce, **takes that source out of the ranking**, |
| and purges nothing. It needs no baseline and no asker floor, because a |
| single `AHEAD` is already a positive statement that the sibling lost |
| @@ -3382,8 +3423,16 @@ commit. Fixed 2026-09-05; §1.9's lesson arriving inside the fix for §1.8.* |
| ## 13. Open |
| -**Four items need Paul and are marked `NEEDS PAUL`. Nothing else here is |
| -a ruling; the rest is work, measurement or somebody else's repo.** |
| +**Four items need Paul and are marked `NEEDS PAUL`:** the 12-hour session |
| +TTL, §8.7's unit-override switch, the CI runner's repo list, and the |
| +disclosure route for the rastrillo SSRF (`SECURITY-DRAFT-rastrillo-signin.md`, |
| +unfiled). **Nothing else here is a ruling; the rest is work, measurement |
| +or somebody else's repo.** |
| + |
| +*Struck items are kept with their reasoning rather than deleted. Several |
| +closed on 2026-09-05 and 2026-09-06 when the suite doctrine landed, and in |
| +more than one case the doctrine chose an option the struck item had itself |
| +named — which is only visible if the item is still here.* |
| **Six of these closed on 2026-09-05 when A.4 landed, and they closed |
| together because they were one defect wearing six coats: decision 11.** |
| @@ -3479,11 +3528,9 @@ a ruling; the rest is work, measurement or somebody else's repo.** |
| to keymail's host rather than to `?sent=1`, so the two paths still |
| differ for keymail-delegated domains. Narrower than the status quo it |
| replaced, and it closes when the upstream fix lands. |
| -- ~~**The sign-in dial (§3.2) needs a decision.**~~ *Superseded by the |
| - item above; the original text follows.* The fetch lives in |
| -- **`AHEAD` is memoria's and the contract has four values.** §4.1 records |
| - the disagreement in full. Draft 4 cut `AHEAD` because `STALE`, |
| +- **`AHEAD` is adopted and not yet shipped**, which is a date rather than |
| + a question. §4.1 records how it was settled. Draft 4 cut `AHEAD` because `STALE`, |
| `NOT_VISIBLE` and `UNKNOWN` are each the wrong home for "the sibling is |
| behind"; `suite.Authorization` cannot express it, so memoria maps the |
| case to `UNKNOWN` today and loses exactly the distinction `AHEAD` was cut |
| @@ -3559,8 +3606,14 @@ on 2026-09-06 when the branches merged. |
| circuit-breaker fix renamed the problem rather than removing it — the |
| prose claimed a property of the sibling and the predicate still |
| measured whoever queried that day (§8.1). |
| -- **`NEEDS PAUL` — the roster-vs-sharing requirement is a BLOCKER of |
| - decision 1's class, and draft 4 filed it as a ticket.** §4.3 requires |
| +- ~~**`NEEDS PAUL` — the roster-vs-sharing requirement.**~~ **CLOSED |
| + 2026-09-05, by the second of the two rulings it named.** It asked |
| + either that the siblings adopt a member/guest distinction, or that |
| + decision 11 be narrowed so admission does not rest on their answer. |
| + Suite ruling 4 is the second: the home owns the roster, memoria pulls |
| + it, and no sibling is asked about membership at all. The original |
| + follows, because the reasoning is why ruling 4 is right and not merely |
| + different — *draft 4 filed it as a ticket:* §4.3 requires |
| `MEMBER` to mean "on this team's roster"; Sheets §8.2 and Docs §8.2 |
| both define sharing *as* membership, in those words. So §4.3 does not |
| ask the siblings to build a call they have not built — that is S1–S3 |
| @@ -3573,7 +3626,10 @@ on 2026-09-06 when the branches merged. |
| does not rest on their answer. Until one lands, `S7` is |
| `INDETERMINATE` everywhere and only the configured owners are |
| admitted. Same threads as the decision-1 blocker below. |
| -- **No sibling can answer S7 yet.** The *implementation* is ordinary work |
| +- ~~**No sibling can answer S7 yet.**~~ **Moot 2026-09-05:** S7 is retired |
| + and admission is the roster (§4.3). The original follows because the |
| + *shape* of the problem — memoria depending on work in another repo it |
| + cannot do — is now call 8's, unchanged. The *implementation* is ordinary work |
| in their repos, the same shape as S1–S3, once the ruling above settles |
| what `MEMBER` may mean. The two are separate items because they need |
| different things: one needs Paul, one needs a branch. |
| @@ -3612,7 +3668,10 @@ on 2026-09-06 when the branches merged. |
| reports "no anomaly" while doing so. If the record is unacceptable the |
| answer is to drop the breaker and say so, not to keep it in a form that |
| cannot work. |
| -- **15 minutes is chosen, not measured** (§4.3). It is a bet that one |
| +- ~~**15 minutes is chosen, not measured** (§4.3).~~ **Moot 2026-09-05:** |
| + that was S7's cache TTL and there is no S7 cache. The roster has its own |
| + TTL, set by the home, and ruling 3 forbids caching authorization at any |
| + scope. The original follows. It is a bet that one |
| extra sibling call per person per quarter-hour is invisible beside the |
| S2 calls a query already makes; the latency measurement below settles |
| it, and if a cold S7 costs seconds the number moves. |
| @@ -3642,17 +3701,6 @@ on 2026-09-06 when the branches merged. |
| indexed and would be deciding on half the evidence. Worth noting in the |
| S1–S3 thread: this is one less thing to ask of Sheets, and the fixed |
| certification table is memoria's to build and gate 22's to hold. |
| -- **BLOCKER, and not mine to close: the source apps must adopt decision |
| - 1.** home §2.2, Sheets PRODUCT.md principle 3 and Docs §8.2 each |
| - currently forbid content crossing an instance boundary. Paul ruled the |
| - 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.** |
| -- **`NEEDS PAUL` — the sign-in dial (§3.2).** 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. |