Surfaced while planning osr-web's phase-4 authored-layer adoption (mmacy/osr-web#53). Filed engine-first per the standing rule.
The gap
_handle_grant_coins (crawl/session.py) emits a bare ItemAcquiredEvent(character_id=..., coins_gp_value=...) — byte-identical in shape to the per-member share a TakeTreasure distribution emits. Same for GrantItem. Commands carry a source stamp; the events they emit do not (Event carries only code and visibility beyond the subclass fields), so at the event level a quest reward counted out per head is indistinguishable from a haul split across the party.
Why it matters downstream
osr-web's renderer collapses adjacent same-command coin acquisitions into one "The party splits N gp in coin." line, because a distributed take really is one haul told member by member. The interpreter expands a quest reward's @party into one GrantCoins per living member, and those adjacent acquisitions collapse the same way — so the bundled quest's per-head payment ("pay twice over", per living member by design) renders as a pot split. Truthful in sum, wrong in frame.
Every honest discriminator is session-side or mode-side, and a mode test at render time would re-word every historical haul on a whole-log re-render — the same class of defect as resolving area events against the party's current location. The emission site knows which command it is executing; the event does not say.
What downstream needs
Provenance on the event — e.g. the issuing command's source stamp carried through, or a grant marker (naming and shape this repo's call), defaulting so old logs still parse, always filled by the engine at emission.
Downstream in the interim
osr-web keeps the collapse unchanged — no re-wording ships until the engine states the fact. No session-side or mode-side discrimination will be built in the interim.
Surfaced while planning osr-web's phase-4 authored-layer adoption (mmacy/osr-web#53). Filed engine-first per the standing rule.
The gap
_handle_grant_coins(crawl/session.py) emits a bareItemAcquiredEvent(character_id=..., coins_gp_value=...)— byte-identical in shape to the per-member share aTakeTreasuredistribution emits. Same forGrantItem. Commands carry asourcestamp; the events they emit do not (Eventcarries onlycodeandvisibilitybeyond the subclass fields), so at the event level a quest reward counted out per head is indistinguishable from a haul split across the party.Why it matters downstream
osr-web's renderer collapses adjacent same-command coin acquisitions into one "The party splits N gp in coin." line, because a distributed take really is one haul told member by member. The interpreter expands a quest reward's
@partyinto oneGrantCoinsper living member, and those adjacent acquisitions collapse the same way — so the bundled quest's per-head payment ("pay twice over", per living member by design) renders as a pot split. Truthful in sum, wrong in frame.Every honest discriminator is session-side or mode-side, and a mode test at render time would re-word every historical haul on a whole-log re-render — the same class of defect as resolving area events against the party's current location. The emission site knows which command it is executing; the event does not say.
What downstream needs
Provenance on the event — e.g. the issuing command's
sourcestamp carried through, or a grant marker (naming and shape this repo's call), defaulting so old logs still parse, always filled by the engine at emission.Downstream in the interim
osr-web keeps the collapse unchanged — no re-wording ships until the engine states the fact. No session-side or mode-side discrimination will be built in the interim.