Protocol 2 gave the guild board a member *count* and nothing else, so the Guilds page could say a guild had 155 members but never who they were, and findGuildForActor deliberately answered only for leaders because membership for rank-and-file was not in the feed at all. Protocol 4 puts it there. `shard_guild_members` holds one row per member per guild, keyed on (guild_id, serial). `guild.roster` replaces a guild's rows; `guild.leave` removes one. A guild.remove now clears the membership too, so a disbanded guild does not leave orphaned rows behind. The chunking needs explaining. A roster over the shard's per-frame cap arrives as several frames carrying seq/more/total. The sidecar reassembles them for its own GET /guilds board, but the live WebSocket feed and the /history backfill both carry the individual frames — so this ingest sees them unreassembled. It copes without buffering, because a table expresses what the sidecar's single JSON column could not: the frame carrying seq 0 clears the guild first, and every frame then upserts its own rows. Upsert rather than insert because the /history backfill replays stored frames on every reconnect, and a redelivery has to be a no-op rather than a duplicate-key error. The cost is a sub-second window during a multi-frame update where the table holds part of a roster; buffering to close it would duplicate the sidecar's reassembly for a projection that is already only as fresh as a 60s sweep. On visibility: both kinds are mapped to the existing `guilds` feature. Without that mapping rule 2 fails an unmapped kind closed to admin-only, which would have quietly kept rosters off the public page forever. Mapping them is safe because a roster is the first frame carrying locked fields inside an ARRAY of actors rather than one nested actor, and the projection walker already recurses into arrays and matches acct/webId by suffix — so a member's account name is stripped below admin by exactly the rule that already strips guild.leader.acct. There is a test for that specifically, because the difference is a public page listing character names versus one publishing 150 account names. `acct`/`web_id` are still stored, since that is what lets a linked member be matched to a site user; they are just never projected below admin. guild.leave is appended to the event log, as the departure counterpart to guild.join and for the same reason — it is what a "so-and-so left" feed reads. guild.roster stays out: it is board state like guild.update, and it is the one fat frame on the wire, so logging it would put a full membership snapshot into shard_events on every membership change. The PUBLIC_KINDS guard test caught the addition, which is what it is for; its expected set now carries a v4 group alongside the v3 one. Refs: docs/website/TEAMS.md Part 12 Phase 1 Co-Authored-By: Claude <noreply@anthropic.com>
58 lines
2.9 KiB
SQL
58 lines
2.9 KiB
SQL
-- ── module-uo's teardown ──────────────────────────────────────────────────
|
|
--
|
|
-- Destructive, and run ONLY by an explicit admin purge (MODULE_API.md §2.6).
|
|
-- Nothing on the boot path ever executes this file — uninstalling a module
|
|
-- leaves its data alone, and removing the data is a separate decision an
|
|
-- operator has to make on purpose.
|
|
--
|
|
-- It exists because `schema.sql` does. A module that can create tables and
|
|
-- cannot drop them leaves an operator with orphaned data and no supported way
|
|
-- to remove it, which is why core refuses to load a module that declares one
|
|
-- without the other.
|
|
--
|
|
-- **The order is the reverse of creation, and that is load-bearing**: two of
|
|
-- these tables carry a foreign key into core's `users`, and several reference
|
|
-- each other. Dropping a parent before its children fails on the constraint,
|
|
-- and a purge that fails halfway is worse than one that does not run — it
|
|
-- leaves exactly the orphaned data this file exists to remove. `IF EXISTS` on
|
|
-- every line so a partially-installed module still tears down cleanly.
|
|
--
|
|
-- What is NOT here, deliberately: rows this module wrote into core's tables.
|
|
-- `notification_subs` rows for `shard.*` streams and `announce_job_legs` rows
|
|
-- with leg `towncrier` belong to core's tables, and a module does not delete
|
|
-- from those — core prunes them when it drops the registrations, which it can
|
|
-- do because it knows which registrant owned what. The two `settings` rows
|
|
-- schema.sql seeds (`game_account_signup`, `uo_link_protocol_3_migrated`) are
|
|
-- the same case with an extra reason: the second is a one-shot MIGRATION
|
|
-- marker, and deleting it would re-arm a protocol bump against tables this
|
|
-- file has just dropped.
|
|
|
|
DROP TABLE IF EXISTS `shard_atlas_pending`;
|
|
DROP TABLE IF EXISTS `shard_atlas_meta`;
|
|
DROP TABLE IF EXISTS `shard_cliloc_meta`;
|
|
DROP TABLE IF EXISTS `shard_clilocs`;
|
|
DROP TABLE IF EXISTS `shard_champion_spawns`;
|
|
DROP TABLE IF EXISTS `shard_landmarks`;
|
|
DROP TABLE IF EXISTS `shard_regions`;
|
|
DROP TABLE IF EXISTS `shard_spawn_point_types`;
|
|
DROP TABLE IF EXISTS `shard_spawn_points`;
|
|
DROP TABLE IF EXISTS `shard_spawn_creatures`;
|
|
DROP TABLE IF EXISTS `shard_feature_visibility`;
|
|
DROP TABLE IF EXISTS `shard_vendor_items`;
|
|
DROP TABLE IF EXISTS `shard_vendors`;
|
|
DROP TABLE IF EXISTS `shard_points_boards`;
|
|
DROP TABLE IF EXISTS `shard_ruleset`;
|
|
DROP TABLE IF EXISTS `shard_presence`;
|
|
DROP TABLE IF EXISTS `shard_governor_terms`;
|
|
DROP TABLE IF EXISTS `shard_governors`;
|
|
DROP TABLE IF EXISTS `shard_guild_members`;
|
|
DROP TABLE IF EXISTS `shard_guilds`;
|
|
DROP TABLE IF EXISTS `shard_pages`;
|
|
DROP TABLE IF EXISTS `shard_champs`;
|
|
DROP TABLE IF EXISTS `shard_account_links`;
|
|
DROP TABLE IF EXISTS `shard_houses`;
|
|
DROP TABLE IF EXISTS `shard_economy`;
|
|
DROP TABLE IF EXISTS `shard_online`;
|
|
DROP TABLE IF EXISTS `shard_events`;
|
|
DROP TABLE IF EXISTS `uo_link_config`;
|