1 import Base 2 import ./world.bend as W 3 import ./world_resource_owner.bend as Resource 4 import ./owner_product.bend as Product 5 import ./capabilities.bend as Cap 6 import ./owned_event_log.bend as Log 7 8 # Trusted engine helpers. Ordinary product declarations bind the canonical log 9 # path and matching key route; gameplay receives only its abstract capability. 10 # R is the entire heterogeneous resource tree, E the existing Data publication 11 # tree. No Type payload or unrelated resource owner is copied or reconstructed. 12 def log_returned(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~Out:Type,worldRest:Resource.Rest,resourceRest:Rest,result:Log.Log

& Out) -> W.World & Out: 13 match result: 14 case (log,output):(Resource.put(~S,~C,~R,~E,worldRest,Product.put_field(~R,~Log.Log

,~Rest,path)(resourceRest,log)),output) 15 def log_taken(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~Out:Type,effect:Log.Log

-> Log.Log

& Out,worldRest:Resource.Rest,result:Rest & Log.Log

) -> W.World & Out: 16 match result: 17 case (resourceRest,log):log_returned(~S,~C,~R,~P,~Rest,~E,~path,~Out,worldRest,resourceRest,effect(log)) 18 def resource_taken(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~Out:Type,effect:Log.Log

-> Log.Log

& Out,result:Resource.Rest & R) -> W.World & Out: 19 match result: 20 case (worldRest,resource):log_taken(~S,~C,~R,~P,~Rest,~E,~path,~Out,effect,worldRest,Product.get_field(~R,~Log.Log

,~Rest,path)(resource)) 21 def with_log(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~Out:Type,effect:Log.Log

-> Log.Log

& Out,world:W.World) -> W.World & Out: 22 resource_taken(~S,~C,~R,~P,~Rest,~E,~path,~Out,effect,Resource.take(~S,~C,~R,~E,world)) 23 24 def injected(~E:Data,~inject:Nat -> E,ids:List<&2,Nat>) -> List<&2,E>: 25 match ids: 26 case []:[] 27 case id <> rest:inject(id) <> injected(~E,~inject,rest) 28 def published(~S:Data,~C:Type,~R:Type,~E:Data,~inject:Nat -> E,result:W.World & List<&2,Nat>) -> W.World: 29 match result: 30 case (world,ids):W.event_publish(~S,~C,~R,~E,world,injected(~E,~inject,ids)) 31 # The transaction adapter calls this after successful canonical ECS finish. One 32 # caller batch retains its FIFO; cross-family action order belongs to that adapter, 33 # using the existing publication journal, not a regrouping by payload type/family. 34 def commit_owned(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~inject:Nat -> E,world:W.World,values:List

) -> W.World: 35 published(~S,~C,~R,~E,~inject,with_log(~S,~C,~R,~P,~Rest,~E,~path,~List<&2,Nat>,log => Log.append_many(~P,log,values),world)) 36 # The runtime chooses surviving records using its unchanged per-family retention 37 # policy, then calls each family's selected path with those records. 38 def retain(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~select:List<&2,E> -> List<&2,Nat>,world:W.World,records:List<&2,E>) -> W.World & List>: 39 with_log(~S,~C,~R,~P,~Rest,~E,~path,~List>,log => Log.retain(~P,log,select(records)),world) 40 # Drain only this log, preserving its next ID and every publication. The outer 41 # shutdown drains ALL family logs and clears their publication tree atomically 42 # before any reader runs. Clearing shared records here would lose sibling events. 43 def drain(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,world:W.World) -> W.World & List>: 44 with_log(~S,~C,~R,~P,~Rest,~E,~path,~List>,Log.drain(~P),world) 45 # Read only the log at the declaration's path. IDs are local to that family; the 46 # ordinary adapter first projects the reader's IDs through the matching key route. 47 # Trusted at preserves its owner; the abstract body cannot extract that owner. 48 def read(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens,Rest>,~Request:Type,~Projection:Data,~Args:Type,~Observation:Type,~at:P -> Request -> P & Projection,~body:@-H:Type -> @-read:Cap.Request -> H -> Args -> H & Observation,world:W.World,id:Nat,args:Args) -> W.World & Log.ReadResult: 49 with_log(~S,~C,~R,~P,~Rest,~E,~path,~Log.ReadResult,log => Log.read(~P,~Request,~Projection,~Args,~Observation,~at,~body,log,id,args),world)