ordinary_recovery_declaration.bend

bendvy-ecs-core@0.1.0.1 · 77 lines · 0 definitions

1import Base
2import bendvy-ecs-core@0.1.0.1/recovery_use.bend as Use
3import bendvy-ecs-core@0.1.0.1/owner_product.bend as Product
4import bendvy-ecs-core@0.1.0.1/capabilities.bend as Cap
5import bendvy-ecs-core@0.1.0.1/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.
12def Builder(~State:Type,~Recovery:Type,~Ops:Type -> Type) -> Type:
13  @-All:Type -> @-Rest:Type -> @-path:Product.Lens<All,Recovery,Rest> -> Unit -> Ops(Frame.Frame<State,All>)
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.
23type 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.
29def empty(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration<S,State,Recovery,Ops,builder>) -> 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.
36def 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>:
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.
44def description(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops),value:Declaration<S,State,Recovery,Ops,builder>) -> 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.
51def PairOps(~L:Type -> Type,~R:Type -> Type,H:Type) -> Type:Cap.Bundle<L(H),R(H)>
52def pair_empty(~L:Type,~R:Type,~left:Unit -> L,~right:Unit -> R,unit:Unit) -> Product.Owner<L,R>:Product.Owner{left(Unit{}),right(unit)}
53def 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.Frame<State,All>),ROps(Frame.Frame<State,All>)>:
54  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)}
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<LeftRecovery, RightRecovery>. 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.
66def 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)>:
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))}
68def identity_take(~R:Type,value:R) -> Unit & R:(Unit{},value)
69def 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.
72def identity(~R:Type) -> Product.Lens<R,R,Unit>: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.
77def root_grant(~S:Data,~State:Type,~Recovery:Type,~Ops:Type -> Type,~builder:Builder(~State,~Recovery,~Ops)) -> Ops(Frame.Frame<State,Recovery>):builder(Recovery,Unit,identity(~Recovery),Unit{})