Skip to content

Commit f236eb0

Browse files
grypezclaude
andcommitted
refactor(kernel-utils): require guard in getSection, add getGlobalSection
`getSection({ guard, lift })` now requires an explicit interface guard, mirroring how `makeExo` always requires one. `getGlobalSection({ lift })` is the new convenience wrapper that computes the full union guard from all presheaf sections, analogous to `makeDefaultExo`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c068476 commit f236eb0

4 files changed

Lines changed: 47 additions & 38 deletions

File tree

packages/kernel-utils/src/sheaf/sheafify.e2e.test.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ describe('e2e: cost-optimal routing', () => {
5454
},
5555
];
5656

57-
let wallet = sheafify({ name: 'Wallet', sections }).getSection({
57+
let wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
5858
lift: argmin,
5959
});
6060

@@ -75,7 +75,7 @@ describe('e2e: cost-optimal routing', () => {
7575
) as unknown as Section,
7676
metadata: { cost: 2 },
7777
});
78-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
78+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
7979
lift: argmin,
8080
});
8181

@@ -145,7 +145,7 @@ describe('e2e: multi-tier capability routing', () => {
145145
metadata: { latencyMs: 500, label: 'network' },
146146
});
147147

148-
let wallet = sheafify({ name: 'Wallet', sections }).getSection({
148+
let wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
149149
lift: fastest,
150150
});
151151

@@ -173,7 +173,7 @@ describe('e2e: multi-tier capability routing', () => {
173173
) as unknown as Section,
174174
metadata: { latencyMs: 1, label: 'local' },
175175
});
176-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
176+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
177177
lift: fastest,
178178
});
179179

@@ -202,7 +202,7 @@ describe('e2e: multi-tier capability routing', () => {
202202
) as unknown as Section,
203203
metadata: { latencyMs: 0, label: 'cache' },
204204
});
205-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
205+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
206206
lift: fastest,
207207
});
208208

@@ -246,7 +246,7 @@ describe('e2e: multi-tier capability routing', () => {
246246
) as unknown as Section,
247247
metadata: { latencyMs: 200, label: 'write-backend' },
248248
});
249-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
249+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
250250
lift: fastest,
251251
});
252252

@@ -308,7 +308,9 @@ describe('e2e: multi-tier capability routing', () => {
308308
];
309309

310310
return {
311-
wallet: sheafify({ name: 'Wallet', sections }).getSection({ lift }),
311+
wallet: sheafify({ name: 'Wallet', sections }).getGlobalSection({
312+
lift,
313+
}),
312314
log,
313315
};
314316
};
@@ -373,7 +375,7 @@ describe('e2e: preferAutonomous recovered as degenerate case', () => {
373375
},
374376
];
375377

376-
const wallet = sheafify({ name: 'PushPull', sections }).getSection({
378+
const wallet = sheafify({ name: 'PushPull', sections }).getGlobalSection({
377379
lift: preferPush,
378380
});
379381

packages/kernel-utils/src/sheaf/sheafify.test.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ describe('sheafify', () => {
3636
},
3737
];
3838

39-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({ lift });
39+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
40+
lift,
41+
});
4042
expect(await E(wallet).getBalance('alice')).toBe(42);
4143
expect(liftCalled).toBe(false);
4244
});
@@ -55,7 +57,7 @@ describe('sheafify', () => {
5557
},
5658
];
5759

58-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
60+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
5961
lift: async (_germs) => Promise.resolve(0),
6062
});
6163
await expect(E(wallet).getBalance('bob')).rejects.toThrow(
@@ -99,7 +101,7 @@ describe('sheafify', () => {
99101
},
100102
];
101103

102-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
104+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
103105
lift: argmin,
104106
});
105107
// argmin picks cost=1 section which returns 42
@@ -131,7 +133,7 @@ describe('sheafify', () => {
131133
},
132134
];
133135

134-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
136+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
135137
lift: async (_germs) => Promise.resolve(0),
136138
});
137139
const guard = wallet[GET_INTERFACE_GUARD]();
@@ -167,7 +169,7 @@ describe('sheafify', () => {
167169
},
168170
];
169171

170-
let wallet = sheafify({ name: 'Wallet', sections }).getSection({
172+
let wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
171173
lift: argmin,
172174
});
173175
expect(await E(wallet).getBalance('alice')).toBe(100);
@@ -189,7 +191,7 @@ describe('sheafify', () => {
189191
) as unknown as Section,
190192
metadata: { cost: 1 },
191193
});
192-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
194+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
193195
lift: argmin,
194196
});
195197

@@ -215,7 +217,7 @@ describe('sheafify', () => {
215217
{ exo: exo as unknown as Section, metadata: { cost: 1 } },
216218
];
217219

218-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
220+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
219221
lift: async (_germs) => Promise.resolve(0),
220222
});
221223
expect(await E(wallet).getBalance('alice')).toBe(42);
@@ -247,7 +249,7 @@ describe('sheafify', () => {
247249
},
248250
];
249251

250-
let wallet = sheafify({ name: 'Wallet', sections }).getSection({
252+
let wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
251253
lift: argmin,
252254
});
253255
expect(await E(wallet).getBalance('alice')).toBe(100);
@@ -267,7 +269,7 @@ describe('sheafify', () => {
267269
},
268270
);
269271
sections.push({ exo: exo as unknown as Section, metadata: { cost: 1 } });
270-
wallet = sheafify({ name: 'Wallet', sections }).getSection({
272+
wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
271273
lift: argmin,
272274
});
273275

