A Lost Update Appears Only Without the Runtime's Serialization of Concurrent Writes

Claim

In the eOS-Harness MVA running against DGD 1.7.9 plus the eOSContinuum/eOS-kernellib feature/cohesive-lift branch, a lost update -- one writer's mutation silently overwritten by another's -- appears only when the writers act on state read before a concurrent commit instead of re-reading at write time. The demonstration is the deliberate contrast to the serialized claim_slot path: obj/room.c carries a claim_slot_stale(user, stale_snapshot) that writes the member list from a snapshot argument (stale_snapshot + ({ user })) rather than re-reading current state. Phase 9b captures one empty member-list snapshot and passes the SAME snapshot to both writers (heidi, ivan). heidi writes empty + ({ heidi }); ivan writes empty + ({ ivan }) -- computed from the same stale empty snapshot, so ivan's write overwrites heidi's, heidi's claim is lost, and only ivan remains (sentinel LOST-UPDATE OK). The lost update is not a property of the runtime; it is a property of acting on a value read before a concurrent commit. The sibling claim_slot avoids it by reading current state at write time, where each writer's read already reflects the other's commit. This bounds the coherent-state mechanism: the runtime's coherent read at write time is what removes the lost update, and the lost update is reproducible only by an application that deliberately caches state across the mutation boundary.

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 (examples/chat-app/obj/room.c and phase 9b of examples/chat-app/sys/test.c):

/* room.c: the stale-snapshot write -- the contrast to claim_slot */
void claim_slot_stale(object user, object *stale_snapshot)
{
    set_property("chat-room.member-list", stale_snapshot + ({ user }));
}

/* test.c phase 9b: both writers act on ONE snapshot captured before either committed */
stale = room_l->query_members();           /* empty, captured once */
room_l->claim_slot_stale(heidi, stale);     /* writes empty + heidi */
room_l->claim_slot_stale(ivan, stale);      /* writes empty + ivan, overwriting heidi */
/* asserts: heidi NOT a member; ivan a member; sizeof(members) == 1 (the lost update) */

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

ChatApp:test: COHERENCE-SERIALIZE OK
ChatApp:test: LOST-UPDATE OK

LOST-UPDATE OK writes only when heidi is NOT a member (her claim was lost), ivan IS a member, and the room holds exactly one member -- i.e. the second stale write overwrote the first. The assertion is inside catch{}; heidi surviving (no lost update reproduced), ivan missing, or a wrong member count each log a distinct FAIL.

What the evidence establishes:

What the evidence does not establish:

What Would Revise It

Sources

Relations