inspector_query.bend

bendvy-ecs-core@0.1.0.0 · 271 lines · 0 definitions

1import Base
2import entity_key.bend as Key
3import inspector.bend as I
4import inspector_query_projection.bend as Q
5import world.bend as W
6import component.bend as C
7import column.bend as Col
8import capabilities.bend as Cap
9
10# Detached query results preserve the abstract owner and nominal entity schema.
11# This adapter adds the four methods of pinned System.QueryHandle. It does not
12# grant writes, construct a held mutable view, or choose foreign-instance policy.
13# Detached lookup refusal: MissingEntity includes dead/stale/foreign handles;
14# QueryMismatch means a live entity does not satisfy the declared selection.
15# entityId is a key for diagnostics, not a World authority.
16type LookupError is Data:
17  MissingEntity{entityId:Key.Key}
18  QueryMismatch{entityId:Key.Key}
19# Cardinality refusal: NoEntities for zero matches, MultipleEntities with
20# the actual Nat count for more than one. It carries no live payload owner.
21type SingleError is Data:
22  NoEntities{}
23  MultipleEntities{count:Nat}
24# Single-family read-only enumeration/lookup capability with one selection
25# mode. Rows are detached Data; raw construction must bind all operations to
26# the same family/mode. Runtime instance validation belongs to its outer wrapper.
27type ReadQuery<-H:Type,-S:Data,-V:Data> is Type:
28  ReadQuery{rows:Cap.ValueRead<H,List<&2,Q.Row<S,V>>>,lookup:I.Lookup<H,S,V>,selection:Q.Selection}
29
30def rows_field(~H:Type,~S:Data,~V:Data,cap:ReadQuery<H,S,V>) -> Cap.ValueRead<H,List<&2,Q.Row<S,V>>>:
31  match cap:
32    case ReadQuery{rows,_,_}:rows
33def lookup_field(~H:Type,~S:Data,~V:Data,cap:ReadQuery<H,S,V>) -> I.Lookup<H,S,V>:
34  match cap:
35    case ReadQuery{_,lookup,_}:lookup
36def selection_field(~H:Type,~S:Data,~V:Data,cap:ReadQuery<H,S,V>) -> Q.Selection:
37  match cap:
38    case ReadQuery{_,_,selection}:selection
39# Enumerate selected detached rows while returning opaque owner H.
40# Canonical grants preserve live-handle traversal order and expose no setters.
41def each(~H:Type,~S:Data,~V:Data,~cap:ReadQuery<H,S,V>,owner:H) -> H & List<&2,Q.Row<S,V>>:
42  Cap.value_read(~H,~List<&2,Q.Row<S,V>>,~rows_field(~H,~S,~V,cap),owner)
43
44def selected(~S:Data,~V:Data,accepted:Bool,+target:W.Handle<S>,value:I.Value<V>) -> Result<&2,&2,LookupError,Q.Row<S,V>>:
45  match accepted target:
46    case True{} target:Done{Q.Row{target,value}}
47    case False{} W.Handle{_,id}:Fail{QueryMismatch{id}}
48def resolved(~S:Data,~V:Data,selection:Q.Selection,+target:W.Handle<S>,value:I.Value<V>) -> Result<&2,&2,LookupError,Q.Row<S,V>>:
49  match target value:
50    case W.Handle{_,id} I.Value{C.MissingEntity{},_,_}:Fail{MissingEntity{id}}
51    case target +value:selected(~S,~V,Q.accepts(~V,selection,value),target,value)
52def got(~H:Type,~S:Data,~V:Data,selection:Q.Selection,target:W.Handle<S>,result:H & I.Value<V>) -> H & Result<&2,&2,LookupError,Q.Row<S,V>>:
53  (owner,value)=result
54  (owner,resolved(~S,~V,selection,target,value))
55# Look up a target through the same declared selection as enumeration.
56# Returns H with Done row, MissingEntity or QueryMismatch. Canonical lookup
57# rejects stale/foreign handles before treating absence as optional membership.
58def get(~H:Type,~S:Data,~V:Data,~cap:ReadQuery<H,S,V>,owner:H,+target:W.Handle<S>) -> H & Result<&2,&2,LookupError,Q.Row<S,V>>:
59  got(~H,~S,~V,selection_field(~H,~S,~V,cap),target,I.lookup(~H,~S,~V,~lookup_field(~H,~S,~V,cap),owner,target))
60
61def single_rows(~S:Data,~V:Data,rows:List<&2,Q.Row<S,V>>) -> Result<&2,&2,SingleError,Q.Row<S,V>>:
62  match rows:
63    case []:Fail{NoEntities{}}
64    case row <> []:Done{row}
65    case _ <> _ <> rest:Fail{MultipleEntities{Nat.add(2n,List.length(&2,Q.Row<S,V>,rest))}}
66def single_observed(~H:Type,~S:Data,~V:Data,result:H & List<&2,Q.Row<S,V>>) -> H & Result<&2,&2,SingleError,Q.Row<S,V>>:
67  (owner,rows)=result
68  (owner,single_rows(~S,~V,rows))
69# Return H and exactly one detached row, or NoEntities/MultipleEntities.
70# Does not pick an arbitrary first row when the query matches multiple entities.
71def single(~H:Type,~S:Data,~V:Data,~cap:ReadQuery<H,S,V>,owner:H) -> H & Result<&2,&2,SingleError,Q.Row<S,V>>:
72  single_observed(~H,~S,~V,each(~H,~S,~V,~cap,owner))
73def optional_rows(~S:Data,~V:Data,rows:List<&2,Q.Row<S,V>>) -> Result<&2,&2,SingleError,Maybe<&2,Q.Row<S,V>>>:
74  match rows:
75    case []:Done{None{}}
76    case row <> []:Done{Some{row}}
77    case _ <> _ <> rest:Fail{MultipleEntities{Nat.add(2n,List.length(&2,Q.Row<S,V>,rest))}}
78def optional_observed(~H:Type,~S:Data,~V:Data,result:H & List<&2,Q.Row<S,V>>) -> H & Result<&2,&2,SingleError,Maybe<&2,Q.Row<S,V>>>:
79  (owner,rows)=result
80  (owner,optional_rows(~S,~V,rows))
81# Return H and None for zero matches, Some row for one, or MultipleEntities
82# for more than one. Empty is a successful result, unlike single.
83def single_optional(~H:Type,~S:Data,~V:Data,~cap:ReadQuery<H,S,V>,owner:H) -> H & Result<&2,&2,SingleError,Maybe<&2,Q.Row<S,V>>>:
84  optional_observed(~H,~S,~V,each(~H,~S,~V,~cap,owner))
85
86# Trusted setup binds enumeration and exact lookup to the same family/mode.
87# Trusted setup binding enumeration and lookup to one component family/mode.
88# Projection must return the affine payload owner alongside Data V. Does not
89# execute a query or advance registered system cursors while constructing it.
90def grant(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~project:Payload -> Payload & V,~family:C.Family<S,Store,Rest,Payload,V,Token,take,put,project>,~mode:Q.Selection) -> ReadQuery<I.Frame<S,Store,R,E>,S,V>:
91  ReadQuery{Q.read_query(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~project,~family,~mode),I.read_family(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~project,~family),mode}
92
93# Generic declaration composition; existing single-family API stays compatible.
94# Detached heterogeneous projection paired with its schema-scoped entity
95# handle. Does not contain a mutable view or an affine component owner.
96type ProjectedRow<S:Data,V:Data> is Data:
97  ProjectedRow{entity:W.Handle<S>,data:V}
98# Trusted closed live-handle enumeration/validity operations for composed
99# queries. Raw callbacks must correspond to the same runtime World and thread H;
100# metadata or schema type alone is not a runtime validation check.
101type WorldRead<-H:Type,-S:Data> is Type:
102  WorldRead{handles:H -> H & List<&2,W.Handle<S>>,valid:H -> W.Handle<S> -> H & Bool}
103# Read-only query over arbitrary declared projection shapes, with matching
104# enumeration and target lookup. Owns operations, not a runtime World;
105# canonical grants provide checked targets and detached values.
106type ComposedReadQuery<-H:Type,-S:Data,-V:Data> is Type:
107  ComposedReadQuery{each_composed:H -> H & List<&2,ProjectedRow<S,V>>,get_composed:H -> W.Handle<S> -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>}
108def composed_handles_field(~H:Type,~S:Data,value:WorldRead<H,S>) -> H -> H & List<&2,W.Handle<S>>:
109  match value:
110    case WorldRead{handles,_}:handles
111def composed_valid_field(~H:Type,~S:Data,value:WorldRead<H,S>) -> H -> W.Handle<S> -> H & Bool:
112  match value:
113    case WorldRead{_,valid}:valid
114def composed_each_field(~H:Type,~S:Data,~V:Data,value:ComposedReadQuery<H,S,V>) -> H -> H & List<&2,ProjectedRow<S,V>>:
115  match value:
116    case ComposedReadQuery{each_composed,_}:each_composed
117def composed_get_field(~H:Type,~S:Data,~V:Data,value:ComposedReadQuery<H,S,V>) -> H -> W.Handle<S> -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
118  match value:
119    case ComposedReadQuery{_,get_composed}:get_composed
120# Enumerate matching projected rows, returning the opaque owner.
121# Canonical enumeration preserves its World handle order and projection shape.
122def each_composed(~H:Type,~S:Data,~V:Data,~cap:ComposedReadQuery<H,S,V>,owner:H) -> H & List<&2,ProjectedRow<S,V>>:
123  composed_each_field(~H,~S,~V,cap)(owner)
124# Return H with detached projection or MissingEntity/QueryMismatch.
125# The canonical grant checks live target validity before selection/projection;
126# no component write operation or payload owner is returned.
127def get_composed(~H:Type,~S:Data,~V:Data,~cap:ComposedReadQuery<H,S,V>,owner:H,target:W.Handle<S>) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
128  composed_get_field(~H,~S,~V,cap)(owner,target)
129def composed_single_rows(~S:Data,~V:Data,rows:List<&2,ProjectedRow<S,V>>) -> Result<&2,&2,SingleError,ProjectedRow<S,V>>:
130  match rows:
131    case []:Fail{NoEntities{}}
132    case row <> []:Done{row}
133    case _ <> _ <> rest:Fail{MultipleEntities{Nat.add(2n,List.length(&2,ProjectedRow<S,V>,rest))}}
134def composed_single_observed(~H:Type,~S:Data,~V:Data,observed:H & List<&2,ProjectedRow<S,V>>) -> H & Result<&2,&2,SingleError,ProjectedRow<S,V>>:
135  (owner,rows)=observed
136  (owner,composed_single_rows(~S,~V,rows))
137# Require exactly one composed row; zero yields NoEntities and multiple
138# yields MultipleEntities with full count. Retains owner H on every result.
139def single_composed(~H:Type,~S:Data,~V:Data,~cap:ComposedReadQuery<H,S,V>,owner:H) -> H & Result<&2,&2,SingleError,ProjectedRow<S,V>>:
140  composed_single_observed(~H,~S,~V,each_composed(~H,~S,~V,~cap,owner))
141def composed_optional_rows(~S:Data,~V:Data,rows:List<&2,ProjectedRow<S,V>>) -> Result<&2,&2,SingleError,Maybe<&2,ProjectedRow<S,V>>>:
142  match rows:
143    case []:Done{None{}}
144    case row <> []:Done{Some{row}}
145    case _ <> _ <> rest:Fail{MultipleEntities{Nat.add(2n,List.length(&2,ProjectedRow<S,V>,rest))}}
146def composed_optional_observed(~H:Type,~S:Data,~V:Data,observed:H & List<&2,ProjectedRow<S,V>>) -> H & Result<&2,&2,SingleError,Maybe<&2,ProjectedRow<S,V>>>:
147  (owner,rows)=observed
148  (owner,composed_optional_rows(~S,~V,rows))
149# Return None for zero composed rows or Some for exactly one; multiple
150# matches return MultipleEntities. Retains H and never selects an arbitrary row.
151def single_optional_composed(~H:Type,~S:Data,~V:Data,~cap:ComposedReadQuery<H,S,V>,owner:H) -> H & Result<&2,&2,SingleError,Maybe<&2,ProjectedRow<S,V>>>:
152  composed_optional_observed(~H,~S,~V,each_composed(~H,~S,~V,~cap,owner))
153
154# One declaration is used for both structural/lifecycle membership paths.
155def composed_lookup_projected(~H:Type,~S:Data,~V:Data,target:W.Handle<S>,observed:H & V) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
156  (owner,value)=observed
157  (owner,Done{ProjectedRow{target,value}})
158def composed_mismatched(~H:Type,~S:Data,~V:Data,target:W.Handle<S>,owner:H) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
159  match target:
160    case W.Handle{_,id}:(owner,Fail{QueryMismatch{id}})
161def composed_missing(~H:Type,~S:Data,~V:Data,target:W.Handle<S>,owner:H) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
162  match target:
163    case W.Handle{_,id}:(owner,Fail{MissingEntity{id}})
164def composed_lookup_matched(~H:Type,~S:Data,~V:Data,project:H -> W.Handle<S> -> H & V,+target:W.Handle<S>,observed:H & Bool) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
165  match observed:
166    case (owner,False{}):composed_mismatched(~H,~S,~V,target,owner)
167    case (owner,True{}):composed_lookup_projected(~H,~S,~V,target,project(owner,target))
168def composed_lookup_valid(~H:Type,~S:Data,~V:Data,matches:H -> W.Handle<S> -> H & Bool,project:H -> W.Handle<S> -> H & V,+target:W.Handle<S>,observed:H & Bool) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
169  match observed:
170    case (owner,False{}):composed_missing(~H,~S,~V,target,owner)
171    case (owner,True{}):composed_lookup_matched(~H,~S,~V,project,target,matches(owner,target))
172def composed_lookup_target(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,~world:WorldRead<H,S>,owner:H,+target:W.Handle<S>) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
173  composed_lookup_valid(~H,~S,~V,Q.matches_field(~H,~S,~V,selection),Q.project_field(~H,~S,~V,selection),target,composed_valid_field(~H,~S,world)(owner,target))
174def composed_lookup(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,~world:WorldRead<H,S>,owner:H,target:W.Handle<S>) -> H & Result<&2,&2,LookupError,ProjectedRow<S,V>>:
175  composed_lookup_target(~H,~S,~V,~selection,~world,owner,target)
176
177# Private recursive result ABI; public query authority and result types unchanged.
178# Advanced scan accumulator result retaining H and detached projected rows.
179# This carrier adds no target validation beyond the chosen scan/selection route.
180type ScanResult<-H:Type,-S:Data,-V:Data> is Type:
181  ScanResult{owner:H,rows:List<&2,ProjectedRow<S,V>>}
182  ScanResultLink{next:ScanResult<H,S,V>}
183def composed_unwrap_scan(~H:Type,~S:Data,~V:Data,result:ScanResult<H,S,V>) -> H & List<&2,ProjectedRow<S,V>>:
184  match result:
185    case ScanResult{owner,rows}:(owner,rows)
186    case ScanResultLink{next}:composed_unwrap_scan(~H,~S,~V,next)
187
188def composed_fold_projected(~H:Type,~S:Data,~V:Data,target:W.Handle<S>,rows:List<&2,ProjectedRow<S,V>>,observed:H & V) -> H & List<&2,ProjectedRow<S,V>>:
189  (owner,value)=observed
190  (owner,ProjectedRow{target,value} <> rows)
191def composed_fold_matched(~H:Type,~S:Data,~V:Data,~project:H -> W.Handle<S> -> H & V,+target:W.Handle<S>,rows:List<&2,ProjectedRow<S,V>>,observed:H & Bool) -> H & List<&2,ProjectedRow<S,V>>:
192  match observed:
193    case (owner,False{}):(owner,rows)
194    case (owner,True{}):composed_fold_projected(~H,~S,~V,target,rows,project(owner,target))
195def composed_fold_step(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,acc:H & List<&2,ProjectedRow<S,V>>,+target:W.Handle<S>) -> H & List<&2,ProjectedRow<S,V>>:
196  (owner,rows)=acc
197  composed_fold_matched(~H,~S,~V,~Q.project_field(~H,~S,~V,selection),target,rows,Q.matches_field(~H,~S,~V,selection)(owner,target))
198def composed_fold_done(~H:Type,~S:Data,~V:Data,observed:H & List<&2,ProjectedRow<S,V>>) -> ScanResult<H,S,V>:
199  (owner,rows)=observed
200  ScanResult{owner,List.reverse(&2,ProjectedRow<S,V>,rows)}
201# Engine scan adapter over supplied targets and a reversed row accumulator.
202# Canonical callers supply live targets and an empty initial accumulator.
203# This helper does not independently validate arbitrary handles; prefer
204# each_composed on a canonical composed grant for application inspection.
205def composed_scan(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,targets:List<&2,W.Handle<S>>,owner:H,rows:List<&2,ProjectedRow<S,V>>) -> ScanResult<H,S,V>:
206  composed_fold_done(~H,~S,~V,List.foldl(~&2,~W.Handle<S>,~(H & List<&2,ProjectedRow<S,V>>),~(acc => target => composed_fold_step(~H,~S,~V,~selection,acc,target)),targets,(owner,rows)))
207def composed_scanned(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,observed:H & List<&2,W.Handle<S>>) -> H & List<&2,ProjectedRow<S,V>>:
208  (owner,targets)=observed
209  composed_unwrap_scan(~H,~S,~V,composed_scan(~H,~S,~V,~selection,targets,owner,[]))
210def composed_enumerate(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,~world:WorldRead<H,S>,owner:H) -> H & List<&2,ProjectedRow<S,V>>:
211  composed_scanned(~H,~S,~V,~selection,composed_handles_field(~H,~S,world)(owner))
212# Trusted constructor combining matching WorldRead and declared selection.
213# Target lookup validates before matching/projecting; enumeration uses the
214# supplied live-handle route. Callbacks must preserve owner correspondence.
215# Source-level composition: ordinary-query-observable.inspect_query.
216def grant_composed(~H:Type,~S:Data,~V:Data,~selection:Q.DeclaredSelection<H,S,V>,~world:WorldRead<H,S>) -> ComposedReadQuery<H,S,V>:
217  ComposedReadQuery{owner => composed_enumerate(~H,~S,~V,~selection,~world,owner),owner => target => composed_lookup(~H,~S,~V,~selection,~world,owner,target)}
218
219# Runtime-data composed relation path. Static component authority remains a
220# DeclaredSelection Type, while a Data relation argument is shared by the
221# query's enumeration and lookup closures. The two static relation workers
222# preserve the existing short-circuit and projection order without storing or
223# duplicating affine closures.
224def composed_runtime_match_right(~H:Type,~S:Data,~A:Data,~Arg:Data,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,+target:W.Handle<S>,argument:Arg,observed:H & Bool) -> H & Bool:
225  match observed:
226    case (owner,False{}):(owner,False{})
227    case (owner,True{}):relation_matches(argument,owner,target)
228def composed_runtime_matches_target(~H:Type,~S:Data,~A:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,+target:W.Handle<S>,argument:Arg,owner:H) -> H & Bool:
229  composed_runtime_match_right(~H,~S,~A,~Arg,~relation_matches,target,argument,Q.matches_field(~H,~S,~A,component)(owner,target))
230def composed_runtime_projected_right(~H:Type,~A:Data,~B:Data,left:A,observed:H & B) -> H & Q.Product<A,B>:
231  (owner,right)=observed
232  (owner,Q.Product{left,right})
233def composed_runtime_projected_left(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+target:W.Handle<S>,argument:Arg,observed:H & A) -> H & Q.Product<A,B>:
234  (owner,left)=observed
235  composed_runtime_projected_right(~H,~A,~B,left,relation_project(argument,owner,target))
236def composed_runtime_project(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+target:W.Handle<S>,argument:Arg,owner:H) -> H & Q.Product<A,B>:
237  composed_runtime_projected_left(~H,~S,~A,~B,~Arg,~relation_project,target,argument,Q.project_field(~H,~S,~A,component)(owner,target))
238def composed_runtime_scan_projected(~H:Type,~S:Data,~A:Data,~B:Data,+target:W.Handle<S>,rows:List<&2,ProjectedRow<S,Q.Product<A,B>>>,continue:H -> List<&2,ProjectedRow<S,Q.Product<A,B>>> -> ScanResult<H,S,Q.Product<A,B>>,observed:H & Q.Product<A,B>) -> ScanResult<H,S,Q.Product<A,B>>:
239  (owner,value)=observed
240  continue(owner,ProjectedRow{target,value} <> rows)
241def composed_runtime_scan_matched(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+target:W.Handle<S>,rows:List<&2,ProjectedRow<S,Q.Product<A,B>>>,continue:H -> List<&2,ProjectedRow<S,Q.Product<A,B>>> -> ScanResult<H,S,Q.Product<A,B>>,argument:Arg,observed:H & Bool) -> ScanResult<H,S,Q.Product<A,B>>:
242  match observed:
243    case (owner,False{}):continue(owner,rows)
244    case (owner,True{}):composed_runtime_scan_projected(~H,~S,~A,~B,target,rows,continue,composed_runtime_project(~H,~S,~A,~B,~Arg,~component,~relation_project,target,argument,owner))
245def composed_runtime_scan(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,targets:List<&2,W.Handle<S>>,+argument:Arg,owner:H,rows:List<&2,ProjectedRow<S,Q.Product<A,B>>>) -> ScanResult<H,S,Q.Product<A,B>>:
246  match targets:
247    case []:ScanResult{owner,List.reverse(&2,ProjectedRow<S,Q.Product<A,B>>,rows)}
248    case +target <> rest:composed_runtime_scan_matched(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,target,rows,(owner => rows => composed_runtime_scan(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,rest,argument,owner,rows)),argument,composed_runtime_matches_target(~H,~S,~A,~Arg,~component,~relation_matches,target,argument,owner))
249def composed_runtime_scanned(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,observed:H & List<&2,W.Handle<S>>,+argument:Arg) -> H & List<&2,ProjectedRow<S,Q.Product<A,B>>>:
250  (owner,targets)=observed
251  composed_unwrap_scan(~H,~S,~Q.Product<A,B>,composed_runtime_scan(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,targets,argument,owner,[]))
252def composed_runtime_enumerate(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,~world:WorldRead<H,S>,argument:Arg,owner:H) -> H & List<&2,ProjectedRow<S,Q.Product<A,B>>>:
253  composed_runtime_scanned(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,composed_handles_field(~H,~S,world)(owner),argument)
254def composed_runtime_lookup_selected(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+target:W.Handle<S>,argument:Arg,observed:H & Bool) -> H & Result<&2,&2,LookupError,ProjectedRow<S,Q.Product<A,B>>>:
255  match observed:
256    case (owner,False{}):composed_mismatched(~H,~S,~Q.Product<A,B>,target,owner)
257    case (owner,True{}):composed_lookup_projected(~H,~S,~Q.Product<A,B>,target,composed_runtime_project(~H,~S,~A,~B,~Arg,~component,~relation_project,target,argument,owner))
258def composed_runtime_lookup_valid(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+target:W.Handle<S>,+argument:Arg,observed:H & Bool) -> H & Result<&2,&2,LookupError,ProjectedRow<S,Q.Product<A,B>>>:
259  match observed:
260    case (owner,False{}):composed_missing(~H,~S,~Q.Product<A,B>,target,owner)
261    case (owner,True{}):composed_runtime_lookup_selected(~H,~S,~A,~B,~Arg,~component,~relation_project,target,argument,composed_runtime_matches_target(~H,~S,~A,~Arg,~component,~relation_matches,target,argument,owner))
262def composed_runtime_lookup_target(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,~world:WorldRead<H,S>,owner:H,+target:W.Handle<S>,argument:Arg) -> H & Result<&2,&2,LookupError,ProjectedRow<S,Q.Product<A,B>>>:
263  composed_runtime_lookup_valid(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,target,argument,composed_valid_field(~H,~S,world)(owner,target))
264def composed_runtime_lookup(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,~world:WorldRead<H,S>,owner:H,target:W.Handle<S>,argument:Arg) -> H & Result<&2,&2,LookupError,ProjectedRow<S,Q.Product<A,B>>>:
265  composed_runtime_lookup_target(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,~world,owner,target,argument)
266# Advanced composed query adding a runtime argument/relation selection to
267# the component projection. Retains H while combining detached results; trusted
268# World and selection callbacks must refer to the same runtime. Does not
269# register a reader, consume a system cursor or expose mutation authority.
270def grant_composed_runtime(~H:Type,~S:Data,~A:Data,~B:Data,~Arg:Data,~component:Q.DeclaredSelection<H,S,A>,~world:WorldRead<H,S>,~relation_matches:Arg -> H -> W.Handle<S> -> H & Bool,~relation_project:Arg -> H -> W.Handle<S> -> H & B,+argument:Arg) -> ComposedReadQuery<H,S,Q.Product<A,B>>:
271  ComposedReadQuery{owner => composed_runtime_enumerate(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,~world,argument,owner),owner => target => composed_runtime_lookup(~H,~S,~A,~B,~Arg,~component,~relation_matches,~relation_project,~world,owner,target,argument)}