ordinary_app_relation.bend

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

1import Base
2import entity_key_render.bend as KeyText
3import bendvy-ecs-core@0.1.0.0/ordinary_app_composer.bend as Build
4import bendvy-ecs-core@0.1.0.0/ordinary_app_recipe.bend as Tree
5import bendvy-ecs-core@0.1.0.0/ordinary_app_observation_data.bend as DTO
6import bendvy-ecs-core@0.1.0.0/ordinary_app_registration_fields.bend as Fields
7import bendvy-ecs-core@0.1.0.0/world.bend as W
8import bendvy-ecs-core@0.1.0.0/inspector.bend as I
9import bendvy-ecs-core@0.1.0.0/relation_failure_reader.bend as Ord
10import bendvy-ecs-core@0.1.0.0/relation_types.bend as G
11import bendvy-ecs-core@0.1.0.0/relation_commands.bend as A
12import bendvy-ecs-core@0.1.0.0/relation_query.bend as RQ
13import bendvy-ecs-core@0.1.0.0/relation_providers.bend as P
14import bendvy-ecs-core@0.1.0.0/inspector_relation_projection.bend as IR
15import bendvy-ecs-core@0.1.0.0/inspector_query.bend as IQ
16import bendvy-ecs-core@0.1.0.0/inspector_query_projection.bend as Select
17import bendvy-ecs-core@0.1.0.0/transaction.bend as T
18import bendvy-ecs-core@0.1.0.0/commands.bend as Cmd
19
20# One trusted ordinary relation declaration drives operational grants and view.
21# Trusted setup projection of the retained relation declaration. The descriptor
22# selects operational authority; presentation strings do not create another grant.
23def descriptor(~S:Data,declaration:Ord.Declaration<S>) -> G.Descriptor<S>:
24  match declaration:
25    case Ord.Declaration{value}:value
26def kind(value:G.RelationKind) -> String:
27  match value:
28    case G.Ordinary{}:"Ordinary"
29    case G.Hierarchy{}:"Hierarchy"
30def descriptor_text(~S:Data,value:G.Descriptor<S>) -> String:
31  match value:
32    case G.Descriptor{key,name,inverseName,tag}:"Relation{key=" ++ U32.show(key) ++ "|name=" ++ name ++ "|inverse=" ++ inverseName ++ "|kind=" ++ kind(tag) ++ "}"
33def declared_spec(~S:Data,+value:G.Descriptor<S>) -> RQ.Spec<S>:
34  match value:
35    case G.Descriptor{+key,+name,+inverseName,+tag}:RQ.Spec{[RQ.optional_relation(~S,name,G.Descriptor{key,name,inverseName,tag}),RQ.optional_related(~S,inverseName,G.Descriptor{key,name,inverseName,tag})]}
36# Inspector setup for optional outgoing and inverse cells of this declaration.
37# Optional cells retain unlinked entities rather than requiring an existing edge.
38def spec(~S:Data,declaration:Ord.Declaration<S>) -> RQ.Spec<S>:
39  match declaration:
40    case Ord.Declaration{+value}:declared_spec(~S,value)
41# Advanced storage projection: relation edges wrap C and relation notices wrap E.
42# The World remains an affine owner threaded through every App operation.
43def World(~S:Data,~C:Type,~R:Type,~E:Data) -> Type:
44  W.World<S,A.Store<S,C>,R,A.Notice<S,E>>
45# Detached inspector row containing an entity handle and optional relation cells.
46def Row(~S:Data) -> Data:
47  IQ.ProjectedRow<S,Select.Product<Unit,List<&2,RQ.Cell<S>>>>
48# Detached relation observation: the declared descriptor and ordered inspector rows.
49# This Data value does not grant access to the underlying World or inverse storage.
50type View<S:Data> is Data:
51  View{descriptor:G.Descriptor<S>,rows:List<&2,Row(~S)>}
52# Advanced observation shape pairing prior rows with the added relation view.
53def ObservedRows(~S:Data,~Rows:Data) -> Data:
54  DTO.Product<Rows,View<S>>
55def handle(~S:Data,value:W.Handle<S>) -> String:
56  match value:
57    case W.Handle{ns,id}:U32.show(ns) ++ ":" ++ KeyText.show(id)
58def relation_value(~S:Data,value:RQ.Value<S>) -> String:
59  match value:
60    case RQ.Missing{}:"Missing"
61    case RQ.Target{target}:"Target:" ++ handle(~S,target)
62    case RQ.Sources{targets}:"Sources:" ++ List.show(&2,W.Handle<S>,handle(~S),targets)
63def end(value:RQ.End) -> String:
64  match value:
65    case RQ.Outgoing{}:"Outgoing"
66    case RQ.Incoming{}:"Incoming"
67def cell(~S:Data,value:RQ.Cell<S>) -> String:
68  match value:
69    case RQ.Cell{key,direction,value}:key ++ ":" ++ end(direction) ++ ":" ++ relation_value(~S,value)
70# Default textual presentation of a detached row; it does not perform a query.
71def builtin_row(~S:Data,value:Row(~S)) -> String:
72  match value:
73    case IQ.ProjectedRow{entity,Select.Product{_,cells}}:handle(~S,entity) ++ ":" ++ List.show(&2,RQ.Cell<S>,cell(~S),cells)
74def rendered(~S:Data,~render:Row(~S) -> String,rows:List<&2,Row(~S)>) -> List<&2,String>:
75  match rows:
76    case []:[]
77    case first <> rest:render(first) <> rendered(~S,~render,rest)
78def presented(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,result:I.Frame<S,A.Store<S,C>,R,A.Notice<S,E>> & List<&2,Row(~S)>) -> World(~S,~C,~R,~E) & DTO.Observation<View<S>>:
79  match result:
80    case (I.Frame{world,_},+rows):(world,DTO.Observation{View{descriptor(~S,declaration),rows},descriptor_text(~S,descriptor(~S,declaration)) <> rendered(~S,~render,rows)})
81# Read a fresh relation inspector view while returning the World owner.
82# Uses a fresh inspector cursor; it does not advance a registered gameplay reader
83# or apply queued commands. The renderer consumes detached rows only.
84def observe(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,world:World(~S,~C,~R,~E)) -> World(~S,~C,~R,~E) & DTO.Observation<View<S>>:
85  presented(~S,~C,~R,~E,~declaration,~render,IQ.each_composed(~I.Frame<S,A.Store<S,C>,R,A.Notice<S,E>>,~S,~Select.Product<Unit,List<&2,RQ.Cell<S>>>,~IR.grant(~S,~C,~R,~E,~Unit,~Select.empty(~I.Frame<S,A.Store<S,C>,R,A.Notice<S,E>>,~S),~spec(~S,declaration)),I.Frame{world,None{}}))
86# Advanced recipe adapter: retain the prior observation, then append this view.
87# The shared World owner is passed through both observers in that order.
88def observation(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>) -> World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<ObservedRows(~S,~Rows)>:
89  Tree.observe_pair(~World(~S,~C,~R,~E),~Rows,~View<S>,~prior,~observe(~S,~C,~R,~E,~declaration,~render))
90# Advanced App type with a caller-supplied detached-row renderer. World,
91# registration owners and the combined observation recipe remain inside the App.
92def presented_Application(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>) -> Type:
93  Build.Registered<S,World(~S,~C,~R,~E),Owners,ObservedRows(~S,~Rows),Tree.observe_pair(~World(~S,~C,~R,~E),~Rows,~View<S>,~prior,~observe(~S,~C,~R,~E,~declaration,~render)),fold>
94# Advanced recipe type for prior rows followed by the custom relation view.
95def presented_Recipe(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>) -> Type:
96  Tree.Recipe<World(~S,~C,~R,~E),ObservedRows(~S,~Rows),Tree.observe_pair(~World(~S,~C,~R,~E),~Rows,~View<S>,~prior,~observe(~S,~C,~R,~E,~declaration,~render))>
97# Install the custom relation observation recipe, preserving World, registration
98# owners and debug state. This does not create edges or register a gameplay system.
99def presented_install(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:Build.Registered<S,World(~S,~C,~R,~E),Owners,Rows,prior,fold>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold):
100  match app:
101    case Build.Registered{world,owners,_,debug}:Build.Registered{world,owners,Tree.Recipe{},debug}
102# Set observation enablement from flag, then snapshot through the installed recipe.
103# Returns the App in both cases; disabled observation returns None.
104def presented_snapshot_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),flag:Bool) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & Maybe<&2,DTO.Product<List<&2,DTO.Binding<S>>,DTO.Observation<ObservedRows(~S,~Rows)>>>:
105  Build.snapshot(~S,~World(~S,~C,~R,~E),~Owners,~ObservedRows(~S,~Rows),~Tree.observe_pair(~World(~S,~C,~R,~E),~Rows,~View<S>,~prior,~observe(~S,~C,~R,~E,~declaration,~render)),~fold,Build.enabled(~S,~World(~S,~C,~R,~E),~Owners,~ObservedRows(~S,~Rows),~Tree.observe_pair(~World(~S,~C,~R,~E),~Rows,~View<S>,~prior,~observe(~S,~C,~R,~E,~declaration,~render)),~fold,app,flag))
106def returned(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,owners:Owners,recipe:presented_Recipe(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),debug:Bool,result:T.Returned<World(~S,~C,~R,~E),Error>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & T.Outcome<Error>:
107  match result:
108    case T.Returned{world,status}:(Build.Registered{world,owners,recipe,debug},status)
109def queue_finished(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,status:A.QueueStatus,result:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & T.Outcome<Error>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
110  match result:
111    case (app,outcome):(app,DTO.Product{status,outcome})
112def queued(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,owners:Owners,recipe:presented_Recipe(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),debug:Bool,outcome:T.Outcome<Error>,result:T.Tx<World(~S,~C,~R,~E),A.Notice<S,E>> & A.QueueStatus) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
113  match result:
114    case (frame,+status):queue_finished(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,~Error,status,returned(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,~Error,owners,recipe,debug,Cmd.tx_finish(~S,~A.Store<S,C>,~R,~A.Notice<S,E>,~Error,frame,outcome)))
115# Stage source-to-target replacement under this declaration, then finish the
116# transaction with the supplied outcome. Return the App, queue status and outcome
117# separately: Queued is not barrier application success. Failure discards staged
118# commands; barrier-time structural rejection is reported through relation notices.
119def presented_relate_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,app:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),targets:P.Targets<S>,outcome:T.Outcome<Error>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
120  match app:
121    case Build.Registered{world,owners,recipe,debug}:queued(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,~Error,owners,recipe,debug,outcome,P.relate(~T.Tx<World(~S,~C,~R,~E),A.Notice<S,E>>,~S,~P.provide_write(~S,~C,~R,~E,~descriptor(~S,declaration)),T.begin(~World(~S,~C,~R,~E),~A.Notice<S,E>,world),targets))
122# Stage removal of this source relation and finish with the supplied outcome.
123# Returns App plus queue status and transaction outcome; successful staging remains
124# invisible to graph reads until a barrier, and transaction failure discards it.
125def presented_unrelate_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,app:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),source:W.Handle<S>,outcome:T.Outcome<Error>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
126  match app:
127    case Build.Registered{world,owners,recipe,debug}:queued(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,~Error,owners,recipe,debug,outcome,P.unrelate(~T.Tx<World(~S,~C,~R,~E),A.Notice<S,E>>,~S,~P.provide_write(~S,~C,~R,~E,~descriptor(~S,declaration)),T.begin(~World(~S,~C,~R,~E),~A.Notice<S,E>,world),source))
128def inverse_finished(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,value:Maybe<&2,List<&2,W.Handle<S>>>,result:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & T.Outcome<Unit>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & Maybe<&2,List<&2,W.Handle<S>>>:
129  match result:
130    case (app,_):(app,value)
131def inverse_taken(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,owners:Owners,recipe:presented_Recipe(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),debug:Bool,result:T.Tx<World(~S,~C,~R,~E),A.Notice<S,E>> & Maybe<&2,List<&2,W.Handle<S>>>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & Maybe<&2,List<&2,W.Handle<S>>>:
132  match result:
133    case (frame,value):inverse_finished(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,value,returned(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,~Unit,owners,recipe,debug,Cmd.tx_finish(~S,~A.Store<S,C>,~R,~A.Notice<S,E>,~Unit,frame,T.Success{})))
134# Read the current inverse list in stored order and return the App owner. None
135# denotes an invalid target; Some may contain an empty list. Pending commands are
136# not applied, and this read does not offer direct inverse-list mutation.
137def presented_inverse_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold),target:W.Handle<S>) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold) & Maybe<&2,List<&2,W.Handle<S>>>:
138  match app:
139    case Build.Registered{world,owners,recipe,debug}:inverse_taken(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold,owners,recipe,debug,P.read(~T.Tx<World(~S,~C,~R,~E),A.Notice<S,E>>,~S,~P.provide_read(~S,~C,~R,~E,~descriptor(~S,declaration)),T.begin(~World(~S,~C,~R,~E),~A.Notice<S,E>,world),target))
140# Apply the World structural barrier, returning the App with its owners and recipe.
141# This drains pending World commands, not only commands for this declaration;
142# structural relation failures are published as notices by their command handlers.
143def presented_barrier_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~render:Row(~S) -> String,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold)) -> presented_Application(~S,~C,~R,~E,~declaration,~render,~Owners,~Rows,~prior,~fold):
144  match app:
145    case Build.Registered{world,owners,recipe,debug}:Build.Registered{W.barrier(~S,~A.Store<S,C>,~R,~A.Notice<S,E>,world),owners,recipe,debug}
146# Ordinary relation App using builtin_row presentation and the retained declaration.
147def Application(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>) -> Type:
148  presented_Application(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold)
149
150# Advanced default-renderer recipe projection for composing typed App adapters.
151def Recipe(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>) -> Type:
152  presented_Recipe(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold)
153
154# Install the default relation observer without changing graph edges or owners.
155# Typical order: install, relate_app with a successful outcome, barrier_app, then
156# inverse_app or snapshot_app. See docs/parity/relations.md for accepted scenarios.
157def install(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:Build.Registered<S,World(~S,~C,~R,~E),Owners,Rows,prior,fold>) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold):
158  presented_install(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,app)
159
160# Default-renderer snapshot; flag controls observation and the App is returned
161# even when the observation is disabled (None). Does not apply pending commands.
162def snapshot_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold),flag:Bool) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold) & Maybe<&2,DTO.Product<List<&2,DTO.Binding<S>>,DTO.Observation<ObservedRows(~S,~Rows)>>>:
163  presented_snapshot_app(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,app,flag)
164
165# Default-renderer source-to-target request. Returns queue status separately from
166# the supplied transaction outcome; call barrier_app before expecting graph changes.
167def relate_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,app:Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold),targets:P.Targets<S>,outcome:T.Outcome<Error>) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
168  presented_relate_app(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,~Error,app,targets,outcome)
169
170# Default-renderer source removal request. The App is returned on refusal or
171# transaction failure; staging and barrier-time relation validity remain distinct.
172def unrelate_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,~Error:Data,app:Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold),source:W.Handle<S>,outcome:T.Outcome<Error>) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold) & DTO.Product<A.QueueStatus,T.Outcome<Error>>:
173  presented_unrelate_app(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,~Error,app,source,outcome)
174
175# Default-renderer inverse read, returning the App and Maybe ordered source handles.
176# Reads the current graph; pending additions and removals require a barrier first.
177def inverse_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold),target:W.Handle<S>) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold) & Maybe<&2,List<&2,W.Handle<S>>>:
178  presented_inverse_app(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,app,target)
179
180# Default-renderer structural barrier for all pending commands in this World.
181def barrier_app(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Ord.Declaration<S>,~Owners:Type,~Rows:Data,~prior:World(~S,~C,~R,~E) -> World(~S,~C,~R,~E) & DTO.Observation<Rows>,~fold:Owners -> Owners & List<&2,Fields.Fields<S>>,app:Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold)) -> Application(~S,~C,~R,~E,~declaration,~Owners,~Rows,~prior,~fold):
182  presented_barrier_app(~S,~C,~R,~E,~declaration,~builtin_row(~S),~Owners,~Rows,~prior,~fold,app)