1 import Base 2 import ./recovery_use.bend as Use 3 import ./owner_product.bend as Product 4 import ./capabilities.bend as Cap 5 import ./ordinary_recoverable_array_resource.bend as Frame 6 # Builder is an erased type index, like a Registry runner. It is specialized 7 # at the closed recovery product before any executable grant is materialized. 8 # Advanced erased grant-builder type for canonical recovery declarations. 9 # Specializes operations to the closed recovery product and an owner-preserving 10 # lens into that product. Ordinary bodies receive the generated Ops; they do not 11 # supply runtime journal routes or inverse callbacks themselves. 12 def Builder(~State:Type,~Recovery:Type,~Ops:Type -> Type) -> Type: 13 @-All:Type -> @-Rest:Type -> @-path:Product.Lens -> Unit -> Ops(Frame.Frame) 14 # Static recovery description for State, recovery owner and operation family Ops. 15 # Canonical component/resource/capture modules supply matching builders, empty 16 # recovery constructors and typed use descriptions. Arbitrary affine Type 17 # payloads are supported by those operations; this is not automatic rollback for 18 # all functions, external IO or arbitrary payload mutation. 19 # The classic Declaration form has opaque use metadata. Automatic App recovery 20 # registration requires a complete description and refuses that opaque form; 21 # the classic runner remains available. See docs/parity/recovery.md for the 22 # accepted operation domains, owner-return rules and qualified scenarios. 23 type Declaration<-S:Data,-State:Type,-Recovery:Type,-Ops:Type -> Type,-builder:Builder(~State,~Recovery,~Ops)> is Type: 24 Declaration{empty:Unit -> Recovery,access:List<&2,String>} 25 Described{empty:Unit -> Recovery,access:List<&2,String>,description:Use.Description} 26 # Consume a declaration and obtain its fresh recovery-owner constructor. 27 # This constructs the accumulator used when a recovery runner finishes; it does 28 # not execute operations, undo a transaction or copy live affine recovery values. 29 def empty(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration) -> Unit -> Recovery: 30 match value: 31 case Declaration{empty,_}:empty 32 case Described{empty,_,_}:empty 33 # Consume a declaration and obtain its declared registration access names. 34 # Order and duplicates are retained. These strings are metadata, not a journal 35 # route or a replacement for the declaration's typed operation authority. 36 def access(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration) -> List<&2,String>: 37 match value: 38 case Declaration{_,access}:access 39 case Described{_,access,_}:access 40 # Consume a declaration and return typed operational-use metadata. 41 # Legacy Declaration returns an opaque description; Described returns its stored 42 # description. Automatic App registration uses completeness rather than parsing 43 # access strings. This projection does not validate an inverse or run recovery. 44 def description(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration) -> Use.Description: 45 match value: 46 case Declaration{_,_}:Use.none() 47 case Described{_,_,description}:description 48 # Operation-family alias for a bundle of left and right recovery grants acting 49 # on the same opaque frame. Keep their order consistent with the paired 50 # recovery product constructed by both. 51 def PairOps(~L:Type -> Type,~R:Type -> Type,H:Type) -> Type:Cap.Bundle 52 def pair_empty(~L:Type,~R:Type,~left:Unit -> L,~right:Unit -> R,unit:Unit) -> Product.Owner:Product.Owner{left(Unit{}),right(unit)} 53 def 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,Rest>,unit:Unit) -> Cap.Bundle),ROps(Frame.Frame)>: 54 Cap.Bundle{left(All,Rest & R,Product.compose(~All,~Product.Owner,~Rest,~L,~R,~path,~Product.lens(~L,~R,~Product.Left{})),Unit{}),right(All,Rest & L,Product.compose(~All,~Product.Owner,~Rest,~R,~L,~path,~Product.lens(~L,~R,~Product.Right{})),unit)} 55 # Compose two closed declarations for the same schema and State. 56 # The body receives Cap.Bundle{left, right}; recovery owners form 57 # Product.Owner. Access entries and typed use lists 58 # are appended left first, preserving duplicates; opacity in either description 59 # remains opaque. This does not execute either operation or create two journals. 60 # The recovery runner uses one shared LIFO journal across both grants: commit 61 # returns displaced originals, rollback restores recorded state and returns 62 # replacements. Effects outside the declared operations are not made reversible. 63 # Canonical leaves: ordinary-recovery-component.declaration, 64 # ordinary-recovery-resource.declaration and ordinary-recovery-capture.declaration; 65 # ordinary-recovery-system registers/runs the resulting declaration. 66 def 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,~right:Declaration) -> Declaration,PairOps(~LOps,~ROps),pair_grant(~S,~State,~L,~R,~LOps,~ROps,~leftBuilder,~rightBuilder)>: 67 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)),Use.pair(description(~S,~State,~L,~LOps,~leftBuilder,left),description(~S,~State,~R,~ROps,~rightBuilder,right))} 68 def identity_take(~R:Type,value:R) -> Unit & R:(Unit{},value) 69 def identity_put(~R:Type,unit:Unit,value:R) -> R:value 70 # Advanced builder lens selecting the complete recovery owner, with Unit rest. 71 # It threads that owner once; it does not clone it or establish rollback by itself. 72 def identity(~R:Type) -> Product.Lens:Product.Lens{identity_take(~R),identity_put(~R)} 73 # Advanced runner projection: instantiate the matching builder at the complete 74 # recovery owner with its identity lens. Returns operations, not live state; 75 # registration, journal execution and recovery results belong to 76 # ordinary-recovery-system. Use canonical declaration constructors for gameplay. 77 def root_grant(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops)) -> Ops(Frame.Frame):builder(Recovery,Unit,identity(~Recovery),Unit{})