A Cross-User Notification Fires Within the Posting Write's Atomic Envelope and Rolls Back With It

Claim

In the eOS-Harness MVA running against DGD 1.7.9 plus the eOSContinuum/eOS-kernellib feature/cohesive-lift branch (Vault + Schema + XML + Index + Merry + the property-change dispatcher), posting a chat message that mentions a user fires a registered observer synchronously, inside the same set_property that records the message, and that observer's cross-user write shares the posting write's atomic fate. The dispatch shape: a chat-room carries an append-to-history main observer and a mention-notify post observer (both registered via MERRY->register_observer under merry:on:chat-room.message:<timing>). The chat daemon's post_message resolves the @name mentions against the room roster and writes one chat-room.message arrival signal via set_property; the dispatcher fires the main append, then the post mention-notify observer, both within that write. The mention-notify observer runs Set($new["mentions"][0], "chat-user.mention-tracker", Get(...) + ({ $this })), so the mentioned user's tracker names the room the instant post_message returns (sentinel EVENT-ATOMIC OK). When the same post is wrapped in a DGD atomic function that then throws, the rollback unwinds every write the task made -- the message-log append and the observer's cross-user Set alike -- so neither the message nor the notification survives (sentinel EVENT-ROLLBACK OK). The sender's post_message contains no notification logic; the "asynchronous" character is the agent-side experience (a registered listener, no polling), while the mechanism is synchronous-within-the-atomic-envelope.

Grounds

This is an Empirical Observation. The grounds are a captured three-boot smoke run 2026-05-30 against the live MVA demonstration instance with examples/chat-app/ overlaid at the isolated runtime staging tree's src/usr/Chat/.

Setup (verifiable from repo state):

Load-bearing source (phases 5 and 7 of examples/chat-app/sys/test.c):

/* phase 5: synchronous notification */
MERRY_DAEMON->register_observer(room_p5, "chat-room.message", "post", SRC_NOTIFY);
CHAT_DAEMON->post_message(alice, room_p5, "@dave hi");
/* dave->query_mention_tracker() == ({ room_p5 }) already */

/* phase 7: the same post inside an atomic envelope that throws */
static atomic void atomic_post_then_fail(object sender, object room, string content)
{
    CHAT_DAEMON->post_message(sender, room, content);
    error("EVENT-ROLLBACK deliberate failure");
}
/* after the caught throw: room has no message, eve has no notification */

SRC_NOTIFY is the post observer source Set($new["mentions"][0], "chat-user.mention-tracker", Get($new["mentions"][0], "chat-user.mention-tracker") + ({ $this })); return TRUE; -- pure Merry, no $delay. post_message writes chat-room.message; the dispatcher's dispatch_set fires the registered observers synchronously around the raw write.

Smoke transcript (the load-bearing portion of the result log after boot 1):

ChatApp:test: EVENT-ATOMIC OK
ChatApp:test: NO-REACT OK
ChatApp:test: EVENT-ROLLBACK OK

EVENT-ATOMIC OK writes only when dave's mention-tracker equals ({ room_p5 }) immediately after post_message returns (the notification landed synchronously). EVENT-ROLLBACK OK writes only when the atomic post threw AND the room's message log is empty AND eve's mention-tracker is empty (both writes rolled back). Both are inside catch{}; a throw or a surviving write logs a distinct FAIL.

What the evidence establishes:

What the evidence does not establish:

What Would Revise It

Sources

Relations