ordinary_owned_event_declaration.bend

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

1import Base
2import bendvy-ecs-core@0.1.0.0/owner_product.bend as Product
3import bendvy-ecs-core@0.1.0.0/capabilities.bend as Cap
4import bendvy-ecs-core@0.1.0.0/owned_event_journal.bend as Frame
5# Canonical event declarations compose heterogeneous payload grants with one
6# ordered journal. Builder remains erased until the full recovery tree is known.
7# Raw constructors/builders are trusted engine administration, not gameplay.
8# Advanced erased builder for an owned-event publication grant family.
9# Specializes the journal recovery path only after the complete heterogeneous
10# recovery product is known. Gameplay receives abstract emission grants rather
11# than constructing runtime journal paths or retaining raw payload aliases.
12def Builder(~State:Type,~Recovery:Type,~Ops:Type -> Type) -> Type:
13  @-All:Type -> @-Rest:Type -> @-path:Product.Lens<All,Recovery,Rest> -> Unit -> Ops(Frame.Stage<State,All>)
14# Detached metadata listing owned event-domain names and whether it is opaque.
15# Names describe provisioned publication uses; they do not grant access or prove
16# that a hand-authored builder targets the named log. Canonical constructors
17# supply this metadata together with their typed operational bindings.
18type Description is Data:
19  Description{events:List<&2,String>,opaque:Bool}
20# Combine metadata left first, preserving duplicate names and propagating
21# opacity from either side. This does not combine live logs or publish payloads.
22def pair_description(left:Description,right:Description) -> Description:
23  match left right:
24    case Description{left,lo} Description{right,ro}:Description{List.append(&2,String,left,right),Bool.or(lo,ro)}
25# Report whether the description is nonopaque. This is the automatic App
26# metadata-admission test, not validation of arbitrary builders or runtime log
27# existence. Use canonical declarations rather than asserting trusted metadata.
28def complete(value:Description) -> Bool:
29  match value:
30    case Description{_,opaque}:Bool.not(opaque)
31# Static publisher declaration carrying a recovery constructor and access names;
32# State, Recovery, Ops and builder keep its operational route typed. Canonical
33# ordinary-owned-event-family-write.declaration supplies the matching log/recovery
34# paths. Payloads may be arbitrary affine Type values; this is not a Data-event
35# stream reader and does not duplicate payloads for multiple readers.
36# Legacy Declaration has opaque metadata. Described adds operational-domain
37# metadata; automatic App publisher registration requires a complete description.
38# Classic publisher registration remains available for the legacy form. Raw
39# constructors/builders are trusted administration, not a gameplay permission API.
40# See docs/parity/affine-events.md for ownership and qualified publication bounds.
41type Declaration<-S:Data,-State:Type,-Recovery:Type,-Ops:Type -> Type,-builder:Builder(~State,~Recovery,~Ops)> is Type:
42  Declaration{empty:Unit -> Recovery,access:List<&2,String>}
43  Described{empty:Unit -> Recovery,access:List<&2,String>,description:Description}
44# Consume a declaration and obtain its fresh recovery-owner constructor.
45# It initializes the finish-time recovery accumulator; it does not copy payloads,
46# publish an event, retire a log entry or execute cleanup.
47def empty(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration<S,State,Recovery,Ops,builder>) -> Unit -> Recovery:
48  match value:
49    case Declaration{empty,_}:empty
50    case Described{empty,_,_}:empty
51# Consume a declaration and return its Registry access strings in stored order.
52# These are metadata, not a reader cursor, payload owner or substitute for the
53# builder's schema-bound publication grant.
54def access(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration<S,State,Recovery,Ops,builder>) -> List<&2,String>:
55  match value:
56    case Declaration{_,access}:access
57    case Described{_,access,_}:access
58# Consume a declaration and obtain its detached event-use description.
59# Legacy Declaration yields an opaque description; Described yields the supplied
60# one. This operation does not read logs, advance readers or publish events.
61def description(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration<S,State,Recovery,Ops,builder>) -> Description:
62  match value:
63    case Declaration{_,_}:Description{[],True{}}
64    case Described{_,_,description}:description
65# Operation-family alias for left/right emission grants on the same opaque
66# journal stage. Its order matches the recovery product produced by both.
67def PairOps(~L:Type -> Type,~R:Type -> Type,H:Type) -> Type:Cap.Bundle<L(H),R(H)>
68def pair_empty(~L:Type,~R:Type,~left:Unit -> L,~right:Unit -> R,unit:Unit) -> Product.Owner<L,R>:Product.Owner{left(Unit{}),right(unit)}
69def pair_grant(~S:Data,~State:Type,~L:Type,~R:Type,~LOps:Type -> Type,~ROps:Type -> Type,~left:Builder(~State,~L,~LOps),~right:Builder(~State,~R,~ROps),~All:Type,~Rest:Type,~path:Product.Lens<All,Product.Owner<L,R>,Rest>,unit:Unit) -> Cap.Bundle<LOps(Frame.Stage<State,All>),ROps(Frame.Stage<State,All>)>:
70  Cap.Bundle{left(All,Rest & R,Product.compose(~All,~Product.Owner<L,R>,~Rest,~L,~R,~path,~Product.lens(~L,~R,~Product.Left{})),Unit{}),right(All,Rest & L,Product.compose(~All,~Product.Owner<L,R>,~Rest,~R,~L,~path,~Product.lens(~L,~R,~Product.Right{})),unit)}
71# Compose owned-event declarations for the same schema and staged State.
72# The body receives Cap.Bundle{left, right}; recovery is the corresponding
73# Product.Owner<LeftRecovery, RightRecovery>. Access/domain lists remain left
74# first, with duplicates; opaque metadata on either side remains opaque.
75# One shared staged journal preserves actual emission order across families,
76# not declaration grouping. The publisher commits payload owners only on success;
77# on abort it publishes none and returns staged owners through the typed recovery
78# product, preserving each family's order. The declaration itself executes none
79# of these actions. No owner restored by another required ECS rollback may also
80# be returned as recovered event data, and no automatic IO finalizer is implied.
81# Use ordinary-owned-event-family-write.declaration for each canonical leaf and
82# ordinary-owned-event-family-publisher for execution. Reader projection,
83# retention and retirement use their separate owned-event APIs.
84def both(~S:Data,~State:Type,~L:Type,~R:Type,~LOps:Type -> Type,~ROps:Type -> Type,~leftBuilder:Builder(~State,~L,~LOps),~rightBuilder:Builder(~State,~R,~ROps),~left:Declaration<S,State,L,LOps,leftBuilder>,~right:Declaration<S,State,R,ROps,rightBuilder>) -> Declaration<S,State,Product.Owner<L,R>,PairOps(~LOps,~ROps),pair_grant(~S,~State,~L,~R,~LOps,~ROps,~leftBuilder,~rightBuilder)>:
85  Described{pair_empty(~L,~R,~empty(~S,~State,~L,~LOps,~leftBuilder,left),~empty(~S,~State,~R,~ROps,~rightBuilder,right)),List.append(&2,String,access(~S,~State,~L,~LOps,~leftBuilder,left),access(~S,~State,~R,~ROps,~rightBuilder,right)),pair_description(description(~S,~State,~L,~LOps,~leftBuilder,left),description(~S,~State,~R,~ROps,~rightBuilder,right))}
86def identity_take(~R:Type,value:R) -> Unit & R:(Unit{},value)
87def identity_put(~R:Type,unit:Unit,value:R) -> R:value
88# Advanced builder lens selecting the complete recovery owner with Unit rest.
89# It threads the owner rather than copying it; it does not publish or abort events.
90def identity(~R:Type) -> Product.Lens<R,R,Unit>:Product.Lens{identity_take(~R),identity_put(~R)}
91# Advanced publisher projection: instantiate builder at the full recovery owner
92# and return its emission operations. The runner supplies the opaque journal
93# stage; gameplay does not construct raw paths, expose stored owners or decide
94# publication by invoking this projection outside the publisher protocol.
95def root_grant(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops)) -> Ops(Frame.Stage<State,Recovery>):builder(Recovery,Unit,identity(~Recovery),Unit{})