docs(engagement): Phase 11b's live walk — three decisions and six defects

The walk is the last piece of 11b and it was not a formality. It found six
defects, four of them in code shipped by earlier phases, and none of the six was
visible in a unit test: each is a disagreement between two things that agree with
each other in a fixture.

Three of the fixes were decisions rather than repairs, all settled by the org
lead before any code:

  11  `uo.house.idoc_warning` ships delay_seconds: 900 and nothing could cancel
      it  ->  add `uo.house.refreshed`, a 26th trigger with a body and a rule
  12  a rule with a cooldown delivered on exactly ONE of its channels
          ->  `channel` joins the cooldown key; a cooldown is per DELIVERY
  13  `uo.vendor.expiring` could not fire, because the market sweep does not
      diff fees  ->  widen BridgeMarket.Signature() with exempt +
      periodsRemaining

Files:

  website/ENGAGEMENT.md   the three decisions, the four repairs, and what the
                          walk proved rung by rung; the 11b bullet and the §8.6
                          family table now read 26 triggers / 34 bodies
  website/BACKEND_DESIGN.md  engagement_cooldowns gains `channel` in its PRIMARY
                          KEY, with the migration's information_schema guard and
                          why MariaDB forces one
  link/v5.md              the sweep has to DIFF the fees or the frame never
                          comes -- stated as the general rule for the next
                          enrichment, since it is emit cadence and not shape
  modules/uo/API.md       §5.7a the cancel-shaped trigger and the Ageless-vs-
                          LikeNew ServUO fact; §5.7b every link comes from
                          config/clientPaths.js, and the two mistakes that made
                          every call-to-action a dead link

Pairs with website#<core>, Module-uo#<uo> and servuo-plugins#<plugin>.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-01 07:13:03 -05:00
parent c9873eff7d
commit cd0d22a225
4 changed files with 203 additions and 11 deletions

View File

@@ -122,6 +122,24 @@ Two naming decisions worth recording, because the obvious spellings are both wro
a dynamic-decay house, though, there is **no randomness in it**: given the current funds it is the
exact tick the vendor is destroyed on.
**The market sweep has to DIFF the fee state, and originally it did not.** `BridgeMarket.Signature()`
compares shop name, owner, map, coordinates and the item/price list — the things a *listing* is made
of — so adding `fees` to the frame did not by itself make a frame arrive when the fees changed. A
vendor quietly running down its gold altered nothing the sweep compared, emitted nothing, and the
consumer that exists for exactly that event could fire only by coincidence: when somebody happened to
reprice an item on a shop that was already broke. Found on the engagement Phase 11b live walk and
fixed there (ENGAGEMENT.md, decision 13).
The signature carries the **derived** values — `exempt` and `periodsRemaining` — not the raw ones. An
integer division moves only when the shard's own answer to "is this vendor in danger" moves, while
`holdGold` changes on every sale and `nextPayAt` on every pay tick; keying on either would re-emit a
fat listing frame for a shop whose listings had not changed. This is emit CADENCE, not frame shape:
no field was added and `PROTOCOL_VERSION` is untouched.
**The general form is worth carrying to the next enrichment.** A sweep-based kind has a change
detector, and a field added to the frame that is not added to the detector is a field that ships
correct and arrives never.
### 2.3 `account.login.result` — a new kind, because the old one cannot be fixed
`account.login.attempt` (protocol 1) is emitted from `EventSink.AccountLogin`, which