@fgv/ts-agent-memory 5.1.0-49 → 5.1.0-51

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.
Files changed (182) hide show
  1. package/dist/packlets/index/memoryIndex.js +23 -16
  2. package/dist/packlets/index/memoryIndex.js.map +1 -1
  3. package/dist/packlets/ingest/orchestrator.js +13 -1
  4. package/dist/packlets/ingest/orchestrator.js.map +1 -1
  5. package/dist/packlets/retrieve/fragmentSemanticRetriever.js +94 -5
  6. package/dist/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -1
  7. package/dist/packlets/retrieve/linkTraversalRetriever.js +12 -26
  8. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  9. package/dist/packlets/retrieve/recencyRetriever.js +7 -7
  10. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
  11. package/dist/packlets/retrieve/retriever.js +91 -10
  12. package/dist/packlets/retrieve/retriever.js.map +1 -1
  13. package/dist/packlets/retrieve/semanticRetriever.js +16 -16
  14. package/dist/packlets/retrieve/semanticRetriever.js.map +1 -1
  15. package/dist/packlets/retrieve/structuredFilterRetriever.js +7 -7
  16. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  17. package/dist/packlets/retrieve/tagRetriever.js +7 -7
  18. package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
  19. package/dist/packlets/retrieve/temporalRetrievers.js +23 -20
  20. package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
  21. package/dist/packlets/store/coverage.js +6 -0
  22. package/dist/packlets/store/coverage.js.map +1 -0
  23. package/dist/packlets/store/fileTreeMemoryStore.js +234 -103
  24. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  25. package/dist/packlets/store/index.js +4 -0
  26. package/dist/packlets/store/index.js.map +1 -1
  27. package/dist/packlets/store/listSelection.js +36 -0
  28. package/dist/packlets/store/listSelection.js.map +1 -0
  29. package/dist/packlets/store/memoryStore.js +6 -0
  30. package/dist/packlets/store/memoryStore.js.map +1 -0
  31. package/dist/packlets/store/reconcile.js +6 -0
  32. package/dist/packlets/store/reconcile.js.map +1 -0
  33. package/dist/packlets/store/storeCoverage.js +102 -0
  34. package/dist/packlets/store/storeCoverage.js.map +1 -0
  35. package/dist/packlets/store/storeIdentity.js +62 -0
  36. package/dist/packlets/store/storeIdentity.js.map +1 -0
  37. package/dist/packlets/store/storeReconcile.js +122 -0
  38. package/dist/packlets/store/storeReconcile.js.map +1 -0
  39. package/dist/packlets/store/vectorMaintenance.js +116 -8
  40. package/dist/packlets/store/vectorMaintenance.js.map +1 -1
  41. package/dist/packlets/store/vectorRecordSource.js +44 -0
  42. package/dist/packlets/store/vectorRecordSource.js.map +1 -0
  43. package/dist/packlets/tools/memoryTools.js +25 -2
  44. package/dist/packlets/tools/memoryTools.js.map +1 -1
  45. package/dist/packlets/types/envelope.js +25 -0
  46. package/dist/packlets/types/envelope.js.map +1 -1
  47. package/dist/packlets/types/identityResolver.js +6 -0
  48. package/dist/packlets/types/identityResolver.js.map +1 -0
  49. package/dist/packlets/types/index.js +2 -0
  50. package/dist/packlets/types/index.js.map +1 -1
  51. package/dist/packlets/types/recordResolver.js +6 -0
  52. package/dist/packlets/types/recordResolver.js.map +1 -0
  53. package/dist/packlets/types/temporal.js.map +1 -1
  54. package/dist/packlets/vector/inMemoryCosineIndex.js +39 -18
  55. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  56. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +109 -14
  57. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  58. package/dist/packlets/vector/rebuildHelpers.js +38 -0
  59. package/dist/packlets/vector/rebuildHelpers.js.map +1 -0
  60. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  61. package/dist/ts-agent-memory.d.ts +1226 -114
  62. package/lib/packlets/index/memoryIndex.d.ts +118 -27
  63. package/lib/packlets/index/memoryIndex.d.ts.map +1 -1
  64. package/lib/packlets/index/memoryIndex.js +23 -16
  65. package/lib/packlets/index/memoryIndex.js.map +1 -1
  66. package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
  67. package/lib/packlets/ingest/orchestrator.js +13 -1
  68. package/lib/packlets/ingest/orchestrator.js.map +1 -1
  69. package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts +79 -1
  70. package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts.map +1 -1
  71. package/lib/packlets/retrieve/fragmentSemanticRetriever.js +94 -5
  72. package/lib/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -1
  73. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +3 -10
  74. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -1
  75. package/lib/packlets/retrieve/linkTraversalRetriever.js +11 -25
  76. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  77. package/lib/packlets/retrieve/recencyRetriever.d.ts +3 -3
  78. package/lib/packlets/retrieve/recencyRetriever.d.ts.map +1 -1
  79. package/lib/packlets/retrieve/recencyRetriever.js +6 -6
  80. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
  81. package/lib/packlets/retrieve/retriever.d.ts +88 -7
  82. package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
  83. package/lib/packlets/retrieve/retriever.js +94 -9
  84. package/lib/packlets/retrieve/retriever.js.map +1 -1
  85. package/lib/packlets/retrieve/semanticRetriever.d.ts +3 -5
  86. package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -1
  87. package/lib/packlets/retrieve/semanticRetriever.js +15 -15
  88. package/lib/packlets/retrieve/semanticRetriever.js.map +1 -1
  89. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +3 -3
  90. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
  91. package/lib/packlets/retrieve/structuredFilterRetriever.js +6 -6
  92. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  93. package/lib/packlets/retrieve/tagRetriever.d.ts +3 -3
  94. package/lib/packlets/retrieve/tagRetriever.d.ts.map +1 -1
  95. package/lib/packlets/retrieve/tagRetriever.js +6 -6
  96. package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
  97. package/lib/packlets/retrieve/temporalRetrievers.d.ts +7 -5
  98. package/lib/packlets/retrieve/temporalRetrievers.d.ts.map +1 -1
  99. package/lib/packlets/retrieve/temporalRetrievers.js +22 -19
  100. package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
  101. package/lib/packlets/store/coverage.d.ts +102 -0
  102. package/lib/packlets/store/coverage.d.ts.map +1 -0
  103. package/lib/packlets/store/coverage.js +7 -0
  104. package/lib/packlets/store/coverage.js.map +1 -0
  105. package/lib/packlets/store/fileTreeMemoryStore.d.ts +56 -167
  106. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  107. package/lib/packlets/store/fileTreeMemoryStore.js +234 -103
  108. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  109. package/lib/packlets/store/index.d.ts +4 -0
  110. package/lib/packlets/store/index.d.ts.map +1 -1
  111. package/lib/packlets/store/index.js +4 -0
  112. package/lib/packlets/store/index.js.map +1 -1
  113. package/lib/packlets/store/listSelection.d.ts +101 -0
  114. package/lib/packlets/store/listSelection.d.ts.map +1 -0
  115. package/lib/packlets/store/listSelection.js +40 -0
  116. package/lib/packlets/store/listSelection.js.map +1 -0
  117. package/lib/packlets/store/memoryStore.d.ts +237 -0
  118. package/lib/packlets/store/memoryStore.d.ts.map +1 -0
  119. package/lib/packlets/store/memoryStore.js +7 -0
  120. package/lib/packlets/store/memoryStore.js.map +1 -0
  121. package/lib/packlets/store/reconcile.d.ts +82 -0
  122. package/lib/packlets/store/reconcile.d.ts.map +1 -0
  123. package/lib/packlets/store/reconcile.js +7 -0
  124. package/lib/packlets/store/reconcile.js.map +1 -0
  125. package/lib/packlets/store/storeCoverage.d.ts +45 -0
  126. package/lib/packlets/store/storeCoverage.d.ts.map +1 -0
  127. package/lib/packlets/store/storeCoverage.js +105 -0
  128. package/lib/packlets/store/storeCoverage.js.map +1 -0
  129. package/lib/packlets/store/storeIdentity.d.ts +38 -0
  130. package/lib/packlets/store/storeIdentity.d.ts.map +1 -0
  131. package/lib/packlets/store/storeIdentity.js +67 -0
  132. package/lib/packlets/store/storeIdentity.js.map +1 -0
  133. package/lib/packlets/store/storeReconcile.d.ts +41 -0
  134. package/lib/packlets/store/storeReconcile.d.ts.map +1 -0
  135. package/lib/packlets/store/storeReconcile.js +125 -0
  136. package/lib/packlets/store/storeReconcile.js.map +1 -0
  137. package/lib/packlets/store/vectorMaintenance.d.ts +74 -0
  138. package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -1
  139. package/lib/packlets/store/vectorMaintenance.js +117 -8
  140. package/lib/packlets/store/vectorMaintenance.js.map +1 -1
  141. package/lib/packlets/store/vectorRecordSource.d.ts +36 -0
  142. package/lib/packlets/store/vectorRecordSource.d.ts.map +1 -0
  143. package/lib/packlets/store/vectorRecordSource.js +47 -0
  144. package/lib/packlets/store/vectorRecordSource.js.map +1 -0
  145. package/lib/packlets/tools/memoryTools.d.ts.map +1 -1
  146. package/lib/packlets/tools/memoryTools.js +25 -2
  147. package/lib/packlets/tools/memoryTools.js.map +1 -1
  148. package/lib/packlets/types/envelope.d.ts +24 -2
  149. package/lib/packlets/types/envelope.d.ts.map +1 -1
  150. package/lib/packlets/types/envelope.js +26 -0
  151. package/lib/packlets/types/envelope.js.map +1 -1
  152. package/lib/packlets/types/identityResolver.d.ts +42 -0
  153. package/lib/packlets/types/identityResolver.d.ts.map +1 -0
  154. package/lib/packlets/types/identityResolver.js +7 -0
  155. package/lib/packlets/types/identityResolver.js.map +1 -0
  156. package/lib/packlets/types/index.d.ts +2 -0
  157. package/lib/packlets/types/index.d.ts.map +1 -1
  158. package/lib/packlets/types/index.js +2 -0
  159. package/lib/packlets/types/index.js.map +1 -1
  160. package/lib/packlets/types/recordResolver.d.ts +39 -0
  161. package/lib/packlets/types/recordResolver.d.ts.map +1 -0
  162. package/lib/packlets/types/recordResolver.js +7 -0
  163. package/lib/packlets/types/recordResolver.js.map +1 -0
  164. package/lib/packlets/types/temporal.d.ts +26 -6
  165. package/lib/packlets/types/temporal.d.ts.map +1 -1
  166. package/lib/packlets/types/temporal.js.map +1 -1
  167. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +9 -2
  168. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
  169. package/lib/packlets/vector/inMemoryCosineIndex.js +40 -19
  170. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  171. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +18 -4
  172. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
  173. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +108 -13
  174. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  175. package/lib/packlets/vector/rebuildHelpers.d.ts +30 -0
  176. package/lib/packlets/vector/rebuildHelpers.d.ts.map +1 -0
  177. package/lib/packlets/vector/rebuildHelpers.js +42 -0
  178. package/lib/packlets/vector/rebuildHelpers.js.map +1 -0
  179. package/lib/packlets/vector/vectorIndex.d.ts +326 -20
  180. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  181. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  182. package/package.json +7 -7
@@ -1,6 +1,7 @@
1
1
  import { AiAssist } from '@fgv/ts-extras';
2
2
  import { Brand } from '@fgv/ts-utils';
3
3
  import { Converter } from '@fgv/ts-utils';
4
+ import { DetailedResult } from '@fgv/ts-utils';
4
5
  import { FileTree } from '@fgv/ts-json-base';
5
6
  import { JsonSchema } from '@fgv/ts-json-base';
6
7
  import { Logging } from '@fgv/ts-utils';
