@oortmem/core 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/address.d.ts +161 -0
- package/dist/address.js +225 -0
- package/dist/agents.d.ts +38 -0
- package/dist/agents.js +67 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +7 -0
- package/dist/consolidate.d.ts +4 -0
- package/dist/consolidate.js +15 -3
- package/dist/date-cue.d.ts +26 -0
- package/dist/date-cue.js +70 -0
- package/dist/export-format.d.ts +77 -0
- package/dist/export-format.js +168 -0
- package/dist/grant.d.ts +122 -15
- package/dist/grant.js +233 -26
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/isolation.d.ts +48 -2
- package/dist/isolation.js +362 -71
- package/dist/levels.d.ts +79 -0
- package/dist/levels.js +140 -0
- package/dist/memory-store.js +27 -23
- package/dist/model.d.ts +17 -0
- package/dist/observe.d.ts +9 -0
- package/dist/observe.js +27 -3
- package/dist/recall.d.ts +27 -1
- package/dist/recall.js +163 -17
- package/dist/store-conformance.d.ts +12 -0
- package/dist/store-conformance.js +366 -2
- package/dist/temporal.js +12 -7
- package/package.json +1 -1
package/dist/grant.js
CHANGED
|
@@ -1,40 +1,156 @@
|
|
|
1
|
+
import { addressOf, assertNode, authorOf, nodeKey, nodeOf, planetOf, sameAddress, sameAuthor, } from './address.js';
|
|
2
|
+
/**
|
|
3
|
+
* The agent id of a caller that named no agent (an MCP entry written before agents existed, a
|
|
4
|
+
* terminal without `--agent`). It reads and writes the person's Planet only: it has no Star, so
|
|
5
|
+
* it can neither see nor create one. No configured agent may use this id.
|
|
6
|
+
*/
|
|
7
|
+
export const ANONYMOUS_AGENT = 'anonymous';
|
|
1
8
|
/**
|
|
2
9
|
* The permission every `MemoryStore` method takes. Opaque: built only by
|
|
3
|
-
* `localGrant` or `
|
|
10
|
+
* `localGrant`, `principalGrant` or `nodeGrant`, frozen, and nominal, so a raw
|
|
4
11
|
* `ScopeFilter` (or any look-alike object) is rejected by the type checker
|
|
5
12
|
* and, for JavaScript callers, by `assertGrant` inside every store.
|
|
6
13
|
*
|
|
7
|
-
* `
|
|
8
|
-
* `coldGet`, `recordAccess`); `
|
|
9
|
-
* `forget`, `setTier`, `expireMany`, `coldPut`).
|
|
10
|
-
*
|
|
14
|
+
* `readNodes` bounds what can be seen (`get`, `lexical`, `dense`, `list`,
|
|
15
|
+
* `coldGet`, `recordAccess`); `writeNodes` bounds what can change (`upsert`,
|
|
16
|
+
* `forget`, `setTier`, `expireMany`, `coldPut`). A memory is covered when
|
|
17
|
+
* any pattern of the side covers its address and author. Cursors belong to
|
|
18
|
+
* the principal. Anything outside a grant behaves exactly like something that
|
|
11
19
|
* does not exist.
|
|
12
20
|
*/
|
|
13
21
|
export class Grant {
|
|
14
22
|
#issued = true;
|
|
15
23
|
principal;
|
|
24
|
+
/** @deprecated The pre-level view of `readNodes`; see `GrantFilter`. */
|
|
16
25
|
read;
|
|
26
|
+
/** @deprecated The pre-level view of `writeNodes`; see `GrantFilter`. */
|
|
17
27
|
write;
|
|
18
|
-
|
|
28
|
+
readNodes;
|
|
29
|
+
writeNodes;
|
|
30
|
+
/**
|
|
31
|
+
* The node new memories are written to (the home node): the principal's
|
|
32
|
+
* Planet unless the agent keeps a Star. Engine code that creates a memory
|
|
33
|
+
* (observe, remember) addresses it here; edits of existing memories keep
|
|
34
|
+
* their own address. Covered by `writeNodes` whenever they are not empty.
|
|
35
|
+
*/
|
|
36
|
+
home;
|
|
37
|
+
constructor(principal, readNodes, writeNodes, home) {
|
|
19
38
|
this.principal = Object.freeze({ ...principal });
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
39
|
+
this.readNodes = Object.freeze(readNodes.map(freezePattern));
|
|
40
|
+
this.writeNodes = Object.freeze(writeNodes.map(freezePattern));
|
|
41
|
+
this.home = Object.freeze(homeNode(principal, this.writeNodes, home));
|
|
42
|
+
this.read = Object.freeze({
|
|
43
|
+
...principal,
|
|
44
|
+
projectIds: legacyProjects(principal, this.readNodes),
|
|
45
|
+
});
|
|
46
|
+
this.write = Object.freeze({
|
|
47
|
+
...principal,
|
|
48
|
+
projectIds: legacyProjects(principal, this.writeNodes),
|
|
49
|
+
});
|
|
22
50
|
Object.freeze(this);
|
|
23
51
|
}
|
|
24
52
|
/** @internal Use `localGrant` or `principalGrant`. */
|
|
25
|
-
static issue(principal, read, write) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
53
|
+
static issue(principal, read, write, home = 'planet') {
|
|
54
|
+
checkPrincipal(principal);
|
|
55
|
+
const anonymous = principal.agentId === ANONYMOUS_AGENT;
|
|
56
|
+
if (anonymous && home === 'star')
|
|
57
|
+
throw new RangeError('grant: an anonymous agent has no Star');
|
|
58
|
+
const readSide = anonymous
|
|
59
|
+
? [ownPlanet(principal, read)]
|
|
60
|
+
: [ownPlanet(principal, read), ownStar(principal, read)];
|
|
61
|
+
// An agent whose home is its Star may read the shared Planet but never change it: its writes
|
|
62
|
+
// (new memories, forget, pin, tiers, confirmations) stay in its Star.
|
|
63
|
+
const writeSide = home === 'star'
|
|
64
|
+
? [ownStar(principal, write)]
|
|
65
|
+
: anonymous
|
|
66
|
+
? [ownPlanet(principal, write)]
|
|
67
|
+
: [ownPlanet(principal, write), ownStar(principal, write)];
|
|
68
|
+
return new Grant(principal, readSide, writeSide, home === 'star' ? starNode(principal) : planetNode(principal));
|
|
69
|
+
}
|
|
70
|
+
/** @internal Use `nodeGrant` or `narrowGrant`. */
|
|
71
|
+
static issueNodes(principal, read, write, home) {
|
|
72
|
+
checkPrincipal(principal);
|
|
73
|
+
return new Grant(principal, read, write, home);
|
|
32
74
|
}
|
|
33
75
|
/** True for a real grant (not a copy, not a look-alike). */
|
|
34
76
|
static is(x) {
|
|
35
77
|
return typeof x === 'object' && x !== null && #issued in x;
|
|
36
78
|
}
|
|
37
79
|
}
|
|
80
|
+
function checkPrincipal(principal) {
|
|
81
|
+
for (const k of ['orgId', 'customerId', 'agentId']) {
|
|
82
|
+
if (typeof principal[k] !== 'string' || principal[k] === '') {
|
|
83
|
+
throw new RangeError(`grant: ${k} must be a non-empty string`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The local grant side's Planet: the principal's own Planet, whichever of the
|
|
89
|
+
* person's agents wrote the memory (CON-62; before it, the pattern was
|
|
90
|
+
* restricted to the principal's own agent).
|
|
91
|
+
*/
|
|
92
|
+
function ownPlanet(p, projectIds) {
|
|
93
|
+
return { node: planetNode(p), projectIds };
|
|
94
|
+
}
|
|
95
|
+
/** The principal's agent's own Star: private to that agent, never another's. */
|
|
96
|
+
function ownStar(p, projectIds) {
|
|
97
|
+
return { node: starNode(p), projectIds };
|
|
98
|
+
}
|
|
99
|
+
/** The Star of a principal's agent (owned by the principal's owner). */
|
|
100
|
+
export function starNode(p) {
|
|
101
|
+
return { level: 'agent', orgId: p.orgId, agentId: p.agentId };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* `home` checked against the write side, or the default: the principal's
|
|
105
|
+
* Planet when the write side names it, else the first node written, else the
|
|
106
|
+
* Planet (a read-only grant writes nothing anyway).
|
|
107
|
+
*/
|
|
108
|
+
function homeNode(p, write, home) {
|
|
109
|
+
if (home !== undefined) {
|
|
110
|
+
assertNode(home);
|
|
111
|
+
const { level: _l, ...rest } = home;
|
|
112
|
+
const node = { level: home.level, ...rest };
|
|
113
|
+
if (write.length > 0 && !write.some((w) => nodeKey(w.node) === nodeKey(node))) {
|
|
114
|
+
throw new RangeError('grant: home must be a node the grant writes');
|
|
115
|
+
}
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
const planet = planetNode(p);
|
|
119
|
+
if (write.length === 0 || write.some((w) => nodeKey(w.node) === nodeKey(planet)))
|
|
120
|
+
return planet;
|
|
121
|
+
return write[0].node;
|
|
122
|
+
}
|
|
123
|
+
function freezePattern(p) {
|
|
124
|
+
if (typeof p !== 'object' || p === null)
|
|
125
|
+
throw new TypeError('grant: a node pattern must be an object');
|
|
126
|
+
assertNode(p.node);
|
|
127
|
+
const { level: _l, ...rest } = p.node;
|
|
128
|
+
const node = Object.freeze({ level: p.node.level, ...rest });
|
|
129
|
+
if (p.authorAgentId !== undefined &&
|
|
130
|
+
(typeof p.authorAgentId !== 'string' || p.authorAgentId === '')) {
|
|
131
|
+
throw new RangeError('grant: authorAgentId must be a non-empty string');
|
|
132
|
+
}
|
|
133
|
+
return Object.freeze({
|
|
134
|
+
node,
|
|
135
|
+
projectIds: freezeProjects(p.projectIds),
|
|
136
|
+
...(p.authorAgentId !== undefined && { authorAgentId: p.authorAgentId }),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The projects of `patterns` that a pre-level reader may assume: those of
|
|
141
|
+
* patterns naming exactly the principal's Planet and covering its agent's
|
|
142
|
+
* writing (no author restriction, or that agent). Never wider than the
|
|
143
|
+
* patterns themselves.
|
|
144
|
+
*/
|
|
145
|
+
function legacyProjects(p, patterns) {
|
|
146
|
+
const own = nodeKey({ level: 'user', orgId: p.orgId, customerId: p.customerId });
|
|
147
|
+
const mine = patterns.filter((x) => (x.authorAgentId === undefined || x.authorAgentId === p.agentId) && nodeKey(x.node) === own);
|
|
148
|
+
if (mine.some((x) => x.projectIds === 'all'))
|
|
149
|
+
return 'all';
|
|
150
|
+
return Object.freeze([
|
|
151
|
+
...new Set(mine.flatMap((x) => x.projectIds)),
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
38
154
|
function freezeProjects(p) {
|
|
39
155
|
if (p === 'all')
|
|
40
156
|
return 'all';
|
|
@@ -51,9 +167,17 @@ function samePrincipal(a, b) {
|
|
|
51
167
|
return a.orgId === b.orgId && a.customerId === b.customerId && a.agentId === b.agentId;
|
|
52
168
|
}
|
|
53
169
|
/**
|
|
54
|
-
* The grant for
|
|
55
|
-
*
|
|
56
|
-
* `write`
|
|
170
|
+
* The grant for one agent of one person (CON-62): read and write the
|
|
171
|
+
* person's Planet (memories any of their agents wrote) and this agent's own
|
|
172
|
+
* Star, in the projects `read` names; `opts.write` may narrow the write side.
|
|
173
|
+
* Another agent's Star is never covered. `opts.home` picks where new memories
|
|
174
|
+
* land: the Planet (default) or the agent's Star; with `star` the Planet is
|
|
175
|
+
* read-only (the agent writes only its Star). `ANONYMOUS_AGENT` gets the
|
|
176
|
+
* Planet alone. `write` must name the same principal as `read`.
|
|
177
|
+
*
|
|
178
|
+
* Before CON-62 the Planet side was restricted to memories the principal's
|
|
179
|
+
* own agent wrote. Every local memory so far was written as `claude-code`,
|
|
180
|
+
* so a local store sees exactly what it saw; nothing is rewritten.
|
|
57
181
|
*/
|
|
58
182
|
export function localGrant(read, opts = {}) {
|
|
59
183
|
const write = opts.write ?? read;
|
|
@@ -64,27 +188,110 @@ export function localGrant(read, opts = {}) {
|
|
|
64
188
|
if (!samePrincipal(read, write)) {
|
|
65
189
|
throw new RangeError('localGrant: read and write must name the same org, customer and agent');
|
|
66
190
|
}
|
|
67
|
-
return Grant.issue(read, read.projectIds, write.projectIds);
|
|
191
|
+
return Grant.issue({ orgId: read.orgId, customerId: read.customerId, agentId: read.agentId }, read.projectIds, write.projectIds, opts.home);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Every project of `p` (and its global memories), for read and write:
|
|
195
|
+
* maintenance such as export. Covers the same nodes as `localGrant`: the
|
|
196
|
+
* person's Planet and this agent's own Star.
|
|
197
|
+
*/
|
|
198
|
+
export function principalGrant(p, opts = {}) {
|
|
199
|
+
return Grant.issue({ orgId: p.orgId, customerId: p.customerId, agentId: p.agentId }, 'all', 'all', opts.home);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* A grant over explicit node patterns, possibly across owners and levels:
|
|
203
|
+
* `read` bounds what is seen, `write` (default: `read`) what may change.
|
|
204
|
+
* Trusted: whoever builds one has already decided the principal may use
|
|
205
|
+
* every node it names (local configuration, or membership checked by a
|
|
206
|
+
* control plane). Nothing in the engine builds one for its own callers yet:
|
|
207
|
+
* the CLI, hooks and MCP server keep the pre-level grants.
|
|
208
|
+
*/
|
|
209
|
+
export function nodeGrant(opts) {
|
|
210
|
+
if (!Array.isArray(opts.read) || (opts.write !== undefined && !Array.isArray(opts.write))) {
|
|
211
|
+
throw new TypeError('nodeGrant: read and write must be arrays of node patterns');
|
|
212
|
+
}
|
|
213
|
+
return Grant.issueNodes(opts.principal, opts.read, opts.write ?? opts.read, opts.home);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* `g` narrowed to the nodes `keep` names (by `nodeKey`), on both sides: the
|
|
217
|
+
* grant recall uses for one node's first stage. Never wider than `g`. The
|
|
218
|
+
* home stays when it is kept, else the default for what remains.
|
|
219
|
+
*/
|
|
220
|
+
export function narrowGrant(g, keep) {
|
|
221
|
+
assertGrant(g);
|
|
222
|
+
const keys = new Set(keep.map((n) => nodeKey(n)));
|
|
223
|
+
const read = g.readNodes.filter((p) => keys.has(nodeKey(p.node)));
|
|
224
|
+
const write = g.writeNodes.filter((p) => keys.has(nodeKey(p.node)));
|
|
225
|
+
const home = write.some((p) => nodeKey(p.node) === nodeKey(g.home)) ? g.home : undefined;
|
|
226
|
+
return Grant.issueNodes(g.principal, read, write, home);
|
|
227
|
+
}
|
|
228
|
+
/** The distinct nodes `g` reads, in the order its patterns name them. */
|
|
229
|
+
export function readableNodes(g) {
|
|
230
|
+
assertGrant(g);
|
|
231
|
+
const seen = new Map();
|
|
232
|
+
for (const p of g.readNodes)
|
|
233
|
+
if (!seen.has(nodeKey(p.node)))
|
|
234
|
+
seen.set(nodeKey(p.node), p.node);
|
|
235
|
+
return [...seen.values()];
|
|
68
236
|
}
|
|
69
|
-
/**
|
|
70
|
-
export function
|
|
71
|
-
|
|
237
|
+
/** The address a new memory gets under `g`: its home node, bound to `projectId` when given. */
|
|
238
|
+
export function homeAddress(g, projectId) {
|
|
239
|
+
assertGrant(g);
|
|
240
|
+
return {
|
|
241
|
+
...g.home,
|
|
242
|
+
...(projectId !== undefined && { projectId }),
|
|
243
|
+
};
|
|
72
244
|
}
|
|
73
245
|
/** Rejects anything that is not a real `Grant`; every store calls it first. */
|
|
74
246
|
export function assertGrant(g) {
|
|
75
247
|
if (!Grant.is(g)) {
|
|
76
|
-
throw new TypeError('MemoryStore methods take a Grant (localGrant or
|
|
248
|
+
throw new TypeError('MemoryStore methods take a Grant (localGrant, principalGrant or nodeGrant)');
|
|
77
249
|
}
|
|
78
250
|
}
|
|
79
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* True iff a memory with `scope` lies inside `f`. Extra scope fields do not widen or narrow it.
|
|
253
|
+
* @deprecated Use `grantReads` / `grantWrites`.
|
|
254
|
+
*/
|
|
80
255
|
export function filterCovers(f, scope) {
|
|
81
256
|
return (scope.orgId === f.orgId &&
|
|
82
257
|
scope.customerId === f.customerId &&
|
|
83
258
|
scope.agentId === f.agentId &&
|
|
84
259
|
(f.projectIds === 'all' || f.projectIds.includes(scope.projectId ?? null)));
|
|
85
260
|
}
|
|
86
|
-
|
|
87
|
-
export
|
|
261
|
+
/** True iff `p` covers a memory at `address` written by `author`. */
|
|
262
|
+
export function patternCovers(p, address, author) {
|
|
263
|
+
return (nodeKey(nodeOf(address)) === nodeKey(p.node) &&
|
|
264
|
+
(p.projectIds === 'all' || p.projectIds.includes(address.projectId ?? null)) &&
|
|
265
|
+
(p.authorAgentId === undefined || p.authorAgentId === author.agentId));
|
|
266
|
+
}
|
|
267
|
+
function covers(patterns, m) {
|
|
268
|
+
const address = addressOf(m);
|
|
269
|
+
const author = authorOf(m);
|
|
270
|
+
return patterns.some((p) => patternCovers(p, address, author));
|
|
271
|
+
}
|
|
272
|
+
/** True iff `g` may read `m` (by its address and author). */
|
|
273
|
+
export const grantReads = (g, m) => covers(g.readNodes, m);
|
|
274
|
+
/** True iff `g` may change `m` (by its address and author). */
|
|
275
|
+
export const grantWrites = (g, m) => covers(g.writeNodes, m);
|
|
276
|
+
/** True iff `g` may read a Planet memory with `scope` (`scope.agentId` as its author). */
|
|
277
|
+
export const canRead = (g, scope) => grantReads(g, { scope });
|
|
278
|
+
/** True iff `g` may change a Planet memory with `scope` (`scope.agentId` as its author). */
|
|
279
|
+
export const canWrite = (g, scope) => grantWrites(g, { scope });
|
|
280
|
+
/**
|
|
281
|
+
* Two records occupy the same place: the same address, the same author and
|
|
282
|
+
* the same scope (extra scope fields included). A write that would change any
|
|
283
|
+
* of them for an existing id is refused.
|
|
284
|
+
*/
|
|
285
|
+
export function sameRecordAddress(a, b) {
|
|
286
|
+
return (sameAddress(addressOf(a), addressOf(b)) &&
|
|
287
|
+
sameAuthor(authorOf(a), authorOf(b)) &&
|
|
288
|
+
sameScope(a.scope, b.scope));
|
|
289
|
+
}
|
|
290
|
+
/** The Planet node of a principal: what pre-level grants cover. */
|
|
291
|
+
export function planetNode(p) {
|
|
292
|
+
const { projectId: _p, ...node } = planetOf({ ...p, agentId: '-' });
|
|
293
|
+
return node;
|
|
294
|
+
}
|
|
88
295
|
/**
|
|
89
296
|
* The key a store keeps a cursor under. The local principal (the CLI's own,
|
|
90
297
|
* `local`/`self`/`claude-code`) keeps the bare key, so cursors written before
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.4.0";
|
|
2
2
|
export * from './model.js';
|
|
3
|
+
export * from './address.js';
|
|
4
|
+
export * from './export-format.js';
|
|
3
5
|
export * from './scope.js';
|
|
4
6
|
export * from './config.js';
|
|
5
7
|
export * from './activation.js';
|
|
6
8
|
export * from './adapters.js';
|
|
7
9
|
export * from './embed-cache.js';
|
|
8
10
|
export * from './grant.js';
|
|
11
|
+
export * from './levels.js';
|
|
12
|
+
export * from './agents.js';
|
|
9
13
|
export * from './fusion.js';
|
|
10
14
|
export * from './memory-store.js';
|
|
11
15
|
export * from './tokenize.js';
|
|
@@ -14,6 +18,7 @@ export * from './recall.js';
|
|
|
14
18
|
export * from './relevance.js';
|
|
15
19
|
export * from './observe.js';
|
|
16
20
|
export * from './temporal.js';
|
|
21
|
+
export { chronoLoaded, mayHaveDateCue, preloadChrono } from './date-cue.js';
|
|
17
22
|
export * from './volatile.js';
|
|
18
23
|
export * from './scrub.js';
|
|
19
24
|
export * from './cap.js';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.4.0';
|
|
2
2
|
export * from './model.js';
|
|
3
|
+
export * from './address.js';
|
|
4
|
+
export * from './export-format.js';
|
|
3
5
|
export * from './scope.js';
|
|
4
6
|
export * from './config.js';
|
|
5
7
|
export * from './activation.js';
|
|
6
8
|
export * from './adapters.js';
|
|
7
9
|
export * from './embed-cache.js';
|
|
8
10
|
export * from './grant.js';
|
|
11
|
+
export * from './levels.js';
|
|
12
|
+
export * from './agents.js';
|
|
9
13
|
export * from './fusion.js';
|
|
10
14
|
export * from './memory-store.js';
|
|
11
15
|
export * from './tokenize.js';
|
|
@@ -14,6 +18,7 @@ export * from './recall.js';
|
|
|
14
18
|
export * from './relevance.js';
|
|
15
19
|
export * from './observe.js';
|
|
16
20
|
export * from './temporal.js';
|
|
21
|
+
export { chronoLoaded, mayHaveDateCue, preloadChrono } from './date-cue.js';
|
|
17
22
|
export * from './volatile.js';
|
|
18
23
|
export * from './scrub.js';
|
|
19
24
|
export * from './cap.js';
|
package/dist/isolation.d.ts
CHANGED
|
@@ -4,13 +4,26 @@
|
|
|
4
4
|
* can require an empty list and a test can prove a broken store is caught.
|
|
5
5
|
* No vitest here; `store-conformance.ts` wires these into `it` blocks.
|
|
6
6
|
*/
|
|
7
|
+
import { type Address, type Author } from './address.js';
|
|
7
8
|
import type { MemoryStore } from './adapters.js';
|
|
8
9
|
import { type Grant } from './grant.js';
|
|
9
10
|
import type { Memory, Scope } from './model.js';
|
|
10
11
|
/** A memory for the isolation checks: text, stub and entities all carry `marker`. */
|
|
11
12
|
export declare function isoMemory(id: string, scope: Scope, marker: string, embedding?: Int8Array): Memory;
|
|
12
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The narrowest grant for one scope: its Planet, its one project (or global),
|
|
15
|
+
* memories its own agent wrote. (The pre-CON-62 local grant; today's
|
|
16
|
+
* `localGrant` also covers the Planet's other authors and the agent's Star.)
|
|
17
|
+
*/
|
|
13
18
|
export declare function soleGrant(s: Scope): Grant;
|
|
19
|
+
/** The local grant of `ISO_SCOPES.mine`'s agent for its one project: Planet plus its own Star. */
|
|
20
|
+
export declare function defaultGrant(s: Scope): Grant;
|
|
21
|
+
/** The narrowest grant for one memory at any level: its node, its one project, its author. */
|
|
22
|
+
export declare function soleGrantFor(m: Pick<Memory, 'scope' | 'address' | 'author'>): Grant;
|
|
23
|
+
/** `m` moved to `scope`: its address and author dropped, so the scope's Planet is the address. */
|
|
24
|
+
export declare function movedTo(m: Memory, scope: Scope): Memory;
|
|
25
|
+
/** A memory at `address`, written by `author`, for the isolation checks. */
|
|
26
|
+
export declare function isoAt(id: string, address: Address, author: Author, marker: string, embedding?: Int8Array): Memory;
|
|
14
27
|
/** The scopes the checks use: the caller, and victims that differ from it in one coordinate each. */
|
|
15
28
|
export declare const ISO_SCOPES: {
|
|
16
29
|
mine: {
|
|
@@ -49,6 +62,23 @@ export declare const ISO_SCOPES: {
|
|
|
49
62
|
projectId: string;
|
|
50
63
|
};
|
|
51
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Victims at the other levels, each next to the caller's own Planet: a Planet
|
|
67
|
+
* memory another of the caller's agents wrote, the caller's agent's own Star,
|
|
68
|
+
* another agent's Star (in the caller's project and global), an Orbit, a
|
|
69
|
+
* Flyby, a Constellation and a Galaxy root of an organisation, and one of the
|
|
70
|
+
* caller's own owner. The narrowest grant sees none of them; the local grant
|
|
71
|
+
* sees only those in `DEFAULT_COVERS`.
|
|
72
|
+
*/
|
|
73
|
+
export declare const ISO_LEVELS: Record<string, {
|
|
74
|
+
address: Address;
|
|
75
|
+
author: Author;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* The victims the local grant of `ISO_SCOPES.mine` legitimately covers (CON-62): Planet memories
|
|
79
|
+
* the person's other agents wrote, and its agent's own Star. Never another agent's Star.
|
|
80
|
+
*/
|
|
81
|
+
export declare const DEFAULT_COVERS: readonly string[];
|
|
52
82
|
/**
|
|
53
83
|
* Every `MemoryStore` method, called with a grant for `ISO_SCOPES.mine`
|
|
54
84
|
* against memories (warm and cold) in each other scope: nothing is seen,
|
|
@@ -56,6 +86,10 @@ export declare const ISO_SCOPES: {
|
|
|
56
86
|
* apart. Also the write-side rules (`GrantError` for an out-of-grant scope
|
|
57
87
|
* and for an id that exists elsewhere, atomic batches, address changes),
|
|
58
88
|
* read/write splits, cursor namespaces and rejection of non-grants.
|
|
89
|
+
*
|
|
90
|
+
* Run twice: as the narrowest grant (every victim out of reach), and as the
|
|
91
|
+
* local grant (`localGrant`, Planet plus own Star), for which every victim
|
|
92
|
+
* but `DEFAULT_COVERS` is out of reach, other agents' Stars included.
|
|
59
93
|
*/
|
|
60
94
|
export declare function isolationViolations(make: () => Promise<MemoryStore>): Promise<string[]>;
|
|
61
95
|
/** A small seeded PRNG (mulberry32), so a failing seed replays exactly. */
|
|
@@ -73,5 +107,17 @@ export declare function seededRng(seed: number): {
|
|
|
73
107
|
* order: SQLite FTS5's bm25 uses table-wide term statistics, so another
|
|
74
108
|
* tenant's text shifts scores (a known side channel; see the PR notes).
|
|
75
109
|
* Every other result is compared exactly, dense scores included.
|
|
110
|
+
*
|
|
111
|
+
* `multiNode`: A's grant spans its Planet, its agent's Star and a
|
|
112
|
+
* Constellation of another owner; B's spans its own Planet and a sibling
|
|
113
|
+
* Constellation. Same property.
|
|
114
|
+
*
|
|
115
|
+
* `peers` (CON-62): A and B are two agents of one person, each with the local
|
|
116
|
+
* grant (the shared Planet plus its own Star). A writes to the Planet and its
|
|
117
|
+
* Star; B writes only to its own Star and aims every method at A's Star ids.
|
|
118
|
+
* Nothing B does through its Star reaches A.
|
|
76
119
|
*/
|
|
77
|
-
export declare function nonInterference(make: () => Promise<MemoryStore>, seed: number, steps: number
|
|
120
|
+
export declare function nonInterference(make: () => Promise<MemoryStore>, seed: number, steps: number, opts?: {
|
|
121
|
+
multiNode?: boolean;
|
|
122
|
+
peers?: boolean;
|
|
123
|
+
}): Promise<string | null>;
|