@@ -293,7 +295,7 @@ describe('sheafify', () => {
293295
{ exo: exo as unknown as Section, metadata: { cost: 1 } },
294296
];
295297

296-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
298+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
297299
lift: async (_germs) => Promise.resolve(0),
298300
});
299301
const guard = wallet[GET_INTERFACE_GUARD]();
@@ -337,7 +339,7 @@ describe('sheafify', () => {
337339
},
338340
];
339341

340-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
342+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
341343
lift: spy,
342344
});
343345
await E(wallet).getBalance('alice');
@@ -387,7 +389,7 @@ describe('sheafify', () => {
387389
},
388390
];
389391

390-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
392+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
391393
lift: spy,
392394
});
393395
await E(wallet).getBalance('alice');
@@ -424,7 +426,7 @@ describe('sheafify', () => {
424426
},
425427
];
426428

427-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
429+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
428430
lift: async (_germs) => {
429431
liftCalled = true;
430432
return Promise.resolve(0);
@@ -470,7 +472,7 @@ describe('sheafify', () => {
470472
{ exo: exo as unknown as Section, metadata: { cost: 1 } },
471473
];
472474

473-
const wallet = sheafify({ name: 'Wallet', sections }).getSection({
475+
const wallet = sheafify({ name: 'Wallet', sections }).getGlobalSection({
474476
lift: argmin,
475477
});
476478
// argmin picks the exo section (cost=1)
@@ -496,7 +498,7 @@ describe('sheafify', () => {
496498
];
497499

498500
const sheaf = sheafify({ name: 'Wallet', sections });
499-
const wallet = sheaf.getSection({
501+
const wallet = sheaf.getGlobalSection({
500502
lift: async () => Promise.resolve(0),
501503
});
502504

@@ -528,7 +530,7 @@ describe('sheafify', () => {
528530
];
529531

530532
const sheaf = sheafify({ name: 'Wallet', sections });
531-
const wallet = sheaf.getSection({
533+
const wallet = sheaf.getGlobalSection({
532534
lift: async () => Promise.resolve(0),
533535
});
534536

@@ -560,7 +562,7 @@ describe('sheafify', () => {
560562
// No sections granted yet
561563
expect(sheaf.getExported()).toBeUndefined();
562564

563-
sheaf.getSection({ lift: async () => Promise.resolve(0) });
565+
sheaf.getGlobalSection({ lift: async () => Promise.resolve(0) });
564566

565567
const exported = sheaf.getExported();
566568
expect(exported).toBeDefined();
@@ -583,7 +585,7 @@ describe('sheafify', () => {
583585
];
584586

585587
const sheaf = sheafify({ name: 'Wallet', sections });
586-
sheaf.getSection({ lift: async () => Promise.resolve(0) });
588+
sheaf.getGlobalSection({ lift: async () => Promise.resolve(0) });
587589

588590
expect(sheaf.getExported()).toBeDefined();
589591

packages/kernel-utils/src/sheaf/sheafify.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,10 @@ export const sheafify = <MetaData = unknown>({
187187
guard,
188188
lift,
189189
}: {
190-
guard?: InterfaceGuard;
190+
guard: InterfaceGuard;
191191
lift: Lift<MetaData>;
192192
}): object => {
193-
const resolvedGuard =
194-
guard ??
195-
collectSheafGuard(
196-
name,
197-
frozenSections.map(({ exo }) => exo),
198-
);
193+
const resolvedGuard = guard;
199194

200195
const asyncMethodGuards = asyncifyMethodGuards(resolvedGuard);
201196
const asyncGuard = M.interface(`${name}:section`, asyncMethodGuards);
@@ -263,6 +258,16 @@ export const sheafify = <MetaData = unknown>({
263258
return exo;
264259
};
265260

261+
const getGlobalSection = ({ lift }: { lift: Lift<MetaData> }): object => {
262+
return getSection({
263+
guard: collectSheafGuard(
264+
name,
265+
frozenSections.map(({ exo }) => exo),
266+
),
267+
lift,
268+
});
269+
};
270+
266271
const revokePoint = (method: string, ...args: unknown[]): void => {
267272
for (const grant of grants) {
268273
if (!grant.isRevoked() && guardCoversPoint(grant.guard, method, args)) {
@@ -291,6 +296,7 @@ export const sheafify = <MetaData = unknown>({
291296

292297
return {
293298
getSection,
299+
getGlobalSection,
294300
revokePoint,
295301
getExported,
296302
revokeAll,

packages/kernel-utils/src/sheaf/types.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,10 @@ export type Presheaf<MetaData = unknown> = PresheafSection<MetaData>[];
6565
* granted authority for auditing and revocation.
6666
*/
6767
export type Sheaf<MetaData = unknown> = {
68-
/** Produce a revocable dispatch exo over the given guard (or the full union). */
69-
getSection: (opts: {
70-
guard?: InterfaceGuard;
71-
lift: Lift<MetaData>;
72-
}) => object;
68+
/** Produce a revocable dispatch exo over the given guard. */
69+
getSection: (opts: { guard: InterfaceGuard; lift: Lift<MetaData> }) => object;
70+
/** Produce a revocable dispatch exo over the full union guard of all presheaf sections. */
71+
getGlobalSection: (opts: { lift: Lift<MetaData> }) => object;
7372
/** Revoke every granted section whose guard covers the point (method, ...args). */
7473
revokePoint: (method: string, ...args: unknown[]) => void;
7574
/** Union guard of all active (non-revoked) granted sections, or undefined. */

0 commit comments

Comments
 (0)