docs(events): Phase 9 as built — UO wave 1, and a budgetMs rule the phase found #217
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/events-phase-9"
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 docs half of
Module-uo#28. Three files, all additive.MODULE_API.md§2.4 — a new contract rulebudgetMsmust EXCEED the timeout of whatever the action talks to. The dispatcher classifies abudget timeout as
retryunconditionally and does not ask the action — it cannot, the action isstill awaiting a socket. So an action whose own client gives up after core's deadline never gets
to classify its own failure, and
retry: falsein its envelope is unreachable code.The default
budgetMsis 10s andmodule-uo's sidecar client waits 12s — the wrong way round, soevery slow shard produced a retry the module had explicitly refused. That is a general rule about a
call with a far end, not a fact about one sidecar, so it belongs beside the envelope rules rather
than in the plan. The "no shape a failure can take reads as success" bullet now cross-references it,
because the two are halves of one thing:
retry: falseis only meaningful if it is reachable.EVENTS.md§F — "What Phase 9 settled, as the contract's first module registrant"Wave 1 is the first time anything but core registered an action. Four findings, three of them rules:
budgetMsrule above;on_failureis not a retry policy — it is what happens afterEVENT_STEP_MAX_ATTEMPTS, soskipdoes not stop a broadcast going out three times, and an action that must be attempted oncehas to answer
retry: falseitself. That is a heavier thing to ask of a declaration than the planassumed, and it is why the
budgetMsrule is load-bearing rather than a tuning note;reconcile()need not be a query — a module that knows when its resources are lost cananswer from a stamp. Wave 1 records the shard
bootIdin the payload and reports in force exactlythe rows whose stamp still matches: correct for the module's own trigger and for core's boot sweep,
where the game may not have restarted at all and "all gone" would abandon live rows;
reconcile()trigger must fire on a LIVE signal, never a replay. §L says the modulesays when; it did not say a module's feed may replay history. Any module wiring this seam owes the
same gate — see the defect below.
EVENTS_PLAN.md— Phase 9 as builtThe four org-lead decisions (2026-09-04, all as recommended); the plan's own broadcast trap and why
its stated fix does not work; the live walk — a real two-phase event against ServUO + the sidecar +
the website, with the shard's audit reading
web:event:3692 broadcast, the dry run refusing a capbreach before publish, the option sources resolving 387/558/800 rows from the real atlas, teardown
reverting both keyed resources, and core orphaning them 31ms after a real shard restart.
Three defects the walk found, two of them data loss, none visible to a unit test — the backfill
replay that would have orphaned every live resource on a WS reconnect; the shard's own refusal
reason being dropped from the run log; and a "not retried" clause that explained the wrong thing on a
permanent status.
And one in Phase 8's shipped code, recorded and deliberately not fixed.
UNRESOLVEDineventRunResources.db.jsincludesorphaned, so cleanup selects an orphaned row, callsrevert()on it and records it
reverted— contradicting §L's own "orphaned, never reverted" rule, andspending a sidecar round trip per row on a shard that has just restarted. It is core's file and wants
its own change.
Notes
docshas no CI; links and anchors checked by hand.MODULE_API.md§2.4 is a real heading(
### 2.4 api — what the module registers) and both new references land inside it.CRLF preserved throughout —
git diff --numstatreports 31/70/13 added lines and one changed,which matches the real content diff rather than a whole-file rewrite.
AI-assisted: Claude Code (Opus 5).
Code: RunicGateway/Module-uo#28.
🤖 Generated with Claude Code