@@ -31,11 +32,12 @@ export declare type AdmissionDecision = {
31
32
  */
32
33
  export declare class AsOfRetriever implements IMemoryRetriever {
33
34
  private readonly _index;
35
+ private readonly _resolver;
34
36
  private constructor();
35
37
  /** {@inheritDoc IMemoryRetriever.capabilities} */
36
38
  get capabilities(): IMemoryRetrieverCapabilities;
37
39
  /** Family-convention factory. */
38
- static create(index: IMemoryIndex): Result<AsOfRetriever>;
40
+ static create(params: IRetrieverCreateParams): Result<AsOfRetriever>;
39
41
  /** {@inheritDoc IMemoryRetriever.retrieve} */
40
42
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
41
43
  }
@@ -164,11 +166,12 @@ export declare function createMemoryTools(params: ICreateMemoryToolsParams): Rea
164
166
  */
165
167
  export declare class CurrentValidRetriever implements IMemoryRetriever {
166
168
  private readonly _index;
169
+ private readonly _resolver;
167
170
  private constructor();
168
171
  /** {@inheritDoc IMemoryRetriever.capabilities} */
169
172
  get capabilities(): IMemoryRetrieverCapabilities;
170
173
  /** Family-convention factory. */
171
- static create(index: IMemoryIndex): Result<CurrentValidRetriever>;
174
+ static create(params: IRetrieverCreateParams): Result<CurrentValidRetriever>;
172
175
  /** {@inheritDoc IMemoryRetriever.retrieve} */
173
176
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
174
177
  }
@@ -245,6 +248,22 @@ export declare const DEFAULT_SIMILARITY_TOP_K: number;
245
248
  */
246
249
  export declare function defaultMemoryScopeEncoding(scope: MemoryScopeKey): Result<string>;
247
250
 
251
+ /**
252
+ * Which derived artifact a {@link IMemoryStore.reconcile} call repairs.
253
+ *
254
+ * @remarks
255
+ * **The operation names its artifact rather than repairing everything wired**,
256
+ * and the reasons are structural rather than stylistic: the record and fragment
257
+ * lanes are independently wirable (so an unnamed repair on a fragment-only store
258
+ * would have to no-op or guess), their units are incommensurable (one vector per
259
+ * record vs. N), and their costs differ by orders of magnitude — a measured case
260
+ * put 68 fragments behind a single 56 KB record. An operation whose cost varies
261
+ * that much along a dimension it does not name is the accidental-expense shape
262
+ * `IMemoryStore.list`'s required selection exists to prevent.
263
+ * @public
264
+ */
265
+ export declare type DerivedArtifact = 'rank' | 'record-vector' | 'fragment-vector';
266
+
248
267
  /**
249
268
  * Converter for an attributed {@link IEdge}.
250
269
  * @public
@@ -287,6 +306,29 @@ export declare function edgeTargetKey(target: IEdgeTarget): string;
287
306
  */
288
307
  export declare const embeddedFragmentConverter: Converter<IEmbeddedFragment>;
289
308
 
309
+ /**
310
+ * The envelope's embedding reference if it carries a usable one, `undefined`
311
+ * otherwise — **the one place `null`-vs-absent is collapsed.**
312
+ *
313
+ * @remarks
314
+ * {@link IMemoryEnvelope.embeddingRef} is `string | null | undefined`, where
315
+ * `null` and absent both mean *not embedded* (`null` is the explicit sentinel;
316
+ * absent is the backwards-compat seam). That makes the obvious presence check
317
+ * wrong in **both** directions, and both mistakes were shipped before this
318
+ * accessor existed: `!== undefined` counts a `null` as an embedding that is not
319
+ * there, and `=== undefined` misses a `null` when looking for one that is
320
+ * missing. Neither is a type error, and neither is visible to a coverage gate,
321
+ * because the sentinel is a *value* rather than a branch.
322
+ *
323
+ * Returning the reference rather than a boolean is deliberate: a caller that
324
+ * needs the string gets the check for free, so there is no second, weaker way
325
+ * to ask.
326
+ *
327
+ * **Do not test `embeddingRef` for presence directly — call this.**
328
+ * @public
329
+ */
330
+ export declare function embeddingRefOf(envelope: IMemoryEnvelope): string | undefined;
331
+
290
332
  /**
291
333
  * Consumer-supplied domain key. The stable entity identity across versions;
292
334
  * the package never mints identity. Equals {@link MemoryId} for non-temporal
@@ -394,9 +436,52 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
394
436
  /** {@inheritDoc IMemoryStore.getById} */
395
437
  getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
396
438
  /** {@inheritDoc IMemoryStore.list} */
397
- list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
439
+ list(selection: MemoryListSelection): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
440
+ /** {@inheritDoc IMemoryStore.coverage} */
441
+ coverage(): Promise<Result<IDerivedStateCoverage>>;
442
+ /** {@inheritDoc IMemoryStore.listEntries} */
443
+ listEntries(): Promise<Result<ReadonlyArray<IIndexedMemoryEntry>>>;
398
444
  /** {@inheritDoc IMemoryStore.listScoped} */
399
445
  listScoped(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
446
+ /** {@inheritDoc IMemoryRecordResolver.resolveRecord} */
447
+ resolveRecord(scope: MemoryScopeKey, id: MemoryId): Result<IMemoryRecord<unknown> | undefined>;
448
+ private _codec;
449
+ /** {@inheritDoc IIdentityResolver.resolveIdentity} */
450
+ resolveIdentity(kind: Kind, entityId: EntityId): Result<IIdentityCodecResult>;
451
+ /**
452
+ * Materialize a selected set of entries into records, dropping any that have
453
+ * vanished since selection.
454
+ *
455
+ * @remarks
456
+ * A miss is not a failure. Selection reads the in-memory index and
457
+ * materialization reads storage, so a record deleted in between is a legitimate
458
+ * race and yields a shorter list rather than an error. A read that FAILS is a
459
+ * real fault and propagates.
460
+ */
461
+ private _materialize;
462
+ /**
463
+ * Materialize one entry, treating "gone" as a fault rather than a miss.
464
+ *
465
+ * @remarks
466
+ * For paths where a vanished record really does mean the index and the vault
467
+ * disagree, rather than that something legitimately removed it in between.
468
+ *
469
+ * Three of the four callers hold the write lock, so nothing can have removed
470
+ * the record since the entry was read. `get()`'s versioned path does not, and
471
+ * is safe only because temporal kinds never physically delete a version — they
472
+ * invalidate in place, and cap-cull does not apply to them. **If eviction is
473
+ * ever added to the temporal path, that caller must change**, or it
474
+ * reintroduces the race this method exists to detect.
475
+ *
476
+ * `listScoped` also does not hold the lock, and uses this deliberately anyway:
477
+ * it feeds a coverage report, so a silent drop there is worse than a loud
478
+ * failure. See its comment, and `docs/FUTURE.md` for the eviction window.
479
+ *
480
+ * The drop-tolerant counterpart is {@link FileTreeMemoryStore._materialize},
481
+ * for readers where a record that vanished between selection and
482
+ * materialization is a miss rather than a fault.
483
+ */
484
+ private _resolveRequired;
400
485
  /** {@inheritDoc IMemoryStore.asRecordSource} */
401
486
  asRecordSource(): IMemoryRecordSource;
402
487
  /**
@@ -407,8 +492,8 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
407
492
  * contributes nothing.
408
493
  */
409
494
  private static _projectAsOf;
410
- /** {@inheritDoc IMemoryStore.reconcileRank} */
411
- reconcileRank(kind: Kind): Promise<Result<number>>;
495
+ /** {@inheritDoc IMemoryStore.reconcile} */
496
+ reconcile(kind: Kind, artifact: DerivedArtifact): Promise<Result<ReconcileReport>>;
412
497
  /** {@inheritDoc IMemoryStore.put} */
413
498
  put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
414
499
  /** {@inheritDoc IMemoryStore.delete} */
@@ -584,7 +669,7 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
584
669
  private _isMutableMetadataUnchanged;
585
670
  private _contentHash;
586
671
  /**
587
- * The locked body of {@link FileTreeMemoryStore.reconcileRank}.
672
+ * The rank branch of {@link FileTreeMemoryStore.reconcile}, under the write lock.
588
673
  *
589
674
  * @remarks
590
675
  * Re-reads each record's file rather than trusting the in-memory index, for
@@ -613,13 +698,15 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
613
698
  * another on a reconcile. `_stampRank` itself is reused verbatim, which also
614
699
  * inherits its throw semantics (logged at `warn`, `rank` cleared).
615
700
  */
701
+ private _reconcileLocked;
702
+ /** The rank branch of {@link FileTreeMemoryStore._reconcileLocked}. */
616
703
  private _reconcileRankLocked;
617
704
  /**
618
705
  * Re-apply the rank projector to one record on disk. Returns whether `rank`
619
706
  * actually changed — an unchanged rank writes nothing, so a reconcile over an
620
707
  * already-consistent store touches no files.
621
708
  */
622
- private _restampOne;
709
+ private _rewriteEnvelope;
623
710
  /**
624
711
  * Stamp the store-computed {@link IMemoryEnvelope.rank} onto a fully-built,
625
712
  * fully-stamped record by running the kind's registered {@link RankProjector}.
@@ -633,7 +720,6 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
633
720
  * than preserving it), so a ranking bug never loses an authoritative write.
634
721
  */
635
722
  private _stampRank;
636
- private _codecFor;
637
723
  private _policyFor;
638
724
  /** {@inheritDoc IMemoryStore.dedupScopeFor} */
639
725
  dedupScopeFor(kind: Kind): DedupScope;
@@ -693,6 +779,28 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
693
779
  private _loadRecordFile;
694
780
  }
695
781
 
782
+ /**
783
+ * The message returned when exactly one of `entityId` / `kind` is supplied.
784
+ *
785
+ * @remarks
786
+ * They travel together because `kind` is what selects the identity codec, and the
787
+ * codec is what makes the resolution unambiguous. One without the other is not a
788
+ * partial narrowing that could be honored best-effort — it is not a narrowing at all.
789
+ * @public
790
+ */
791
+ export declare const FRAGMENT_NARROWING_INCOMPLETE_MESSAGE: string;
792
+
793
+ /**
794
+ * The loud-degradation message returned when a query carries a record narrowing but
795
+ * no {@link IIdentityResolver} is wired to resolve it.
796
+ *
797
+ * @remarks
798
+ * Deliberately a `Failure` rather than a silently-global search: answering a scoped
799
+ * question with an unscoped result is the failure this narrowing exists to remove.
800
+ * @public
801
+ */
802
+ export declare const FRAGMENT_NARROWING_UNRESOLVABLE_MESSAGE: string;
803
+
696
804
  /**
697
805
  * The loud-degradation message a {@link FragmentSemanticRetriever} returns when a
698
806
  * fragment query is issued but no {@link IFragmentSemanticBackend | backend} is
@@ -745,18 +853,44 @@ export declare const fragmentLocatorConverter: Converter<IFragmentLocator>;
745
853
  */
746
854
  export declare class FragmentSemanticRetriever {
747
855
  private readonly _backend;
856
+ private readonly _identityResolver;
748
857
  private constructor();
749
858
  /** What this retriever can do given its wiring. */
750
859
  get capabilities(): IFragmentRetrieverCapabilities;
751
- /** Family-convention factory. */
860
+ /**
861
+ * Family-convention factory.
862
+ *
863
+ * @param params - `backend` wires fragment recall itself. `identityResolver`
864
+ * resolves a query's `(kind, entityId)` narrowing to a storage address;
865
+ * `IMemoryStore` implements it, so the usual wiring is
866
+ * `{ backend, identityResolver: store }`. It is optional because an unscoped
867
+ * fragment search needs nothing to resolve — but a query that *does* carry a
868
+ * narrowing fails loudly without it rather than quietly searching everything.
869
+ */
752
870
  static create(params: {
753
871
  readonly backend?: IFragmentSemanticBackend;
872
+ readonly identityResolver?: IIdentityResolver;
754
873
  }): Result<FragmentSemanticRetriever>;
755
874
  /**
756
875
  * Embed `query.semantic`, query the fragment index, and return the per-fragment
757
876
  * hits in descending score order. Fails loudly when no backend is wired.
758
877
  */
759
878
  retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
879
+ /**
880
+ * Turn the query's consumer-facing narrowing into the storage-address narrowing
881
+ * the index understands.
882
+ *
883
+ * @remarks
884
+ * `kind` selects the identity codec and the codec computes the record's storage
885
+ * address, so this is a deterministic resolution rather than a search —
886
+ * which is what makes a colliding `entityId` across kinds a non-issue.
887
+ *
888
+ * A **versioned** kind resolves to the entity's own subtree scope and deliberately
889
+ * carries no `id`, so the narrowing covers every version of the entity — including
890
+ * superseded ones, which are invalidated but never pruned from the index. A
891
+ * non-versioned kind resolves to exactly one record.
892
+ */
893
+ private _resolveOptions;
760
894
  /**
761
895
  * Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
762
896
  * and a thrown/rejected promise into a single `fragment recall: <label> failed`
@@ -788,11 +922,12 @@ export declare function guardRetrieverCapabilities(query: IMemoryQuery, capabili
788
922
  */
789
923
  export declare class HistoryRetriever implements IMemoryRetriever {
790
924
  private readonly _index;
925
+ private readonly _resolver;
791
926
  private constructor();
792
927
  /** {@inheritDoc IMemoryRetriever.capabilities} */
793
928
  get capabilities(): IMemoryRetrieverCapabilities;
794
929
  /** Family-convention factory. */
795
- static create(index: IMemoryIndex): Result<HistoryRetriever>;
930
+ static create(params: IRetrieverCreateParams): Result<HistoryRetriever>;
796
931
  /** {@inheritDoc IMemoryRetriever.retrieve} */
797
932
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
798
933
  /** A version's world-truth start: its `valid_at`, defaulting to `created` when absent. */
@@ -855,6 +990,31 @@ export declare class HybridRetriever implements IMemoryRetriever {
855
990
  private _projectQuery;
856
991
  }
857
992
 
993
+ /**
994
+ * How much of one derived artifact exists, for one {@link Kind}.
995
+ *
996
+ * @remarks
997
+ * Two numbers rather than a percentage, deliberately: a ratio cannot express
998
+ * *"nothing was expected"*, and a kind that is intentionally not derived (an
999
+ * excluded kind, a kind with no projector) is a normal and healthy state that a
1000
+ * `0%` would render as an alarm.
1001
+ * @public
1002
+ */
1003
+ export declare interface IArtifactCoverage {
1004
+ /**
1005
+ * Records of this kind the store would derive this artifact for, **after** any
1006
+ * exclusion. Read against {@link IDerivedStateCoverage.records} for the same
1007
+ * kind: `records: 40, expected: 0` is the exclusion story, stated rather than
1008
+ * inferred.
1009
+ */
1010
+ readonly expected: number;
1011
+ /**
1012
+ * Of those, how many the **store believes** are covered. See
1013
+ * {@link IIndexCoverage.indexSize} for why the word "believes" is load-bearing.
1014
+ */
1015
+ readonly covered: number;
1016
+ }
1017
+
858
1018
  /**
859
1019
  * Registry of per-kind body Converters. Each memory {@link Kind} registers the
860
1020
  * validated shape of its body; the store dispatches an `unknown` body through
@@ -998,6 +1158,35 @@ export declare interface ICycleGuardEdge {
998
1158
  readonly type: LinkType;
999
1159
  }
1000
1160
 
1161
+ /**
1162
+ * A snapshot of how much of the store's **derived state** exists, resolved by
1163
+ * {@link Kind} — the answer to *"is my derived state consistent with my
1164
+ * records?"*.
1165
+ *
1166
+ * @remarks
1167
+ * **Absent is not zero.** Each artifact member is optional, and `undefined` means
1168
+ * *this artifact is not derived here at all* — no rank projector is registered,
1169
+ * or that index lane is not wired. It never means *nothing is covered*. Folding
1170
+ * the two would make a health surface render a confident `0%` for a feature the
1171
+ * deployment deliberately did not turn on, which is the same defect as
1172
+ * `embeddingRef`'s three-way ambiguity one level up.
1173
+ *
1174
+ * So: `fragmentVectors: undefined` is a store with no fragment index and is not a
1175
+ * problem. `fragmentVectors: { indexRecordCount: 0, indexFragmentCount: 0 }` is a
1176
+ * wired fragment index holding nothing, and probably is.
1177
+ * @public
1178
+ */
1179
+ export declare interface IDerivedStateCoverage {
1180
+ /** Records per kind — the denominator every other number is read against. */
1181
+ readonly records: ReadonlyMap<Kind, number>;
1182
+ /** Absent when no kind has a registered {@link RankProjector}. */
1183
+ readonly rank?: ReadonlyMap<Kind, IArtifactCoverage>;
1184
+ /** Absent when the record-vector lane is not wired. */
1185
+ readonly recordVectors?: IIndexCoverage;
1186
+ /** Absent when the fragment lane is not wired. */
1187
+ readonly fragmentVectors?: IFragmentIndexCoverage;
1188
+ }
1189
+
1001
1190
  /**
1002
1191
  * An attributed link between two records. Carries the relation type, the
1003
1192
  * scope-qualified {@link IEdgeTarget | target}, and optional confidence /
@@ -1121,6 +1310,27 @@ export declare interface IEntityResolver {
1121
1310
  resolve(candidate: ICandidateRecord, similar: ReadonlyArray<IEntityResolutionCandidate>): Promise<Result<ResolutionVerdict>>;
1122
1311
  }
1123
1312
 
1313
+ /**
1314
+ * The minimum a temporal helper needs: something carrying an envelope.
1315
+ *
1316
+ * @remarks
1317
+ * Every predicate and selector in this module reads `envelope.temporal`,
1318
+ * `envelope.created` and `envelope.seq` and **nothing else** — no body has ever
1319
+ * been consulted. Taking the structural shape rather than `IMemoryRecord` lets
1320
+ * the same helpers serve both an `IMemoryRecord<unknown>` (which satisfies it)
1321
+ * and an `IIndexedMemoryEntry` from the index's projected read surface, so the
1322
+ * temporal `asOf` projection can run over envelopes and materialize only the
1323
+ * versions that survive it.
1324
+ *
1325
+ * The selectors are generic in this shape so they return exactly what they were
1326
+ * given rather than widening to the constraint.
1327
+ * @public
1328
+ */
1329
+ export declare interface IEnvelopeCarrier {
1330
+ /** The envelope the temporal predicates read. */
1331
+ readonly envelope: IMemoryEnvelope;
1332
+ }
1333
+
1124
1334
  /**
1125
1335
  * Stage 3 — the host's fact extractor. Turns a classified item into zero or more
1126
1336
  * {@link ICandidateRecord}s. Each candidate's body is validated against the
@@ -1328,6 +1538,31 @@ export declare interface IFileTreeMemoryStoreCreateParams {
1328
1538
  readonly onRecordError?: MemoryRecordErrorMode;
1329
1539
  }
1330
1540
 
1541
+ /**
1542
+ * Coverage of the fragment-granular vector index.
1543
+ *
1544
+ * @remarks
1545
+ * **Aggregate only, and the reason is structural rather than an omission.** The
1546
+ * record lane has a per-record marker on the envelope (`embeddingRef`), so its
1547
+ * numerator falls out of the same free walk that produces the denominator. The
1548
+ * fragment lane has **no envelope marker at all** — nothing on a record says
1549
+ * whether it has fragments — so a per-kind numerator would cost one
1550
+ * `IFragmentVectorIndex.has` call per record, and coverage is contractually
1551
+ * cheap (see {@link IMemoryStore.coverage}).
1552
+ *
1553
+ * The per-kind **denominator** is still available on
1554
+ * {@link IDerivedStateCoverage.records}. A caller who needs the per-kind
1555
+ * numerator runs `reconcile(kind, 'fragment-vector')`, which reports it because
1556
+ * it is already paying for the walk.
1557
+ * @public
1558
+ */
1559
+ export declare interface IFragmentIndexCoverage {
1560
+ /** Records with at least one fragment held. Mirrors `IFragmentVectorIndex.recordCount`. */
1561
+ readonly indexRecordCount: number;
1562
+ /** Total fragments held — the fan-out. Mirrors `IFragmentVectorIndex.fragmentCount`. */
1563
+ readonly indexFragmentCount: number;
1564
+ }
1565
+
1331
1566
  /**
1332
1567
  * A half-open `[start, end)` span into a record's body — the in-record locator a
1333
1568
  * {@link IFragmentVectorIndex} may carry on a fragment. `start` is inclusive,
@@ -1373,6 +1608,104 @@ export declare interface IFragmentQuery {
1373
1608
  * Applied during selection (before the `topK` cut). Omit for uncapped.
1374
1609
  */
1375
1610
  readonly maxPerRecord?: number;
1611
+ /**
1612
+ * Narrow the search to one record's fragments: the consumer-supplied domain key
1613
+ * of the record to search within. **Must be supplied with
1614
+ * {@link IFragmentQuery.kind}.**
1615
+ *
1616
+ * @remarks
1617
+ * The narrowing is applied **during selection, before the `topK` cut**, so the
1618
+ * `topK` you ask for is the `topK` you get. Filtering a global result afterwards
1619
+ * is not equivalent: it truncates to `topK` across every record first, so a scoped
1620
+ * search would come back short whenever other records outscored this one's
1621
+ * fragments.
1622
+ *
1623
+ * For a versioned kind this narrows to **every version of the entity** — literally
1624
+ * every version, superseded ones included, because invalidation stamps `invalid_at`
1625
+ * without pruning that version's fragments. Nothing on a hit distinguishes a
1626
+ * current fragment from a historical one. That matches the record-granular vector
1627
+ * lane; it is not currency filtering.
1628
+ */
1629
+ readonly entityId?: EntityId;
1630
+ /**
1631
+ * The kind of the record named by {@link IFragmentQuery.entityId}. **Must be
1632
+ * supplied with it.**
1633
+ *
1634
+ * @remarks
1635
+ * This is not decoration and not a filter: `kind` **selects the identity codec**,
1636
+ * and the codec computes the storage address. An `EntityId` promises no uniqueness
1637
+ * beyond a scope — the same id under two kinds is the ordinary case, not a
1638
+ * pathological one — so without `kind` the resolution is ambiguous, and with it
1639
+ * ambiguity is structurally impossible.
1640
+ */
1641
+ readonly kind?: Kind;
1642
+ }
1643
+
1644
+ /**
1645
+ * Selection-time narrowing for {@link IFragmentVectorIndex.query}. Every member is
1646
+ * applied **before** the `topK` cut.
1647
+ *
1648
+ * @remarks
1649
+ * `scope` (optionally with `id`) is the record narrowing. It is expressed as a
1650
+ * storage address rather than as a consumer-facing `(kind, entityId)` because that
1651
+ * is what the index is keyed by; resolving one to the other is
1652
+ * `IIdentityResolver.resolveIdentity`'s job, and doing it above the index keeps the
1653
+ * index dealing only in the keys it actually holds.
1654
+ *
1655
+ * **`scope` alone is not a coarser accident — it is what a versioned kind needs.**
1656
+ * `TemporalIdentityCodec` files every version of an entity in its own per-entity
1657
+ * subtree, so for a versioned kind the entity's subtree *is* the narrowing and
1658
+ * `{ scope }` means "every version of this entity". A non-versioned kind resolves to
1659
+ * a single record and supplies `{ scope, id }`.
1660
+ *
1661
+ * **"Every version" is literal, and includes superseded ones.** Invalidation stamps
1662
+ * `invalid_at` on an envelope; it does not prune that version's fragments from the
1663
+ * index. So a scope-narrowed query returns current and historical fragments alike,
1664
+ * and a hit carries nothing that distinguishes them — `IVectorQueryHit` has no
1665
+ * temporal fields. This is the record-granular vector lane's existing behaviour
1666
+ * rather than something this narrowing introduces, but do not read the subtree
1667
+ * narrowing as currency filtering: it is not, and there is no `asOf` axis here to
1668
+ * make it so.
1669
+ * @public
1670
+ */
1671
+ export declare interface IFragmentQueryOptions {
1672
+ /**
1673
+ * Maximum number of fragments any single record may contribute. Omit for
1674
+ * uncapped. With a single-record narrowing (`scope` + `id`) this caps the one
1675
+ * record's contribution, which is a second cap on the same axis rather than a
1676
+ * cross-record fairness knob — usually you want one or the other, not both.
1677
+ */
1678
+ readonly maxPerRecord?: number;
1679
+ /**
1680
+ * Restrict the search to fragments of records in this scope. Omit to search every
1681
+ * record.
1682
+ */
1683
+ readonly scope?: MemoryScopeKey;
1684
+ /**
1685
+ * With {@link IFragmentQueryOptions.scope}, restrict further to the single record
1686
+ * at `(scope, id)`. Ignored — and meaningless — without `scope`, since a bare `id`
1687
+ * does not address a record.
1688
+ */
1689
+ readonly id?: MemoryId;
1690
+ }
1691
+
1692
+ /**
1693
+ * A fragment-vector reconcile.
1694
+ *
1695
+ * @remarks
1696
+ * Note there is no `restamped`: the fragment lane has **no envelope marker**, so
1697
+ * there is no reference that can go missing and nothing to restamp. The
1698
+ * asymmetry with {@link IVectorReconcileReport} is real rather than an oversight.
1699
+ * @public
1700
+ */
1701
+ export declare interface IFragmentReconcileReport extends IReconcileReportBase {
1702
+ readonly artifact: 'fragment-vector';
1703
+ /** Records already represented, needing no embedder call. */
1704
+ readonly alreadyIndexed: number;
1705
+ /** Records whose embedder produced no fragments — this lane's decline. */
1706
+ readonly declined: number;
1707
+ /** Fragments written by this call — the fan-out `repaired` cannot express. */
1708
+ readonly fragments: number;
1376
1709
  }
1377
1710
 
1378
1711
  /**
@@ -1433,12 +1766,124 @@ export declare interface IFragmentVectorIndex {
1433
1766
  /**
1434
1767
  * Return the `topK` nearest fragments to `vector`, in descending score order,
1435
1768
  * each hit carrying its record `target` plus whichever of `locator` /
1436
- * `fragmentId` the stored fragment was added with. When
1437
- * `maxPerRecord` is supplied, no more than that many fragments of any single
1438
- * record appear in the result — the cap is applied during selection (before the
1439
- * `topK` cut) so one long document cannot crowd out others.
1769
+ * `fragmentId` the stored fragment was added with.
1770
+ *
1771
+ * @remarks
1772
+ * **Every member of `options` is applied during selection, before the `topK`
1773
+ * cut.** That ordering is the contract, not an implementation detail: a narrowing
1774
+ * applied afterwards would mean the caller's `topK` is not the `topK` that reached
1775
+ * the index, so a scoped search would be exact only when a global over-fetch
1776
+ * happened to be generous enough. See {@link IFragmentQueryOptions}.
1777
+ */
1778
+ query(vector: Float32Array, topK: number, options?: IFragmentQueryOptions): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
1779
+ /**
1780
+ * Whether this index holds **any** fragment for the scope-qualified `target`.
1781
+ *
1782
+ * @remarks
1783
+ * The record-granular rationale on {@link IVectorIndex.has} applies verbatim —
1784
+ * a repair that trusts `embeddingRef` is not a repair. Note the granularity
1785
+ * this deliberately does **not** offer: it answers *"is this record
1786
+ * represented?"*, not *"is this particular fragment present?"*. Fragment
1787
+ * writes are whole-record-replace, so a record is either represented by the
1788
+ * current fragment set or not represented at all; a per-fragment membership
1789
+ * check would imply an incremental write path that does not exist.
1790
+ */
1791
+ has(target: IEdgeTarget): Promise<Result<boolean>>;
1792
+ /**
1793
+ * The number of **records** with at least one fragment held.
1794
+ *
1795
+ * @remarks
1796
+ * Deliberately **not** named `size`, unlike {@link IVectorIndex.size}. This
1797
+ * index is one-to-many, so `size` has two defensible readings and a reader
1798
+ * arriving from the record-granular sibling — where `size` counts vectors —
1799
+ * would take the wrong one silently. Two explicitly-named counts cost one extra
1800
+ * member and cannot be misread.
1801
+ */
1802
+ readonly recordCount: number;
1803
+ /**
1804
+ * The total number of **fragments** held across all records.
1805
+ *
1806
+ * @remarks
1807
+ * The fan-out, and the number a caller actually watches: fragments-per-record
1808
+ * is what makes a fragment reconcile expensive, and neither `recordCount` nor a
1809
+ * record-granular count answers it.
1440
1810
  */
1441
- query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
1811
+ readonly fragmentCount: number;
1812
+ /**
1813
+ * Re-embed every record from `source` and rebuild the fragment index from
1814
+ * scratch — the **backfill / reconcile** operation, sibling to
1815
+ * {@link IVectorIndex.rebuild}.
1816
+ *
1817
+ * @remarks
1818
+ * On the contract for exactly the reasons its record-granular sibling is, and
1819
+ * the fragment lane was worse off: `rebuild` existed only on the bundled
1820
+ * in-memory class, and the durable `SqliteVecFragmentIndex` had **no backfill
1821
+ * at all**, so a persistent fragment index could not be reconciled by any
1822
+ * route — contractual or concrete. Records written while it was unwired, a
1823
+ * re-embed after a segmenter change, and reconciliation after a swallowed
1824
+ * fragment-embed failure were all unreachable.
1825
+ *
1826
+ * Semantics are kept observably identical to the record-granular sibling so a
1827
+ * caller who has learned one has learned both: a `source.list()` failure is
1828
+ * fatal and carries no detail (nothing was attempted, and the existing index is
1829
+ * untouched); a genuine rebuild then resets first; `onRecordError` defaults to
1830
+ * `'fail'`; and a failure carries whatever the attempt had established on the
1831
+ * `detail`.
1832
+ *
1833
+ * **A rebuild does NOT re-establish the vector dimension on a persistent
1834
+ * index, and this is the one place the two shipped implementations genuinely
1835
+ * differ.** The in-memory indexes forget their dimension when they reset, so a
1836
+ * rebuild with a different-dimension embedder simply re-establishes it. A
1837
+ * `vec0`-backed index cannot: its reset is a `DELETE FROM`, the table's
1838
+ * declared dimension is part of its schema, and `vec0` has no `ALTER TABLE`.
1839
+ * So a rebuild that changes dimension **succeeds in memory and fails on
1840
+ * SQLite**, where it needs the same drop-and-re-index the package README
1841
+ * prescribes for any schema change (drop the table, or point the index at a
1842
+ * fresh `tableName`). Only embedding time is at risk — vectors are derived and
1843
+ * the vault records remain authoritative.
1844
+ */
1845
+ rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder, options?: IVectorRebuildOptions): Promise<DetailedResult<IFragmentVectorRebuildReport, IFragmentVectorRebuildReport>>;
1846
+ }
1847
+
1848
+ /**
1849
+ * What an {@link IFragmentVectorIndex.rebuild} established, resolved by
1850
+ * {@link Kind} — the fragment-granular sibling of {@link IVectorRebuildReport}.
1851
+ *
1852
+ * @remarks
1853
+ * The rule stated on {@link IVectorRebuildReport} applies here verbatim and is
1854
+ * not re-opened: **every count is resolved by kind unless there is a stated
1855
+ * reason it cannot be**, `excluded` is optional because only the source can know
1856
+ * it, and the report is carried on a failure as well as a success.
1857
+ *
1858
+ * The one member with no record-granular analogue is
1859
+ * {@link IFragmentVectorRebuildReport.fragments | fragments} — the fan-out. It is
1860
+ * the number that distinguishes this lane: `indexed: 40` says forty records are
1861
+ * represented and says nothing about whether that cost forty embedding round
1862
+ * trips or four thousand, which is the difference between a reconcile that
1863
+ * finishes in a second and one that blocks a request past thirty.
1864
+ *
1865
+ * A **declined** record is one whose {@link FragmentEmbedder} returned an empty
1866
+ * array — the fragment lane's way of saying *intentionally not embedded*. Note
1867
+ * this is a different mechanism from a {@link MemoryEmbedder} decline: an empty
1868
+ * array still performs a real whole-record-replace (which is what clears any
1869
+ * stale fragments), where a record-granular decline skips the index entirely.
1870
+ * @public
1871
+ */
1872
+ export declare interface IFragmentVectorRebuildReport {
1873
+ /** Records that ended with at least one fragment held, per kind. */
1874
+ readonly indexed: ReadonlyMap<Kind, number>;
1875
+ /** Fragments held, per kind — the fan-out `indexed` cannot express. */
1876
+ readonly fragments: ReadonlyMap<Kind, number>;
1877
+ /** Records whose embedder intentionally produced no fragments, per kind. */
1878
+ readonly declined: ReadonlyMap<Kind, number>;
1879
+ /**
1880
+ * Records the source filtered out before the rebuild saw them, per kind.
1881
+ * `undefined` means *this source does not report exclusions*; an empty map
1882
+ * means *it does, and excluded nothing*.
1883
+ */
1884
+ readonly excluded?: ReadonlyMap<Kind, number>;
1885
+ /** Records that failed, per record, with the error — a fault, never a decline. */
1886
+ readonly skipped: ReadonlyArray<ISkippedVectorRecord>;
1442
1887
  }
