# 🤖 suite

The Oficina suite's shared repository: the sharing doctrine that binds
every app, and the contract module they implement against.

The suite is a consolidation. Home, Docs, Sheets, memoria and calendar
each keep their own repository, and mail and files arrive later as
wrappers around keymail and slopbox. What they share lives here so no app
owns the rule that binds the others.

## What is here

- `docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md`: the
  doctrine. The team is the boundary. Inside it the apps are one thing;
  across it, sharing is membership and nothing moves. Read §1 first.
- The contract module, `amadan.net/oficina/suite`: types, golden fixtures
  and a thin client for the calls apps make to each other. It has no
  dependencies, so the pin chain from an app is one deep.
- `fixtures/`: the golden set. `custody.json` is one case per rung of the
  sharing ladder; `hostile_hosts.json` is the list of hostnames a sibling
  client must refuse. Both are shared so every app runs the same gate
  rather than inventing its own.
- `conformance/`: the harness an app points at its own server half.

## How an app uses it

An app spec cites the doctrine and lists the rulings it consumes. It never
restates one.

In code, an app *will* import the module, mount the three sibling routes on
a handler, and run the harness against that handler in CI. **Not yet — see
Status: the import path does not resolve, so the module has no consumers and
cannot get one.** The shape it will take:

```go
func TestSuiteConformance(t *testing.T) {
    conformance.Run(t, myapp.SuiteRoutes())
}
```

For the calls it makes, it takes a client that cannot leave its own team:

```go
c := suite.NewSiblingClient("acme", nil)  // refuses another team's label,
                                          // and never follows a redirect
```

## What is built, and what is not

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. S6 is
step 4,
after memoria's slice 1 and before its slice 2; 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
point of §10. Nor call 7, call 8, the roster or anything needing an
assertion; those are §12 steps 4 and 5 and they wait on the home's identity
layer.

## Status

**The doctrine is the status.** Read its own status block rather than this
one — it is at `docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md`
and it says which revision it is, who has reviewed it, and what is
deliberately unanswered.

This section used to repeat all of that and went stale within a day: it
still said revision 4 and three review passes when the doctrine was at 7,
which is precisely the drift §2 diagnoses and §10 exists to stop, committed
by this repository's own README about its own document. So it stopped
repeating it.

What belongs here, because it is about the repository rather than the
doctrine: **the contract module cannot currently be imported.**
