fix(engagement): four defects the Phase 11b live walk found, and the 26th trigger #24
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/engagement-live-walk-uo"
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?
The module's half of Phase 11b's acceptance walk. Needs website#179 (the cooldown key and the seed-rule ceiling); pairs with servuo-plugins# and docs#.
Four defects. The first two meant the flagship family did not work at all, and neither was visible in any test — which is the point of the walk.
1. Every
owner-audienced trigger reached NOBODYshardLinks.model.toSafecamel-cases the row on the way out. So houses, vendors, logins, unlinks, skills, quests, deaths and the governor's letter all resolved tonull— and the failure is indistinguishable from the ordinary unlinked-account case, which this file treats as normal and deliberately does not log. On the rig: theGreatlytransition reached the wire withownerAcct: seed_002, the account was linked, and no outbox row appeared.The test fake returned
user_idand therefore agreed with the bug.shardStreams.test.js's fake next door — same model, and the path this file's own header says it copies — returnsuserId, andshardPush.jsreadsowner.userId. The fake is now built by running the realtoSafeover a stubbed db row, so its shape is not a hand-written opinion that can drift from the model again.2.
uo.house.refreshed— the 26th trigger (decision 11)uo.house.idoc_warning's seeded rule carriesdelay_seconds: 900so a player who repairs the house inside the quarter-hour is never told it is in peril. §4.2a is explicit that a delay without a cancellation is just a late mail — and nothing could cancel it.cancel_onnameduo.house.collapsed, the outcome where the warning is pointless, and nothing named the outcome where it is wrong, because the mapper returned early on every transition that was not a late stage. The wire had carried the transition all along.The Office of Deeds' one non-warning letter
Three things about it are load-bearing:
subjectKeyas the warning.outboxDb.cancelmatches on(rule, subject_key); a refresh carrying any other subject would cancel nothing.Agelessas well asLikeNew, andAgelessis the common case. A condemned house cannot be refreshed —BaseHouse.RefreshDecay()returns false forDecayType.Condemned— so the rescue is the owner logging back in. Their newest house then becomesAutoRefreshand readsAgeless; an older one becomesManualRefreshand readsLikeNew. The live rig producedAgeless, and a mapper reading onlyLikeNewwould have missed it.cancel_onis read off the warning's rule, so an operator who wants the cancellation without the reassurance simply leaves this one off — which, every seeded rule shipping disabled, is what a fresh install already does.3. Every call-to-action in every in-universe body was a dead link
Two independent mistakes with one symptom.
The prefix is the module ID, not the mount.
registry.registerRoutesprefixes a module's client routes with<id>/and nothing else, so the real paths are/uo/houses,/uo/market,/uo/leaderboards. Every declaredexampleread/shard/…(frommodule.json'smounts) and every hard-coded href was one of/shard/…or/player/uo/houses— a route that does not exist at all. Anexampleis what the template editor previews and test-sends with, so this was wrong in the operator's face as well as in the mail.And no
urlvariable was ever populated. All eight were declared, none was ever set by the mapper — so every button rendered with an empty href and dropped out of the text part entirely. The Office of Deeds' warning simply had no "Review thy holdings" line.Both now read the new
config/clientPaths.js, and two tests close it: everyurlexample must name a route this module mounts, and every declaredurlvariable must actually be supplied on the path that emits its trigger — driven off the declarations, so the next one added is covered the day it is declared.4. A raw wire timestamp was signing off the Merchants' Guild's letter
Core has no interpolation filters by design, so a
datetimerenders as whatever string the payload holds. Same argumentplace()anddetailLine()already make: the readable form is assembled in the mapper and arrives as its own value. The machine value stays —dismissalAtandautoPickAtare what an operator writesis at mostconditions against — soautoPickWhenis an additional optional besideautoPickAt, not a replacement.Also: a latent flake
hoursRemainingfloors a live clock, soFEES(20)asserted19only if a millisecond had passed since the fixture was built. It went green or red on scheduling. NowFEES(20.5)→20, deterministic for the next half hour.Verification
Greatlytransition produced one notification to the linked owner on both channels and nothing to a second linked-and-subscribed player; the owner logging back in cancelled both pending rows and delivered the letter above; the governor's letter arrived with a working/uo/governorslink.AI-assisted: written with Claude Code.
🤖 Generated with Claude Code