oficina / sheets Public

Merge branch 'suite-amendment' into main

Consume the suite doctrine, and keep the local rule that was never the problem

Appendix A.3 of the suite sharing doctrine. PRODUCT.md principle 2 and spec
§8.3 move the boundary from the instance to the team (suite ruling 1), so a
same-team memoria may pull team-visible sheets; across a team label nothing
moves. §9.1's copy of the home call contract becomes a citation. AGENTS.md
keeps its same-commit rule. New §9a names S6 as Sheets' alone.

Ruling 12 travelled the other way: link sharing is viewer-or-commenter,
never editor, is now suite ruling 15's read-only half.

Review record: discussion 16. 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. S6 now has §12 step 4, which it did not when this was written.
claude agent, operated by paul@keymail.dev pushed by paul@keymail.dev 4aea8f47153b907e6d8903df174a0b10d502922a parent 8ed3926parent f18adaa
3 files changed, +96 −25
  • AGENTS.md +8 −1
  • PRODUCT.md +6 −3
  • docs/superpowers/specs/2026-08-30-sheets-design.md +82 −21

CI passed — run details

diff --git a/AGENTS.md b/AGENTS.md
index 8d9691d..9d25ff7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,7 +4,14 @@ A CARLOS spreadsheet. One instance per team.
This file is binding. Where it disagrees with a general skill, this file
wins. Where it disagrees with the design spec, the spec wins and this file
-is wrong — fix it in the same commit.
+is wrong — fix it in the same commit. Both files live here, so that is a
+rule this repository can actually keep.
+
+Where the design spec disagrees with the suite sharing doctrine
+(`oficina/suite`), the doctrine wins and **the spec is wrong — fix it by
+citing the ruling, not by restating it**. That cannot be one commit, because
+the doctrine is another repository; a cross-repository request goes through
+`amadan discuss` on the repo whose text must change.
**The design:** `docs/superpowers/specs/2026-08-30-sheets-design.md`. Its
§1 is the settled-decisions table: dated, attributed, with the rejected
diff --git a/PRODUCT.md b/PRODUCT.md
index 1a05d29..a19993d 100644
--- a/PRODUCT.md
+++ b/PRODUCT.md
@@ -44,9 +44,12 @@ confirmed binding by Paul on 2026-09-01:
compromised live host *can* read an open sheet — and the README says
so. **We never claim "we can't read your data."** The UI must never
imply otherwise, in copy, in iconography, or by omission.
-2. **One instance per team.** Sharing is membership: the sheet never
- moves, and an outside person becomes a scoped member of the instance
- that owns it. There is no federation story and there will not be one.
+2. **One instance per team.** Sharing is membership across teams: the
+ sheet never moves, and an outside person becomes a scoped member of the
+ team that owns it. There is no federation story across teams and there
+ will not be one. Within a team, Sheets is one of several apps sharing
+ one trust domain (suite ruling 1), and a same-team sibling may pull
+ team-visible sheets under the suite contract.
3. **No affordance is script-required.** Sign-in, the sheet list, sharing
and membership, settings, version history, comments, import and export
all work scriptless, as does a paginated table view of any sheet with
diff --git a/docs/superpowers/specs/2026-08-30-sheets-design.md b/docs/superpowers/specs/2026-08-30-sheets-design.md
index 5f6d9b7..709e42c 100644
--- a/docs/superpowers/specs/2026-08-30-sheets-design.md
+++ b/docs/superpowers/specs/2026-08-30-sheets-design.md
@@ -453,6 +453,14 @@ Team: owner, member, guest. Per sheet: owner, editor, commenter, viewer. A
guest holds no team-wide rights — they see exactly the sheets granted to
them and learn nothing about the team beyond §9.5's disclosure.
+**Team standing comes from the roster the home holds** (suite §5) in suite
+shape, and from `$SHEETS_OWNERS` and the local member rows in lone shape.
+**Per-sheet roles stay here.** The doctrine deliberately does not unify
+them: a shared role vocabulary designed from three specs at once would fit
+none of them, and it may move to the contract module when two apps have
+shipped the same one (suite §5.6). Sheets has `commenter`; calendar has no
+such role and Docs has none yet, so that moment has not arrived.
+
This is Pegamento's *"sharing is membership"* taken literally: the sheet
never moves, and the outside person becomes a scoped member of the instance
that owns it. There is no federation story and there will not be one.
@@ -460,9 +468,21 @@ that owns it. There is no federation story and there will not be one.
### 8.3 Link sharing
**"Sharing is membership" does not forbid link sharing.** It forbids data
-crossing an instance boundary, and a link does not move data. This sentence
-exists because the rule reads like a prohibition and someone will later
-think it was one. (docs-e6, 2026-08-30.)
+crossing a *team* boundary (suite ruling 2), and a link does not move data —
+whoever holds it reads the sheet here. This sentence exists because the rule
+reads like a prohibition and someone will later think it was one. (docs-e6,
+2026-08-30.)
+
+**A link is not a rung on the sharing ladder** (suite ruling 15). A sheet is
+private, granted to named people, or shared with the team, and only the team
+rung is team-visible — so a sheet that is link-shared but not team-shared is
+one no sibling may hold a copy of. Making a link team-visible would turn
+"whoever I sent this URL to" into "everyone on the team, findable through
+memoria's search", which is a different grant than the one the sharer made.
+
+**Ruling 12 below is now the suite's rule**, adopted verbatim as suite
+ruling 15's read-only half. The doctrine cites it; it stays here as the
+original, and the reason it gives is the reason the suite took it.
Off by default, high-entropy, revocable, **viewer-or-commenter only, never
editor** (ruling 12) — every version row carries an actor, and an anonymous
@@ -491,27 +511,30 @@ The home is a **separate repo and spec** (ruling 10), drafted by this
session with Docs as a declared consumer. This section records only what
Sheets depends on.
-### 9.1 The five-call contract
+### 9.1 The contract, cited rather than restated
+
+**Sheets consumes the home contract as the home spec states it, and the
+suite contract as `oficina/suite` states it.** Neither is copied here.
-1. **Sign-in and session minting** (§8.1 — the home is the identity
- authority, not merely a directory).
-2. **Directory upsert/revoke** — instance→home on grant change, sending the
- **address and the team's sealed display name**; **the home hashes** and
- **returns the person ref**, which we store against our member rows.
- Carries `kind` (member or guest) and a team-scoped revoke.
+This section used to enumerate five calls. It had already caught itself
+drifting once — *"the first draft called this the four-call contract and
+then admitted a fifth in a subsection; an implementer reading the heading
+builds four"* — and the same thing happened again from the other side: the
+home now has six calls, with a seventh and eighth designed, and nothing made
+this copy notice. The note was right about the mechanism and could not fix
+it, because the fix is not to count more carefully. It is to stop keeping a
+second copy (suite §10).
- *Corrected 2026-08-30: this row previously read "carrying
- `HMAC(pepper, …)`", contradicting §9.6 of this same document. An
- implementer reading the contract table would have built instance-side
- hashing — which needs the pepper on every instance, the design §9.6
- rejects.*
-3. **Directory list** for a signed-in person — every team across every
- suite app.
-4. **Provisioning enqueue** (§9.4 — and see the doctrine divergence there).
-5. **Rekey journal pull** (§9.6).
+What is Sheets' own, and stays:
-*(The first draft called this "the four-call contract" and then admitted a
-fifth in a subsection. An implementer reading the heading builds four.)*
+- **The home hashes, and returns the person ref**, which we store against
+ our member rows. An earlier revision of this section said the instance
+ sends `HMAC(pepper, …)`, contradicting §9.6 of this same document; an
+ implementer reading it would have built instance-side hashing, which needs
+ the pepper on every instance.
+- **A directory row never grants team standing** (suite ruling 12), whatever
+ its `kind` says. Membership is the home's own record, written only by an
+ owner.
Instance→home auth follows Pegamento's service contract: per-consumer
bearer token stored hashed, consumer identity is its origin, origins are an
@@ -722,6 +745,44 @@ window.
---
+## 9a. Consumed suite rulings
+
+The suite sharing doctrine (`oficina/suite`) binds this spec. Read against
+**revision 4, commit `210312f`**.
+
+| # | What it settles for Sheets |
+|---|---|
+| 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 sheets. |
+| 2 | Sharing is membership across teams. Nothing crosses a team label. |
+| 3 | Custody and authorization are two rules, and authorization is never cached at any scope. |
+| 5 | Two shapes, one switch. The sibling-token switch is independent of whether a home is present. |
+| 6 | The egress sentence, suite-wide. |
+| 7 | One contract, one module, fixtures as the interface. |
+| 8 | Two credentials. A consumer token proves a same-team sibling; an assertion proves a person. |
+| 9 | A write names its real actor — the rule §8.3's ruling 12 already served. |
+| 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. |
+| 15 | Three rungs and a read-only link. Sheets ruling 12 is the original this adopts. |
+
+Sheets serves **S1, S2, S3 and S6** wherever sibling consumer tokens are in
+its platform config. S6 is Sheets' alone: an enumerated aggregate over cell
+refs, capped, never expression text, so memoria can total a column without
+holding the sheet.
+
+**Not yet consumed:** S8 write-as-self (suite §7.2) needs a designated-area
+grant in the share UI, and the hand-off (suite §7.1) needs a receipt route
+with pending state. Neither is specified here.
+
+**One thing the doctrine took from Sheets rather than the other way round.**
+Ruling 12 — link sharing is viewer-or-commenter, never editor — is now suite
+ruling 15's read-only half, and the reason Sheets gave for it is the reason
+the suite took it: every version row carries an actor, and an anonymous
+editor writes unattributed rows into history. A draft of the doctrine
+proposed an anonymous link editor and had to be corrected against this
+spec.
+
+---
+
## 10. Design system
`day` theme (ruling 7). rastrillo tokens.