Skip to content

feat(kernel-utils): declare the narrowing API surface - #1049

Draft
ci-belphegor wants to merge 1 commit into
grypez/narrowing-2-guard-algebrafrom
grypez/narrowing-3-api-surface
Draft

feat(kernel-utils): declare the narrowing API surface#1049
ci-belphegor wants to merge 1 commit into
grypez/narrowing-2-guard-algebrafrom
grypez/narrowing-3-api-surface

Conversation

@ci-belphegor

Copy link
Copy Markdown

Explanation

Declares the narrowing API without implementing it: NarrowingDelta, and narrow({ name, base, delta }) / join({ name, refs }) with final signatures and throw new Error('not implemented') bodies. pathUnder(segments) is fully implemented, since it is six lines with no dependencies and the next PR needs it to express real deltas.

This exists so that the end-to-end test vat in PR 4 can bundle. A vat importing narrow before it exists fails at bundle time and takes the whole test file down, which it.fails cannot absorb.

Notes for reviewers

base is typed object, and that is not laziness. A real exo does not satisfy Methods: Methods = Record<RemotableMethodName, CallableFunction> demands an index signature, while Guarded<M> is an intersection carrying RemotableObject's non-callable [PASS_STYLE] and Symbol.toStringTag, so it has none. Partial<Methods> (what sheaves uses for Section) and Record<string, unknown> fail identically — all three verified with tsc. object is the honest floor, and it accepts a promised base for free, which is correct since the forward goes through E().

The consequence lands on the return side: Guarded<Methods> collapses under E()'s mapped type, because keyof an index-signature-only type yields nothing. So a caller who wants E() method access on a narrowing must supply the type parameter explicitlynarrow<{ readFile: (p: string[], enc: string) => Promise<string> }>({ ... }). This is documented in narrow's JSDoc.

pathUnder([]) matches every ..-free segment array rather than throwing. It is the top of the prefix lattice, and stripping the identity out of the combinator would cost join the representable top the design doc asks for. Rejecting an empty scope is the config layer's job, which PR 12 does.

Stack

PR 3 of 12. Base: #1048.

Fix the signatures of narrow and join and export them alongside a fully
implemented pathUnder, so that callers and deltas can be written against
the API before the algebra behind it exists. Both narrow and join throw;
the changelog says so.

pathUnder([]) matches every ..-free segment array rather than throwing.
It is the top of the prefix lattice and a well-defined element of the
vocabulary; a capability for which unbounded authority is a mistake
rejects an empty prefix in its own config validation, where throwing here
would buy nothing anyway since the caller could write the pattern by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ci-belphegor
ci-belphegor force-pushed the grypez/narrowing-3-api-surface branch from f885dec to 2c386ec Compare September 11, 2026 11:42
@ci-belphegor
ci-belphegor added this pull request to stack #1060 September 11, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant