@fgv/ts-agent-memory 5.1.0-39 → 5.1.0-41
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/.rush/temp/{b82cf6bdece20481260e6bab946179eeec9d7b46.tar.log → cbbdbe09515171b4eba8f2592be2dace1e4e8142.tar.log} +14 -2
- package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +2 -2
- package/.rush/temp/operation/build/all.log +2 -2
- package/.rush/temp/operation/build/log-chunks.jsonl +2 -2
- package/.rush/temp/operation/build/state.json +1 -1
- package/dist/packlets/converters/envelopeConverter.js +17 -3
- package/dist/packlets/converters/envelopeConverter.js.map +1 -1
- package/dist/packlets/index/memoryIndex.js +58 -10
- package/dist/packlets/index/memoryIndex.js.map +1 -1
- package/dist/packlets/ingest/cycleGuard.js +13 -6
- package/dist/packlets/ingest/cycleGuard.js.map +1 -1
- package/dist/packlets/ingest/hostStages.js.map +1 -1
- package/dist/packlets/ingest/model.js.map +1 -1
- package/dist/packlets/ingest/orchestrator.js +94 -49
- package/dist/packlets/ingest/orchestrator.js.map +1 -1
- package/dist/packlets/retrieve/hybridRetriever.js +13 -2
- package/dist/packlets/retrieve/hybridRetriever.js.map +1 -1
- package/dist/packlets/retrieve/linkTraversalRetriever.js +46 -57
- package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/dist/packlets/retrieve/recencyRetriever.js +3 -3
- package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/dist/packlets/retrieve/retriever.js +50 -7
- package/dist/packlets/retrieve/retriever.js.map +1 -1
- package/dist/packlets/retrieve/semanticRetriever.js +9 -3
- package/dist/packlets/retrieve/semanticRetriever.js.map +1 -1
- package/dist/packlets/retrieve/structuredFilterRetriever.js +3 -3
- package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/dist/packlets/retrieve/tagRetriever.js +3 -3
- package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
- package/dist/packlets/retrieve/temporalRetrievers.js +3 -3
- package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/dist/packlets/store/fileTreeMemoryStore.js +72 -16
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/tools/memoryTools.js +104 -21
- package/dist/packlets/tools/memoryTools.js.map +1 -1
- package/dist/packlets/types/envelope.js +13 -1
- package/dist/packlets/types/envelope.js.map +1 -1
- package/dist/packlets/vector/inMemoryCosineIndex.js +22 -17
- package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/dist/packlets/vector/vectorIndex.js.map +1 -1
- package/dist/test/unit/converters/antagonistRoundTrip.test.js +3 -3
- package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +1 -1
- package/dist/test/unit/converters/envelopeConverter.test.js +125 -8
- package/dist/test/unit/converters/envelopeConverter.test.js.map +1 -1
- package/dist/test/unit/index/memoryIndex.test.js +87 -25
- package/dist/test/unit/index/memoryIndex.test.js.map +1 -1
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +20 -16
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -1
- package/dist/test/unit/ingest/cycleGuard.test.js +28 -1
- package/dist/test/unit/ingest/cycleGuard.test.js.map +1 -1
- package/dist/test/unit/ingest/orchestrator.test.js +187 -45
- package/dist/test/unit/ingest/orchestrator.test.js.map +1 -1
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +106 -31
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -1
- package/dist/test/unit/retrieve/retrievers.test.js +299 -37
- package/dist/test/unit/retrieve/retrievers.test.js.map +1 -1
- package/dist/test/unit/store/embedOnWrite.test.js +69 -12
- package/dist/test/unit/store/embedOnWrite.test.js.map +1 -1
- package/dist/test/unit/store/listScoped.test.js +109 -0
- package/dist/test/unit/store/listScoped.test.js.map +1 -0
- package/dist/test/unit/store/rankAxis.test.js +254 -0
- package/dist/test/unit/store/rankAxis.test.js.map +1 -0
- package/dist/test/unit/tools/memoryTools.test.js +280 -11
- package/dist/test/unit/tools/memoryTools.test.js.map +1 -1
- package/dist/test/unit/types/writePolicy.test.js +9 -2
- package/dist/test/unit/types/writePolicy.test.js.map +1 -1
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js +95 -35
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -1
- package/dist/test/unit/vector/vectorIndex.test.js +24 -15
- package/dist/test/unit/vector/vectorIndex.test.js.map +1 -1
- package/dist/ts-agent-memory.d.ts +384 -97
- package/etc/ts-agent-memory.api.md +64 -22
- package/lib/packlets/converters/envelopeConverter.d.ts +8 -1
- package/lib/packlets/converters/envelopeConverter.d.ts.map +1 -1
- package/lib/packlets/converters/envelopeConverter.js +18 -4
- package/lib/packlets/converters/envelopeConverter.js.map +1 -1
- package/lib/packlets/index/memoryIndex.d.ts +42 -10
- package/lib/packlets/index/memoryIndex.d.ts.map +1 -1
- package/lib/packlets/index/memoryIndex.js +58 -10
- package/lib/packlets/index/memoryIndex.js.map +1 -1
- package/lib/packlets/ingest/cycleGuard.d.ts +5 -5
- package/lib/packlets/ingest/cycleGuard.d.ts.map +1 -1
- package/lib/packlets/ingest/cycleGuard.js +13 -6
- package/lib/packlets/ingest/cycleGuard.js.map +1 -1
- package/lib/packlets/ingest/hostStages.d.ts +3 -3
- package/lib/packlets/ingest/hostStages.d.ts.map +1 -1
- package/lib/packlets/ingest/hostStages.js.map +1 -1
- package/lib/packlets/ingest/model.d.ts +25 -14
- package/lib/packlets/ingest/model.d.ts.map +1 -1
- package/lib/packlets/ingest/model.js.map +1 -1
- package/lib/packlets/ingest/orchestrator.d.ts +18 -4
- package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
- package/lib/packlets/ingest/orchestrator.js +93 -48
- package/lib/packlets/ingest/orchestrator.js.map +1 -1
- package/lib/packlets/retrieve/hybridRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/hybridRetriever.js +12 -1
- package/lib/packlets/retrieve/hybridRetriever.js.map +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +18 -23
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.js +45 -56
- package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/lib/packlets/retrieve/recencyRetriever.js +2 -2
- package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/lib/packlets/retrieve/retriever.d.ts +70 -11
- package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/retriever.js +52 -7
- package/lib/packlets/retrieve/retriever.js.map +1 -1
- package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/semanticRetriever.js +9 -3
- package/lib/packlets/retrieve/semanticRetriever.js.map +1 -1
- package/lib/packlets/retrieve/structuredFilterRetriever.js +2 -2
- package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/lib/packlets/retrieve/tagRetriever.js +2 -2
- package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.js +3 -3
- package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +57 -3
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +72 -16
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/tools/memoryTools.d.ts +24 -0
- package/lib/packlets/tools/memoryTools.d.ts.map +1 -1
- package/lib/packlets/tools/memoryTools.js +104 -21
- package/lib/packlets/tools/memoryTools.js.map +1 -1
- package/lib/packlets/types/envelope.d.ts +61 -8
- package/lib/packlets/types/envelope.d.ts.map +1 -1
- package/lib/packlets/types/envelope.js +14 -0
- package/lib/packlets/types/envelope.js.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts +9 -5
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.js +22 -17
- package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/lib/packlets/vector/vectorIndex.d.ts +46 -20
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
- package/lib/packlets/vector/vectorIndex.js.map +1 -1
- package/lib/test/unit/converters/antagonistRoundTrip.test.js +3 -3
- package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +1 -1
- package/lib/test/unit/converters/envelopeConverter.test.js +124 -7
- package/lib/test/unit/converters/envelopeConverter.test.js.map +1 -1
- package/lib/test/unit/index/memoryIndex.test.js +86 -24
- package/lib/test/unit/index/memoryIndex.test.js.map +1 -1
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +20 -16
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -1
- package/lib/test/unit/ingest/cycleGuard.test.js +28 -1
- package/lib/test/unit/ingest/cycleGuard.test.js.map +1 -1
- package/lib/test/unit/ingest/orchestrator.test.js +186 -44
- package/lib/test/unit/ingest/orchestrator.test.js.map +1 -1
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +106 -31
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -1
- package/lib/test/unit/retrieve/retrievers.test.js +298 -36
- package/lib/test/unit/retrieve/retrievers.test.js.map +1 -1
- package/lib/test/unit/store/embedOnWrite.test.js +68 -11
- package/lib/test/unit/store/embedOnWrite.test.js.map +1 -1
- package/lib/test/unit/store/listScoped.test.d.ts +2 -0
- package/lib/test/unit/store/listScoped.test.d.ts.map +1 -0
- package/lib/test/unit/store/listScoped.test.js +111 -0
- package/lib/test/unit/store/listScoped.test.js.map +1 -0
- package/lib/test/unit/store/rankAxis.test.d.ts +2 -0
- package/lib/test/unit/store/rankAxis.test.d.ts.map +1 -0
- package/lib/test/unit/store/rankAxis.test.js +256 -0
- package/lib/test/unit/store/rankAxis.test.js.map +1 -0
- package/lib/test/unit/tools/memoryTools.test.js +280 -11
- package/lib/test/unit/tools/memoryTools.test.js.map +1 -1
- package/lib/test/unit/types/writePolicy.test.js +9 -2
- package/lib/test/unit/types/writePolicy.test.js.map +1 -1
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js +95 -35
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -1
- package/lib/test/unit/vector/vectorIndex.test.js +24 -15
- package/lib/test/unit/vector/vectorIndex.test.js.map +1 -1
- package/package.json +7 -7
- package/rush-logs/ts-agent-memory.build.cache.log +1 -1
- package/rush-logs/ts-agent-memory.build.log +2 -2
- package/src/packlets/converters/envelopeConverter.ts +27 -4
- package/src/packlets/index/memoryIndex.ts +86 -22
- package/src/packlets/ingest/cycleGuard.ts +22 -11
- package/src/packlets/ingest/hostStages.ts +3 -3
- package/src/packlets/ingest/model.ts +25 -14
- package/src/packlets/ingest/orchestrator.ts +143 -67
- package/src/packlets/retrieve/hybridRetriever.ts +14 -1
- package/src/packlets/retrieve/linkTraversalRetriever.ts +51 -62
- package/src/packlets/retrieve/recencyRetriever.ts +3 -3
- package/src/packlets/retrieve/retriever.ts +97 -13
- package/src/packlets/retrieve/semanticRetriever.ts +10 -5
- package/src/packlets/retrieve/structuredFilterRetriever.ts +3 -3
- package/src/packlets/retrieve/tagRetriever.ts +3 -3
- package/src/packlets/retrieve/temporalRetrievers.ts +3 -3
- package/src/packlets/store/fileTreeMemoryStore.ts +117 -12
- package/src/packlets/tools/memoryTools.ts +152 -25
- package/src/packlets/types/envelope.ts +66 -8
- package/src/packlets/vector/inMemoryCosineIndex.ts +45 -22
- package/src/packlets/vector/vectorIndex.ts +47 -20
- package/src/test/unit/converters/antagonistRoundTrip.test.ts +3 -3
- package/src/test/unit/converters/envelopeConverter.test.ts +168 -11
- package/src/test/unit/index/memoryIndex.test.ts +99 -14
- package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +23 -18
- package/src/test/unit/ingest/cycleGuard.test.ts +44 -2
- package/src/test/unit/ingest/orchestrator.test.ts +234 -41
- package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +134 -35
- package/src/test/unit/retrieve/retrievers.test.ts +381 -25
- package/src/test/unit/store/embedOnWrite.test.ts +83 -11
- package/src/test/unit/store/listScoped.test.ts +138 -0
- package/src/test/unit/store/rankAxis.test.ts +349 -0
- package/src/test/unit/tools/memoryTools.test.ts +362 -13
- package/src/test/unit/types/writePolicy.test.ts +11 -2
- package/src/test/unit/vector/inMemoryCosineIndex.test.ts +115 -39
- package/src/test/unit/vector/vectorIndex.test.ts +33 -17
- package/temp/build/lint/_eslint-5eVG3S6w.json +41 -33
- package/temp/build/typescript/ts_8nwakTlr.json +1 -1
- package/temp/ts-agent-memory.api.json +1080 -136
- package/temp/ts-agent-memory.api.md +64 -22
|
@@ -91,10 +91,32 @@ function candidate(kind, entityId, body, opts = {}) {
|
|
|
91
91
|
body
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* A scope-qualified target, authored as `scope#id` or a bare id defaulting to the
|
|
96
|
+
* knowledge scope (where the note/num fixtures live). `kt` is the assertion-side
|
|
97
|
+
* spelling of the same helper.
|
|
98
|
+
*/
|
|
99
|
+
function scopedTarget(spec) {
|
|
100
|
+
const hash = spec.indexOf('#');
|
|
101
|
+
const scope = hash >= 0 ? spec.slice(0, hash) : 'knowledge';
|
|
102
|
+
const id = hash >= 0 ? spec.slice(hash + 1) : spec;
|
|
103
|
+
return { scope: scope, id: id };
|
|
104
|
+
}
|
|
105
|
+
function kt(id, scope = 'knowledge') {
|
|
106
|
+
return { scope: scope, id: id };
|
|
107
|
+
}
|
|
108
|
+
/** The scope-qualified reference of a candidate about to be written, by its entityId. */
|
|
109
|
+
function srcOf(ctx, entityId) {
|
|
110
|
+
const found = ctx.candidates.find((rc) => rc.candidate.envelope.entityId === entityId);
|
|
111
|
+
if (found === undefined) {
|
|
112
|
+
throw new Error(`test relater: no candidate with entityId '${entityId}'`);
|
|
113
|
+
}
|
|
114
|
+
return found.id;
|
|
115
|
+
}
|
|
94
116
|
function candEdge(source, type, target, confidence) {
|
|
95
117
|
return {
|
|
96
|
-
source: source,
|
|
97
|
-
edge: Object.assign({ type: type, target: target }, (confidence !== undefined ? { confidence } : {}))
|
|
118
|
+
source: scopedTarget(source),
|
|
119
|
+
edge: Object.assign({ type: type, target: scopedTarget(target) }, (confidence !== undefined ? { confidence } : {}))
|
|
98
120
|
};
|
|
99
121
|
}
|
|
100
122
|
function buildStore(params = {}) {
|
|
@@ -165,7 +187,10 @@ describe('MemoryIngestOrchestrator', () => {
|
|
|
165
187
|
test('classifies, extracts, and writes one record end-to-end with host-ingest provenance + derivedFrom', async () => {
|
|
166
188
|
const store = buildStore();
|
|
167
189
|
const orch = buildOrchestrator({ store });
|
|
168
|
-
const sourceId =
|
|
190
|
+
const sourceId = {
|
|
191
|
+
scope: 'conversations/c1',
|
|
192
|
+
id: 'turn-3'
|
|
193
|
+
};
|
|
169
194
|
const result = await orch.ingestItem({ id: 'doc-1', content: 'the sky is blue', sourceId });
|
|
170
195
|
expect(result).toSucceedAndSatisfy((r) => {
|
|
171
196
|
var _a, _b, _c;
|
|
@@ -176,7 +201,7 @@ describe('MemoryIngestOrchestrator', () => {
|
|
|
176
201
|
expect(rec.resolution.verdict).toBe('new');
|
|
177
202
|
expect(rec.id).toBe('doc-1');
|
|
178
203
|
expect((_a = rec.record) === null || _a === void 0 ? void 0 : _a.envelope.provenance.source).toBe(index_1.HOST_INGEST_PROVENANCE_SOURCE);
|
|
179
|
-
expect((_b = rec.record) === null || _b === void 0 ? void 0 : _b.envelope.provenance.derivedFrom).
|
|
204
|
+
expect((_b = rec.record) === null || _b === void 0 ? void 0 : _b.envelope.provenance.derivedFrom).toEqual(sourceId);
|
|
180
205
|
expect((_c = rec.record) === null || _c === void 0 ? void 0 : _c.body).toBe('the sky is blue');
|
|
181
206
|
expect(rec.interlock).toBeUndefined();
|
|
182
207
|
});
|
|
@@ -251,6 +276,25 @@ describe('MemoryIngestOrchestrator', () => {
|
|
|
251
276
|
});
|
|
252
277
|
expect(await orch.ingestItem({ id: 'o-1', content: 'x' })).toFailWith(/no identity codec/);
|
|
253
278
|
});
|
|
279
|
+
test('fails loudly when a pre-existing snapshot record cannot be scoped (no codec for its kind)', async () => {
|
|
280
|
+
// The store can persist a note (it has the note codec), but the orchestrator
|
|
281
|
+
// below is wired WITHOUT a note codec — so when it snapshots the store to run
|
|
282
|
+
// the edge path, it cannot resolve the seeded note's scope and fails loudly
|
|
283
|
+
// (never silently drops it from the cycle graph). This is the branch the
|
|
284
|
+
// scope-qualified edge change added.
|
|
285
|
+
const store = buildStore();
|
|
286
|
+
await putNote(store, 'legacy', 'anchor');
|
|
287
|
+
const orch = index_1.MemoryIngestOrchestrator.create({
|
|
288
|
+
store,
|
|
289
|
+
registry: registry(),
|
|
290
|
+
// Deliberately omit the note codec (and any default) that the seeded record needs.
|
|
291
|
+
codecs: new Map([[numKind, new index_1.KnowledgeIdentityCodec()]]),
|
|
292
|
+
classifier: classifier(() => (0, ts_utils_1.succeed)({ kind: numKind })),
|
|
293
|
+
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(numKind, 'n-1', 7)])),
|
|
294
|
+
relationExtractor: noEdges
|
|
295
|
+
}).orThrow();
|
|
296
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/cannot resolve scope for stored record 'legacy'.*no identity codec registered for kind 'note'/i);
|
|
297
|
+
});
|
|
254
298
|
});
|
|
255
299
|
describe('stage 4 — exact dedup (layer 1)', () => {
|
|
256
300
|
test('an exact {kind,body} match in scope is duplicate-of (no resolver)', async () => {
|
|
@@ -261,7 +305,7 @@ describe('MemoryIngestOrchestrator', () => {
|
|
|
261
305
|
});
|
|
262
306
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
263
307
|
expect(r.records[0].disposition).toBe('deduped');
|
|
264
|
-
expect(r.records[0].resolution).toEqual({ verdict: 'duplicate-of', target: 'doc-a' });
|
|
308
|
+
expect(r.records[0].resolution).toEqual({ verdict: 'duplicate-of', target: kt('doc-a') });
|
|
265
309
|
expect(r.records[0].id).toBe('doc-a');
|
|
266
310
|
});
|
|
267
311
|
// doc-b was never written.
|
|
@@ -318,13 +362,17 @@ async function putNote(store, id, body) {
|
|
|
318
362
|
(await store.put(rec)).orThrow();
|
|
319
363
|
}
|
|
320
364
|
function mockStore(overrides) {
|
|
321
|
-
var _a, _b, _c, _d, _e;
|
|
365
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
322
366
|
return {
|
|
323
367
|
get: (_a = overrides.get) !== null && _a !== void 0 ? _a : (() => Promise.resolve((0, ts_utils_1.succeed)(undefined))),
|
|
324
368
|
getById: (_b = overrides.getById) !== null && _b !== void 0 ? _b : (() => Promise.resolve((0, ts_utils_1.succeed)(undefined))),
|
|
325
369
|
list: (_c = overrides.list) !== null && _c !== void 0 ? _c : (() => Promise.resolve((0, ts_utils_1.succeed)([]))),
|
|
326
|
-
|
|
327
|
-
|
|
370
|
+
listScoped: (_d = overrides.listScoped) !== null && _d !== void 0 ? _d : (() => Promise.resolve((0, ts_utils_1.succeed)([]))),
|
|
371
|
+
asRecordSource: (_e = overrides.asRecordSource) !== null && _e !== void 0 ? _e : (() => ({
|
|
372
|
+
list: () => Promise.resolve((0, ts_utils_1.succeed)([]))
|
|
373
|
+
})),
|
|
374
|
+
put: (_f = overrides.put) !== null && _f !== void 0 ? _f : ((r) => Promise.resolve((0, ts_utils_1.succeed)(r))),
|
|
375
|
+
delete: (_g = overrides.delete) !== null && _g !== void 0 ? _g : (() => Promise.resolve((0, ts_utils_1.fail)('n/a')))
|
|
328
376
|
};
|
|
329
377
|
}
|
|
330
378
|
describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
@@ -352,7 +400,7 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
352
400
|
store,
|
|
353
401
|
vectorIndex,
|
|
354
402
|
embed,
|
|
355
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'duplicate-of', target: similar[0].
|
|
403
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'duplicate-of', target: similar[0].target })),
|
|
356
404
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
357
405
|
});
|
|
358
406
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
@@ -369,12 +417,12 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
369
417
|
store,
|
|
370
418
|
vectorIndex,
|
|
371
419
|
embed,
|
|
372
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'supersede', target: similar[0].
|
|
420
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'supersede', target: similar[0].target })),
|
|
373
421
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
374
422
|
});
|
|
375
423
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
376
424
|
expect(r.records[0].disposition).toBe('written');
|
|
377
|
-
expect(r.records[0].resolution).toEqual({ verdict: 'supersede', target: 'doc-a' });
|
|
425
|
+
expect(r.records[0].resolution).toEqual({ verdict: 'supersede', target: kt('doc-a') });
|
|
378
426
|
expect(r.records[0].id).toBe('doc-b');
|
|
379
427
|
});
|
|
380
428
|
expect(await store.get(noteKind, 'doc-b')).toSucceedAndSatisfy((rec) => expect(rec === null || rec === void 0 ? void 0 : rec.body).toBe('apple tart'));
|
|
@@ -387,7 +435,7 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
387
435
|
store,
|
|
388
436
|
vectorIndex,
|
|
389
437
|
embed,
|
|
390
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].
|
|
438
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].target })),
|
|
391
439
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
392
440
|
});
|
|
393
441
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
@@ -406,10 +454,10 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
406
454
|
store,
|
|
407
455
|
vectorIndex,
|
|
408
456
|
embed,
|
|
409
|
-
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: 'ghost' })),
|
|
457
|
+
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: kt('ghost') })),
|
|
410
458
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
411
459
|
});
|
|
412
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/merge-into target 'ghost' does not exist/);
|
|
460
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/merge-into target 'knowledge\/ghost' does not exist/);
|
|
413
461
|
});
|
|
414
462
|
test('a below-threshold neighbor is not surfaced (resolver not called)', async () => {
|
|
415
463
|
const vectorIndex = index_1.InMemoryCosineIndex.create().orThrow();
|
|
@@ -446,9 +494,9 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
446
494
|
});
|
|
447
495
|
test('a surfaced hit with no backing record is skipped', async () => {
|
|
448
496
|
const ghostIndex = {
|
|
449
|
-
add: (
|
|
450
|
-
remove: (
|
|
451
|
-
query: () => Promise.resolve((0, ts_utils_1.succeed)([{
|
|
497
|
+
add: (t) => Promise.resolve((0, ts_utils_1.succeed)(t.id)),
|
|
498
|
+
remove: (t) => Promise.resolve((0, ts_utils_1.succeed)(t)),
|
|
499
|
+
query: () => Promise.resolve((0, ts_utils_1.succeed)([{ target: kt('ghost'), score: 0.99 }]))
|
|
452
500
|
};
|
|
453
501
|
const orch = buildOrchestrator({
|
|
454
502
|
store: buildStore(),
|
|
@@ -474,8 +522,8 @@ describe('MemoryIngestOrchestrator — stage 4 similarity (layer 2)', () => {
|
|
|
474
522
|
});
|
|
475
523
|
test('a similarity-query failure surfaces loudly', async () => {
|
|
476
524
|
const failingIndex = {
|
|
477
|
-
add: (
|
|
478
|
-
remove: (
|
|
525
|
+
add: (t) => Promise.resolve((0, ts_utils_1.succeed)(t.id)),
|
|
526
|
+
remove: (t) => Promise.resolve((0, ts_utils_1.succeed)(t)),
|
|
479
527
|
query: () => Promise.resolve((0, ts_utils_1.fail)('query kaput'))
|
|
480
528
|
};
|
|
481
529
|
const orch = buildOrchestrator({
|
|
@@ -547,7 +595,7 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
547
595
|
var _a;
|
|
548
596
|
expect(r.records[0].edges).toHaveLength(1);
|
|
549
597
|
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([
|
|
550
|
-
{ type: 'mentions', target: 'doc-a', confidence: 0.7 }
|
|
598
|
+
{ type: 'mentions', target: kt('doc-a'), confidence: 0.7 }
|
|
551
599
|
]);
|
|
552
600
|
});
|
|
553
601
|
});
|
|
@@ -560,7 +608,7 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
560
608
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
561
609
|
var _a;
|
|
562
610
|
expect(r.records).toHaveLength(2);
|
|
563
|
-
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: 'doc-c' }]);
|
|
611
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: kt('doc-c') }]);
|
|
564
612
|
expect(r.records[1].edges).toEqual([]);
|
|
565
613
|
});
|
|
566
614
|
});
|
|
@@ -570,7 +618,7 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
570
618
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'x')])),
|
|
571
619
|
relationExtractor: relater(() => (0, ts_utils_1.succeed)([candEdge('ghost', 'rel', 'doc-b')]))
|
|
572
620
|
});
|
|
573
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/edge source 'ghost' is not a candidate being written/);
|
|
621
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/edge source 'knowledge\/ghost' is not a candidate being written/);
|
|
574
622
|
});
|
|
575
623
|
test('rejects an edge whose target resolves to nothing', async () => {
|
|
576
624
|
const orch = buildOrchestrator({
|
|
@@ -578,7 +626,7 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
578
626
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'x')])),
|
|
579
627
|
relationExtractor: relater(() => (0, ts_utils_1.succeed)([candEdge('doc-b', 'rel', 'ghost')]))
|
|
580
628
|
});
|
|
581
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/edge target 'ghost' resolves to neither/);
|
|
629
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/edge target 'knowledge\/ghost' resolves to neither/);
|
|
582
630
|
});
|
|
583
631
|
test('rejects a cycle-inducing edge (default guard)', async () => {
|
|
584
632
|
const orch = buildOrchestrator({
|
|
@@ -597,8 +645,8 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
597
645
|
});
|
|
598
646
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
599
647
|
var _a, _b;
|
|
600
|
-
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: 'doc-c' }]);
|
|
601
|
-
expect((_b = r.records[1].record) === null || _b === void 0 ? void 0 : _b.envelope.links).toEqual([{ type: 'rel', target: 'doc-b' }]);
|
|
648
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: kt('doc-c') }]);
|
|
649
|
+
expect((_b = r.records[1].record) === null || _b === void 0 ? void 0 : _b.envelope.links).toEqual([{ type: 'rel', target: kt('doc-b') }]);
|
|
602
650
|
});
|
|
603
651
|
});
|
|
604
652
|
test('a contradicts edge on a NON-temporal kind persists as a plain link (no interlock)', async () => {
|
|
@@ -612,7 +660,89 @@ describe('MemoryIngestOrchestrator — stage 5 relate + cycle guard', () => {
|
|
|
612
660
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
613
661
|
var _a;
|
|
614
662
|
expect(r.records[0].interlock).toBeUndefined();
|
|
615
|
-
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'contradicts', target: 'doc-a' }]);
|
|
663
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'contradicts', target: kt('doc-a') }]);
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
describe('_validateEdges cross-scope target disambiguation', () => {
|
|
667
|
+
// Two EXISTING records share the idStem 'turn-3' across two conversations
|
|
668
|
+
// (the MTM codec mints per-scope stems). A stage-5 edge target must resolve
|
|
669
|
+
// to the CORRECT (scope, id) — with bare-id keying both would alias and a
|
|
670
|
+
// wrong-scope target would silently validate. Guards the ingest-validation seam.
|
|
671
|
+
const mtmKind = 'mtm';
|
|
672
|
+
function mtmRegistry() {
|
|
673
|
+
const reg = registry();
|
|
674
|
+
reg.register(mtmKind, ts_utils_1.Converters.string);
|
|
675
|
+
return reg;
|
|
676
|
+
}
|
|
677
|
+
const mtmCodecs = new Map([
|
|
678
|
+
[mtmKind, new index_1.MtmIdentityCodec()]
|
|
679
|
+
]);
|
|
680
|
+
async function seedTurn(store, entityId, body) {
|
|
681
|
+
const addr = new index_1.MtmIdentityCodec().encode(entityId).orThrow();
|
|
682
|
+
const rec = {
|
|
683
|
+
envelope: {
|
|
684
|
+
id: addr.idStem,
|
|
685
|
+
entityId: entityId,
|
|
686
|
+
kind: mtmKind,
|
|
687
|
+
tags: [],
|
|
688
|
+
links: [],
|
|
689
|
+
created: 0,
|
|
690
|
+
updated: 0,
|
|
691
|
+
seq: 0,
|
|
692
|
+
contentHash: '',
|
|
693
|
+
provenance: { source: 'agent' }
|
|
694
|
+
},
|
|
695
|
+
body
|
|
696
|
+
};
|
|
697
|
+
(await store.put(rec)).orThrow();
|
|
698
|
+
}
|
|
699
|
+
function buildMtmOrchestrator(store, relationExtractor) {
|
|
700
|
+
return index_1.MemoryIngestOrchestrator.create({
|
|
701
|
+
store,
|
|
702
|
+
registry: mtmRegistry(),
|
|
703
|
+
codecs: mtmCodecs,
|
|
704
|
+
classifier: classifier(() => (0, ts_utils_1.succeed)({ kind: mtmKind })),
|
|
705
|
+
// The candidate is a fresh turn-5 under conv-a (distinct stem from the seeds).
|
|
706
|
+
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(mtmKind, 'conv-a:5', 'a new turn')])),
|
|
707
|
+
relationExtractor
|
|
708
|
+
}).orThrow();
|
|
709
|
+
}
|
|
710
|
+
async function seededStore() {
|
|
711
|
+
const store = index_1.FileTreeMemoryStore.create({
|
|
712
|
+
root: mutableRoot(),
|
|
713
|
+
registry: mtmRegistry(),
|
|
714
|
+
codecs: mtmCodecs,
|
|
715
|
+
clock
|
|
716
|
+
}).orThrow();
|
|
717
|
+
await seedTurn(store, 'conv-a:3', 'anchor in conversation a');
|
|
718
|
+
await seedTurn(store, 'conv-b:3', 'anchor in conversation b');
|
|
719
|
+
return store;
|
|
720
|
+
}
|
|
721
|
+
test('accepts a same-stem edge target that resolves to the correct scope', async () => {
|
|
722
|
+
const store = await seededStore();
|
|
723
|
+
const orch = buildMtmOrchestrator(store, relater((ctx) => (0, ts_utils_1.succeed)([
|
|
724
|
+
{
|
|
725
|
+
source: srcOf(ctx, 'conv-a:5'),
|
|
726
|
+
edge: { type: 'rel', target: kt('turn-3', 'conversations/conv-a') }
|
|
727
|
+
}
|
|
728
|
+
])));
|
|
729
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
730
|
+
var _a;
|
|
731
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([
|
|
732
|
+
{ type: 'rel', target: kt('turn-3', 'conversations/conv-a') }
|
|
733
|
+
]);
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
test('rejects a same-stem edge target whose scope has no matching record', async () => {
|
|
737
|
+
const store = await seededStore();
|
|
738
|
+
const orch = buildMtmOrchestrator(store, relater((ctx) => (0, ts_utils_1.succeed)([
|
|
739
|
+
{
|
|
740
|
+
source: srcOf(ctx, 'conv-a:5'),
|
|
741
|
+
// turn-3 exists under conv-a and conv-b, but NOT conv-z.
|
|
742
|
+
edge: { type: 'rel', target: kt('turn-3', 'conversations/conv-z') }
|
|
743
|
+
}
|
|
744
|
+
])));
|
|
745
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/edge target 'conversations\/conv-z\/turn-3' resolves to neither a sibling candidate nor an existing record/);
|
|
616
746
|
});
|
|
617
747
|
});
|
|
618
748
|
});
|
|
@@ -633,13 +763,20 @@ describe('MemoryIngestOrchestrator — contradicts→temporal interlock', () =>
|
|
|
633
763
|
store,
|
|
634
764
|
classifier: classifyFact,
|
|
635
765
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(factKind, 'fact-1', 'the sky is grey')])),
|
|
636
|
-
relationExtractor: relater(() => (0, ts_utils_1.succeed)([
|
|
766
|
+
relationExtractor: relater((ctx) => (0, ts_utils_1.succeed)([
|
|
767
|
+
{
|
|
768
|
+
source: srcOf(ctx, 'fact-1'),
|
|
769
|
+
edge: { type: index_1.CONTRADICTS_LINK_TYPE, target: kt(v1Id, 'facts/entities/fact-1') }
|
|
770
|
+
}
|
|
771
|
+
]))
|
|
637
772
|
});
|
|
638
773
|
expect(await secondOrch.ingestItem({ id: 'fact-1', content: 'the sky is grey' })).toSucceedAndSatisfy((r) => {
|
|
639
774
|
var _a;
|
|
640
775
|
expect(r.records[0].interlock).toBe('temporal-versioned');
|
|
641
776
|
expect(r.records[0].disposition).toBe('written');
|
|
642
|
-
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([
|
|
777
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([
|
|
778
|
+
{ type: index_1.CONTRADICTS_LINK_TYPE, target: kt(v1Id, 'facts/entities/fact-1') }
|
|
779
|
+
]);
|
|
643
780
|
});
|
|
644
781
|
// The current version is the new (contradicting) one.
|
|
645
782
|
expect(await store.get(factKind, 'fact-1')).toSucceedAndSatisfy((rec) => expect(rec === null || rec === void 0 ? void 0 : rec.body).toBe('the sky is grey'));
|
|
@@ -661,7 +798,12 @@ describe('MemoryIngestOrchestrator — contradicts→temporal interlock', () =>
|
|
|
661
798
|
store,
|
|
662
799
|
classifier: classifyFact,
|
|
663
800
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(factKind, 'fact-1', 'grey')])),
|
|
664
|
-
relationExtractor: relater(() => (0, ts_utils_1.succeed)([
|
|
801
|
+
relationExtractor: relater((ctx) => (0, ts_utils_1.succeed)([
|
|
802
|
+
{
|
|
803
|
+
source: srcOf(ctx, 'fact-1'),
|
|
804
|
+
edge: { type: index_1.CONTRADICTS_LINK_TYPE, target: kt(v1Id, 'facts/entities/fact-1') }
|
|
805
|
+
}
|
|
806
|
+
]))
|
|
665
807
|
});
|
|
666
808
|
(await o2.ingestItem({ id: 'fact-1', content: 'grey' })).orThrow();
|
|
667
809
|
// Re-introduce the ORIGINAL body: the invalidated v1 must be skipped by exact
|
|
@@ -792,7 +934,7 @@ describe('MemoryIngestOrchestrator — review-punch-list fixes', () => {
|
|
|
792
934
|
});
|
|
793
935
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceedAndSatisfy((r) => {
|
|
794
936
|
var _a;
|
|
795
|
-
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: 'doc-a' }]);
|
|
937
|
+
expect((_a = r.records[0].record) === null || _a === void 0 ? void 0 : _a.envelope.links).toEqual([{ type: 'rel', target: kt('doc-a') }]);
|
|
796
938
|
});
|
|
797
939
|
});
|
|
798
940
|
test('two candidates merging into the same target do not duplicate a shared edge', async () => {
|
|
@@ -804,13 +946,13 @@ describe('MemoryIngestOrchestrator — review-punch-list fixes', () => {
|
|
|
804
946
|
store,
|
|
805
947
|
vectorIndex,
|
|
806
948
|
embed,
|
|
807
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].
|
|
949
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].target })),
|
|
808
950
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart'), candidate(noteKind, 'doc-c', 'apple tart')])),
|
|
809
951
|
relationExtractor: relater(() => (0, ts_utils_1.succeed)([candEdge('doc-a', 'rel', 'doc-x')]))
|
|
810
952
|
});
|
|
811
953
|
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toSucceed();
|
|
812
954
|
expect(await store.get(noteKind, 'doc-a')).toSucceedAndSatisfy((rec) => {
|
|
813
|
-
expect(rec === null || rec === void 0 ? void 0 : rec.envelope.links).toEqual([{ type: 'rel', target: 'doc-x' }]);
|
|
955
|
+
expect(rec === null || rec === void 0 ? void 0 : rec.envelope.links).toEqual([{ type: 'rel', target: kt('doc-x') }]);
|
|
814
956
|
});
|
|
815
957
|
});
|
|
816
958
|
});
|
|
@@ -840,18 +982,18 @@ describe('MemoryIngestOrchestrator — merge-into safety (second review)', () =>
|
|
|
840
982
|
const store = buildStore({ vectorIndex, embed });
|
|
841
983
|
await putFull(store, noteKind, 'doc-a', 'apple pie', {
|
|
842
984
|
tags: ['old-tag'],
|
|
843
|
-
links: [{ type: 'existing', target: 'doc-z' }]
|
|
985
|
+
links: [{ type: 'existing', target: kt('doc-z') }]
|
|
844
986
|
});
|
|
845
987
|
await putFull(store, noteKind, 'doc-x', 'target of stage-5');
|
|
846
988
|
const orch = buildOrchestrator({
|
|
847
989
|
store,
|
|
848
990
|
vectorIndex,
|
|
849
991
|
embed,
|
|
850
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].
|
|
992
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].target })),
|
|
851
993
|
extractor: extractor(() => (0, ts_utils_1.succeed)([
|
|
852
994
|
candidate(noteKind, 'doc-b', 'apple tart', {
|
|
853
995
|
tags: ['new-tag'],
|
|
854
|
-
links: [{ type: 'candlink', target: 'doc-z' }]
|
|
996
|
+
links: [{ type: 'candlink', target: kt('doc-z') }]
|
|
855
997
|
})
|
|
856
998
|
])),
|
|
857
999
|
relationExtractor: relater(() => (0, ts_utils_1.succeed)([candEdge('doc-a', 'stage5', 'doc-x')]))
|
|
@@ -865,9 +1007,9 @@ describe('MemoryIngestOrchestrator — merge-into safety (second review)', () =>
|
|
|
865
1007
|
expect([...((_a = rec === null || rec === void 0 ? void 0 : rec.envelope.tags) !== null && _a !== void 0 ? _a : [])].sort()).toEqual(['new-tag', 'old-tag']);
|
|
866
1008
|
// Original link + candidate link + stage-5 edge, each exactly once.
|
|
867
1009
|
expect(rec === null || rec === void 0 ? void 0 : rec.envelope.links).toEqual([
|
|
868
|
-
{ type: 'existing', target: 'doc-z' },
|
|
869
|
-
{ type: 'candlink', target: 'doc-z' },
|
|
870
|
-
{ type: 'stage5', target: 'doc-x' }
|
|
1010
|
+
{ type: 'existing', target: kt('doc-z') },
|
|
1011
|
+
{ type: 'candlink', target: kt('doc-z') },
|
|
1012
|
+
{ type: 'stage5', target: kt('doc-x') }
|
|
871
1013
|
]);
|
|
872
1014
|
});
|
|
873
1015
|
});
|
|
@@ -880,10 +1022,10 @@ describe('MemoryIngestOrchestrator — merge-into safety (second review)', () =>
|
|
|
880
1022
|
store,
|
|
881
1023
|
vectorIndex,
|
|
882
1024
|
embed,
|
|
883
|
-
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].
|
|
1025
|
+
entityResolver: resolver((__c, similar) => (0, ts_utils_1.succeed)({ verdict: 'merge-into', target: similar[0].target })),
|
|
884
1026
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
885
1027
|
});
|
|
886
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/merge-into target 'conv-1' is kind 'ltm' but the candidate is kind 'note'/);
|
|
1028
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/merge-into target 'conversations\/conv-1' is kind 'ltm' but the candidate is kind 'note'/);
|
|
887
1029
|
});
|
|
888
1030
|
test('supersede with a non-existent target fails loudly', async () => {
|
|
889
1031
|
const vectorIndex = index_1.InMemoryCosineIndex.create().orThrow();
|
|
@@ -893,10 +1035,10 @@ describe('MemoryIngestOrchestrator — merge-into safety (second review)', () =>
|
|
|
893
1035
|
store,
|
|
894
1036
|
vectorIndex,
|
|
895
1037
|
embed,
|
|
896
|
-
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'supersede', target: 'ghost' })),
|
|
1038
|
+
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'supersede', target: kt('ghost') })),
|
|
897
1039
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
898
1040
|
});
|
|
899
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/supersede target 'ghost' does not exist/);
|
|
1041
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/supersede target 'knowledge\/ghost' does not exist/);
|
|
900
1042
|
});
|
|
901
1043
|
test('duplicate-of with a non-existent target fails loudly', async () => {
|
|
902
1044
|
const vectorIndex = index_1.InMemoryCosineIndex.create().orThrow();
|
|
@@ -906,10 +1048,10 @@ describe('MemoryIngestOrchestrator — merge-into safety (second review)', () =>
|
|
|
906
1048
|
store,
|
|
907
1049
|
vectorIndex,
|
|
908
1050
|
embed,
|
|
909
|
-
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'duplicate-of', target: 'ghost' })),
|
|
1051
|
+
entityResolver: resolver(() => (0, ts_utils_1.succeed)({ verdict: 'duplicate-of', target: kt('ghost') })),
|
|
910
1052
|
extractor: extractor(() => (0, ts_utils_1.succeed)([candidate(noteKind, 'doc-b', 'apple tart')]))
|
|
911
1053
|
});
|
|
912
|
-
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/duplicate-of target 'ghost' does not exist/);
|
|
1054
|
+
expect(await orch.ingestItem({ id: 'i', content: 'x' })).toFailWith(/duplicate-of target 'knowledge\/ghost' does not exist/);
|
|
913
1055
|
});
|
|
914
1056
|
});
|
|
915
1057
|
//# sourceMappingURL=orchestrator.test.js.map
|