Merge branch 'suite-amendment' into main
Consume the suite doctrine: cite it, and stop restating it Appendix A.2 of the suite sharing doctrine. The boundary becomes the team rather than the instance (suite ruling 1), the second copy of the home call list becomes a citation, and §11.2's conversion-API rejection stands with its edge named under ruling 6. Closes discussion 33. Review record: discussion 37. Cites doctrine revision 4; revision 7 is current and a citation bump is owed — not a red gate, since gate 9 is not built yet.
1 file changed,
+99
−24
docs/superpowers/specs/2026-08-30-docs-design.md+99 −24
CI passed — run details
diff --git a/docs/superpowers/specs/2026-08-30-docs-design.md b/docs/superpowers/specs/2026-08-30-docs-design.md| index 8b7fce9..28d8d7d 100644 |
| --- a/docs/superpowers/specs/2026-08-30-docs-design.md |
| +++ b/docs/superpowers/specs/2026-08-30-docs-design.md |
| @@ -589,8 +589,23 @@ capability, viewer or commenter, never editor. |
| membership.** A view link mints nothing. The moment somebody comments they |
| sign in, which mints a guest member and produces a directory entry then. |
| -"Sharing is membership" forbids *data crossing the instance boundary*. A link |
| -does not move data, so it forbids nothing here. |
| +"Sharing is membership" forbids *data crossing a team boundary* (suite |
| +ruling 2). A link does not move data — whoever holds it reads the document |
| +here, on this instance — so it forbids nothing here. |
| + |
| +**Within a team, Docs is one of several apps sharing one trust domain** |
| +(suite ruling 1). Same-team siblings may pull team-visible documents under |
| +the suite contract, and Docs serves S1, S2, S3 and S8 wherever sibling |
| +consumer tokens are in its platform config. That switch is independent of |
| +whether a home is present (suite §3): Docs serves a lone memoria with no |
| +home in the picture. |
| + |
| +**Only the team rung is team-visible** (suite ruling 15). A document that is |
| +private, granted to named people, or reachable only by link is never |
| +team-visible, so no sibling may hold a copy of it — and §8.2's existing rule |
| +that a link share is *viewer or commenter, never editor* is the rule suite |
| +ruling 15 adopts suite-wide. It stays here as the original; the doctrine |
| +cites it rather than restating it. |
| --- |
| @@ -601,34 +616,41 @@ written against a superseded draft** and got the contract wrong in two ways |
| that mattered: it said four calls where there are five, and it had the |
| instance computing the directory HMAC when Sheets ruled the opposite. |
| -### 9.1 The five-call contract |
| +### 9.1 The contract, cited rather than restated |
| -1. **Sign-in and session minting** — the home is the identity authority. |
| -2. **Directory upsert/revoke**, carrying the address over the authenticated |
| - channel with `(app, team sqid, host, kind)`, `kind` being member or guest. |
| -3. **Directory list** for a signed-in person. |
| -4. **Provisioning enqueue.** |
| -5. **Rekey journal pull.** |
| +**Docs consumes the home contract as the home spec states it, and the suite |
| +contract as `oficina/suite` states it.** Neither is copied here. |
| -**Instances never hold the pepper.** Call 2 sends the address and *the home |
| -hashes it*. An instance holding the pepper would enable offline dictionary |
| -attacks against the entire suite directory from one compromised team, which |
| -inverts the whole point of instance-per-team. |
| +This section used to list five calls. That list was the drift the suite |
| +doctrine was written to stop: it was correct when written, the home spec now |
| +has six calls, the activity design adds a seventh and the roster an eighth, |
| +and nothing made this copy notice. A reader who trusted it would have |
| +implemented against a contract that no longer existed. |
| -Docs never sends a document title to the home. |
| +Two things that are Docs' own and stay: |
| -### 9.2 Consumed rulings |
| +- **Instances never hold the pepper.** The home hashes the address. An |
| + instance holding the pepper would enable offline dictionary attacks |
| + against the whole suite directory from one compromised team, which |
| + inverts the point of instance-per-team. |
| +- **Docs never sends a document title to the home.** |
| -- **The directory is a hint, never an authority.** A failed upsert never |
| - fails a share; call 2 goes through an outbox, never the request path; every |
| - instance re-checks authorization on every request. The outbox drains on |
| - wake and on share mutation, not on a ticker (§7.3). |
| -- **Split origins.** A credential origin carrying no account-authored string, |
| - and a separate directory origin carrying no credentials. |
| +### 9.2 What Docs does about it |
| + |
| +The rules below belong to the home spec or the suite doctrine and are cited, |
| +not restated. What is written out is the part Docs owes. |
| + |
| +- **The directory is a hint, never an authority** (home ruling 9, suite |
| + ruling 12 — a directory row never grants team standing however its `kind` |
| + reads). Docs' obligation: a failed upsert never fails a share; call 2 goes |
| + through an outbox, never the request path; every instance re-checks |
| + authorization on every request; the outbox drains on wake and on share |
| + mutation, not on a ticker (§7.3). |
| +- **Split origins** (home's). Docs holds no credential origin of its own. |
| - **A guest grant discloses the granting team's name**, and the share dialog |
| - says so in words. |
| -- **Re-keying** is call 5, a cursor-based journal carrying `old_hmac → |
| - new_hmac`. Pepper rotation needs a re-announce sweep, not outbox retry. |
| + says so in words. Docs' own, and it stays here. |
| +- **Re-keying** is the home's journal call. Docs' obligation: pepper |
| + rotation needs a re-announce sweep, not outbox retry. |
| - **The RP rename drill is `LegacyRPID` plus a window**, not a multi-phase |
| invention. The window is still sized by the guest tail — the person who |
| signed in once, months ago, to comment on one document. Docs has far more |
| @@ -930,6 +952,27 @@ Rejected on the record: pandoc (a second runtime, breaks the static binary) |
| and conversion APIs (ships customer documents to a third party, contradicting |
| §2). |
| +**The conversion-API rejection stands, and suite §8 now says where its edge |
| +is.** The suite's egress sentence is one rule for every app: egress that is a |
| +property of the product is forbidden; egress that is per-team opt-in, to one |
| +named recipient, disclosed in the README's first paragraph and on every |
| +artefact it produced, with a working floor when it is off, is admissible |
| +(suite ruling 6). |
| + |
| +**This is a qualification, not a discovery.** §11.2's own reason was that a |
| +conversion API ships customer documents to a third party, and that reason |
| +does not by itself distinguish an opt-in converter with one named provider |
| +from a compulsory one. Suite ruling 6 draws that line; the earlier text did |
| +not, and claiming it always meant to would be reading something into it that |
| +is not there. A per-team, named, disclosed converter with a working floor |
| +would satisfy suite §8 — Docs has not been asked for one and is not adding |
| +one here. |
| + |
| +This closes `oficina/docs` discussion 33, which asked for the boundary to be |
| +recorded rather than the rejection reversed. memoria's model provider is |
| +admissible under the second clause and Docs does not restate that reasoning: |
| +see suite §8. |
| + |
| ### 11.3 Export |
| DOCX as clean OOXML. PDF emitted from the same box tree the screen renders, |
| @@ -1075,6 +1118,38 @@ amendment. Pagination and PDF still do.)* |
| --- |
| +## 14a. Consumed suite rulings |
| + |
| +The suite sharing doctrine (`oficina/suite`) binds this spec. Read against |
| +**revision 4, commit `210312f`**. |
| + |
| +Rulings Docs consumes: |
| + |
| +| # | What it settles for Docs | |
| +|---|---| |
| +| 1 | The team is the boundary. A team's instances across every app are one trust domain, so a same-team memoria may hold team-visible documents. | |
| +| 2 | Sharing is membership across teams. Nothing crosses a team label; a link share moves nothing. | |
| +| 3 | Custody and authorization are two rules, and authorization is never cached at any scope. | |
| +| 5 | Two shapes, one switch. Docs is lone or suite, and the sibling-token switch is independent of it. | |
| +| 6 | The egress sentence. §11.2 cites it rather than restating it. | |
| +| 7 | One contract, one module, fixtures as the interface. Docs imports it, serves its half, and runs the conformance suite in CI. | |
| +| 8 | Two credentials: an assertion proves a person, a consumer token proves a same-team sibling. | |
| +| 9 | A write names its real actor. No sibling ever writes as a person. | |
| +| 12 | Membership is the home's own record. A directory row never grants team standing. | |
| +| 14 | Custody is bounded at acquisition and retired by the feed, not enforced by erasure. | |
| +| 15 | Three rungs and a read-only link. Docs' own "viewer or commenter, never editor" is the rule this adopts suite-wide. | |
| + |
| +Docs does **not** restate any of them. Where this spec previously did — the |
| +five-call contract in §9.1, the instance boundary in §8.2, the egress reason |
| +in §11.2 — the restatement has been replaced by a citation. |
| + |
| +**Not yet consumed**, because they need work this spec has not specified: |
| +the hand-off (suite §7.1), which needs a receipt route, pending state and a |
| +confirmation step on the create endpoint; and S8 write-as-self (suite §7.2), |
| +which needs a designated-area grant in the share UI. |
| + |
| +--- |
| + |
| ## 15. Open |
| 1. ~~**The passkey RP ruling**~~ — **closed 2026-08-30**, confirmed by Paul |