feat(bridge): protocol 6 — first-party clans, one board and five events #6

Merged
whitlocktech merged 1 commits from feat/phase-9-clans into edge 2026-09-23 05:33:29 -05:00
Member

Phase 9 (R5). The bridge reports Rust's own clan system, which the website turns into core's Teams. Spec: docs/rust-link/PROTOCOL.md §12. Design: docs/modules/rust/PLAN.md §24.

What it sends

  • The clans board. Every clan the game will list, with its roster and role ranks, plus enabled, backend, supported, truncated and umodClans. It is re-sent on connect, every 60 s, and about 3 s after any clan hook fires.
  • Five events: clan.created, clan.disbanded, clan.member.added, clan.member.left and clan.member.kicked.
  • A member's LastSeen is never sent, because it is presence (§23).

What the game's assemblies dictated

  • There is no enumerate-all call. The clan leaderboard is the only listing, and the game clamps it to 100. A board at that ceiling says truncated, as does one past 768 KiB (the sidecar drops lines over 1 MiB). The org lead accepted the ceiling (D55).
  • The local backend is synchronous behind ValueTask. A task that has not completed means another backend, such as Nexus. It is refused with a reason, never waited on from the main thread.
  • A clan id is not an identity, so every frame carries createdMs.
  • OnClanMemberAdded hands over a bare id, fired before the game's cache refreshes. The plugin reads the clan back for its identity.
  • uMod Clans raises OnClanDisbanded(string, List<ulong>), the same name and arity as the game's hook. The bridge types it exactly.

overlay.toml moves to protocol 6 and drops Clans from requires_plugins (D47, amending R6): Teams come from the game's own clans, and the plugin splits a server's players across two systems.

Verified

  • checkPlugin: protocol 6, 29 hooks, every one void and listed. The self-tests pass (14).
  • Oxide rig: compiled and loaded. A rig-only helper drove the game's clan backend with synthetic Steam ids, and every clan hook fired (rg.hooks: created 2, added 3, left 1, kicked 1, colour 1, disbanded 1). The board and all five events reached the website end to end.
  • Carbon rig: the byte-identical file compiled and loaded, and the same helper fired every clan hook with the right counts.
  • On both frameworks: raising uMod's two OnClanDisbanded shapes left the bridge's count at the one real disband, with nothing logged.

AI disclosure

Written with Claude Code (Opus 5.5).

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

Phase 9 (R5). The bridge reports Rust's **own** clan system, which the website turns into core's Teams. Spec: `docs/rust-link/PROTOCOL.md` §12. Design: `docs/modules/rust/PLAN.md` §24. ### What it sends * **The `clans` board.** Every clan the game will list, with its roster and role ranks, plus `enabled`, `backend`, `supported`, `truncated` and `umodClans`. It is re-sent on connect, every 60 s, and about 3 s after any clan hook fires. * **Five events:** `clan.created`, `clan.disbanded`, `clan.member.added`, `clan.member.left` and `clan.member.kicked`. * A member's `LastSeen` is never sent, because it is presence (§23). ### What the game's assemblies dictated * **There is no enumerate-all call.** The clan leaderboard is the only listing, and the game **clamps it to 100**. A board at that ceiling says `truncated`, as does one past 768 KiB (the sidecar drops lines over 1 MiB). The org lead accepted the ceiling (D55). * **The local backend is synchronous behind `ValueTask`.** A task that has not completed means another backend, such as Nexus. It is refused with a reason, never waited on from the main thread. * **A clan id is not an identity**, so every frame carries `createdMs`. * **`OnClanMemberAdded` hands over a bare id**, fired before the game's cache refreshes. The plugin reads the clan back for its identity. * **uMod Clans raises `OnClanDisbanded(string, List<ulong>)`**, the same name and arity as the game's hook. The bridge types it exactly. `overlay.toml` moves to protocol 6 and **drops `Clans` from `requires_plugins`** (D47, amending R6): Teams come from the game's own clans, and the plugin splits a server's players across two systems. ### Verified * `checkPlugin`: protocol 6, 29 hooks, every one void and listed. The self-tests pass (14). * **Oxide rig:** compiled and loaded. A rig-only helper drove the game's clan backend with synthetic Steam ids, and every clan hook fired (`rg.hooks`: created 2, added 3, left 1, kicked 1, colour 1, disbanded 1). The board and all five events reached the website end to end. * **Carbon rig:** the byte-identical file compiled and loaded, and the same helper fired every clan hook with the right counts. * **On both frameworks:** raising uMod's two `OnClanDisbanded` shapes left the bridge's count at the one real disband, with nothing logged. ### AI disclosure Written with Claude Code (Opus 5.5). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-09-23 05:29:30 -05:00
feat(bridge): protocol 6 — first-party clans, one board and five events
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 12s
568fc873b3
The `clans` board carries every clan the game will list, with its roster
and roles, plus the facts the website needs to trust it: enabled,
backend, supported, truncated, and whether the optional uMod Clans
plugin is loaded. It is re-sent on connect and on the 60-second cadence,
and a few seconds after any membership change. The five events are
clan.created, clan.disbanded, clan.member.added, clan.member.left and
clan.member.kicked.

What the game's assemblies dictated:
- The game has no enumerate-all call. The clan leaderboard is the only
  listing, and the game clamps it to 100 clans. A board at that ceiling
  says `truncated`, as does one that would not fit in 768 KiB (the
  sidecar drops lines over 1 MiB).
- The local backend is synchronous behind ValueTask. A task that has not
  completed means another backend (Nexus), which is refused with a reason
  rather than waited on from the main thread.
- A clan id is not an identity, so every frame carries createdMs.
- OnClanMemberAdded hands over a bare id before the game's cache
  refreshes, so the clan is read back, with a fallback to the id alone.
- uMod Clans raises OnClanDisbanded(string, List<ulong>), which has the
  same name and arity as the game's hook, so the bridge types it exactly.

A member's LastSeen is never sent: it is presence (PLAN.md §23).
overlay.toml moves to protocol 6 and drops Clans from requires_plugins
(D47): Teams come from the game's own clans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech merged commit 7096e06257 into edge 2026-09-23 05:33:29 -05:00
whitlocktech deleted branch feat/phase-9-clans 2026-09-23 05:33:30 -05:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Rust-Plugins#6
No description provided.