oficina / docs Public

Consume the suite doctrine: cite it, and stop restating it

Appendix A.2 of the suite sharing doctrine (oficina/suite, revision 4,
commit 210312f). Four sections change, and one is added.

§8.2 said "Sharing is membership" forbids data crossing the *instance*
boundary. The boundary is the team (suite ruling 1): a team's instances
across every app are one trust domain, so a same-team memoria may hold
team-visible documents under the suite contract, and Docs serves S1, S2, S3
and S8 wherever sibling consumer tokens are configured. That switch does not
depend on a home being present, so the wording is "wherever tokens are
configured" rather than "in suite shape" — Docs has to serve a lone memoria
before any home exists.

§9.1 listed five home calls. That list is the exact drift the doctrine was
written to stop: correct when written, and now wrong, because the home spec
has six calls with a seventh and eighth designed, and nothing made this copy
notice. Deleted in favour of a citation. The two things in it that are Docs'
own — the home hashes the address, and Docs never sends a title — stay.

§9.2 kept everything that is Docs' obligation and cited the rules those
obligations serve. The GPT-6 review of the doctrine warned about exactly
this: replacing a whole section with a citation loses locally-owned
behaviour along with the copies. The outbox mechanics, the guest tail, the
share dialog's disclosure and the full-host RP ID are all still here.

§11.2's conversion-API rejection stands, and now says where its edge is.
This is written as a qualification under suite ruling 6, not as 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 separate an opt-in converter
with one named provider from a compulsory one. Ruling 6 draws that line and
the earlier text did not. Claiming it always meant to would be reading
something in that is not there.

That closes discussion 33, which asked for the boundary to be recorded
rather than the rejection reversed.

New §14a names every ruling Docs consumes, with the doctrine's commit and
revision so the currency gate can check both, and says plainly which two are
not consumed yet: the hand-off needs a receipt route, pending state and a
confirmation step on the create endpoint, and S8 needs a designated-area
grant in the share UI.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev fad41bdc80121776a9697d247575f7f34e618988 parent f6cf5c2
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