22
33Runtime capability routing adapted from sheaf theory in algebraic topology.
44
5- ` sheafify({ name, sections }) ` produces a ** sheaf** — an authority manager
6- over a presheaf of capabilities . The sheaf produces dispatch sections via
7- ` getSection ` , each of which routes invocations through the presheaf .
5+ ` sheafify({ name, providers }) ` produces a ** sheaf** — an authority manager
6+ over a collection of capability providers . The sheaf produces dispatch handlers via
7+ ` getSection ` , each of which routes invocations through the provider set .
88
99See [ USAGE.md] ( ./USAGE.md ) for annotated examples and [ LIFT.md] ( ./LIFT.md ) for
10- the lift coroutine protocol and semantic equivalence assumption.
10+ the policy coroutine protocol and semantic equivalence assumption.
11+
12+ ## Install
13+
14+ ``` sh
15+ yarn add @metamask/sheaves
16+ ```
17+
18+ ``` sh
19+ npm install @metamask/sheaves
20+ ```
1121
1222## Concepts
1323
14- ** Presheaf section ** (` PresheafSection ` ) — The input data: a capability (exo)
15- paired with operational metadata, assigned over the open set defined by the
16- exo's guard. This is an element of the presheaf F = F_sem x F_op.
24+ ** Provider ** (` Provider ` ) — The input data: a capability handler paired with
25+ operational metadata, assigned over the open set defined by the handler's guard.
26+ This is an element of the presheaf F = F_sem x F_op.
1727
18- > A ` getBalance(string) ` provider with ` { cost: 100 } ` is one presheaf
19- > section. A ` getBalance("alice") ` provider with ` { cost: 1 } ` is another,
20- > covering a narrower open set.
28+ > A ` getBalance(string) ` provider with ` { cost: 100 } ` is one provider. A
29+ > ` getBalance("alice") ` provider with ` { cost: 1 } ` is another, covering a
30+ > narrower open set.
2131
22- ** Germ ** — An equivalence class of presheaf sections at an invocation point,
23- identified by metadata. At dispatch time, sections in the stalk with identical
24- metadata are collapsed into a single germ ; the system picks an arbitrary
32+ ** Candidate ** — An equivalence class of providers at an invocation point,
33+ identified by metadata. At dispatch time, providers in the stalk with identical
34+ metadata are collapsed into a single candidate ; the system picks an arbitrary
2535representative for dispatch. If two capabilities are indistinguishable by
2636metadata, the sheaf has no data to prefer one over the other.
2737
2838> Two ` getBalance(string) ` providers both with ` { cost: 1 } ` collapse into
29- > one germ . The lift never sees both — it receives one representative.
39+ > one candidate . The policy never sees both — it receives one representative.
3040
31- ** Stalk** — The set of germs matching a specific ` (method, args) ` invocation,
41+ ** Stalk** — The set of candidates matching a specific ` (method, args) ` invocation,
3242computed at dispatch time by guard filtering and then collapsing equivalent
3343entries.
3444
35- > Stalk at ` ("getBalance", "alice") ` might contain two germs (cost 1 vs 100);
45+ > Stalk at ` ("getBalance", "alice") ` might contain two candidates (cost 1 vs 100);
3646> stalk at ` ("transfer", ...) ` might contain one.
3747
38- ** Lift ** — An ` async function* ` coroutine that yields candidates from a
39- multi-germ stalk in preference order. See [ LIFT.md] ( ./LIFT.md ) for the
40- coroutine protocol, ` LiftContext ` , and the semantic equivalence assumption
41- required of all lifts .
48+ ** Policy ** — An ` async function* ` coroutine that yields candidates from a
49+ multi-candidate stalk in preference order. See [ LIFT.md] ( ./LIFT.md ) for the
50+ coroutine protocol, ` PolicyContext ` , and the semantic equivalence assumption
51+ required of all policies .
4252
4353At dispatch time, metadata is decomposed into ** constraints** (keys with the
44- same value across every germ — topologically determined, not a choice) and
45- ** options** (the remaining keys — the lift 's actual decision space). The lift
46- receives only options on each germ ; constraints arrive separately in the
54+ same value across every candidate — topologically determined, not a choice) and
55+ ** options** (the remaining keys — the policy 's actual decision space). The policy
56+ receives only options on each candidate ; constraints arrive separately in the
4757context.
4858
4959> ` argmin ` by cost, ` argmin ` by latency, or any custom selection logic. The
50- > lift is never invoked when the stalk resolves to a single germ — either
51- > because only one section matched, or because all matching sections had
60+ > policy is never invoked when the stalk resolves to a single candidate — either
61+ > because only one provider matched, or because all matching providers had
5262> identical metadata and collapsed to one representative.
5363
54- ** Sheaf** — The authority manager returned by ` sheafify ` . Holds the presheaf
55- data (sections frozen at construction time) and exposes factory methods that
56- produce dispatch exos on demand.
64+ ** Sheaf** — The authority manager returned by ` sheafify ` . Holds the provider
65+ data (frozen at construction time) and exposes factory methods that
66+ produce dispatch handlers on demand.
5767
5868```
59- const sheaf = sheafify({ name: 'Wallet', sections });
69+ const sheaf = sheafify({ name: 'Wallet', providers });
6070```
6171
62- - ` sheaf.getSection({ guard, lift }) ` — produce a dispatch exo
63- - ` sheaf.getDiscoverableSection({ guard, lift, schema }) ` — same, but the exo exposes its guard
72+ - ` sheaf.getSection({ guard, lift }) ` — produce a dispatch handler
73+ - ` sheaf.getDiscoverableSection({ guard, lift, schema }) ` — same, but the handler exposes its guard
6474
6575## Dispatch pipeline
6676
6777At each invocation point ` (method, args) ` within a granted section:
6878
6979```
70- getStalk(sections , method, args) presheaf → stalk (filter by guard)
80+ getStalk(providers , method, args) presheaf → stalk (filter by guard)
7181evaluateMetadata(stalk, args) metadata specs → concrete values
7282collapseEquivalent(stalk) locality condition (quotient by metadata)
7383decomposeMetadata(collapsed) restriction map (constraints / options)
74- lift(stripped , { method, args, operational selection (extra-theoretic)
75- constraints })
76- dispatch to chosen.exo evaluation
84+ policy(candidates , { method, args, operational selection (extra-theoretic)
85+ constraints })
86+ dispatch to chosen.handler evaluation
7787```
7888
79- The pipeline short-circuits at two points: if only one section matches the
80- guard, it is invoked directly without evaluate/collapse/lift ; if all matching
81- sections collapse to an identical germ , the single representative is invoked
82- without calling the lift .
89+ The pipeline short-circuits at two points: if only one provider matches the
90+ guard, it is invoked directly without evaluate/collapse/policy ; if all matching
91+ providers collapse to an identical candidate , the single representative is invoked
92+ without calling the policy .
8393
8494` callable ` and ` source ` metadata specs make the stalk shape depend on the
85- invocation arguments. A ` swap(amount) ` section can produce ` { cost: 'low' } `
95+ invocation arguments. A ` swap(amount) ` provider can produce ` { cost: 'low' } `
8696for small amounts and ` { cost: 'high' } ` for large ones, yielding a different
87- set of germs — and potentially a different lift outcome — for the same method
88- called with different arguments.
97+ set of candidates — and potentially a different policy outcome — for the same
98+ method called with different arguments.
8999
90100## Design choices
91101
92- ** Germ identity is metadata identity.** The collapse step quotients by
93- metadata: if two sections should be distinguishable, the caller must give them
94- distinguishable metadata. Sections with identical metadata are treated as
102+ ** Candidate identity is metadata identity.** The collapse step quotients by
103+ metadata: if two providers should be distinguishable, the caller must give them
104+ distinguishable metadata. Providers with identical metadata are treated as
95105interchangeable. Under the sheaf condition (effect-equivalence), this recovers
96106the classical equivalence relation on germs.
97107
98108** Pseudosheafification.** The sheafification functor would precompute the full
99109etale space. This system defers to invocation time: compute the stalk,
100- collapse, decompose, lift . The trade-off is that global coherence (a lift
101- choosing consistently across points) is not guaranteed.
110+ collapse, decompose, select via policy . The trade-off is that global coherence
111+ (a policy choosing consistently across points) is not guaranteed.
102112
103113** Restriction and gluing are implicit.** Guard restriction induces a
104114restriction map on metadata: restricting to a point filters the presheaf to
105- covering sections (` getStalk ` ), then ` decomposeMetadata ` strips the metadata
115+ covering providers (` getStalk ` ), then ` decomposeMetadata ` strips the metadata
106116to distinguishing keys — the restricted metadata over that point. The join
107- works dually: the union of two sections has the join of their metadata, and
117+ works dually: the union of two providers has the join of their metadata, and
108118restriction at any point recovers the local distinguishing keys in O(n).
109- Gluing follows: compatible sections (equal metadata on their overlap) produce a
119+ Gluing follows: compatible providers (equal metadata on their overlap) produce a
110120well-defined join. The dispatch pipeline computes all of this implicitly. The
111121remaining gap is ` revokeSite ` (revoking over an open set rather than a point),
112122which requires an ` intersects ` operator on guards not yet available.
@@ -115,7 +125,7 @@ which requires an `intersects` operator on guards not yet available.
115125
116126This construction is more properly a ** stack** in algebraic geometry. We call
117127it a sheaf because engineers already know "stack" as a LIFO data structure, and
118- the algebraic geometry term is unrelated. Within a germ , any representative
128+ the algebraic geometry term is unrelated. Within a candidate , any representative
119129will do — authority-equivalence is asserted by constructor contract, not
120- verified at runtime. Between germs , metadata distinguishes them and the lift
121- resolves the choice.
130+ verified at runtime. Between candidates , metadata distinguishes them and the
131+ policy resolves the choice.
0 commit comments