docs(teams): Team core, MODULE_API 1.6.0, and what phase 2 disproved #154
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/teams-phase2-team-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Teams Phase 2, docs half. Targets
edge.Pairs with website #151 and Module-uo #9.
MODULE_API.md— 1.6.0The Team surface becomes contract. Additions only, so minor; module-uo's
coreApi: "^1.3.0"still resolves.Per your decision, one 1.6.0 covers all seven additions rather than a minor per phase. The consequence is that the document describes members that do not work yet, so each carries the phase it arrives in, and the two that cannot function —
ctx.teams.activity.push(phase 3) andapi.registerSlashCommands(phase 7) — are documented as present and throwing, with an error naming that phase. Present rather than absent so a module written against the published version fails at registration with an explanation, instead of at whatever moment someone first exercises the feature.registerTeamProvidergets the fullest treatment, because it is the first registration where core calls the module and waits. The envelope, the 10-second budget and the refusal semantics are contract rather than implementation: they are how a module says "I cannot answer" without core hearing "there is nothing".ctx.teamsis documented as push-only, with the reason there is no reader — a module answers questions about Teams, it does not ask them.BACKEND_DESIGN.mdThe six Team tables, the rename rule, the active-only uniqueness encoding, the per-column account-deletion decisions, and all eighteen routes across the three tier tables.
Two entries exist specifically to stop a future reader "fixing" them: why
team_forum_grantsdoes not use the obvious generated column, and why two columns TEAMS.md never mentions have to exist.TEAMS.md— five amendmentsMarked inline as amendments with their date, rather than silently rewriting the plan. Each was found by building or testing the thing the plan describes:
ON DELETE SET NULLon a base column of a stored generated column (1901), so §2.5'sactive_userforces theCASCADE§2.10 exists to prevent. §2.10 wins.team_forum_grantslands in phase 2, so the four-path resolver is written once and its non-contamination tests are real.roster_synced_atandmembers_empty_since, both serving §2.4's gates, which per-module sync state cannot express.leaderon the member shape is not path 2. Taking §2.3 and §2.5 both literally gives one column two writers, and the roster writes first — so a refusedgetTeamLeaders()silently demoted everyone.One thing recorded but not acted on, in Module-uo #9 rather than here: §2.5's multiple leaders are unreachable for UO, because Protocol 4 does not carry guild rank on the wire. That is a protocol change if it is wanted.
AI-assisted: written with Claude Code. Commits carry
Co-Authored-By: Claude <noreply@anthropic.com>.Documents phase 2 of docs/website/TEAMS.md across the three files that had to change, and records the five places building it disagreed with the design. ## MODULE_API.md — 1.6.0 The Team surface becomes contract: `api.registerTeamProvider(...)`, `ctx.teams.publish` / `ctx.teams.reconcile` / `ctx.teams.activity.push`, `api.registerSlashCommands(...)`, and the two client slots. Additions only, so minor; module-uo's `coreApi: "^1.3.0"` still resolves. Per the org lead's decision, one 1.6.0 covers the whole surface rather than a minor per phase -- so the document names the phase against each member, and the two that cannot work yet are marked as present-and-throwing rather than left to be discovered at runtime. `registerTeamProvider` gets the fullest treatment because it is the first registration where core calls the MODULE and waits for an answer. The envelope, the 10-second budget and the refusal semantics are all contract, not implementation: they are how a module says "I cannot answer" without core hearing "there is nothing". `ctx.teams` is documented as push-only, with the reason there is no reader — a module answers questions about Teams, it does not ask them. ## BACKEND_DESIGN.md The six Team tables, the rename rule, the active-only uniqueness encoding, the per-column account-deletion decisions, and all eighteen routes across the three tier tables. Two entries there exist to stop a future reader "fixing" them: why `team_forum_grants` does not use the obvious generated column, and why the two columns TEAMS.md never mentioned have to exist. ## TEAMS.md — five amendments, marked as amendments with their date - **§2.5's SQL and §2.10's decision cannot both hold.** MariaDB refuses ON DELETE SET NULL on a base column of a stored generated column (1901), so §2.5's `active_user` forces the CASCADE that §2.10 exists to prevent. §2.10 wins; the marker is re-encoded for identical semantics. - **`team_forum_grants` lands in phase 2**, so the four-path resolver is written once and its non-contamination tests are real. - **Two columns the document did not contemplate**, both serving §2.4's gates: `roster_synced_at`, because sync state is per MODULE and gate 3 leaves one Team behind while the others sync; and `members_empty_since`, gate 4's per-Team quarantine. - **`leader` on the member shape is not path 2.** Taking §2.3 and §2.5 both literally gives one column two writers, and the roster writes first — so a refused `getTeamLeaders()` silently demoted everyone. Found by its own test. - **§2.8.2's matcher needed two narrow widenings**, both real impersonation vectors the whole-word rule missed: a term matches a name word's singular ("Guild of Moderators"), and a run of single-letter words is compared joined ("G.M."). Neither re-admits substring matching. Pairs with website (Teams phase 2) and Module-uo (the provider). Refs docs/website/TEAMS.md Part 12 phase 2 Co-Authored-By: Claude <noreply@anthropic.com>Correction: the last line of this description is now out of date
I closed with "§2.5's multiple leaders are unreachable for UO, because Protocol 4 does not carry guild rank on the wire. That is a protocol change if it is wanted."
It was wanted, and it is not a protocol change in the versioning sense: Protocol 4 is on
edgeand unreleased, so it has been amended in place with no bump — a bump is owed only once a protocol reachesmain.Roster members now carry
rank, andgetTeamLeaders()returns every member at rank 4:v4.md§2.3 andINTEGRATION.mdNothing in this PR changes.
TEAMS.mdnever asserted the limitation — it was only in this description and in Module-uo #9's — so there is no amendment here to correct. §2.5's multiple leaders now simply work as written.One thing #155 adds that is worth knowing about while reviewing this:
PlayerMobile.GuildRankreports Leader for anyone at GameMaster or above whatever their real rank, so the bridge omits the rank entirely for staff. An absent rank means "not known" and must be read as neither 0 nor leadership — otherwise a staff member appears as a guild leader on a public page, which is the §2.8 impersonation concern arriving by a different door.