docs(link): protocol 5 — the decay schedule, vendor fee state and account.login.result #193
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/protocol-v5"
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?
Design of record for the bump, the reference updates it obliges, and Engagement Phase 10 as built.
Companion PRs: servuo-plugins#18, link#…, Module-uo#….
link/v5.md— newThree enrichments in one bump, because a bump costs a sidecar release, a republished bundle and an operator update on every shard. A field left out costs a whole second round of that, not a follow-up commit.
house.decaygainsownerNameand a nestedschedule.estimatedCollapseis present only where it is exact: under dynamic decay each stage's duration is drawn at random on entry, so collapse is knowable only once the house is already at IDOC; under static decay it is exact at every stage. Omitted rather than approximated — an absent field is honest where a wrong date becomes a dated promise in a player's mail.vendor.listinggainsownerAcct— a character name identifies nobody, only the game account joins toshard_account_links— and afeesblock resolvingPlayerVendor.PayTimer's dismissal rule into adismissalAtinstant. There is deliberately nodaysRemaining: a pay period is a UO day on an old-system shard, so the name would be wrong by a factor of twelve.account.login.resultis a new kind.account.login.attemptfires from a veto hook that runs before the auth decision and constructs withAccepted = true, so it fires on successful logins too and cannot carry a verdict.Also records the sidecar's non-change as a property rather than an omission (no store migration, unlike v4 — the dumb-forwarder invariant doing its job), the three visibility classifications, and §6.1's two rig traps.
Corrections to the existing references
Three things the docs asserted that turned out not to be true:
PLAN.md§5.1 listedAccountLoginunder "Failed-login / IP signals for the website". It cannot give you a failed login — it is a veto hook that fires before the decision, and the args construct withAccepted = true, so a handler reading the verdict there reports every login as accepted.PLAN.md§7's frames are 1.0's design sketch, not the shipped wire, and have not been for four versions — itshouse.decayshows anownerobject and a flatnextStage, neither of which ships. Now marked as such, pointing atINTEGRATION.mdfor the normative field lists.INTEGRATION.md'saccount.login.attemptrow described an attempt without saying it fires on successes too, which is what made building a security notice on it look reasonable.Plus the ordinary updates: the version banner to 5, the Housing and Market tables and examples, the new kind, and the
README.mdindex row.ENGAGEMENT.md— Phase 10 as builtTwo decisions taken during the build and not in the phase text:
daysRemaining, for the reason above.And one improvement worth calling out because it is the protocol-4 bug seen from the other side:
module-uo's schema test assertedDEFAULT 4at each declaration site, so when the emitters moved and one site was left behind, every site still agreed with itself and the test passed. It now readsDEFAULT_PROTOCOLfrom the model, making the assertion "the declarations agree".runicgateway.com'splatform.json.protocol→ 5 stays Phase 12's:checkFacts.mjsfetches frommain, so setting it during theedgeperiod turns that repo red at once.🤖 Generated with Claude Code
Two scope decisions taken by the org lead on 2026-08-31, before any Phase 10 code, plus the three factual corrections that finding them out produced. Phase 10 — the protocol bump now carries three enrichments, not one. The argument is specific to this phase: a bump costs a sidecar release, a republished bundle and an operator update on every shard, so a field left out does not cost a follow-up commit, it costs a second bump with the same lead time and a split operator population. The two additions: * player-vendor fee state on vendor.listing (ownerAcct, holdGold, chargePerDay, daysRemaining), because uo.vendor.expiring is the same "owned asset at risk with a deadline" shape as the flagship and today has neither an address nor a deadline; * a post-decision account.login.result, because EventSink.AccountLogin is a veto hook that fires BEFORE the auth decision. Moving vendor.sale out of the opt-in patch tier was explicitly declined. Phase 11 — ships every checked row of 8.6 rather than a single rule, carving out uo.market.item_listed (a saved search; no per-user query store exists). ~23 triggers grouped by the audience kind each family exercises, since exercising the ceiling lattice at scale is the point rather than volume of mail. Every rule still ships enabled = 0 per Q3. Notes that the phase will likely want an 11a/11b split on the 4a/4b precedent, to confirm at its start. Three corrections to 8.6, each verified against the emitters rather than the table: * uo.vendor.sale is real and does carry ownerAcct, but lives in servuo-plugins/ patches/ (opt-in, verified only against ServUO 57.4) — dormant, not broken, on a shard that declined the tier; * uo.vendor.expiring had no data at all, not merely no mapper — vendor.listing carries ownerSerial/ownerName and nothing carries held gold or daily charge; * uo.account.login_attempt could not have been built as described — it would have mailed "someone tried to log into your account" on every successful login. Renamed uo.account.login_failed so the id cannot be misread again. Also amended: the status header, scope decision 3, and 6.0b's documentation assignment for rows 10 and 11 (v5.md now earned; the patch-tier caveat is an operator-facing doc obligation; runicgateway.com's capability claim changes when "one rule" becomes "the catalogue"). Co-Authored-By: Claude <noreply@anthropic.com>Design of record for the bump, plus the reference updates it obliges. Engagement Phase 10, as built. link/v5.md is new. Three enrichments in one bump, because a bump costs a sidecar release, a republished bundle and an operator update on every shard — a field left out costs a whole second round of that, not a follow-up commit. a. house.decay gains ownerName and a nested `schedule`. estimatedCollapse is present ONLY where it is exact: under dynamic decay each stage's duration is drawn at random on entry, so collapse is knowable only once the house is already at IDOC; under static decay it is exact at every stage. Omitted rather than approximated — an absent field is honest where a wrong date becomes a dated promise in a player's mail. b. vendor.listing gains ownerAcct — a character name identifies nobody, only the game account joins to shard_account_links — and a `fees` block resolving PlayerVendor.PayTimer's dismissal rule into a dismissalAt instant. There is deliberately no daysRemaining: a pay period is a UO day on an old-system shard, so the name would be wrong by a factor of twelve. c. account.login.result is a NEW kind. account.login.attempt fires from a veto hook that runs before the auth decision and constructs with Accepted = true, so it fires on successful logins too and cannot carry a verdict. INTEGRATION.md: the version banner to 5, the Housing and Market field tables and examples, and the new kind beside the attempt — with the attempt's own row corrected to say why it is not a failure signal. PLAN.md: 5.1's "failed-login signals" row was wrong about what AccountLogin can tell you; 5.3 and 5.4 gain the two new signals; 5.4's dynamic-decay model gets the consequence for publishing a collapse time, and the CanDecay rule gets its testing trap. 7's frames are marked as 1.0's design sketch rather than the shipped wire, which they have not been for four versions. ENGAGEMENT.md: Phase 10 as built. Two decisions taken during the build (both field groups nested, so one admin rule governs each and a future field inherits the gate; no daysRemaining), the three visibility classifications, and the pin improvement — the schema test now asserts the declarations AGREE rather than that they all say a literal, which is the protocol-4 bug seen from the other side. Co-Authored-By: Claude <noreply@anthropic.com>