1443
1888
 
1444
1889
  /**
@@ -1482,6 +1927,97 @@ export declare interface IIdentityCodecResult {
1482
1927
  readonly isVersioned: boolean;
1483
1928
  }
1484
1929
 
1930
+ /**
1931
+ * Resolves a consumer-facing `(kind, entityId)` address to the storage address the
1932
+ * vault files it under, **without reading the record**.
1933
+ *
1934
+ * @remarks
1935
+ * This is the resolution `IMemoryStore.get(kind, entityId)` already performs before
1936
+ * it reads anything: `kind` selects the kind's `IIdentityCodec`, and the codec's
1937
+ * `encode` computes `{ scope, idStem, isVersioned }`. Exposing it separately lets a
1938
+ * caller that needs only the *address* — a fragment query narrowing to one record,
1939
+ * say — avoid paying for a read it does not want.
1940
+ *
1941
+ * **The resolution is a function, not a search, and that is the load-bearing
1942
+ * property.** A consumer holds an `EntityId`; a vector hit is addressed by a
1943
+ * `(scope, id)` pair; and `EntityId` promises no uniqueness beyond a scope, so the
1944
+ * same id may legitimately appear in several scopes (a document `acme-corp` under
1945
+ * one kind and the entity `acme-corp` under another is the ordinary case, not a
1946
+ * pathological one). Supplying `kind` selects one codec, and a codec cannot return
1947
+ * two answers — so ambiguity is structurally impossible rather than merely unlikely,
1948
+ * and no disambiguation pass is needed anywhere downstream.
1949
+ *
1950
+ * Narrow by design, mirroring `IMemoryRecordResolver`: a component that needs to
1951
+ * turn an entity address into a storage address should depend on this rather than on
1952
+ * the whole store.
1953
+ * @public
1954
+ */
1955
+ export declare interface IIdentityResolver {
1956
+ /**
1957
+ * The storage address `(kind, entityId)` maps to, without reading the record.
1958
+ *
1959
+ * @param kind - Selects the identity codec. Required: it is what makes the
1960
+ * resolution unambiguous.
1961
+ * @param entityId - The consumer-supplied domain key.
1962
+ * @returns `Success` with the codec's `{ scope, idStem, isVersioned }`, or
1963
+ * `Failure` if no codec is registered for `kind` (and no default is wired) or the
1964
+ * codec rejects the id. Both are caller errors and both are loud.
1965
+ */
1966
+ resolveIdentity(kind: Kind, entityId: EntityId): Result<IIdentityCodecResult>;
1967
+ }
1968
+
1969
+ /**
1970
+ * Coverage of the record-granular vector index.
1971
+ * @public
1972
+ */
1973
+ export declare interface IIndexCoverage {
1974
+ /** Per-kind expected/covered, derived from the envelope walk. */
1975
+ readonly perKind: ReadonlyMap<Kind, IArtifactCoverage>;
1976
+ /**
1977
+ * What the index **actually holds**, whole-index.
1978
+ *
1979
+ * @remarks
1980
+ * **This is a fact and {@link IArtifactCoverage.covered} is a belief, and the
1981
+ * two are reported separately because their disagreement is the only free
1982
+ * signal that distinguishes a persistent index from a fresh one.** `covered`
1983
+ * counts envelopes carrying an `embeddingRef`; `indexSize` counts vectors. With
1984
+ * a persistent index they agree. With an in-memory index at open they do not —
1985
+ * the envelopes still claim references from previous sessions while the index
1986
+ * holds nothing, so `covered` **lies, in the confident direction**.
1987
+ *
1988
+ * Collapsing them into one "coverage %" would destroy that signal, which is why
1989
+ * this type does not offer one.
1990
+ */
1991
+ readonly indexSize: number;
1992
+ }
1993
+
1994
+ /**
1995
+ * What the index HOLDS and what every index read returns: a record's scope and
1996
+ * its {@link IMemoryEnvelope}, and **no body**.
1997
+ *
1998
+ * @remarks
1999
+ * The index is a derived *selection* structure, and selection has never needed a
2000
+ * body — every filter the store and the retrievers apply reads envelope fields
2001
+ * (`scope` / `kind` / `tags` / `contentHash` / `provenance` / `links` /
2002
+ * `temporal` / `updated` / `seq` / `rank`). Returning whole records made every
2003
+ * conforming index hold every body by construction, which was the store's
2004
+ * resident-memory ceiling; returning envelopes removes it from the contract
2005
+ * rather than from one implementation.
2006
+ *
2007
+ * A caller that needs the body **materializes it explicitly** — through
2008
+ * {@link IMemoryStore.getById}, or an `IMemoryRecordResolver` where one is
2009
+ * wired. That is deliberately visible: a lazy `body` getter would have kept
2010
+ * every call site compiling while turning a memory read into a file read behind
2011
+ * an unchanged type, which is a silent performance cliff rather than a migration.
2012
+ * @public
2013
+ */
2014
+ export declare interface IIndexedMemoryEntry {
2015
+ /** The scope the record is stored under. */
2016
+ readonly scope: MemoryScopeKey;
2017
+ /** The record's envelope. No body — see the remarks. */
2018
+ readonly envelope: IMemoryEnvelope;
2019
+ }
2020
+
1485
2021
  /**
1486
2022
  * A memory record paired with the {@link MemoryScopeKey | scope} it lives
1487
2023
  * under. The scope is not carried on the {@link IMemoryEnvelope} (it is derived
@@ -1689,7 +2225,7 @@ export declare interface IMemoryEnvelope {
1689
2225
  * below every subsequently-written one regardless of what the projector would
1690
2226
  * have scored them, so the result is not a partial ordering but one inverted
1691
2227
  * with respect to the projector's intent, with nothing failing to say so. Call
1692
- * `IMemoryStore.reconcileRank` after registering a projector against a
2228
+ * `IMemoryStore.reconcile(kind, 'rank')` after registering a projector against a
1693
2229
  * populated store.
1694
2230
  */
