- conforms_to::[[Observation Form Contract]]
- has_epistemic_status::[[Empirical Observation]]
- in_practice_domain::[[eOS Continuum]]
- authored_by::[[Christopher Allen]]
- has_lifecycle::[[Seed Stage]]↗
- has_curation::[[Working Draft]]↗
A Property Change Fires No Reaction Where No Observer Is Registered
Claim
In the eOS-Harness MVA running against DGD 1.7.9 plus the eOSContinuum/eOS-kernellib feature/cohesive-lift branch, a chat message that mentions a user, posted to a room that has no mention-notify observer registered, fires no cross-user reaction. The room carries only an append-to-history main observer; it has no observer at merry:on:chat-room.message:post. bob posts @dave2 yo; the chat daemon's post_message resolves the mention against the roster and writes the chat-room.message arrival signal via set_property; the dispatcher fires the append (so the message is recorded in the room's log) but finds nothing registered at post timing, so no cross-user notification runs. dave2's chat-user.mention-tracker stays empty (sentinel NO-REACT OK). The append observer is registered and fires, which isolates the absence of reaction to the missing post observer rather than to a broken post path.
Grounds
This is an Empirical Observation. The grounds are the same captured three-boot smoke run 2026-05-30 that grounds the positive peer.
Setup (verifiable from repo state):
- Driver: DGD 1.7.9 built from
dworkin/dgd. - Kernel layer:
eOSContinuum/eOS-kernellibonfeature/cohesive-liftat HEADd333bd4. - Application layer:
examples/chat-app/, deployed into the isolated runtime staging tree with the Chat domain overlay.
Load-bearing source (phase 6 of examples/chat-app/sys/test.c):
MERRY_DAEMON->register_observer(room_p6, "chat-room.message", "main", SRC_APPEND);
/* deliberately NO mention-notify post observer registered. */
CHAT_DAEMON->post_message(bob, room_p6, "@dave2 yo");
if (sizeof(dave2->query_mention_tracker()) != 0) { /* FAIL */ }
if (sizeof(room_p6->query_messages()) != 1) { /* FAIL */ }
The contrast is exact: the positive peer registers the same SRC_NOTIFY post observer on its room and the target's tracker is populated synchronously; here the post observer is omitted and the target's tracker stays empty after the identical post.
Smoke transcript (the load-bearing line after boot 1):
ChatApp:test: NO-REACT OK
NO-REACT OK writes only when dave2's mention-tracker is empty AND the room's message log has exactly the one posted message (the append fired; the notification did not).
What the evidence establishes:
- Reactions are exactly the registered observers. A property change on a timing slot with no registered observer is inert -- the dispatcher has nothing to invoke and runs no reaction.
- The absence is specific to the unobserved slot, not to a broken post: the main-timing append observer on the same room fires and records the message.
What the evidence does not establish:
- That registration is the only gate. The capability gate on
register_observer(which decides who may register) is exercised elsewhere by the positive path's accept case; this negative only shows that an unregistered slot fires nothing, not the registration-authorization boundary. - Removal semantics. This is a never-registered case, not an
unregister_observercase; whether clearing a registered observer returns the slot to inert is a separate probe.
What Would Revise It
- A reaction firing on the unobserved slot would falsify the claim; the current evidence shows the target's tracker untouched after the post.
- The append failing to record the message would mean the negative was a broken-post artifact rather than a missing-observer result; the current evidence shows the message recorded, isolating the cause.
- A DGD or eOS-kernellib change to the dispatcher's observer-lookup (e.g., a default reaction in the absence of a registration) would invalidate the snapshot; the claim rests on
feature/cohesive-liftHEADd333bd4.
Sources
examples/chat-app/sys/test.c(ineOS-kernellib feature/cohesive-lift) -- phase 6 (NO-REACT); contrast with phase 5 (EVENT-ATOMIC).examples/chat-app/sys/chat.c--post_message+scan_mentions; the mention is resolved even though no observer consumes it.src/usr/Merry/sys/merry.c--find_observersreturns an empty list for an unregistered(path, timing)slot, sodispatch_setfires nothing there.docs/chat-applications.md(ineOS-kernellib feature/cohesive-lift) -- the "Async events" walkthrough, phase 6.- The isolated runtime staging tree's
src/usr/Chat/data/test-result.log-- carriesNO-REACT OKafter a clean boot. - The three-boot regression harness.
Relations
-
conforms_to::[[Observation Form Contract]]
- Carries
has_epistemic_status::[[Empirical Observation]], names the measurement (the phase-6 assertion in the same three-boot smoke), states the limits (never-registered case, not removal or authorization), and lists concrete revision conditions.
- Carries
-
informs_downstream::[[Event Notification Is Atomic With State Change, Not Polled or Queued]]
- The Conviction's stance is that the platform is the event coordinator -- listeners fire because they are registered, not because application code polls. This negative grounds the boundary: where no listener is registered, no reaction occurs; the platform does not synthesize one. It is the complement to the positive's synchronous-fire evidence.
-
contrasts_with::[[A Cross-User Notification Fires Within the Posting Write's Atomic Envelope and Rolls Back With It]]
- The positive-case peer. The identical post -- same daemon, same arrival signal, same mention resolution -- notifies synchronously when the post observer is registered and fires nothing when it is not. The only difference between the two rooms is the presence of the post observer, which is what makes the pair a clean isolation of "reaction requires a registered observer".