execution_trace.bend
bendvy-ecs-core@0.1.0.0 · 80 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/change_tick.bend as Tick
3import bendvy-ecs-core@0.1.0.0/trace_facts.bend as Facts
4
5# Detached copied facts. No World, registration, cursor or stream owner is held.
6# Copied system identity for presentation: namespace/id and optional name.
7# It is metadata, not a registration owner or capability for invoking that system.
8type Identity is Data:
9 Identity{namespace:U32,id:U32,name:Maybe<&2,String>}
10# Completion status of one executed system, retaining its detached Data error.
11type Status<Error:Data> is Data:
12 SystemOk{}
13 SystemError{error:Error}
14# Schedule-level completion distinguishes failure, admission rejection and missing
15# execution from success; it is not a replacement for the retained App run result.
16type Completion<Error:Data> is Data:
17 EndOk{}
18 EndFailed{error:Error}
19 EndRejected{}
20 EndMissing{}
21# Ordered copied execution facts: schedule/phase boundaries, systems, operations
22# and admission outcomes. Facts describe the actual run; they grant no mutable
23# World access and do not imply that a failed transaction committed its operations.
24type TraceEvent<Error:Data> is Data:
25 ScheduleStarted{namespace:U32,name:String}
26 PhaseEntered{name:String}
27 SystemCompleted{identity:Identity,before:Tick.Tick,after:Tick.Tick,status:Status<Error>}
28 OperationObserved{identity:Identity,fact:Facts.Fact}
29 BarrierOperationObserved{fact:Facts.Fact}
30 ExecutionOperationObserved{fact:Facts.Fact}
31 SystemSkipped{id:U32}
32 DeferredApplied{}
33 ScheduleEnded{outcome:Completion<Error>}
34 ScheduleAdmissionRefused{namespace:U32,name:String,outcome:Completion<Error>}
35# Detached delivery value returned after execution. Disabled differs from an
36# enabled Ready batch with no events. No live reader or stream retention is held;
37# keeping or dropping a copied batch does not acknowledge an ECS event reader.
38type Batch<Error:Data> is Data:
39 Disabled{}
40 Ready{events:List<&2,TraceEvent<Error>>}
41
42# Each subscription is its actual affine state owner, not a copied callback.
43# The erased reusable step is supplied as a top-level definition.
44type Subscriber<State:Type,Error:Data,-step:State -> TraceEvent<Error> -> State> is Type:
45 Subscriber{state:State}
46# Wrap the supplied actual State owner with a reusable erased step definition.
47# This creates a local subscriber, not an ECS registration or automatic callback.
48def subscribe(~State:Type,~Error:Data,~step:State -> TraceEvent<Error> -> State,state:State) -> Subscriber<State,Error,step>:
49 Subscriber{state}
50# Consume the subscriber and return its actual State for reuse or explicit
51# disposal. No implicit user cleanup/destructor callback is invoked.
52def unsubscribe(~State:Type,~Error:Data,~step:State -> TraceEvent<Error> -> State,value:Subscriber<State,Error,step>) -> State:
53 match value:
54 case Subscriber{state}:state
55# Replace subscription state and return the displaced actual owner separately.
56# Neither owner is copied or silently restored into ECS storage.
57def reset(~State:Type,~Error:Data,~step:State -> TraceEvent<Error> -> State,value:Subscriber<State,Error,step>,incoming:State) -> Subscriber<State,Error,step> & State:
58 match value:
59 case Subscriber{state}:(Subscriber{incoming},state)
60def delivered(~State:Type,~Error:Data,~step:State -> TraceEvent<Error> -> State,events:List<&2,TraceEvent<Error>>,state:State) -> State:
61 match events:
62 case []:state
63 case event <> rest:delivered(~State,~Error,~step,rest,step(state,event))
64# Thread subscriber State through Ready events in list order; Disabled returns
65# the subscriber unchanged. Delivery is explicitly called after the ECS run.
66# Any external printing/file IO performed by a consumer is outside ECS rollback,
67# not an in-transaction observer. See examples/scheduled-health/application.bend.
68def deliver(~State:Type,~Error:Data,~step:State -> TraceEvent<Error> -> State,value:Subscriber<State,Error,step>,batch:Batch<Error>) -> Subscriber<State,Error,step>:
69 match value batch:
70 case subscriber Disabled{}:subscriber
71 case Subscriber{state} Ready{events}:Subscriber{delivered(~State,~Error,~step,events,state)}
72
73# Generic owner composition has no arity or subscriber-count bound. Order is
74# left then right; each reusable delivery function can itself be another pair.
75# Deliver the same detached batch to two actual owners, left then right, returning
76# both results. Compose this adapter recursively for additional subscribers; this
77# is owner composition, not a global subscription registry.
78def both(~Left:Type,~Right:Type,~Error:Data,~left:Left -> Batch<Error> -> Left,~right:Right -> Batch<Error> -> Right,value:Left & Right,+batch:Batch<Error>) -> Left & Right:
79 match value:
80 case (first,second):(left(first,batch),right(second,batch))