1695
2231
  readonly rank?: number;
@@ -1723,40 +2259,98 @@ export declare interface IMemoryFileParts {
1723
2259
  * patched incrementally on every write ({@link IMemoryIndex.patch}).
1724
2260
  *
1725
2261
  * @remarks
1726
- * B1 builds the maps; link-traversal BFS over {@link IMemoryIndex.backlinks}
1727
- * is B2. The accessors return records (not bare ids) so the B2 retrievers can
1728
- * consume them directly.
2262
+ * Every read returns the projected {@link IIndexedMemoryEntry} scope and
2263
+ * envelope, no body. See that type for why.
2264
+ *
2265
+ * **The conformance rule: an index is a derived, COMPLETE, FAITHFUL projection
2266
+ * of the vault.** An implementation may change *where* entries are stored and
2267
+ * *how* they are looked up; it may not change *which* entries exist or *what any
2268
+ * envelope says*. Concretely, {@link IMemoryIndex.entries} must return exactly
2269
+ * one entry per record the store has written and not deleted, and each entry's
2270
+ * envelope must be the one the store patched in.
2271
+ *
2272
+ * An index that filters, truncates, deduplicates, or synthesizes entries is not
2273
+ * a conforming implementation, and the reason is not tidiness: **the store's
2274
+ * write path derives from these reads** — content-hash dedup, write-policy
2275
+ * admission cohorts, and temporal version histories all read the index. An index
2276
+ * that hides an entry does not merely hide it from queries; it changes what the
2277
+ * next write does. That is why the previous guidance said only a faithful
2278
+ * delegating decorator was safe to inject. This invariant is what that guidance
2279
+ * was reaching for, stated so that a genuinely different implementation (a
2280
+ * SQLite-backed index, a lazily-paged one) is permitted while the reshaping that
2281
+ * was the actual hazard stays out.
2282
+ *
2283
+ * **Ordering is NOT part of the contract.** {@link IMemoryIndex.entries} may
2284
+ * return entries in any order and callers that need one sort explicitly. Note
2285
+ * this is a *behavioural* freedom the compiler cannot police: the bundled
2286
+ * {@link MemoryIndex} iterates a `Map` and so returns insertion order, which is
2287
+ * stable and observable, so code that came to rely on it keeps compiling and
2288
+ * changes results. The ordered accessors ({@link IMemoryIndex.byRecency},
2289
+ * {@link IMemoryIndex.byRank}, and the recency-ordered `byKind` / `byTag`) are
2290
+ * the supported way to ask for an order.
1729
2291
  * @public
1730
2292
  */
1731
2293
  export declare interface IMemoryIndex {
1732
2294
  /**
1733
- * Replace the entire index from a full set of records (a store walk).
1734
- * @returns The number of records indexed.
2295
+ * Replace the entire index from a full set of entries (a store walk).
2296
+ *
2297
+ * @remarks
2298
+ * Takes the **projected** {@link IIndexedMemoryEntry} form, not whole records,
2299
+ * and the distinction is load-bearing rather than cosmetic: **`patch` writes,
2300
+ * `rebuild` reads.** A rebuild is a whole-vault read that happens to terminate
2301
+ * in the index, so requiring whole records here would force every caller — the
2302
+ * store's own open path included — to materialize N bodies purely to feed a
2303
+ * structure that projects the envelope back out and discards them. `patch`
2304
+ * keeps whole records because it carries exactly one, which its caller already
2305
+ * holds.
2306
+ *
2307
+ * @returns The number of entries indexed.
1735
2308
  */
1736
- rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;
2309
+ rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number>;
1737
2310
  /**
1738
2311
  * Apply a single incremental change. `'put'` inserts or replaces the entry
1739
2312
  * at its `(scope, id)` key (removing any prior associations first); `'delete'`
1740
2313
  * removes it.
2314
+ *
2315
+ * @remarks
2316
+ * Takes the whole record — see {@link IMemoryIndex.rebuild} for why this one
2317
+ * does and that one does not. It costs nothing (the caller is mid-write and
2318
+ * holds the record already) and it is the single point at which an index
2319
+ * maintaining a body-derived view could observe content without a re-read.
2320
+ * What is *held* is still only the projection.
2321
+ *
1741
2322
  * @returns The entry that was applied.
1742
2323
  */
1743
2324
  patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;
1744
- /** Every indexed entry (scope + record). Primary read surface for the store. */
1745
- entries(): ReadonlyArray<IIndexedMemoryRecord>;
1746
- /** Records of the given kind, in recency order (most-recently-updated first). */
1747
- byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
1748
- /** Records carrying the given tag, in recency order. */
1749
- byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
1750
- /** All records in recency order (most-recently-updated first). */
1751
- byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
1752
- /**
1753
- * All records ordered by store-computed {@link IMemoryEnvelope.rank} descending,
1754
- * with recency (most-recently-updated, then `seq`) as a tiebreak. Records with
1755
- * an absent `rank` sort LAST (after every ranked record), then by recency among
2325
+ /** Every indexed entry (scope + envelope). Primary read surface for the store. */
2326
+ entries(): ReadonlyArray<IIndexedMemoryEntry>;
2327
+ /**
2328
+ * The entry at a scope-qualified address, or `undefined` if none.
2329
+ *
2330
+ * @remarks
2331
+ * On the contract because its absence made every caller that wanted **one**
2332
+ * entry rebuild a map of **all** of them: both `SemanticRetriever` (resolving
2333
+ * at most `topK` hits) and `LinkTraversalRetriever` (resolving a BFS frontier)
2334
+ * built a full-index `Map` per query for want of this. The index already keys
2335
+ * on `(scope, id)` internally, so this exposes a lookup it was doing anyway.
2336
+ */
2337
+ get(target: IEdgeTarget): IIndexedMemoryEntry | undefined;
2338
+ /** Entries of the given kind, in recency order (most-recently-updated first). */
2339
+ byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry>;
2340
+ /** Entries carrying the given tag, in recency order. */
2341
+ byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry>;
2342
+ /** All entries in recency order (most-recently-updated first). */
2343
+ byRecency(): ReadonlyArray<IIndexedMemoryEntry>;
2344
+ /**
2345
+ * All entries ordered by store-computed {@link IMemoryEnvelope.rank} descending,
2346
+ * with recency (most-recently-updated, then `seq`) as a tiebreak. Entries with
2347
+ * an absent `rank` sort LAST (after every ranked entry), then by recency among
1756
2348
  * themselves. Serves a bounded top-M ({@link IMemoryEnvelope.rank}-ordered) page
1757
- * from the in-memory index with no full-vault (filesystem) scan.
2349
+ * from the in-memory index with no full-vault (filesystem) scan — and since the
2350
+ * page is envelope-only, a caller taking the top M materializes M bodies rather
2351
+ * than the vault.
1758
2352
  */
1759
- byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
2353
+ byRank(): ReadonlyArray<IIndexedMemoryEntry>;
1760
2354
  /**
1761
2355
  * The scope-qualified sources of records whose `links` point AT `target`
1762
2356
  * (inbound edges), keyed on the target's `(scope, id)` address. The seed map
@@ -2058,6 +2652,72 @@ export declare interface IMemoryRecord<TBody = unknown> {
2058
2652
  readonly body: TBody;
2059
2653
  }
2060
2654
 
2655
+ /**
2656
+ * What a {@link IMemoryRecordSource.list} call yields: the records the rebuild
2657
+ * should embed, plus — when the source can say — what it filtered out on the way.
2658
+ *
2659
+ * @remarks
2660
+ * The exclusion count originates here because **this is the layer where the
2661
+ * decision is made**. A rebuild never sees an excluded record, so it cannot count
2662
+ * one; a report assembled without this would silently undercount coverage, and
2663
+ * undercount in the direction of looking healthier.
2664
+ *
2665
+ * A store accessor answering "how many are excluded right now" was considered and
2666
+ * declined: it answers a *different question* than the report does — "excluded
2667
+ * right now" versus "excluded in this reconcile" — and the two legitimately differ
2668
+ * whenever records are written between reconciles. Two correct-and-unequal numbers
2669
+ * are worse than one absent number: they invite treating a real difference as a
2670
+ * bug, or picking whichever supports the conclusion already held.
2671
+ * @public
2672
+ */
2673
+ export declare interface IMemoryRecordListing {
2674
+ /** Every record the rebuild should embed, each paired with its scoped address. */
2675
+ readonly records: ReadonlyArray<IScopedMemoryRecord>;
2676
+ /**
2677
+ * Records this source filtered out, counted by {@link Kind}. Omit it entirely if
2678
+ * the source does not track exclusions — that reads as *"cannot say"* on
2679
+ * {@link IVectorRebuildReport.excluded}, which is distinct from an empty map
2680
+ * (*"nothing was excluded"*).
2681
+ */
2682
+ readonly excluded?: ReadonlyMap<Kind, number>;
2683
+ }
2684
+
2685
+ /**
2686
+ * Materializes one record's body from its scope-qualified address — the other
2687
+ * half of the partial-read split, and the narrowest seam that can be.
2688
+ *
2689
+ * @remarks
2690
+ * The index holds `IIndexedMemoryEntry` (scope + envelope, no body), so anything
2691
+ * that *selects* works from envelopes and anything that must *return records*
2692
+ * resolves the survivors through this. `FileTreeMemoryStore` implements it over
2693
+ * the same read path `getById` uses, so a resolved record is byte-identical to a
2694
+ * keyed read, verification included.
2695
+ *
2696
+ * **Deliberately one method, and deliberately not the store.** A retriever needs
2697
+ * exactly this capability; handing it an `IMemoryStore` would hand it `put` and
2698
+ * `delete` as well, and would invert the construction direction (the store builds
2699
+ * retrievers today, not the reverse). One method also keeps a test double
2700
+ * trivial.
2701
+ *
2702
+ * Synchronous `Result` rather than `Promise<Result>` because every shipped
2703
+ * `FileTree` backend resolves without awaiting, and an async signature here would
2704
+ * have rippled through retrievers that are otherwise synchronous over the index.
2705
+ * A future backend that genuinely needs I/O should be adapted at its own boundary
2706
+ * rather than by making this contract async for everyone.
2707
+ *
2708
+ * Resolving an address the vault does not hold is `succeed(undefined)`, not a
2709
+ * failure — an entry can legitimately vanish between selection and
2710
+ * materialization (a concurrent delete), and that is a miss rather than a fault.
2711
+ * A failure means the record is there and could not be read.
2712
+ * @public
2713
+ */
2714
+ export declare interface IMemoryRecordResolver {
2715
+ /**
2716
+ * The record at `(scope, id)`, or `undefined` if the vault does not hold one.
2717
+ */
2718
+ resolveRecord(scope: MemoryScopeKey, id: MemoryId): Result<IMemoryRecord<unknown> | undefined>;
2719
+ }
2720
+
2061
2721
  /**
2062
2722
  * The minimal record-source surface {@link InMemoryCosineIndex.rebuild} reads to
2063
2723
  * re-embed an entire vault. Each entry carries the record's scope-qualified
@@ -2069,8 +2729,12 @@ export declare interface IMemoryRecord<TBody = unknown> {
2069
2729
  * @public
2070
2730
  */
2071
2731
  export declare interface IMemoryRecordSource {
2072
- /** List every record in the vault, each paired with its scoped address. */
2073
- list(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
2732
+ /**
2733
+ * List every record the rebuild should embed, each paired with its scoped
2734
+ * address, plus the exclusions this source applied if it tracks them. See
2735
+ * {@link IMemoryRecordListing}.
2736
+ */
2737
+ list(): Promise<Result<IMemoryRecordListing>>;
2074
2738
  }
2075
2739
 
2076
2740
  /**
@@ -2108,15 +2772,23 @@ export declare interface IMemoryRetrieverCapabilities {
2108
2772
 
2109
2773
  /**
2110
2774
  * The writable, FileTree-backed, content-hash-deduped memory store.
2775
+ *
2776
+ * @remarks
2777
+ * Extends {@link IMemoryRecordResolver} because the retrievers take a resolver
2778
+ * and a store is the obvious one to hand them — `{ index, resolver: store }` is
2779
+ * the documented wiring, and it has to type-check for the `IMemoryStore` handle
2780
+ * a consumer actually holds, not only for the concrete `FileTreeMemoryStore`.
2111
2781
  * @public
2112
2782
  */
2113
- export declare interface IMemoryStore {
2783
+ export declare interface IMemoryStore extends IMemoryRecordResolver, IIdentityResolver {
2114
2784
  /**
2115
2785
  * Keyed read by entity id. Resolves `entityId` to a storage address via the
2116
2786
  * registered {@link IIdentityCodec} for `kind`. Returns `undefined` when no
2117
- * record exists. For a versioned (temporal) kind this returns the current
2118
- * version, resolved from the derived in-memory index (not re-read/re-verified
2119
- * from disk per callthe index is kept in sync with every write).
2787
+ * record exists. For a versioned (temporal) kind the current version is
2788
+ * *selected* from the derived in-memory index the version history is walked
2789
+ * over envelopes, never bodiesand then that one version is read from
2790
+ * storage. So the selection costs no file reads and the result costs exactly
2791
+ * one, rather than one per version.
2120
2792
  */
2121
2793
  get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
2122
2794
  /**
@@ -2124,9 +2796,77 @@ export declare interface IMemoryStore {
2124
2796
  */
2125
2797
  getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
2126
2798
  /**
2127
- * List records, filtered in-memory over the derived index.
2799
+ * List records: select over the derived index, then materialize the survivors.
2800
+ *
2801
+ * @remarks
2802
+ * **The selection is required and must narrow.** Since the index holds
2803
+ * envelopes only, every returned record is read from storage — so a call that
2804
+ * narrows nothing reads the whole vault, and that has to be a decision rather
2805
+ * than a default. Omitting the argument is a compile error; passing one with no
2806
+ * `scope` / `kind` / `tag` fails with a message naming {@link scanEveryRecord},
2807
+ * which is how a caller says it meant it.
2808
+ *
2809
+ * The requirement buys **explicitness, not a cost bound** — `{ kind }` on a
2810
+ * vault dominated by that kind still materializes most of it. What it prevents
2811
+ * is the whole-vault read nobody chose.
2812
+ *
2813
+ * If you only need to select, use {@link IMemoryStore.listEntries} instead: no
2814
+ * selection, no file reads.
2815
+ */
2816
+ list(selection: MemoryListSelection): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
2817
+ /**
2818
+ * How much of the store's **derived state** exists, resolved by {@link Kind}.
2819
+ *
2820
+ * @remarks
2821
+ * Answers *"is my derived state consistent with my records, and if not by how
2822
+ * much?"* for every artifact the store derives — `rank`, record vectors, and
2823
+ * fragment vectors — in one call.
2824
+ *
2825
+ * **Cheap and total, by contract rather than by implementation.** Every input is
2826
+ * an envelope field or an index-side count: it reads **no record bodies** and
2827
+ * calls **no embedder**, and the walk over the vault's own state touches the
2828
+ * filesystem not at all. That is why it takes no selection, unlike
2829
+ * {@link IMemoryStore.list} — the guard there exists because an unnarrowed list
2830
+ * reads the vault, and putting one here would decorate a free operation and make
2831
+ * that guard mean less.
2832
+ *
2833
+ * **The index-side counts are the one exception, and it is the caller's own
2834
+ * index that spends it.** A persistent index answers `size` / `recordCount` /
2835
+ * `fragmentCount` with a query — `SqliteVecVectorIndex` runs a prepared `COUNT`
2836
+ * — so on a durable backend this call does I/O and can **fail**. It is bounded
2837
+ * (one count per wired index, never per record) and it is why the return is a
2838
+ * `Result` rather than a bare value.
2839
+ *
2840
+ * *If a future addition to the report would require reading a record body, it
2841
+ * does not belong on this report.*
2842
+ *
2843
+ * The counterpart is {@link IMemoryStore.reconcile}: coverage says **how big**
2844
+ * the gap is, cheaply; reconcile says **what it was** and closes what it can, at
2845
+ * the cost of re-running the embedder. Neither substitutes for the other.
2846
+ *
2847
+ * **A lane is reported here whenever its *index* is wired**, which is weaker
2848
+ * than what reconcile requires (index **and** embedder). That is intended: an
2849
+ * index without an embedder still holds vectors and still answers queries, so
2850
+ * its coverage is a real number worth reporting. The consequence to expect is a
2851
+ * half-wired store that reports a gap `reconcile` will refuse to close, naming
2852
+ * the missing embedder.
2853
+ */
2854
+ coverage(): Promise<Result<IDerivedStateCoverage>>;
2855
+ /**
2856
+ * Every entry in the vault — scope and envelope, **no bodies**. Reads no files
2857
+ * and requires no selection, because there is nothing to be careful about: it
2858
+ * returns what the index already holds.
2859
+ *
2860
+ * @remarks
2861
+ * This is the whole-vault read most callers actually want. Selection, grouping,
2862
+ * counting, "which kinds are in here", "what links at this" — all of it is
2863
+ * envelope work. Reach for {@link IMemoryStore.list} with
2864
+ * {@link scanEveryRecord} only when you genuinely need every body.
2865
+ *
2866
+ * Synchronous in spirit but `Promise`-returning for consistency with the rest
2867
+ * of the store surface.
2128
2868
  */
2129
- list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
2869
+ listEntries(): Promise<Result<ReadonlyArray<IIndexedMemoryEntry>>>;
2130
2870
  /**
2131
2871
  * List EVERY record in the vault, each paired with its scope-qualified
2132
2872
  * `(scope, id)` address — the projection {@link IMemoryRecordSource} requires.
@@ -2148,6 +2888,11 @@ export declare interface IMemoryStore {
2148
2888
  * every kind participates and the filter is the identity. `listScoped` itself is
2149
2889
  * **not** filtered and remains the whole-vault surface.
2150
2890
  *
2891
+ * The filter also **counts what it drops**, onto
2892
+ * {@link IMemoryRecordListing.excluded} — this is the layer where the exclusion
2893
+ * decision is made and so the only one that can. The count is always present
2894
+ * (empty when nothing was excluded).
2895
+ *
2151
2896
  * The store cannot implement {@link IMemoryRecordSource} directly because its
2152
2897
  * `list(filter?)` returns bare records (the ergonomic query surface) while the
2153
2898
  * seam's `list()` returns scope-qualified records.
@@ -2209,35 +2954,42 @@ export declare interface IMemoryStore {
2209
2954
  */
2210
2955
  put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
2211
2956
  /**
2212
- * Re-apply the kind's {@link RankProjector} to every record of `kind` already
2213
- * in the store, restamping {@link IMemoryEnvelope.rank}. Returns the number of
2214
- * records whose `rank` actually changed.
2957
+ * Repair one derived artifact for one {@link Kind} **targeted and
2958
+ * non-destructive**, unlike `IVectorIndex.rebuild`, which resets the index and
2959
+ * re-embeds everything.
2215
2960
  *
2216
2961
  * @remarks
2217
- * **This exists because `rank` is otherwise new-store-only, and fails in a way
2218
- * that looks like it works.** The projector runs on the write path only, so
2219
- * registering one against a populated store ranks nothing already written
2220
- * and because an absent `rank` sorts *last*, every pre-registration record
2221
- * lands below every post-registration one no matter what the projector would
2222
- * have scored it. The ordering is not merely partial; it is **inverted with
2223
- * respect to the projector's own intent**, with no failure anywhere to say so.
2962
+ * The counterpart to {@link IMemoryStore.coverage}: coverage says **how big**
2963
+ * the gap is and costs nothing; reconcile says **what it was** and closes what
2964
+ * it can, at the cost of reading bodies and re-running the embedder. Neither
2965
+ * substitutes for the other in particular, only reconcile can distinguish a
2966
+ * *declined* record from a *failed* one, because learning that requires calling
2967
+ * the embedder again.
2224
2968
  *
2225
- * Deliberately **does not** touch `created` / `updated` / `seq`, and fires no
2226
- * `'write'` observation. Routing a reconcile through {@link IMemoryStore.put}
2227
- * would bump transaction time on every record trading a wrong `rank` order
2228
- * for a wrong recency order, and flooding any wired observer with writes that
2229
- * are not writes. The body is re-serialized verbatim from the file's own
2230
- * bytes; only the envelope's `rank` moves.
2969
+ * **It only touches what is missing.** For the vector lanes it asks
2970
+ * `has(target)` per record and skips the ones already held, so a repair after a
2971
+ * brief outage costs a handful of embedder calls rather than a whole vault.
2972
+ * That check is also the only way to see a record whose vector the index holds
2973
+ * but whose envelope lost its `embeddingRef` which needs a restamp and no
2974
+ * embedder call at all, and which an `embeddingRef`-only repair cannot detect.
2231
2975
  *
2232
- * Fails loudly if `kind` has no registered projector: asking to reconcile a
2233
- * kind you never configured is a caller error, not a no-op.
2976
+ * **`artifact` is required and names one lane.** See {@link DerivedArtifact}
2977
+ * for why an operation repairing "everything wired" would be the wrong shape.
2234
2978
  *
2235
- * **Not atomic, and safe for it.** A failure part-way leaves earlier records
2236
- * restamped. That is benign because restamping is idempotent — re-running
2237
- * converges which is also why no report shape is offered here. A count is
2238
- * enough.
2979
+ * **A vector lane must be wired on BOTH halves index *and* embedder — or this
2980
+ * fails, and it is deliberately stricter than {@link IMemoryStore.coverage}.**
2981
+ * The two ask different questions of the same wiring. Coverage asks *what does
2982
+ * the index hold*, which an index alone can answer: an index wired without an
2983
+ * embedder is a legal store (queries work; writes simply do not embed), so
2984
+ * coverage reports that lane rather than pretending it is absent. Reconcile
2985
+ * asks to *produce* vectors, which needs the embedder. So a half-wired store
2986
+ * legitimately reports a coverage gap it cannot repair, and reconcile names the
2987
+ * missing half rather than returning a cheerful success with every record in
2988
+ * `failed`.
2989
+ *
2990
+ * Runs under the store's write lock, like any other mutation.
2239
2991
  */
2240
- reconcileRank(kind: Kind): Promise<Result<number>>;
2992
+ reconcile(kind: Kind, artifact: DerivedArtifact): Promise<Result<ReconcileReport>>;
2241
2993
  /**
2242
2994
  * Delete a record by `(kind, entityId)`. Non-temporal kinds physically delete
2243
2995
  * the file and return the deleted record's {@link MemoryId}. Temporal
@@ -2250,9 +3002,29 @@ export declare interface IMemoryStore {
2250
3002
 
2251
3003
  /**
2252
3004
  * Filter for {@link IMemoryStore.list}. All present fields are ANDed together.
3005
+ *
3006
+ * @remarks
3007
+ * **At least one of `scope` / `kind` / `tag` must be present.** `asOf` is a
3008
+ * temporal *projection*, not a narrowing — it collapses versions rather than
3009
+ * excluding entities — so it does not satisfy the requirement on its own. A
3010
+ * selection that narrows nothing fails with a message naming
3011
+ * {@link scanEveryRecord}.
2253
3012
  * @public
2254
3013
  */
2255
3014
  export declare interface IMemoryStoreListFilter {
3015
+ /**
3016
+ * Never present on a narrowing filter.
3017
+ *
3018
+ * @remarks
3019
+ * Exclusivity marker, paired with the `never`s on {@link IWholeVaultScan}.
3020
+ * Without it `{ scanEveryRecord: true, kind }` type-checks — TypeScript's
3021
+ * excess-property check on a union admits any property declared by *any*
3022
+ * member — and `list` then takes the scan branch and silently discards the
3023
+ * narrowing. Since the whole point of requiring a selection is that a
3024
+ * whole-vault read must be deliberate, a call that reads the whole vault while
3025
+ * *looking* narrowed is the one outcome this surface must not permit.
3026
+ */
3027
+ readonly scanEveryRecord?: never;
2256
3028
  /** Restrict to records in this scope. */
2257
3029
  readonly scope?: MemoryScopeKey;
2258
3030
  /** Restrict to records of this kind. */
@@ -2323,7 +3095,7 @@ export declare interface IMergeStrategy {
2323
3095
  * are each retriever's own concern.
2324
3096
  * @public
2325
3097
  */
2326
- export declare function indexedRecordMatchesQuery(entry: IIndexedMemoryRecord, query: IMemoryQuery): boolean;
3098
+ export declare function indexedRecordMatchesQuery(entry: IIndexedMemoryEntry, query: IMemoryQuery): boolean;
2327
3099
 
2328
3100
  /**
2329
3101
  * How a candidate was ultimately written (or not) after resolution.
@@ -2376,6 +3148,8 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
2376
3148
  static create(): Result<InMemoryCosineIndex>;
2377
3149
  /** {@inheritDoc IVectorIndex.add} */
2378
3150
  add(target: IEdgeTarget, vector: Float32Array): Promise<Result<string>>;
3151
+ /** {@inheritDoc IVectorIndex.has} */
3152
+ has(target: IEdgeTarget): Promise<Result<boolean>>;
2379
3153
  /** {@inheritDoc IVectorIndex.remove} */
2380
3154
  remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
2381
3155
  /** {@inheritDoc IVectorIndex.query} */
@@ -2408,6 +3182,11 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
2408
3182
  * A {@link MemoryEmbedder} decline is not a failure under either mode: it is
2409
3183
  * counted on {@link IVectorRebuildReport.declined} and never appears in `skipped`.
2410
3184
  *
3185
+ * **A `'fail'` failure carries the partial report on its `detail`** — the
3186
+ * rollback still runs, so that report describes the aborted attempt rather than
3187
+ * the (now empty) index. The one failure with no detail is a `list` failure,
3188
+ * which disturbs nothing and has nothing to describe.
3189
+ *
2411
3190
  * Both consumer-supplied hooks are capture-wrapped, so a `source` or `embed`
2412
3191
  * that throws or rejects becomes a `Failure` on the path above rather than an
2413
3192
  * exception escaping mid-rebuild — which would bypass the rollback entirely.
@@ -2416,7 +3195,7 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
2416
3195
  * @param embed - The embedder applied to each record.
2417
3196
  * @param options - Rebuild options; omit for the historical `'fail'` behavior.
2418
3197
  */
2419
- rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<Result<IVectorRebuildReport>>;
3198
+ rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<DetailedResult<IVectorRebuildReport, IVectorRebuildReport>>;
2420
3199
  /** Empty the index and forget the established dimension. */
2421
3200
  private _reset;
2422
3201
  /** The Euclidean magnitude (L2 norm) of a vector. */
@@ -2474,10 +3253,23 @@ export declare class InMemoryFragmentCosineIndex implements IFragmentVectorIndex
2474
3253
  static create(): Result<InMemoryFragmentCosineIndex>;
2475
3254
  /** {@inheritDoc IFragmentVectorIndex.addFragments} */
2476
3255
  addFragments(target: IEdgeTarget, fragments: ReadonlyArray<IEmbeddedFragment>): Promise<Result<number>>;
3256
+ /** {@inheritDoc IFragmentVectorIndex.has} */
3257
+ has(target: IEdgeTarget): Promise<Result<boolean>>;
2477
3258
  /** {@inheritDoc IFragmentVectorIndex.remove} */
2478
3259
  remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
2479
3260
  /** {@inheritDoc IFragmentVectorIndex.query} */
2480
- query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
3261
+ query(vector: Float32Array, topK: number, options?: IFragmentQueryOptions): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
3262
+ /**
3263
+ * The records a query is allowed to score, honoring the `scope` / `id` narrowing.
3264
+ *
3265
+ * @remarks
3266
+ * The single-record case is an O(1) map lookup rather than a scan, because the
3267
+ * record map is keyed by `edgeTargetKey`. The scope-only case (a versioned kind's
3268
+ * per-entity subtree) is a filtered walk — still bounded by the vault, but it
3269
+ * scores only the entity's own fragments, which is what makes the caller's `topK`
3270
+ * meaningful.
3271
+ */
3272
+ private _selectRecords;
2481
3273
  /**
2482
3274
  * Re-embed every record from `source` and rebuild the fragment index from
2483
3275
  * scratch. Clears the current contents (and the established dimension) first, so
@@ -2497,7 +3289,8 @@ export declare class InMemoryFragmentCosineIndex implements IFragmentVectorIndex
2497
3289
  * @param source - The scope-qualified record source to re-embed.
2498
3290
  * @param embed - The fragment embedder applied to each record.
2499
3291
  */
2500
- rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder): Promise<Result<number>>;
3292
+ /** {@inheritDoc IFragmentVectorIndex.rebuild} */
3293
+ rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder, options?: IVectorRebuildOptions): Promise<DetailedResult<IFragmentVectorRebuildReport, IFragmentVectorRebuildReport>>;
2501
3294
  /** Empty the index and forget the established dimension. */
2502
3295
  private _reset;
2503
3296
  /** The Euclidean magnitude (L2 norm) of a vector. */
@@ -2538,6 +3331,23 @@ export declare interface IProvenance {
2538
3331
  readonly [key: string]: unknown;
2539
3332
  }
2540
3333
 
3334
+ /** A `rank` reconcile: re-run the projector and restamp what changed. @public */
3335
+ export declare interface IRankReconcileReport extends IReconcileReportBase {
3336
+ readonly artifact: 'rank';
3337
+ }
3338
+
3339
+ /** What every reconcile reports, whatever the artifact. @public */
3340
+ export declare interface IReconcileReportBase {
3341
+ /** The kind reconciled — named by the caller, so every count below is scalar. */
3342
+ readonly kind: Kind;
3343
+ /** Records of this kind considered. The denominator for everything else. */
3344
+ readonly examined: number;
3345
+ /** Records whose derived artifact was (re)produced by this call. */
3346
+ readonly repaired: number;
3347
+ /** Records that failed, with the error. A fault, never a decline. */
3348
+ readonly failed: ReadonlyArray<ISkippedVectorRecord>;
3349
+ }
3350
+
2541
3351
  /**
2542
3352
  * A candidate paired with its resolved reference id, handed to the relation
2543
3353
  * extractor so it can source edges from it.
@@ -2580,6 +3390,24 @@ export declare interface IRelationExtractor {
2580
3390
  relate(context: IRelationContext): Promise<Result<ReadonlyArray<ICandidateEdge>>>;
2581
3391
  }
2582
3392
 
3393
+ /**
3394
+ * What every index-backed retriever needs: the index it selects over, and the
3395
+ * resolver it materializes survivors through.
3396
+ *
3397
+ * @remarks
3398
+ * The resolver is the whole of the partial-read migration for a caller that
3399
+ * constructs retrievers directly — the index projection itself is invisible to
3400
+ * anyone who only consumes `retrieve()`. `FileTreeMemoryStore` implements
3401
+ * {@link IMemoryRecordResolver}, so wiring is `{ index, resolver: store }`.
3402
+ * @public
3403
+ */
3404
+ export declare interface IRetrieverCreateParams {
3405
+ /** The derived index to select over. */
3406
+ readonly index: IMemoryIndex;
3407
+ /** Materializes the selected entries' bodies. */
3408
+ readonly resolver: IMemoryRecordResolver;
3409
+ }
3410
+
2583
3411
  /**
2584
3412
  * A record paired with its scope-qualified {@link IEdgeTarget | address}, as
2585
3413
  * yielded by {@link IMemoryRecordSource.list}. The address is required because
@@ -2613,9 +3441,7 @@ export declare interface ISemanticBackend {
2613
3441
  * Construction options for {@link SemanticRetriever.create}.
2614
3442
  * @public
2615
3443
  */
2616
- export declare interface ISemanticRetrieverCreateParams {
2617
- /** The record index, used to resolve vector hits back to full records. */
2618
- readonly index: IMemoryIndex;
3444
+ export declare interface ISemanticRetrieverCreateParams extends IRetrieverCreateParams {
2619
3445
  /**
2620
3446
  * The semantic backend. When absent, the retriever reports
2621
3447
  * `supportsSemanticRecall: false` and a `query.semantic` request degrades
@@ -2668,7 +3494,7 @@ export declare function isTemporalIdentityCodec(codec: IIdentityCodec): codec is
2668
3494
  * divergence (MTM is flat yet has `entityId !== id`).
2669
3495
  * @public
2670
3496
  */
2671
- export declare function isTemporalRecord(record: IMemoryRecord<unknown>): boolean;
3497
+ export declare function isTemporalRecord(record: IEnvelopeCarrier): boolean;
2672
3498
 
2673
3499
  /**
2674
3500
  * Whether a temporal record is a *current* version — its `temporal.invalid_at`
@@ -2676,7 +3502,7 @@ export declare function isTemporalRecord(record: IMemoryRecord<unknown>): boolea
2676
3502
  * current in this sense (returns `false`).
2677
3503
  * @public
2678
3504
  */
2679
- export declare function isVersionCurrent(record: IMemoryRecord<unknown>): boolean;
3505
+ export declare function isVersionCurrent(record: IEnvelopeCarrier): boolean;
2680
3506
 
2681
3507
  /**
2682
3508
  * Whether a temporal record's validity interval contains `asOf` (epoch ms):
@@ -2685,7 +3511,13 @@ export declare function isVersionCurrent(record: IMemoryRecord<unknown>): boolea
2685
3511
  * record is never "valid at" a point (returns `false`).
2686
3512
  * @public
2687
3513
  */
2688
- export declare function isVersionValidAt(record: IMemoryRecord<unknown>, asOf: number): boolean;
3514
+ export declare function isVersionValidAt(record: IEnvelopeCarrier, asOf: number): boolean;
3515
+
3516
+ /**
3517
+ * Whether a selection is the explicit whole-vault opt-out.
3518
+ * @public
3519
+ */
3520
+ export declare function isWholeVaultScan(selection: MemoryListSelection): selection is IWholeVaultScan;
2689
3521
 
2690
3522
  /**
2691
3523
  * Optional bi-temporal validity block on an envelope. Present only on
@@ -2769,6 +3601,32 @@ export declare interface IVectorIndex {
2769
3601
  * Return the `topK` nearest records to `vector`, in descending score order.
2770
3602
  */
2771
3603
  query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
3604
+ /**
3605
+ * Whether this index holds a vector for the scope-qualified `target`.
3606
+ *
3607
+ * @remarks
3608
+ * On the contract because it is what makes a **targeted** repair possible, and
3609
+ * the reason is sharper than convenience: the only other way to ask *"is this
3610
+ * record indexed?"* is {@link IMemoryEnvelope.embeddingRef} — and that field is
3611
+ * the store's **belief**, which is wrong in precisely the situation a repair
3612
+ * runs in. A reopened vault backed by a fresh in-memory index carries an
3613
+ * `embeddingRef` on every record while holding no vectors at all. **A repair
3614
+ * that trusts the field it is repairing is not a repair.**
3615
+ *
3616
+ * It also makes a case *detectable* that an `embeddingRef`-only check cannot
3617
+ * see at all: the index holds the vector but the envelope lost its reference
3618
+ * (a failure swallowed after the vector was committed). That record needs its
3619
+ * reference restamped and **no embedder call**, which is only knowable by
3620
+ * asking the index.
3621
+ *
3622
+ * `Promise<Result<boolean>>`, unlike the synchronous {@link IVectorIndex.size},
3623
+ * because the two are not the same kind of accessor and should not be made to
3624
+ * look alike: `size` is a count both shipped implementations hold or can read
3625
+ * without a failure mode, while `has` on a durable backend is a keyed query
3626
+ * that can fail. Idempotent and side-effect-free; an absent target is
3627
+ * `succeed(false)`, never a failure.
3628
+ */
3629
+ has(target: IEdgeTarget): Promise<Result<boolean>>;
2772
3630
  /**
2773
3631
  * The number of vectors currently held.
2774
3632
  *
@@ -2806,8 +3664,36 @@ export declare interface IVectorIndex {
2806
3664
  *
2807
3665
  * See {@link IVectorRebuildReport} for what it reports and
2808
3666
  * {@link IVectorRebuildOptions} for the failure mode.
2809
- */
2810
- rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<Result<IVectorRebuildReport>>;
3667
+ *
3668
+ * **A failure carries the report too, on the `detail`** — coverage is most
3669
+ * wanted exactly when a rebuild did not complete, and withholding it there made
3670
+ * the answer depend on the error-handling mode rather than on the question. The
3671
+ * `'fail'` contract itself is unchanged: it still resets, still aborts, still
3672
+ * returns a failure. It simply also says what it had established before it
3673
+ * stopped. See {@link IVectorRebuildReport} for how to read a report that
3674
+ * arrived on a failure — it describes the attempt, not the surviving index.
3675
+ *
3676
+ * On success the report is the **value** — that is where it belongs, and the
3677
+ * `detail` is not also populated. A failure carries no report when nothing was
3678
+ * attempted: always a `source.list()` failure, and additionally whatever
3679
+ * pre-loop step an implementation needs before it can start (the durable
3680
+ * `SqliteVecVectorIndex` must clear its table, and a failure to do so is such a
3681
+ * case). Those leave the existing index untouched, so an all-zero report would
3682
+ * describe an index the call never disturbed.
3683
+ *
3684
+ * **A rebuild does NOT re-establish the vector dimension on a persistent
3685
+ * index, and this is the one place the two shipped implementations genuinely
3686
+ * differ.** The in-memory indexes forget their dimension when they reset, so a
3687
+ * rebuild with a different-dimension embedder simply re-establishes it. A
3688
+ * `vec0`-backed index cannot: its reset is a `DELETE FROM`, the table's
3689
+ * declared dimension is part of its schema, and `vec0` has no `ALTER TABLE`.
3690
+ * So a rebuild that changes dimension **succeeds in memory and fails on
3691
+ * SQLite**, where it needs the same drop-and-re-index the package README
3692
+ * prescribes for any schema change (drop the table, or point the index at a
3693
+ * fresh `tableName`). Only embedding time is at risk — vectors are derived and
3694
+ * the vault records remain authoritative.
3695
+ */
3696
+ rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<DetailedResult<IVectorRebuildReport, IVectorRebuildReport>>;
2811
3697
  }
2812
3698
 
2813
3699
  /**
@@ -2883,26 +3769,141 @@ export declare interface IVectorRebuildOptions {
2883
3769
  * What a rebuild actually did — the structural answer to "is this index complete?".
2884
3770
  *
2885
3771
  * @remarks
2886
- * A bare count cannot distinguish the three ways a record can be absent from the
2887
- * index, and that distinction is the entire point: **`declined` was intentional,
2888
- * `skipped` was a fault, and neither is the same as "never attempted"**. A caller
2889
- * deriving coverage from a count alone cannot tell an embedder outage from a
2890
- * deliberate policy, which is precisely the confusion this type exists to end.
3772
+ * A bare count cannot distinguish the ways a record can be absent from the index,
3773
+ * and that distinction is the entire point: **`declined` was intentional,
3774
+ * `excluded` was never offered, `skipped` was a fault, and none of them is the
3775
+ * same as "never attempted"**. A caller deriving coverage from a count alone
3776
+ * cannot tell an embedder outage from a deliberate policy, which is precisely the
3777
+ * confusion this type exists to end.
3778
+ *
3779
+ * **Every count in this report is resolved by kind.** A coverage report exists to
3780
+ * answer *"is my coverage what I intended?"*, and a bare total cannot:
3781
+ * `indexed: 500` reads identically whether the right kinds were indexed or a
3782
+ * policy drift silently redirected coverage, and the same is true of every other
3783
+ * count here. Totals are derivable by summing; the per-kind breakdown is not
3784
+ * derivable from anything else — {@link IVectorQueryHit} carries no `kind`,
3785
+ * {@link IVectorIndex.query} answers "what is near this" rather than "what is in
3786
+ * here", and {@link IVectorIndex.size} is a scalar, so the index cannot be
3787
+ * interrogated after the fact for any of them. **A new count added to this report
3788
+ * is resolved by kind unless there is a stated reason it cannot be.**
3789
+ *
3790
+ * `indexed` is the count most tempting to leave bare and the most dangerous to,
3791
+ * because it is the number a coverage surface actually renders: 500 bookkeeping
3792
+ * rows and zero knowledge rows is a healthy-looking number for a catastrophically
3793
+ * broken index.
3794
+ *
3795
+ * **Reading a report that arrived on a failure.** Under
3796
+ * {@link VectorRebuildErrorMode | `onRecordError: 'fail'`} the report is handed
3797
+ * back on the failure's `detail` — *after* the rollback has already run. It
3798
+ * describes the attempt, not the surviving index: `indexed` names what had been
3799
+ * established when the rebuild stopped, and the index itself now holds nothing. It
3800
+ * is a diagnostic ("we were 340 knowledge rows in when the embedder died"), not a
3801
+ * coverage statement. Only a report from a **successful** rebuild describes what
3802
+ * the index holds.
2891
3803
  * @public
2892
3804
  */
2893
3805
  export declare interface IVectorRebuildReport {
2894
- /** Records embedded and added to the index. */
2895
- readonly indexed: number;
2896
- /** Records the embedder deliberately declined (resolved `undefined`). */
2897
- readonly declined: number;
3806
+ /**
3807
+ * Records embedded and added to the index, counted by {@link Kind}.
3808
+ *
3809
+ * @remarks
3810
+ * A count of successful `add` calls, so it lines up with its per-record
3811
+ * siblings and the buckets sum back to the listing. It is deliberately **not**
3812
+ * read back off {@link IVectorIndex.size} at the end, which no implementation
3813
+ * could resolve by kind anyway. The trade that makes: a `source` that lists the
3814
+ * same `(scope, id)` twice contributes twice here while the index holds one
3815
+ * vector, where a size read would have self-corrected. A source that does that
3816
+ * is malformed, and a total that silently disagreed with the per-kind
3817
+ * breakdown would be the worse failure.
3818
+ */
3819
+ readonly indexed: ReadonlyMap<Kind, number>;
3820
+ /**
3821
+ * Records the embedder deliberately declined (resolved `undefined`), counted by
3822
+ * {@link Kind}. The embedder was called and answered — contrast `excluded`,
3823
+ * where it never was.
3824
+ */
3825
+ readonly declined: ReadonlyMap<Kind, number>;
3826
+ /**
3827
+ * Records the `source` filtered out before the rebuild ever saw them, counted by
3828
+ * {@link Kind} — for a store-backed source, the kinds outside
3829
+ * {@link IMemoryStore.embedsKind | embedsKind}.
3830
+ *
3831
+ * **Optional, and the optionality is semantic rather than cosmetic**: it is the
3832
+ * one count a rebuild genuinely cannot know for itself, because the decision is
3833
+ * made upstream in the source. `undefined` means *this source does not report
3834
+ * exclusions* — distinct from an empty map, which means *this source reports
3835
+ * them and excluded nothing*. `indexed` and `declined` are knowable by
3836
+ * construction (the rebuild either added the vector or the embedder answered)
3837
+ * and so are never optional.
3838
+ */
3839
+ readonly excluded?: ReadonlyMap<Kind, number>;
2898
3840
  /**
2899
3841
  * Records whose embedding or add FAILED and were skipped. Non-empty only under
2900
3842
  * {@link VectorRebuildErrorMode | `onRecordError: 'skip'`} — under `'fail'` the
2901
- * first failure aborts the rebuild and no report is returned at all.
3843
+ * first failure aborts the rebuild, so a `'fail'` report names the casualty in
3844
+ * its failure message rather than here.
3845
+ *
3846
+ * Per-record and carrying the error, so it already implies the per-kind
3847
+ * breakdown the counts above spell out; that is the stated reason this one field
3848
+ * is not a `ReadonlyMap<Kind, number>`.
2902
3849
  */
2903
3850
  readonly skipped: ReadonlyArray<ISkippedVectorRecord>;
2904
3851
  }
2905
3852
 
3853
+ /**
3854
+ * A record-vector reconcile.
3855
+ * @public
3856
+ */
3857
+ export declare interface IVectorReconcileReport extends IReconcileReportBase {
3858
+ readonly artifact: 'record-vector';
3859
+ /**
3860
+ * Records the index already held and which needed **no embedder call** — the
3861
+ * whole point of a targeted repair, and the number that shows what it saved
3862
+ * against a `rebuild`.
3863
+ */
3864
+ readonly alreadyIndexed: number;
3865
+ /**
3866
+ * Records whose vector the index held but whose envelope had **lost its
3867
+ * `embeddingRef`** — repaired by restamping the reference, with no embedder
3868
+ * call.
3869
+ *
3870
+ * @remarks
3871
+ * This case is invisible to an `embeddingRef`-only check, which is one of the
3872
+ * two reasons `IVectorIndex.has` is on the contract: a reference-absent record
3873
+ * looks identical to a never-embedded one until you ask the index.
3874
+ */
3875
+ readonly restamped: number;
3876
+ /** Records the embedder intentionally declined. Not a failure, not a gap. */
3877
+ readonly declined: number;
3878
+ }
3879
+
3880
+ /**
3881
+ * The named, deliberately uncomfortable opt-out from
3882
+ * {@link IMemoryStore.list}'s narrowing requirement — build one with
3883
+ * {@link scanEveryRecord}.
3884
+ * @public
3885
+ */
3886
+ export declare interface IWholeVaultScan {
3887
+ /** Discriminator. Always `true`; produced only by {@link scanEveryRecord}. */
3888
+ readonly scanEveryRecord: true;
3889
+ /**
3890
+ * Never present on a whole-vault scan — see
3891
+ * {@link IMemoryStoreListFilter.scanEveryRecord} for why these markers exist.
3892
+ * A scan that also carried a narrowing axis would have that axis dropped.
3893
+ */
3894
+ readonly scope?: never;
3895
+ /** Never present on a whole-vault scan. See {@link IWholeVaultScan.scope}. */
3896
+ readonly kind?: never;
3897
+ /** Never present on a whole-vault scan. See {@link IWholeVaultScan.scope}. */
3898
+ readonly tag?: never;
3899
+ /**
3900
+ * Optional temporal projection, exactly as on {@link IMemoryStoreListFilter}.
3901
+ * NOT excluded, because `asOf` projects rather than narrows and composes with
3902
+ * a whole-vault read exactly as it does with a filtered one.
3903
+ */
3904
+ readonly asOf?: number;
3905
+ }
3906
+
2906
3907
  /**
2907
3908
  * A per-kind write policy, injected at store construction. Invoked AFTER
2908
3909
  * content-hash dedup (dedup is always pre-policy). The policy decides
@@ -3074,6 +4075,13 @@ export declare class KnowledgeLwwPolicy implements IWritePolicy {
3074
4075
  private _rebuild;
3075
4076
  }
3076
4077
 
4078
+ /**
4079
+ * The {@link limitRecords} window, applied to entries — used on the
4080
+ * no-body-filter path so paging happens before anything is read.
4081
+ * @public
4082
+ */
4083
+ export declare function limitEntries(entries: ReadonlyArray<IIndexedMemoryEntry>, limit?: number, offset?: number): ReadonlyArray<IIndexedMemoryEntry>;
4084
+
3077
4085
  /**
3078
4086
  * Apply the `{ offset, limit }` page window to an ordered record set. Applied
3079
4087
  * last, after ordering, so it always takes a stable window of the ordered
@@ -3130,22 +4138,16 @@ export declare const LINK_TRAVERSAL_UNWIRED_MESSAGE: string;
3130
4138
  */
3131
4139
  export declare class LinkTraversalRetriever implements IMemoryRetriever {
3132
4140
  private readonly _index;
4141
+ private readonly _resolver;
3133
4142
  private constructor();
3134
4143
  /** Family-convention factory. */
3135
- static create(index: IMemoryIndex): Result<LinkTraversalRetriever>;
4144
+ static create(params: IRetrieverCreateParams): Result<LinkTraversalRetriever>;
3136
4145
  /** {@inheritDoc IMemoryRetriever.capabilities} */
3137
4146
  get capabilities(): IMemoryRetrieverCapabilities;
3138
4147
  /** {@inheritDoc IMemoryRetriever.retrieve} */
3139
4148
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
3140
4149
  /** Run the bounded, cycle-safe BFS and post-filter the reached records. */
3141
4150
  private _traverse;
3142
- /**
3143
- * Group the index's entries by their scope-qualified {@link edgeTargetKey}
3144
- * `(scope, id)` composite. Each composite is the index's primary key, so it maps
3145
- * to exactly one entry — two records that reuse a filename stem across scopes
3146
- * (e.g. `turn-0` in two conversations) get distinct keys and never collide.
3147
- */
3148
- private _indexByKey;
3149
4151
  /** Outbound neighbors: the scope-qualified targets of every edge on the record at `node`. */
3150
4152
  private _outbound;
3151
4153
  /** Inbound neighbors: the scope-qualified sources whose edges point AT `node` (the backlinks). */
@@ -3185,6 +4187,45 @@ export declare class LtmIdentityCodec implements IIdentityCodec {
3185
4187
  verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
3186
4188
  }
3187
4189
 
4190
+ /**
4191
+ * Materialize entries through the resolver, dropping any that have vanished
4192
+ * since selection — a concurrent delete between selecting an envelope and
4193
+ * reading its body is a legitimate race and yields a shorter list, not an error.
4194
+ * A read that FAILS is a real fault and propagates.
4195
+ * @public
4196
+ */
4197
+ export declare function materializeEntries(entries: ReadonlyArray<IIndexedMemoryEntry>, resolver: IMemoryRecordResolver): Result<ReadonlyArray<IMemoryRecord<unknown>>>;
4198
+
4199
+ /**
4200
+ * Materialize a selected, ordered page — **applying `query.filter` and paging in
4201
+ * the right order**, which is the whole reason this is shared rather than
4202
+ * open-coded per retriever.
4203
+ *
4204
+ * @remarks
4205
+ * Two paths, and the choice is forced by where the predicate can run:
4206
+ *
4207
+ * - **No `filter`** — order and page over *envelopes*, then read only the page.
4208
+ * `limit` bounds the READ, not just the result.
4209
+ * - **With `filter`** — the predicate takes a whole record, so every
4210
+ * envelope-survivor must be read first, then filtered, then paged. Paging
4211
+ * before filtering would return fewer than `limit` rows for no reason a caller
4212
+ * could see.
4213
+ *
4214
+ * **Every retriever must route through this.** `indexedRecordMatchesQuery`
4215
+ * structurally *cannot* apply `filter` — it is handed an envelope — so a
4216
+ * retriever that pre-filters with it and then materializes on its own silently
4217
+ * ignores the predicate. That regression shipped once, in the stream that moved
4218
+ * `filter` out of the pre-filter; this function exists so it cannot recur.
4219
+ *
4220
+ * @param selected - Entries surviving the envelope pre-filter.
4221
+ * @param query - The query whose `filter` / `orderBy` / `limit` / `offset` apply.
4222
+ * @param resolver - Body resolver.
4223
+ * @param order - Applied to whichever collection is paged; identity is legal for
4224
+ * a retriever whose ordering is intrinsic (semantic score, traversal order).
4225
+ * @public
4226
+ */
4227
+ export declare function materializePage<T extends IIndexedMemoryEntry>(selected: ReadonlyArray<T>, query: IMemoryQuery, resolver: IMemoryRecordResolver, order?: (candidates: ReadonlyArray<T>) => ReadonlyArray<T>): Result<ReadonlyArray<IMemoryRecord<unknown>>>;
4228
+
3188
4229
  /**
3189
4230
  * Bounded-ring write policy for the experience (memory) kind families.
3190
4231
  * Admission accepts until `maxRecords` is reached, then evicts the oldest
@@ -3344,7 +4385,10 @@ export declare type MemoryId = Brand<string, 'MemoryId'>;
3344
4385
  * @public
3345
4386
  */
3346
4387
  export declare class MemoryIndex implements IMemoryIndex {
3347
- /** Primary store: `(scope, id)` composite key → indexed entry. */
4388
+ /**
4389
+ * Primary store: `(scope, id)` composite key → indexed entry. Holds the
4390
+ * PROJECTED form, so the index never retains a body.
4391
+ */
3348
4392
  private readonly _byKey;
3349
4393
  /** kind → set of composite keys. */
3350
4394
  private readonly _byKind;
@@ -3371,19 +4415,21 @@ export declare class MemoryIndex implements IMemoryIndex {
3371
4415
  */
3372
4416
  private static _keyOf;
3373
4417
  /** {@inheritDoc IMemoryIndex.rebuild} */
3374
- rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;
4418
+ rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number>;
3375
4419
  /** {@inheritDoc IMemoryIndex.patch} */
3376
4420
  patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;
3377
4421
  /** {@inheritDoc IMemoryIndex.entries} */
3378
- entries(): ReadonlyArray<IIndexedMemoryRecord>;
4422
+ entries(): ReadonlyArray<IIndexedMemoryEntry>;
4423
+ /** {@inheritDoc IMemoryIndex.get} */
4424
+ get(target: IEdgeTarget): IIndexedMemoryEntry | undefined;
3379
4425
  /** {@inheritDoc IMemoryIndex.byKind} */
3380
- byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
4426
+ byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry>;
3381
4427
  /** {@inheritDoc IMemoryIndex.byTag} */
3382
- byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
4428
+ byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry>;
3383
4429
  /** {@inheritDoc IMemoryIndex.byRecency} */
3384
- byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
4430
+ byRecency(): ReadonlyArray<IIndexedMemoryEntry>;
3385
4431
  /** {@inheritDoc IMemoryIndex.byRank} */
3386
- byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
4432
+ byRank(): ReadonlyArray<IIndexedMemoryEntry>;
3387
4433
  /** {@inheritDoc IMemoryIndex.backlinks} */
3388
4434
  backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
3389
4435
  /**
@@ -3401,6 +4447,8 @@ export declare class MemoryIndex implements IMemoryIndex {
3401
4447
  * approach; the sort is over the in-memory index, never a filesystem walk.
3402
4448
  */
3403
4449
  private _rankOrdered;
4450
+ /** Resolve composite keys to their entries, skipping any that are absent. */
4451
+ private static _resolve;
3404
4452
  /**
3405
4453
  * Rank-descending comparator with an absent-`rank`-last rule and a recency
3406
4454
  * (`updated`, then `seq`) tiebreak. Duplicated from the retrieve packlet's
@@ -3603,6 +4651,13 @@ export declare class MemoryIngestOrchestrator implements IMemoryIngestOrchestrat
3603
4651
  private static _asStringBody;
3604
4652
  }
3605
4653
 
4654
+ /**
4655
+ * What {@link IMemoryStore.list} accepts: a narrowing filter, or the explicit
4656
+ * whole-vault scan.
4657
+ * @public
4658
+ */
4659
+ export declare type MemoryListSelection = IMemoryStoreListFilter | IWholeVaultScan;
4660
+
3606
4661
  /**
3607
4662
  * The outcome of the observed operation.
3608
4663
  * @public
@@ -3812,7 +4867,7 @@ export declare const NON_SEMANTIC_CAPABILITIES: IMemoryRetrieverCapabilities;
3812
4867
  * default, byte-identical to the pre-`orderBy` behavior).
3813
4868
  * @public
3814
4869
  */
3815
- export declare function orderingCompare(orderBy?: IMemoryQuery['orderBy']): (a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>) => number;
4870
+ export declare function orderingCompare(orderBy?: IMemoryQuery['orderBy']): (a: IEnvelopeCarrier, b: IEnvelopeCarrier) => number;
3816
4871
 
3817
4872
  /**
3818
4873
  * Parse a complete memory file into a typed {@link IMemoryRecord}. Splits the
@@ -3852,7 +4907,7 @@ export declare type QueryEmbedder = (text: string) => Promise<Result<Float32Arra
3852
4907
  * index's rank-view ordering.
3853
4908
  * @public
3854
4909
  */
3855
- export declare function rankCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number;
4910
+ export declare function rankCompare(a: IEnvelopeCarrier, b: IEnvelopeCarrier): number;
3856
4911
 
3857
4912
  /**
3858
4913
  * A per-kind host projection from a fully-resolved (post-merge) memory record
@@ -3864,7 +4919,7 @@ export declare function rankCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<
3864
4919
  * for this record" (logged at `warn`), never failing the write.
3865
4920
  *
3866
4921
  * Runs on writes only. To apply a newly-registered projector to records that
3867
- * already exist, call `IMemoryStore.reconcileRank`.
4922
+ * already exist, call `IMemoryStore.reconcile(kind, 'rank')`.
3868
4923
  * @public
3869
4924
  */
3870
4925
  export declare type RankProjector = (record: IMemoryRecord<unknown>) => number;
@@ -3874,7 +4929,7 @@ export declare type RankProjector = (record: IMemoryRecord<unknown>) => number;
3874
4929
  * equal-`updated` records sort deterministically. Mirrors the B1 index ordering.
3875
4930
  * @public
3876
4931
  */
3877
- export declare function recencyCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number;
4932
+ export declare function recencyCompare(a: IEnvelopeCarrier, b: IEnvelopeCarrier): number;
3878
4933
 
3879
4934
  /**
3880
4935
  * Returns records matching the query's scope / kind / tag / provenance-source / predicate filters,
@@ -3884,15 +4939,22 @@ export declare function recencyCompare(a: IMemoryRecord<unknown>, b: IMemoryReco
3884
4939
  */
3885
4940
  export declare class RecencyRetriever implements IMemoryRetriever {
3886
4941
  private readonly _index;
4942
+ private readonly _resolver;
3887
4943
  private constructor();
3888
4944
  /** {@inheritDoc IMemoryRetriever.capabilities} */
3889
4945
  get capabilities(): IMemoryRetrieverCapabilities;
3890
4946
  /** Family-convention factory. */
3891
- static create(index: IMemoryIndex): Result<RecencyRetriever>;
4947
+ static create(params: IRetrieverCreateParams): Result<RecencyRetriever>;
3892
4948
  /** {@inheritDoc IMemoryRetriever.retrieve} */
3893
4949
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
3894
4950
  }
3895
4951
 
4952
+ /**
4953
+ * What a {@link IMemoryStore.reconcile} established, discriminated by artifact.
4954
+ * @public
4955
+ */
4956
+ export declare type ReconcileReport = IRankReconcileReport | IVectorReconcileReport | IFragmentReconcileReport;
4957
+
3896
4958
  /**
3897
4959
  * The four dedup verdicts a {@link IEntityResolver} (or fgv's exact-match layer)
3898
4960
  * returns for a candidate. See the design note §3 for the verdict → write
@@ -3914,6 +4976,53 @@ export declare type ResolutionVerdict = {
3914
4976
  readonly target: IEdgeTarget;
3915
4977
  };
3916
4978
 
4979
+ /**
4980
+ * The shared select → order → page → materialize pipeline every non-semantic
4981
+ * retriever runs, and the one place the body-vs-envelope ordering decision lives.
4982
+ *
4983
+ * @public
4984
+ * @remarks
4985
+ * **Without `query.filter`, ordering and paging happen over envelopes and only
4986
+ * the page is materialized** — so `limit` genuinely bounds the number of records
4987
+ * read, not merely the number returned. That is what makes `limit` a legitimate
4988
+ * narrowing axis rather than a loophole, and it is conditional on the ordering
4989
+ * key being an envelope field: both shipped comparators (`recencyCompare`,
4990
+ * `rankCompare`) read `updated` / `seq` / `rank` and qualify. **An ordering that
4991
+ * keyed on a body field could not use this path** and would have to sort after
4992
+ * materialization, at which point `limit` bounds the result and not the read.
4993
+ *
4994
+ * **With `query.filter`, every envelope-survivor must be materialized first**,
4995
+ * because the predicate takes a whole record. Semantics are preserved exactly;
4996
+ * the cost is not. Pair `filter` with an envelope axis when the read cost
4997
+ * matters.
4998
+ */
4999
+ export declare function resolveQuery(entries: ReadonlyArray<IIndexedMemoryEntry>, query: IMemoryQuery, resolver: IMemoryRecordResolver): Result<ReadonlyArray<IMemoryRecord<unknown>>>;
5000
+
5001
+ /**
5002
+ * Ask {@link IMemoryStore.list} for **every record in the vault**, bodies
5003
+ * included.
5004
+ *
5005
+ * @remarks
5006
+ * `list` requires a selection and rejects one that narrows nothing, so this is
5007
+ * the only way to get the whole vault — and that is the point. Since the index
5008
+ * holds envelopes only, `list` materializes every survivor from storage, so an
5009
+ * unnarrowed call reads one file per record. Making it impossible to write by
5010
+ * accident is worth more than making it fast.
5011
+ *
5012
+ * It is named for what it costs rather than for what it returns, and it is
5013
+ * greppable: `scanEveryRecord` enumerates every whole-vault read in a codebase in
5014
+ * one search. This mirrors `@fgv/ts-extras`' `safer-fetch`, where `addressGuard`
5015
+ * is required with no default and `allowAnyAddress()` is the named opt-out.
5016
+ *
5017
+ * **If you only need to select, you do not need this.** Use
5018
+ * {@link IMemoryStore.listEntries}, which returns every entry's scope and
5019
+ * envelope, reads no files, and needs no selection.
5020
+ * @public
5021
+ */
5022
+ export declare function scanEveryRecord(options?: {
5023
+ readonly asOf?: number;
5024
+ }): IWholeVaultScan;
5025
+
3917
5026
  /**
3918
5027
  * The reference {@link IMergeStrategy}: a score-union. Every record is scored by
3919
5028
  * the number of composed result sets it appears in (deduplicated by
@@ -3940,7 +5049,7 @@ export declare class ScoreUnionMergeStrategy implements IMergeStrategy {
3940
5049
  * unlimited).
3941
5050
  * @public
3942
5051
  */
3943
- export declare function selectByQuery(entries: ReadonlyArray<IIndexedMemoryRecord>, query: IMemoryQuery): IMemoryRecord<unknown>[];
5052
+ export declare function selectByQuery(entries: ReadonlyArray<IIndexedMemoryEntry>, query: IMemoryQuery): IIndexedMemoryEntry[];
3944
5053
 
3945
5054
  /**
3946
5055
  * Select the current version from a set of an entity's versions: the newest
@@ -3948,7 +5057,7 @@ export declare function selectByQuery(entries: ReadonlyArray<IIndexedMemoryRecor
3948
5057
  * entity has no current version (fully invalidated / soft-deleted, or empty).
3949
5058
  * @public
3950
5059
  */
3951
- export declare function selectCurrentVersion(versions: ReadonlyArray<IMemoryRecord<unknown>>): IMemoryRecord<unknown> | undefined;
5060
+ export declare function selectCurrentVersion<T extends IEnvelopeCarrier>(versions: ReadonlyArray<T>): T | undefined;
3952
5061
 
3953
5062
  /**
3954
5063
  * Select the version of an entity valid at `asOf` (epoch ms): the newest
@@ -3956,7 +5065,7 @@ export declare function selectCurrentVersion(versions: ReadonlyArray<IMemoryReco
3956
5065
  * when no version was valid at that instant.
3957
5066
  * @public
3958
5067
  */
3959
- export declare function selectVersionAsOf(versions: ReadonlyArray<IMemoryRecord<unknown>>, asOf: number): IMemoryRecord<unknown> | undefined;
5068
+ export declare function selectVersionAsOf<T extends IEnvelopeCarrier>(versions: ReadonlyArray<T>, asOf: number): T | undefined;
3960
5069
 
3961
5070
  /**
3962
5071
  * The loud-degradation message a retriever returns when `query.semantic` is set
@@ -3979,6 +5088,7 @@ export declare const SEMANTIC_UNWIRED_MESSAGE: string;
3979
5088
  */
3980
5089
  export declare class SemanticRetriever implements IMemoryRetriever {
3981
5090
  private readonly _index;
5091
+ private readonly _resolver;
3982
5092
  private readonly _backend;
3983
5093
  private constructor();
3984
5094
  /** {@inheritDoc IMemoryRetriever.capabilities} */
@@ -4050,11 +5160,12 @@ export declare type StoreStampedEnvelopeField = 'id' | 'seq' | 'contentHash' | '
4050
5160
  */
4051
5161
  export declare class StructuredFilterRetriever implements IMemoryRetriever {
4052
5162
  private readonly _index;
5163
+ private readonly _resolver;
4053
5164
  private constructor();
4054
5165
  /** {@inheritDoc IMemoryRetriever.capabilities} */
4055
5166
  get capabilities(): IMemoryRetrieverCapabilities;
4056
5167
  /** Family-convention factory. */
4057
- static create(index: IMemoryIndex): Result<StructuredFilterRetriever>;
5168
+ static create(params: IRetrieverCreateParams): Result<StructuredFilterRetriever>;
4058
5169
  /** {@inheritDoc IMemoryRetriever.retrieve} */
4059
5170
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
4060
5171
  }
@@ -4074,11 +5185,12 @@ export declare type Tag = Brand<string, 'Tag'>;
4074
5185
  */
4075
5186
  export declare class TagRetriever implements IMemoryRetriever {
4076
5187
  private readonly _index;
5188
+ private readonly _resolver;
4077
5189
  private constructor();
4078
5190
  /** {@inheritDoc IMemoryRetriever.capabilities} */
4079
5191
  get capabilities(): IMemoryRetrieverCapabilities;
4080
5192
  /** Family-convention factory. */
4081
- static create(index: IMemoryIndex): Result<TagRetriever>;
5193
+ static create(params: IRetrieverCreateParams): Result<TagRetriever>;
4082
5194
  /** {@inheritDoc IMemoryRetriever.retrieve} */
4083
5195
  retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
4084
5196
  }