ordinary_system.bend
bendvy-ecs-core@0.1.0.1 · 114 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.1/change_tick.bend as Tick
3import bendvy-ecs-core@0.1.0.1/trace_facts.bend as TraceFacts
4import bendvy-ecs-core@0.1.0.1/ordinary_query_declaration.bend as Query
5import bendvy-ecs-core@0.1.0.1/compose.bend as Q
6import bendvy-ecs-core@0.1.0.1/world.bend as W
7import bendvy-ecs-core@0.1.0.1/system.bend as Sys
8import bendvy-ecs-core@0.1.0.1/transaction.bend as T
9import bendvy-ecs-core@0.1.0.1/ordinary_query_observable.bend as O
10import bendvy-ecs-core@0.1.0.1/inspector.bend as I
11
12# Retain clauses from the same declaration used to execute the registered body.
13# This is ordinary registration state, not a caller-supplied debug description.
14# Registered ordinary-query system owner retaining its actual Registry,
15# authored slot and clauses derived from the operational declaration.
16# Contains registration metadata, not a second user-authored debug schema.
17type Owner<-S:Data,-Registry:Type> is Type:
18 Owner{registry:Registry,slot:String,clauses:List<&2,Query.Clause<S>>}
19# Defined returns World and ordinary registration owner; Rejected returns
20# World on registration refusal. No system body is executed by definition.
21type Defined<-S:Data,-World:Type,-Registry:Type> is Type:
22 Defined{world:World,owner:Owner<S,Registry>}
23 Rejected{world:World}
24# Project ordered component names from declaration clauses as registration
25# access metadata. Does not validate runtime identity or grant payload access.
26def access(~S:Data,clauses:List<&2,Query.Clause<S>>) -> List<&2,String>:
27 match clauses:
28 case []:[]
29 case Query.Clause{name,_} <> rest:name <> access(~S,rest)
30
31def plan_parts(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>) -> Q.Plan<S,C,R,E,Ops>:
32 match declaration:
33 case Query.Declaration{grant,select,_}:Q.Plan{grant,select}
34# Lower a closed ordinary declaration into its operational query plan.
35# Grant and row predicate come from that declaration; this performs no scan.
36# Trusted setup must keep the declaration consistent with the body Ops.
37def plan(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out)) -> Q.Plan<S,C,R,E,Ops>:
38 plan_parts(~S,~C,~R,~E,~Ops,query)
39def completed(~S:Data,~C:Type,~R:Type,~E:Data,~U:Data,~Out:Data,result:Q.Executed<W.World<S,C,R,E>,Q.Error<U>,Out>) -> Sys.Outcome<W.World<S,C,R,E>,Q.Error<U>,List<&2,Out>>:
40 match result:
41 case Q.Executed{world,T.Success{},values}:Sys.Succeeded{world,values}
42 case Q.Executed{world,T.Failure{error},_}:Sys.Failed{world,error}
43# Lower-level query execution with Data arguments and explicit lifecycle
44# cursor. Runs the enclosing Compose transaction over selected rows; failure
45# reports query error and discards row outputs. This bypasses Registry checks;
46# use define/run or App registration for ordinary runtime-bound execution.
47def runner(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),world:W.World<S,C,R,E>,args:A & Maybe<&2,Tick.Tick>) -> Sys.Outcome<W.World<S,C,R,E>,Q.Error<U>,List<&2,Out>>:
48 match args:
49 case (args,cursor):completed(~S,~C,~R,~E,~U,~Out,Q.each_since(~S,~C,~R,~E,~Ops,~A,~U,~Out,~plan(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body),~body,args,world,cursor))
50def registered(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),slot:String,clauses:List<&2,Query.Clause<S>>,result:Sys.RegistrationResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)>) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)>>:
51 match result:
52 case Sys.RegistrationFailed{world}:Rejected{world}
53 case Sys.Registered{world,registry}:Defined{world,Owner{registry,slot,clauses}}
54# Register an ordinary query body with access derived from query clauses.
55# Returns Defined with World/owner, or Rejected with World. Does not execute
56# body or flush deferred commands. Schema/query/body indices must agree.
57# Application starting point: examples/scheduled-health/registration.bend.
58def define(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),world:W.World<S,C,R,E>,name:String,slot:String) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)>>:
59 registered(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body,slot,Query.clauses(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),query),Sys.register(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body),world,name,access(~S,Query.clauses(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),query))))
60def run_cursor(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),slot:String,clauses:List<&2,Query.Clause<S>>,observed:Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)> & Maybe<&2,Tick.Tick>,world:W.World<S,C,R,E>,args:A) -> Sys.RunResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)> & (String & List<&2,Query.Clause<S>>):
61 match observed:
62 case (registry,cursor):(Sys.run(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body),registry,world,(args,cursor)),(slot,clauses))
63# Execute the registered query using its retained lifecycle cursor.
64# Returns System.RunResult plus retained slot/clauses; Registry is inside
65# the RunResult and can be rewrapped as Owner. Success advances cursor to
66# the captured execution tick; completed failure consumes it too. Row transaction
67# rollback and deferred visibility follow Compose/explicit barriers.
68def run(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Query.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),owner:Owner<S,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)>>,world:W.World<S,C,R,E>,args:A) -> Sys.RunResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body)> & (String & List<&2,Query.Clause<S>>):
69 match owner:
70 case Owner{registry,slot,clauses}:run_cursor(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body,slot,clauses,Sys.cursor(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~query,~body),registry),world,args)
71
72# The same ordinary declaration also retains detached inspection lowering.
73# The Registry runner index retains this declaration; execution projects only
74# its operational part. Runtime-bound registered inspection is supplied by
75# the separate checked Inspector entry points, not this execution adapter.
76# Lower only the operational half of an observable query declaration.
77# Detached inspection remains separate; writes do not enter Inspector grants.
78def observable_plan(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out)) -> Q.Plan<S,C,R,E,Ops>:
79 plan_parts(~S,~C,~R,~E,~Ops,O.operational(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),~I.Frame<S,C,R,E>,~V,query))
80# Lower-level observable-declaration query runner with explicit cursor.
81# Executes operational grants in the Compose transaction; runtime registration
82# validation belongs to observable_run or the derived App dispatch path.
83def observable_runner(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),world:W.World<S,C,R,E>,args:A & Maybe<&2,Tick.Tick>) -> Sys.Outcome<W.World<S,C,R,E>,Q.Error<U>,List<&2,Out>>:
84 match args:
85 case (args,cursor):completed(~S,~C,~R,~E,~U,~Out,Q.each_since(~S,~C,~R,~E,~Ops,~A,~U,~Out,~observable_plan(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body),~body,args,world,cursor))
86def observable_registered(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),slot:String,clauses:List<&2,Query.Clause<S>>,result:Sys.RegistrationResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)>) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)>>:
87 match result:
88 case Sys.RegistrationFailed{world}:Rejected{world}
89 case Sys.Registered{world,registry}:Defined{world,Owner{registry,slot,clauses}}
90# Register from one observable declaration, deriving operational access
91# and retaining its typed runner. Returns Defined or Rejected with World.
92# Inspection is a separate read-only route; defining a system reads no rows.
93def observable_define(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),world:W.World<S,C,R,E>,name:String,slot:String) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)>>:
94 observable_registered(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body,slot,Query.clauses(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),O.operational(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),~I.Frame<S,C,R,E>,~V,query)),Sys.register(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body),world,name,access(~S,Query.clauses(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),O.operational(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),~I.Frame<S,C,R,E>,~V,query)))))
95def observable_run_cursor(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),slot:String,clauses:List<&2,Query.Clause<S>>,observed:Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)> & Maybe<&2,Tick.Tick>,world:W.World<S,C,R,E>,args:A) -> Sys.RunResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)> & (String & List<&2,Query.Clause<S>>):
96 match observed:
97 case (registry,cursor):(Sys.run(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body),registry,world,(args,cursor)),(slot,clauses))
98# Execute the runtime-bound observable query system and retain Registry
99# plus slot/clauses in the result. Uses its real cursor, advancing only on
100# success. Registration refusal returns unconsumed (args,cursor) with World.
101def observable_run(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),owner:Owner<S,Sys.Registry<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)>>,world:W.World<S,C,R,E>,args:A) -> Sys.RunResult<S,C,R,E,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body)> & (String & List<&2,Query.Clause<S>>):
102 match owner:
103 case Owner{registry,slot,clauses}:observable_run_cursor(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body,slot,clauses,Sys.cursor(~S,~C,~R,~E,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~observable_runner(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body),registry),world,args)
104
105def completed_observed(~S:Data,~C:Type,~R:Type,~E:Data,~U:Data,~Out:Data,result:Q.Executed<W.World<S,C,R,E>,Q.Error<U>,Out> & TraceFacts.State) -> Sys.Outcome<W.World<S,C,R,E>,Q.Error<U>,List<&2,Out>> & TraceFacts.State:
106 match result:
107 case (executed,trace):(completed(~S,~C,~R,~E,~U,~Out,executed),trace)
108
109# Trusted traced adapter for the same operational query/body and cursor.
110# Returns runner outcome with actual transaction facts; does not register
111# another system or consume detached Inspector visibility.
112def observable_runner_observed(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~V:Data,~query:O.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>),I.Frame<S,C,R,E>,V>,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & (T.Outcome<U> & Out),trace:TraceFacts.State,world:W.World<S,C,R,E>,args:A & Maybe<&2,Tick.Tick>) -> Sys.Outcome<W.World<S,C,R,E>,Q.Error<U>,List<&2,Out>> & TraceFacts.State:
113 match args:
114 case (args,cursor):completed_observed(~S,~C,~R,~E,~U,~Out,Q.each_since_observed(~S,~C,~R,~E,~Ops,~A,~U,~Out,~observable_plan(~S,~C,~R,~E,~Ops,~A,~U,~Out,~V,~query,~body),~body,trace,args,world,cursor))