oficina / suite Public

Merge branch 'worktree-s6-schedule' into main

claude agent, operated by paul@keymail.dev pushed by paul@keymail.dev 7876689c4ba56fb75ea667051071d88d3c8884a9 parent 47ae0e8parent 6fd72e1
2 files changed, +40 −10
  • README.md +3 −1
  • docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md +37 −9
diff --git a/README.md b/README.md
index c7bcad6..5d084f7 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,9 @@ c := suite.NewSiblingClient("acme", nil) // refuses another team's label,
Built: S1 the change feed, S2 authorization with its total decoder, S3
content, the typed asker subject, the team-bound client, and gates 1 to 4.
-That is the doctrine's §12 step 2, and it does not wait on the home.
+That is the doctrine's §12 step 2, and it does not wait on the home. S6 is
+step 3, with Sheets serving and memoria calling; it is specified and has no
+fixture yet.
Not built, deliberately: the server half — that arrives with the first app
that serves one, and the fixtures get corrected by the second, which is the
diff --git a/docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md b/docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md
index 440ad3f..9bcad6a 100644
--- a/docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md
+++ b/docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md
@@ -3,7 +3,16 @@
How the apps of the suite share identity, membership and content with
each other, and where the line is that nothing crosses.
-**Status:** design, **revision 5**, 2026-09-05.
+**Status:** design, **revision 6**, 2026-09-05.
+
+**Revision 6 schedules S6, which had a number and no builder.** It is in §6's
+contract table and A.4 tells memoria to cite it, and no step of §12 ever
+built it — so it read as settled because it had a number. That is the hole
+§6's S4/S5 paragraph exists to prevent, with the difference that S4 and S5
+were resolved away deliberately and said so, while S6 was live and merely
+unscheduled. Caught by the `oficina/home` activity-pull session while
+answering a memoria status check, before memoria adopted A.4 against a
+fixture nobody was going to write.
**Why 5 and not 4, which is this document breaking its own gate 9.** Two
commits after revision 4 changed rules while leaving the number alone:
@@ -663,6 +672,14 @@ spec, which owns them, and are cited here for completeness of direction.
was no roster of record; call 8 is that record. A lone instance never
needed it. memoria decision 11 is superseded (Appendix A.4).
+**S6 is a call, and until step 3 it is a specification without a fixture.**
+Ruling 7 says fixtures are the interface, so a call with no fixture has no
+interface — it has a description. §12 step 3 builds it, beside memoria
+slice 1, because Sheets is its only server and memoria its only caller,
+and neither is useful to it alone. Until then a consumer cites S6's
+specification here and not a golden fixture, and A.4 says so rather than
+implying one exists.
+
**S4 and S5 are not calls, and no number is reserved for them.** memoria
§6.1 resolved S4, the tombstone, into a feed row — `gone` covers deletion
and departure from team-visibility indistinguishably — and S5, consumer
@@ -1125,16 +1142,23 @@ that cannot be written as stated is a spec bug.
2. **The contract module**, types and fixtures only: S1, S2, S3, the
hostile-hostname fixture, gates 1 to 4. No server half yet. Docs moves
its module path.
-3. **memoria slice 1 against the module**, with Sheets and Docs serving
+3. **S6, with the same pair.** Sheets serves it, memoria calls it, and it
+ ships with slice 1 rather than after it: an enumerated aggregate over
+ cell refs, capped at 64, never expression text, with the typed asker and
+ the custody intersection S2 carries. It is listed separately from the
+ line below because revision 5 left it in the contract table and in A.4
+ with no step at all, and a call that is numbered but unscheduled is
+ indistinguishable from one that is finished.
+4. **memoria slice 1 against the module**, with Sheets and Docs serving
S1 to S3. The second adoption corrects the fixtures.
-4. **The home's identity layer** (home §13 step 4) and, on top of it,
+5. **The home's identity layer** (home §13 step 4) and, on top of it,
call 8 and the roster (§5). Gates 5 and 8.
-5. **Call 7**, the activity pull, once the home can mint assertions
+6. **Call 7**, the activity pull, once the home can mint assertions
(home §13 step 10).
-6. **The hand-off** from memoria to Docs. Gate 7.
-7. **S8** and the designation UI in one receiving app. Gate 6.
+7. **The hand-off** from memoria to Docs. Gate 7.
+8. **S8** and the designation UI in one receiving app. Gate 6.
-Steps 2 and 3 do not wait for the home. That is deliberate: the sibling
+Steps 2 to 4 do not wait for the home. That is deliberate: the sibling
contract has no home in the loop and its tokens are a separate switch
(§3), so memoria can ship against Sheets and Docs in lone shape with
sibling tokens and an owners list, and the roster arrives later as a
@@ -1368,7 +1392,11 @@ and the S1 visibility flag, reopened on S2. *(Review pass, 2026-09-05.)*
"at least one sibling says MEMBER" rule, which is what made a guest a
member.
-§6: move the S1 to S6 definitions to the contract module and cite them.
+§6: move the S1 to S6 definitions to the contract module and cite them —
+**with S6 cited as a specification rather than a fixture until §12 step 3
+builds it.** The module on `main` is S1, S2 and S3; there is no S6 fixture
+to conform to, and memoria's §8.7 numeric path would otherwise cite one that
+does not exist. Adopt the rest of A.4 without waiting for it.
Replace §6.4's *"Any write"* with *"Any write except suite §7: a
person's own hand-off, and S8 as memoria itself into its designated
area."*
@@ -1406,7 +1434,7 @@ own uploads. *(GPT-6 review, finding 3.)*
§11: memoria's person-ref and home dependency on slice 1 survives A.4 as
written. Slice 1 runs in lone shape against sibling tokens (suite §3, §12
-step 3), so the dependency is on the typed asker subject, not on the
+step 4), so the dependency is on the typed asker subject, not on the
home. Correct it, or slice 1 stays blocked on something that is not
actually in its way.