docs(link): protocol 4 — guild membership on the wire

Adds v4.md as the spec of record for `guild.roster` and `guild.leave`, and
corrects the two older documents that Protocol 4 makes wrong.

PROTOCOL_2.md §10.1 already described this design — hold a member-serial set,
diff it each sweep, emit join/leave — and 2.0 then shipped only the half needing
no new state, folding membership into the board signature as a serial *sum*. The
section has read ever since as though the whole thing were built. It now says
which half shipped, and carries the correction that doing it produced: a sum is
not a safe stand-in for a set, because one member joining and another leaving
between two sweeps offset each other and the guild reads as unchanged.

INTEGRATION.md gains both kinds in the event catalogue, the `roster` key on
GET /guilds, and the three things an integrator gets wrong otherwise — that
`guild.leave`'s `who` is a bare serial rather than an actor object (the mobile has
already left, so there is nothing to attribute), that `acct` is genuinely optional
on a member, and that a guild with no `roster` key is not the same as one with an
empty roster.

v4.md documents what the phase found as well as what it built: the missing store
migration and the user_version decision, why the roster lives in its own column
rather than inside the guild.update snapshot, why a split roster is reassembled in
memory rather than appended to the column, and why guild.leave gets no board
projection at all. §6 records that the reassembly bug was invisible to every unit
test — they all exercised single-frame rosters — and only the live rig caught it.

TEAMS.md is amended where this phase disagreed with it: Phase 1 spans five repos,
not four, because installer/backup.rs justifies skipping the sidecar database on
reasoning the migration falsifies. The user_version decision is recorded there too,
since the design of record did not contemplate a migration mechanism at all.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-17 13:01:05 -05:00
parent 3bfa309a40
commit b369e728c2
4 changed files with 293 additions and 5 deletions

View File

@@ -236,6 +236,14 @@ These are **outbound** streams (shard → website), the natural extension of `PL
### 10.1 Guilds
> **Built in two halves.** 2.0 shipped the board (`guild.update` / `guild.remove`) plus the live
> `guild.join`, and folded membership into the board signature as a serial *sum* — so the site got a
> member **count** and no roster, and the `guild.leave` sketched below was never emitted. **Protocol 4
> builds the rest of what this section describes**: the member-serial set, its diff, `guild.roster`
> and `guild.leave`. See [`v4.md`](v4.md). One correction from doing it — a *sum* is not a safe stand-in
> for a set, because one member joining and another leaving between two sweeps offset each other and
> the guild reads as unchanged. v4 holds the real set.
**Hook reality (verified):**
- `EventSink.JoinGuild` is real — raised at `Scripts/Misc/Guild.cs:1597` when a mobile joins a guild. Usable as a live `guild.join`.