docs(engagement): scope Phase 11 — six decisions, three carve-outs, the 11a/11b split #194
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/engagement-phase-11-decisions"
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?
Phase 11's own text asks for its 11a/11b split to be confirmed with the org lead "at the start of the phase rather than assumed here". Confirming it turned up five further questions the plan had not asked, three of which change what ships. This records all six before any code, on Phase 2's precedent.
No code in this PR. 11a follows.
The three carve-outs
Phase 11 inverted the burden of proof — a ✅ row that does not ship needs a reason recorded — so all three are written into §8.6 and the phase. All three came from checking §8.6's rows against what the website can address, which is a different question from whether the wire carries the event. In every case the event keeps being ingested.
uo.guild.joinedteam.member.joined. A UO guild is a Team andmodule-uois this deployment's Team provider, soteamSync.notifyRosteralready emits on every roster reconcile and core already seeds a (disabled) rule for it. An operator enabling the obvious two rules would get two mails for one join.uo.guild.leftanduo.guild.disbandedstill ship — core has noteam.member.leftand no disband event at all. The trade given up is latency (~15 min vs real-time), which is the right thing to give up: a duplicate mail is a defect discovered in production.uo.link.requestedshard_account_linkshas no row andownerresolves to nobody. AndttlSecdefaults to five minutes; every channel here is slower than that in the worst case and allowed to be. The player is looking at the code on screen when it fires.uo.points.rank_changed— the personal halfpoints.board'stop[]entries are{rank, serial, name, points}— a mobile serial — andshard_account_linksis keyed by game account. No general serial→account map exists (shard_onlinecovers only who is logged in right now,shard_guild_membersonly guilded characters), so "you were pushed out of the top ten" would reach some players and silently not others. The board-changed feed ships atsubscribers; the owner half waits for something that actually needs a serial→account map.The three that change mechanism
1. The ceiling lattice gains
admin, as a child ofstaff—MODULE_API_VERSION→ 1.8.0.§8.6 describes
uo.audit.staff_action,uo.economy.milestoneanduo.world.savedas admin-audience, andlink/v5.md§4 classifiesaccount.login.resultas admin, by omission — "there is no rung below admin that a frame carrying an IP address and an auth verdict belongs on". The lattice had no such rung: its narrowest staff-ish value isstaff, whichceilings.jsdefines as admin / editor / moderator. Ceilinging the operator-facing family there would let a rule mail the staff audit digest to every editor.adminis the only genuine refinement in the whole tree — every admin is staff, which is exactly the containment every other pair of leaves lacks — so it is a child rather than a seventh leaf, andpermits/meet/meetAllneed no change beyond the newPARENTentry. Cheap now because nothing anywhere stores anadminaudience yet; expensive after cutover.2. §7.1 Q9 —
news.postcontinuity: the emit replaces the raw tickle, and core seeds the rule DISABLED.The Phase 6 Team precedent applied unchanged. The consequence is stated plainly in the doc because it is deliberate: news push stops on upgrade until an operator switches the seeded rule on. Keeping the raw tickle beside the emit "for one release" was considered and refused — it is an exception with a deadline nobody owns, and Phase 6 already refused the analogous carve-out. Two mitigations become phase deliverables rather than nice-to-haves:
EngagementRules.jsx's existing banner must name news alongside Teams (11a)3. The split is confirmed and specified.
module-uo's 24 declarations + the wire-kind →ctx.events.emitmapper hung offshardIngest.ingest; core'sadminceiling, thenews.postemitter, 1.8.0, manifest regen. Acceptance here is the catalogue-shaped half: no staff- or admin-ceiling trigger by name in a player's catalogue, andcheck:modulesclean.enabled = 0), the template bodies, and the live five-rung walk.Two mechanisms recorded, not decisions
uo.vendor.expiringanduo.economy.milestoneare threshold events, butconditions.jscompares a declared variable against a literal only — no arithmetic, no relative time — so "within 24 hours of dismissal" is not expressible as a rule condition. Nor can the trigger fire per frame:vendor.listingis a sweep frame re-emitted on any price change andeconomy.supplyarrives every five minutes. So the crossing is tracked module-side, in the in-process trackershardStreams.jsalready uses forchampActive/cityGovernor, withperiodsRemaining/hoursRemainingdeclared as ints so an operator can still narrow withlte.Also names
module-uo's first three registered audiences (§5.1a said "Phase 11" and never said which):uo.guild.members,uo.governors,uo.linked.accounts— distinguished in the doc from themembersaudience the guild triggers use, which travels on the envelope asrecipientUserIdsbecause its answer differs per firing.Shipped set
24 triggers after the carve-outs, across five audience kinds (
owner,members,subscribers,staff,admin).AI disclosure
Co-Authored-By: Claudetrailer.🤖 Generated with Claude Code