inspector_failure_projection.bend

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

1import Base
2import bendvy-ecs-core@0.1.0.0/change_tick.bend as Tick
3import bendvy-ecs-core@0.1.0.0/event_runtime.bend as Ev
4import bendvy-ecs-core@0.1.0.0/relation_commands.bend as A
5import bendvy-ecs-core@0.1.0.0/relation_types.bend as G
6import bendvy-ecs-core@0.1.0.0/relation_graph.bend as Graph
7import bendvy-ecs-core@0.1.0.0/capabilities.bend as Cap
8import bendvy-ecs-core@0.1.0.0/inspector_stream_frame.bend as F
9
10# Selects a relation failure projection by descriptor key. The descriptor must
11# belong to the application schema; this raw declaration does not validate it.
12type Declaration<S:Data> is Data:
13  Declaration{relation:G.Descriptor<S>}
14# This declaration-scoped grant exposes selected failures and non-payload
15# timing only. Shared Notice payloads and reader counts stay in the owner harness.
16type FailureView<S:Data,E:Data> is Data:
17  FailureView{relation:G.Descriptor<S>,visible:List<&2,G.Failure<S>>,retained:List<&2,G.Failure<S>>,tick:Nat,boundary:Nat}
18def selected(~S:Data,keep:Bool,failure:G.Failure<S>,rest:List<&2,G.Failure<S>>) -> List<&2,G.Failure<S>>:
19  match keep:
20    case False{}:rest
21    case True{}:failure <> rest
22def select_failure(~S:Data,+relation:G.Descriptor<S>,+failure:G.Failure<S>,rest:List<&2,G.Failure<S>>) -> List<&2,G.Failure<S>>:
23  match failure:
24    case G.Failure{+actual,operation,source,target,error}:selected(~S,U32.is_eq(Graph.key(~S,actual),Graph.key(~S,relation)),G.Failure{actual,operation,source,target,error},rest)
25def select_notice(~S:Data,~E:Data,relation:G.Descriptor<S>,notice:A.Notice<S,E>,rest:List<&2,G.Failure<S>>) -> List<&2,G.Failure<S>>:
26  match notice:
27    case A.RelationFailed{failure}:select_failure(~S,relation,failure,rest)
28    case _:rest
29# Extract relation failures matching the descriptor key, preserving notice order.
30# Other notice variants are omitted; no payload owners or reader positions change.
31def failures(~S:Data,~E:Data,+relation:G.Descriptor<S>,notices:List<&2,A.Notice<S,E>>) -> List<&2,G.Failure<S>>:
32  match notices:
33    case []:[]
34    case notice <> rest:select_notice(~S,~E,relation,notice,failures(~S,~E,relation,rest))
35# Project visible and retained failures separately from a detached snapshot.
36# Preserve its tick and retention boundary; this does not acknowledge a reader.
37def view(~S:Data,~E:Data,+relation:G.Descriptor<S>,snapshot:Ev.Snapshot<A.Notice<S,E>>) -> FailureView<S,E>:
38  match snapshot:
39    case Ev.Snapshot{visible,retained,_,tick,boundary}:FailureView{relation,failures(~S,~E,relation,visible),failures(~S,~E,relation,retained),tick,boundary}
40def joined(~S:Data,~C:Type,~R:Type,~E:Data,relation:G.Descriptor<S>,cursor:Maybe<&2,Tick.Tick>,observed:Ev.Runtime<S,C,R,A.Notice<S,E>> & Ev.Snapshot<A.Notice<S,E>>) -> F.Frame<S,C,R,E> & FailureView<S,E>:
41  (runtime,snapshot)=observed
42  (F.Frame{runtime,cursor},view(~S,~E,relation,snapshot))
43# Return the runtime frame with a detached failure view. Preserve the Inspector
44# cursor and runtime reader positions; inspection does not drain retained notices.
45def read(~S:Data,~C:Type,~R:Type,~E:Data,relation:G.Descriptor<S>,frame:F.Frame<S,C,R,E>) -> F.Frame<S,C,R,E> & FailureView<S,E>:
46  match frame:
47    case F.Frame{runtime,cursor}:joined(~S,~C,~R,~E,relation,cursor,Ev.inspect(~S,~C,~R,~A.Notice<S,E>,runtime))
48# Recover the descriptor carried by this declaration, without validation.
49def descriptor(~S:Data,declaration:Declaration<S>) -> G.Descriptor<S>:
50  match declaration:
51    case Declaration{relation}:relation
52# Build the read capability for this declaration. It exposes only selected
53# failures and timing metadata, returning the affine frame after inspection.
54def inspect(~S:Data,~C:Type,~R:Type,~E:Data,~declaration:Declaration<S>) -> Cap.ValueRead<F.Frame<S,C,R,E>,FailureView<S,E>>:
55  Cap.ValueRead{frame => read(~S,~C,~R,~E,descriptor(~S,declaration),frame)}