ordinary_app_execution_recipe.bend
bendvy-ecs-core@0.1.0.1 · 116 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.1/ordinary_app_composer.bend as Build
3import bendvy-ecs-core@0.1.0.1/ordinary_app_records.bend as Leaf
4import bendvy-ecs-core@0.1.0.1/ordinary_app_registration_fields.bend as Records
5import bendvy-ecs-core@0.1.0.1/ordinary_app_observation_data.bend as DTO
6import bendvy-ecs-core@0.1.0.1/execution_context.bend as Ctx
7import bendvy-ecs-core@0.1.0.1/system.bend as Sys
8import bendvy-ecs-core@0.1.0.1/schedule_provision.bend as SP
9import bendvy-ecs-core@0.1.0.1/schedule.bend as Sch
10import bendvy-ecs-core@0.1.0.1/captured_schedule_composition.bend as Identity
11
12# Advanced erased execution recipe retaining plan/dispatch/provision types, not
13# a second runtime owner bundle. Actual owners remain in Registered.app. Closed
14# callbacks are trusted setup, not authority inferred from a Data plan or id.
15type Recipe<S:Data,World:Type,Owners:Type,Error:Data,-plan:Owners -> Owners & SP.Plan<S>,-dispatch:Owners -> Ctx.Context<World> -> U32 -> Owners & Sys.Outcome<Ctx.Context<World>,Error,Unit>,-provide:World -> World & List<&2,SP.Requirement<S>>> is Type:
16 Recipe{}
17# Execution-enabled App pairing the actual composer App with its typed Recipe.
18# World, registrations and affine Local/capture state are retained in app; this
19# wrapper alone neither dispatches a system nor validates arbitrary callbacks.
20type Registered<S:Data,World:Type,Owners:Type,Rows:Data,-observe:World -> World & DTO.Observation<Rows>,-fold:Owners -> Owners & List<&2,Records.Fields<S>>,Error:Data,-plan:Owners -> Owners & SP.Plan<S>,-dispatch:Owners -> Ctx.Context<World> -> U32 -> Owners & Sys.Outcome<Ctx.Context<World>,Error,Unit>,-provide:World -> World & List<&2,SP.Requirement<S>>> is Type:
21 Registered{app:Build.Registered<S,World,Owners,Rows,observe,fold>,execution:Recipe<S,World,Owners,Error,plan,dispatch,provide>}
22# Advanced metadata conversion retaining namespace/id/name/ordered access.
23# Does not inspect payloads or turn presentation metadata into gameplay grants.
24def identities(~S:Data,fields:List<&2,Records.Fields<S>>) -> List<&2,Identity.Identity>:
25 match fields:
26 case []:[]
27 case Records.Fields{namespace,id,name,access,_,_,_,_} <> rest:Identity.Identity{namespace,id,name,access} <> identities(~S,rest)
28# Extract the recorded system id without validating its World or runner owner.
29def registration_id(~S:Data,fields:Records.Fields<S>) -> U32:
30 match fields:
31 case Records.Fields{_,id,_,_,_,_,_,_}:id
32# Advanced dispatch-routing membership test by id against supplied field records.
33# Not a namespace/provenance or capability check for arbitrary forged records.
34def member(~S:Data,fields:List<&2,Records.Fields<S>>,id:U32) -> Bool:
35 Identity.member(identities(~S,fields),id)
36# Empty execution setup: retain Unit owner and return SP.Empty, with no steps.
37def empty_plan(~S:Data,owner:Unit) -> Unit & SP.Plan<S>:
38 (owner,SP.Empty{})
39# Empty provisioning returns World unchanged and no schedule requirements.
40def empty_provide(~S:Data,~World:Type,world:World) -> World & List<&2,SP.Requirement<S>>:
41 (world,[])
42# Empty dispatcher retains owner/context and returns Sys.Failed(Unit) for every
43# id. It never treats an unknown id as a successfully executed empty system.
44def empty_dispatch(~World:Type,owner:Unit,world:Ctx.Context<World>,id:U32) -> Unit & Sys.Outcome<Ctx.Context<World>,Unit,Unit>:
45 (owner,Sys.Failed{world,Unit{}})
46# Start an empty execution-enabled App with debug disabled and no steps or
47# requirements. Does not execute empty_dispatch or register a runner.
48def empty(~S:Data,~World:Type,world:World) -> Registered<S,World,Unit,Unit,Build.empty_observe(~World),Leaf.empty(~S),Unit,empty_plan(~S),empty_dispatch(~World),empty_provide(~S,~World)>:
49 Registered{Build.empty(~S,~World,world),Recipe{}}
50def plan_right(~S:Data,~L:Type,~R:Type,left:L,before:SP.Plan<S>,result:R & SP.Plan<S>) -> (L & R) & SP.Plan<S>:
51 match result:
52 case (right,after):((left,right),SP.Sequence{before,after})
53def plan_left(~S:Data,~L:Type,~R:Type,~right:R -> R & SP.Plan<S>,owner:R,result:L & SP.Plan<S>) -> (L & R) & SP.Plan<S>:
54 match result:
55 case (left,before):plan_right(~S,~L,~R,left,before,right(owner))
56# Advanced ordered plan composition: call left then right with their respective
57# actual owners, returning both owners and SP.Sequence(before,after). No scheduling
58# conflict or registration validation is added by this adapter.
59def plan_pair(~S:Data,~L:Type,~R:Type,~left:L -> L & SP.Plan<S>,~right:R -> R & SP.Plan<S>,owners:L & R) -> (L & R) & SP.Plan<S>:
60 match owners:
61 case (a,b):plan_left(~S,~L,~R,~right,b,left(a))
62def provision_right(~S:Data,~World:Type,before:List<&2,SP.Requirement<S>>,result:World & List<&2,SP.Requirement<S>>) -> World & List<&2,SP.Requirement<S>>:
63 match result:
64 case (world,after):(world,List.append(&2,SP.Requirement<S>,before,after))
65def provision_left(~S:Data,~World:Type,~right:World -> World & List<&2,SP.Requirement<S>>,result:World & List<&2,SP.Requirement<S>>) -> World & List<&2,SP.Requirement<S>>:
66 match result:
67 case (world,before):provision_right(~S,~World,before,right(world))
68# Advanced requirement composition threading the World through left then right.
69# Concatenate requirements in that order; callbacks must return their actual World.
70# This does not grant gameplay access from requirement strings.
71def provision_pair(~S:Data,~World:Type,~left:World -> World & List<&2,SP.Requirement<S>>,~right:World -> World & List<&2,SP.Requirement<S>>,world:World) -> World & List<&2,SP.Requirement<S>>:
72 provision_left(~S,~World,~right,left(world))
73def left_outcome(~World:Type,~LE:Data,~RE:Data,outcome:Sys.Outcome<Ctx.Context<World>,LE,Unit>) -> Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
74 match outcome:
75 case Sys.Succeeded{world,output}:Sys.Succeeded{world,output}
76 case Sys.Failed{world,error}:Sys.Failed{world,Identity.LeftError{error}}
77def right_outcome(~World:Type,~LE:Data,~RE:Data,outcome:Sys.Outcome<Ctx.Context<World>,RE,Unit>) -> Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
78 match outcome:
79 case Sys.Succeeded{world,output}:Sys.Succeeded{world,output}
80 case Sys.Failed{world,error}:Sys.Failed{world,Identity.RightError{error}}
81def left_returned(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,right:R,result:L & Sys.Outcome<Ctx.Context<World>,LE,Unit>) -> (L & R) & Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
82 match result:
83 case (left,outcome):((left,right),left_outcome(~World,~LE,~RE,outcome))
84def right_returned(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,left:L,result:R & Sys.Outcome<Ctx.Context<World>,RE,Unit>) -> (L & R) & Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
85 match result:
86 case (right,outcome):((left,right),right_outcome(~World,~LE,~RE,outcome))
87def dispatch_selected(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~left:L -> Ctx.Context<World> -> U32 -> L & Sys.Outcome<Ctx.Context<World>,LE,Unit>,~right:R -> Ctx.Context<World> -> U32 -> R & Sys.Outcome<Ctx.Context<World>,RE,Unit>,found:Bool,a:L,b:R,world:Ctx.Context<World>,id:U32) -> (L & R) & Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
88 match found:
89 case True{}:left_returned(~World,~L,~R,~LE,~RE,b,left(a,world,id))
90 case False{}:right_returned(~World,~L,~R,~LE,~RE,a,right(b,world,id))
91def dispatch_folded(~S:Data,~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~left:L -> Ctx.Context<World> -> U32 -> L & Sys.Outcome<Ctx.Context<World>,LE,Unit>,~right:R -> Ctx.Context<World> -> U32 -> R & Sys.Outcome<Ctx.Context<World>,RE,Unit>,b:R,world:Ctx.Context<World>,+id:U32,result:L & List<&2,Records.Fields<S>>) -> (L & R) & Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
92 match result:
93 case (a,fields):dispatch_selected(~World,~L,~R,~LE,~RE,~left,~right,member(~S,fields,id),a,b,world,id)
94# Advanced owner-preserving routing: fold left metadata, dispatch left if its id
95# is present, otherwise delegate to right. Return both actual owners and tag failed
96# outcomes LeftError/RightError. This is not two-system execution, global duplicate
97# id validation or an extra transaction; each dispatcher supplies its own contract.
98def dispatch_pair(~S:Data,~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~fold:L -> L & List<&2,Records.Fields<S>>,~left:L -> Ctx.Context<World> -> U32 -> L & Sys.Outcome<Ctx.Context<World>,LE,Unit>,~right:R -> Ctx.Context<World> -> U32 -> R & Sys.Outcome<Ctx.Context<World>,RE,Unit>,owners:L & R,world:Ctx.Context<World>,id:U32) -> (L & R) & Sys.Outcome<Ctx.Context<World>,Identity.Choice<LE,RE>,Unit>:
99 match owners:
100 case (a,b):dispatch_folded(~S,~World,~L,~R,~LE,~RE,~left,~right,b,world,id,fold(a))
101# Affine registered invocation owner retaining its actual token, Data arguments
102# and latest detached row outputs. Field metadata alone cannot reconstruct token
103# or guarantee authority; ordinary App runners define output/refusal updates.
104type Invocation<S:Data,Token:Type,Args:Data,Out:Data> is Type:
105 Invocation{record:Leaf.Record<S,Token>,args:Args,outputs:List<&2,Out>}
106# Advanced owner-returning fold exposing this invocation's single field record.
107# Arguments, outputs and actual token remain retained unchanged.
108def invocation_fields(~S:Data,~Token:Type,~Args:Data,~Out:Data,value:Invocation<S,Token,Args,Out>) -> Invocation<S,Token,Args,Out> & List<&2,Records.Fields<S>>:
109 match value:
110 case Invocation{Leaf.Record{token,+fields},args,outputs}:(Invocation{Leaf.Record{token,fields},args,outputs},[fields])
111# Advanced owner-returning plan for this registered id: one System step with
112# condition slot zero and no requirements. Does not derive requirement grants from
113# field access metadata, invoke gameplay or change retained invocation outputs.
114def invocation_plan(~S:Data,~Token:Type,~Args:Data,~Out:Data,value:Invocation<S,Token,Args,Out>) -> Invocation<S,Token,Args,Out> & SP.Plan<S>:
115 match value:
116 case Invocation{Leaf.Record{token,Records.Fields{+namespace,+id,+name,+access,+cursor,+slot,+clauses,+kind}},args,outputs}:(Invocation{Leaf.Record{token,Records.Fields{namespace,id,name,access,cursor,slot,clauses,kind}},args,outputs},SP.Entry{Sch.System{id,0},[]})