@fgv/ts-agent-memory 5.1.0-39 → 5.1.0-41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/.rush/temp/{b82cf6bdece20481260e6bab946179eeec9d7b46.tar.log → cbbdbe09515171b4eba8f2592be2dace1e4e8142.tar.log} +14 -2
  2. package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +2 -2
  3. package/.rush/temp/operation/build/all.log +2 -2
  4. package/.rush/temp/operation/build/log-chunks.jsonl +2 -2
  5. package/.rush/temp/operation/build/state.json +1 -1
  6. package/dist/packlets/converters/envelopeConverter.js +17 -3
  7. package/dist/packlets/converters/envelopeConverter.js.map +1 -1
  8. package/dist/packlets/index/memoryIndex.js +58 -10
  9. package/dist/packlets/index/memoryIndex.js.map +1 -1
  10. package/dist/packlets/ingest/cycleGuard.js +13 -6
  11. package/dist/packlets/ingest/cycleGuard.js.map +1 -1
  12. package/dist/packlets/ingest/hostStages.js.map +1 -1
  13. package/dist/packlets/ingest/model.js.map +1 -1
  14. package/dist/packlets/ingest/orchestrator.js +94 -49
  15. package/dist/packlets/ingest/orchestrator.js.map +1 -1
  16. package/dist/packlets/retrieve/hybridRetriever.js +13 -2
  17. package/dist/packlets/retrieve/hybridRetriever.js.map +1 -1
  18. package/dist/packlets/retrieve/linkTraversalRetriever.js +46 -57
  19. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  20. package/dist/packlets/retrieve/recencyRetriever.js +3 -3
  21. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
  22. package/dist/packlets/retrieve/retriever.js +50 -7
  23. package/dist/packlets/retrieve/retriever.js.map +1 -1
  24. package/dist/packlets/retrieve/semanticRetriever.js +9 -3
  25. package/dist/packlets/retrieve/semanticRetriever.js.map +1 -1
  26. package/dist/packlets/retrieve/structuredFilterRetriever.js +3 -3
  27. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  28. package/dist/packlets/retrieve/tagRetriever.js +3 -3
  29. package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
  30. package/dist/packlets/retrieve/temporalRetrievers.js +3 -3
  31. package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
  32. package/dist/packlets/store/fileTreeMemoryStore.js +72 -16
  33. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  34. package/dist/packlets/tools/memoryTools.js +104 -21
  35. package/dist/packlets/tools/memoryTools.js.map +1 -1
  36. package/dist/packlets/types/envelope.js +13 -1
  37. package/dist/packlets/types/envelope.js.map +1 -1
  38. package/dist/packlets/vector/inMemoryCosineIndex.js +22 -17
  39. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  40. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  41. package/dist/test/unit/converters/antagonistRoundTrip.test.js +3 -3
  42. package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +1 -1
  43. package/dist/test/unit/converters/envelopeConverter.test.js +125 -8
  44. package/dist/test/unit/converters/envelopeConverter.test.js.map +1 -1
  45. package/dist/test/unit/index/memoryIndex.test.js +87 -25
  46. package/dist/test/unit/index/memoryIndex.test.js.map +1 -1
  47. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +20 -16
  48. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -1
  49. package/dist/test/unit/ingest/cycleGuard.test.js +28 -1
  50. package/dist/test/unit/ingest/cycleGuard.test.js.map +1 -1
  51. package/dist/test/unit/ingest/orchestrator.test.js +187 -45
  52. package/dist/test/unit/ingest/orchestrator.test.js.map +1 -1
  53. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +106 -31
  54. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -1
  55. package/dist/test/unit/retrieve/retrievers.test.js +299 -37
  56. package/dist/test/unit/retrieve/retrievers.test.js.map +1 -1
  57. package/dist/test/unit/store/embedOnWrite.test.js +69 -12
  58. package/dist/test/unit/store/embedOnWrite.test.js.map +1 -1
  59. package/dist/test/unit/store/listScoped.test.js +109 -0
  60. package/dist/test/unit/store/listScoped.test.js.map +1 -0
  61. package/dist/test/unit/store/rankAxis.test.js +254 -0
  62. package/dist/test/unit/store/rankAxis.test.js.map +1 -0
  63. package/dist/test/unit/tools/memoryTools.test.js +280 -11
  64. package/dist/test/unit/tools/memoryTools.test.js.map +1 -1
  65. package/dist/test/unit/types/writePolicy.test.js +9 -2
  66. package/dist/test/unit/types/writePolicy.test.js.map +1 -1
  67. package/dist/test/unit/vector/inMemoryCosineIndex.test.js +95 -35
  68. package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -1
  69. package/dist/test/unit/vector/vectorIndex.test.js +24 -15
  70. package/dist/test/unit/vector/vectorIndex.test.js.map +1 -1
  71. package/dist/ts-agent-memory.d.ts +384 -97
  72. package/etc/ts-agent-memory.api.md +64 -22
  73. package/lib/packlets/converters/envelopeConverter.d.ts +8 -1
  74. package/lib/packlets/converters/envelopeConverter.d.ts.map +1 -1
  75. package/lib/packlets/converters/envelopeConverter.js +18 -4
  76. package/lib/packlets/converters/envelopeConverter.js.map +1 -1
  77. package/lib/packlets/index/memoryIndex.d.ts +42 -10
  78. package/lib/packlets/index/memoryIndex.d.ts.map +1 -1
  79. package/lib/packlets/index/memoryIndex.js +58 -10
  80. package/lib/packlets/index/memoryIndex.js.map +1 -1
  81. package/lib/packlets/ingest/cycleGuard.d.ts +5 -5
  82. package/lib/packlets/ingest/cycleGuard.d.ts.map +1 -1
  83. package/lib/packlets/ingest/cycleGuard.js +13 -6
  84. package/lib/packlets/ingest/cycleGuard.js.map +1 -1
  85. package/lib/packlets/ingest/hostStages.d.ts +3 -3
  86. package/lib/packlets/ingest/hostStages.d.ts.map +1 -1
  87. package/lib/packlets/ingest/hostStages.js.map +1 -1
  88. package/lib/packlets/ingest/model.d.ts +25 -14
  89. package/lib/packlets/ingest/model.d.ts.map +1 -1
  90. package/lib/packlets/ingest/model.js.map +1 -1
  91. package/lib/packlets/ingest/orchestrator.d.ts +18 -4
  92. package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
  93. package/lib/packlets/ingest/orchestrator.js +93 -48
  94. package/lib/packlets/ingest/orchestrator.js.map +1 -1
  95. package/lib/packlets/retrieve/hybridRetriever.d.ts.map +1 -1
  96. package/lib/packlets/retrieve/hybridRetriever.js +12 -1
  97. package/lib/packlets/retrieve/hybridRetriever.js.map +1 -1
  98. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +18 -23
  99. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -1
  100. package/lib/packlets/retrieve/linkTraversalRetriever.js +45 -56
  101. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  102. package/lib/packlets/retrieve/recencyRetriever.js +2 -2
  103. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
  104. package/lib/packlets/retrieve/retriever.d.ts +70 -11
  105. package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
  106. package/lib/packlets/retrieve/retriever.js +52 -7
  107. package/lib/packlets/retrieve/retriever.js.map +1 -1
  108. package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -1
  109. package/lib/packlets/retrieve/semanticRetriever.js +9 -3
  110. package/lib/packlets/retrieve/semanticRetriever.js.map +1 -1
  111. package/lib/packlets/retrieve/structuredFilterRetriever.js +2 -2
  112. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  113. package/lib/packlets/retrieve/tagRetriever.js +2 -2
  114. package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
  115. package/lib/packlets/retrieve/temporalRetrievers.js +3 -3
  116. package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
  117. package/lib/packlets/store/fileTreeMemoryStore.d.ts +57 -3
  118. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  119. package/lib/packlets/store/fileTreeMemoryStore.js +72 -16
  120. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  121. package/lib/packlets/tools/memoryTools.d.ts +24 -0
  122. package/lib/packlets/tools/memoryTools.d.ts.map +1 -1
  123. package/lib/packlets/tools/memoryTools.js +104 -21
  124. package/lib/packlets/tools/memoryTools.js.map +1 -1
  125. package/lib/packlets/types/envelope.d.ts +61 -8
  126. package/lib/packlets/types/envelope.d.ts.map +1 -1
  127. package/lib/packlets/types/envelope.js +14 -0
  128. package/lib/packlets/types/envelope.js.map +1 -1
  129. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +9 -5
  130. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
  131. package/lib/packlets/vector/inMemoryCosineIndex.js +22 -17
  132. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  133. package/lib/packlets/vector/vectorIndex.d.ts +46 -20
  134. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  135. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  136. package/lib/test/unit/converters/antagonistRoundTrip.test.js +3 -3
  137. package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +1 -1
  138. package/lib/test/unit/converters/envelopeConverter.test.js +124 -7
  139. package/lib/test/unit/converters/envelopeConverter.test.js.map +1 -1
  140. package/lib/test/unit/index/memoryIndex.test.js +86 -24
  141. package/lib/test/unit/index/memoryIndex.test.js.map +1 -1
  142. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +20 -16
  143. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -1
  144. package/lib/test/unit/ingest/cycleGuard.test.js +28 -1
  145. package/lib/test/unit/ingest/cycleGuard.test.js.map +1 -1
  146. package/lib/test/unit/ingest/orchestrator.test.js +186 -44
  147. package/lib/test/unit/ingest/orchestrator.test.js.map +1 -1
  148. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +106 -31
  149. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -1
  150. package/lib/test/unit/retrieve/retrievers.test.js +298 -36
  151. package/lib/test/unit/retrieve/retrievers.test.js.map +1 -1
  152. package/lib/test/unit/store/embedOnWrite.test.js +68 -11
  153. package/lib/test/unit/store/embedOnWrite.test.js.map +1 -1
  154. package/lib/test/unit/store/listScoped.test.d.ts +2 -0
  155. package/lib/test/unit/store/listScoped.test.d.ts.map +1 -0
  156. package/lib/test/unit/store/listScoped.test.js +111 -0
  157. package/lib/test/unit/store/listScoped.test.js.map +1 -0
  158. package/lib/test/unit/store/rankAxis.test.d.ts +2 -0
  159. package/lib/test/unit/store/rankAxis.test.d.ts.map +1 -0
  160. package/lib/test/unit/store/rankAxis.test.js +256 -0
  161. package/lib/test/unit/store/rankAxis.test.js.map +1 -0
  162. package/lib/test/unit/tools/memoryTools.test.js +280 -11
  163. package/lib/test/unit/tools/memoryTools.test.js.map +1 -1
  164. package/lib/test/unit/types/writePolicy.test.js +9 -2
  165. package/lib/test/unit/types/writePolicy.test.js.map +1 -1
  166. package/lib/test/unit/vector/inMemoryCosineIndex.test.js +95 -35
  167. package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -1
  168. package/lib/test/unit/vector/vectorIndex.test.js +24 -15
  169. package/lib/test/unit/vector/vectorIndex.test.js.map +1 -1
  170. package/package.json +7 -7
  171. package/rush-logs/ts-agent-memory.build.cache.log +1 -1
  172. package/rush-logs/ts-agent-memory.build.log +2 -2
  173. package/src/packlets/converters/envelopeConverter.ts +27 -4
  174. package/src/packlets/index/memoryIndex.ts +86 -22
  175. package/src/packlets/ingest/cycleGuard.ts +22 -11
  176. package/src/packlets/ingest/hostStages.ts +3 -3
  177. package/src/packlets/ingest/model.ts +25 -14
  178. package/src/packlets/ingest/orchestrator.ts +143 -67
  179. package/src/packlets/retrieve/hybridRetriever.ts +14 -1
  180. package/src/packlets/retrieve/linkTraversalRetriever.ts +51 -62
  181. package/src/packlets/retrieve/recencyRetriever.ts +3 -3
  182. package/src/packlets/retrieve/retriever.ts +97 -13
  183. package/src/packlets/retrieve/semanticRetriever.ts +10 -5
  184. package/src/packlets/retrieve/structuredFilterRetriever.ts +3 -3
  185. package/src/packlets/retrieve/tagRetriever.ts +3 -3
  186. package/src/packlets/retrieve/temporalRetrievers.ts +3 -3
  187. package/src/packlets/store/fileTreeMemoryStore.ts +117 -12
  188. package/src/packlets/tools/memoryTools.ts +152 -25
  189. package/src/packlets/types/envelope.ts +66 -8
  190. package/src/packlets/vector/inMemoryCosineIndex.ts +45 -22
  191. package/src/packlets/vector/vectorIndex.ts +47 -20
  192. package/src/test/unit/converters/antagonistRoundTrip.test.ts +3 -3
  193. package/src/test/unit/converters/envelopeConverter.test.ts +168 -11
  194. package/src/test/unit/index/memoryIndex.test.ts +99 -14
  195. package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +23 -18
  196. package/src/test/unit/ingest/cycleGuard.test.ts +44 -2
  197. package/src/test/unit/ingest/orchestrator.test.ts +234 -41
  198. package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +134 -35
  199. package/src/test/unit/retrieve/retrievers.test.ts +381 -25
  200. package/src/test/unit/store/embedOnWrite.test.ts +83 -11
  201. package/src/test/unit/store/listScoped.test.ts +138 -0
  202. package/src/test/unit/store/rankAxis.test.ts +349 -0
  203. package/src/test/unit/tools/memoryTools.test.ts +362 -13
  204. package/src/test/unit/types/writePolicy.test.ts +11 -2
  205. package/src/test/unit/vector/inMemoryCosineIndex.test.ts +115 -39
  206. package/src/test/unit/vector/vectorIndex.test.ts +33 -17
  207. package/temp/build/lint/_eslint-5eVG3S6w.json +41 -33
  208. package/temp/build/typescript/ts_8nwakTlr.json +1 -1
  209. package/temp/ts-agent-memory.api.json +1080 -136
  210. package/temp/ts-agent-memory.api.md +64 -22
@@ -96,6 +96,12 @@ export function defaultMemoryScopeEncoding(scope: MemoryScopeKey): Result<string
96
96
  // @public
97
97
  export const edgeConverter: Converter<IEdge>;
98
98
 
99
+ // @public
100
+ export const edgeTargetConverter: Converter<IEdgeTarget>;
101
+
102
+ // @public
103
+ export function edgeTargetKey(target: IEdgeTarget): string;
104
+
99
105
  // @public
100
106
  export type EntityId = Brand<string, 'EntityId'>;
101
107
 
@@ -107,11 +113,13 @@ export const envelopeYamlConverter: Converter<IMemoryEnvelope>;
107
113
 
108
114
  // @public
109
115
  export class FileTreeMemoryStore implements IMemoryStore {
116
+ asRecordSource(): IMemoryRecordSource;
110
117
  static create(params: IFileTreeMemoryStoreCreateParams): Result<FileTreeMemoryStore>;
111
118
  delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;
112
119
  get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
113
120
  getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
114
121
  list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
122
+ listScoped(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
115
123
  put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
116
124
  }
117
125
 
@@ -147,7 +155,7 @@ export interface IBodyConverterRegistry {
147
155
  // @public
148
156
  export interface ICandidateEdge {
149
157
  readonly edge: IEdge;
150
- readonly source: MemoryId;
158
+ readonly source: IEdgeTarget;
151
159
  }
152
160
 
153
161
  // @public
@@ -162,6 +170,7 @@ export interface ICreateMemoryToolsParams {
162
170
  readonly defaultCodec?: IIdentityCodec;
163
171
  readonly handleFor?: (record: IMemoryRecord<unknown>) => string;
164
172
  readonly kinds?: ReadonlyArray<Kind>;
173
+ readonly projectItem?: (record: IMemoryRecord<unknown>, detail: MemoryDetailTier) => IMemoryToolResultItem;
165
174
  readonly registry: IBodyConverterRegistry;
166
175
  readonly retriever: IMemoryRetriever;
167
176
  readonly store: IMemoryStore;
@@ -171,9 +180,9 @@ export interface ICreateMemoryToolsParams {
171
180
  // @public
172
181
  export interface ICycleGuardEdge {
173
182
  // (undocumented)
174
- readonly source: MemoryId;
183
+ readonly source: IEdgeTarget;
175
184
  // (undocumented)
176
- readonly target: MemoryId;
185
+ readonly target: IEdgeTarget;
177
186
  // (undocumented)
178
187
  readonly type: LinkType;
179
188
  }
@@ -183,16 +192,22 @@ export interface IEdge {
183
192
  readonly confidence?: number;
184
193
  readonly invalid_at?: number | null;
185
194
  readonly provenance?: IProvenance;
186
- readonly target: MemoryId;
195
+ readonly target: IEdgeTarget;
187
196
  readonly type: LinkType;
188
197
  readonly valid_at?: number;
189
198
  }
190
199
 
191
200
  // @public
192
- export interface IEntityResolutionCandidate {
201
+ export interface IEdgeTarget {
193
202
  readonly id: MemoryId;
203
+ readonly scope: MemoryScopeKey;
204
+ }
205
+
206
+ // @public
207
+ export interface IEntityResolutionCandidate {
194
208
  readonly record: IMemoryRecord<unknown>;
195
209
  readonly score: number;
210
+ readonly target: IEdgeTarget;
196
211
  }
197
212
 
198
213
  // @public
@@ -213,6 +228,7 @@ export interface IFileTreeMemoryStoreCreateParams {
213
228
  readonly embed?: MemoryEmbedder;
214
229
  readonly logger?: Logging.ILogger;
215
230
  readonly observers?: ReadonlyArray<IMemoryObserver>;
231
+ readonly rankProjectors?: ReadonlyMap<Kind, RankProjector>;
216
232
  readonly registry: IBodyConverterRegistry;
217
233
  readonly root: FileTree.IMutableFileTreeDirectoryItem;
218
234
  readonly scopeEncoding?: (scope: MemoryScopeKey) => Result<string>;
@@ -256,7 +272,7 @@ export interface IIngestItem {
256
272
  readonly content: unknown;
257
273
  readonly id: string;
258
274
  readonly metadata?: Record<string, unknown>;
259
- readonly sourceId?: MemoryId;
275
+ readonly sourceId?: IEdgeTarget;
260
276
  }
261
277
 
262
278
  // @public
@@ -294,6 +310,7 @@ export interface IMemoryEnvelope {
294
310
  readonly kind: Kind;
295
311
  readonly links: ReadonlyArray<IEdge>;
296
312
  readonly provenance: IProvenance;
313
+ readonly rank?: number;
297
314
  readonly seq: number;
298
315
  readonly tags: ReadonlyArray<Tag>;
299
316
  readonly temporal?: ITemporalBlock;
@@ -308,8 +325,9 @@ export interface IMemoryFileParts {
308
325
 
309
326
  // @public
310
327
  export interface IMemoryIndex {
311
- backlinks(target: MemoryId): ReadonlyArray<MemoryId>;
328
+ backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
312
329
  byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
330
+ byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
313
331
  byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
314
332
  byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
315
333
  entries(): ReadonlyArray<IIndexedMemoryRecord>;
@@ -384,9 +402,12 @@ export interface IMemoryQuery {
384
402
  readonly filter?: (record: IMemoryRecord<unknown>) => boolean;
385
403
  readonly hops?: number;
386
404
  readonly kind?: Kind;
405
+ readonly kinds?: ReadonlyArray<Kind>;
387
406
  readonly limit?: number;
388
- readonly linkedFrom?: MemoryId;
389
- readonly linkedTo?: MemoryId;
407
+ readonly linkedFrom?: IEdgeTarget;
408
+ readonly linkedTo?: IEdgeTarget;
409
+ readonly offset?: number;
410
+ readonly orderBy?: 'recency' | 'rank';
390
411
  readonly scope?: MemoryScopeKey;
391
412
  readonly semantic?: string;
392
413
  readonly tag?: Tag;
@@ -401,7 +422,7 @@ export interface IMemoryRecord<TBody = unknown> {
401
422
 
402
423
  // @public
403
424
  export interface IMemoryRecordSource {
404
- list(): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
425
+ list(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
405
426
  }
406
427
 
407
428
  // @public
@@ -419,10 +440,12 @@ export interface IMemoryRetrieverCapabilities {
419
440
 
420
441
  // @public
421
442
  export interface IMemoryStore {
443
+ asRecordSource(): IMemoryRecordSource;
422
444
  delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;
423
445
  get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
424
446
  getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
425
447
  list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
448
+ listScoped(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
426
449
  put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
427
450
  }
428
451
 
@@ -464,11 +487,11 @@ export type IngestDisposition = 'written' | 'deduped' | 'merged';
464
487
 
465
488
  // @public
466
489
  export class InMemoryCosineIndex implements IVectorIndex {
467
- add(id: MemoryId, vector: Float32Array): Promise<Result<string>>;
490
+ add(target: IEdgeTarget, vector: Float32Array): Promise<Result<string>>;
468
491
  static create(): Result<InMemoryCosineIndex>;
469
492
  query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
470
493
  rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder): Promise<Result<number>>;
471
- remove(id: MemoryId): Promise<Result<MemoryId>>;
494
+ remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
472
495
  get size(): number;
473
496
  }
474
497
 
@@ -477,7 +500,7 @@ export interface IProvenance {
477
500
  readonly [key: string]: unknown;
478
501
  readonly by?: string;
479
502
  readonly confidence?: number;
480
- readonly derivedFrom?: MemoryId;
503
+ readonly derivedFrom?: IEdgeTarget;
481
504
  readonly model?: string;
482
505
  readonly source: ProvenanceSource;
483
506
  }
@@ -485,7 +508,7 @@ export interface IProvenance {
485
508
  // @public
486
509
  export interface IRelationCandidate {
487
510
  readonly candidate: ICandidateRecord;
488
- readonly id: MemoryId;
511
+ readonly id: IEdgeTarget;
489
512
  }
490
513
 
491
514
  // @public
@@ -499,6 +522,12 @@ export interface IRelationExtractor {
499
522
  relate(context: IRelationContext): Promise<Result<ReadonlyArray<ICandidateEdge>>>;
500
523
  }
501
524
 
525
+ // @public
526
+ export interface IScopedMemoryRecord {
527
+ readonly record: IMemoryRecord<unknown>;
528
+ readonly target: IEdgeTarget;
529
+ }
530
+
502
531
  // @public
503
532
  export interface ISemanticBackend {
504
533
  readonly embedQuery: QueryEmbedder;
@@ -543,15 +572,15 @@ export interface ITemporalVersionAddress {
543
572
 
544
573
  // @public
545
574
  export interface IVectorIndex {
546
- add(id: MemoryId, vector: Float32Array): Promise<Result<string>>;
575
+ add(target: IEdgeTarget, vector: Float32Array): Promise<Result<string>>;
547
576
  query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
548
- remove(id: MemoryId): Promise<Result<MemoryId>>;
577
+ remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
549
578
  }
550
579
 
551
580
  // @public
552
581
  export interface IVectorQueryHit {
553
- readonly id: MemoryId;
554
582
  readonly score: number;
583
+ readonly target: IEdgeTarget;
555
584
  }
556
585
 
557
586
  // @public
@@ -586,7 +615,7 @@ export class KnowledgeLwwPolicy implements IWritePolicy {
586
615
  }
587
616
 
588
617
  // @public
589
- export function limitRecords(records: ReadonlyArray<IMemoryRecord<unknown>>, limit?: number): ReadonlyArray<IMemoryRecord<unknown>>;
618
+ export function limitRecords(records: ReadonlyArray<IMemoryRecord<unknown>>, limit?: number, offset?: number): ReadonlyArray<IMemoryRecord<unknown>>;
590
619
 
591
620
  // @public
592
621
  export const LINK_TRAVERSAL_NO_SEED_MESSAGE: string;
@@ -621,6 +650,9 @@ export class MemoryCapCullPolicy implements IWritePolicy {
621
650
  readonly mutableFields: ReadonlyArray<string>;
622
651
  }
623
652
 
653
+ // @public
654
+ export type MemoryDetailTier = 'gist' | 'full';
655
+
624
656
  // @public
625
657
  export type MemoryEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<Float32Array>>;
626
658
 
@@ -629,8 +661,9 @@ export type MemoryId = Brand<string, 'MemoryId'>;
629
661
 
630
662
  // @public
631
663
  export class MemoryIndex implements IMemoryIndex {
632
- backlinks(target: MemoryId): ReadonlyArray<MemoryId>;
664
+ backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
633
665
  byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
666
+ byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
634
667
  byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
635
668
  byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
636
669
  static create(): Result<MemoryIndex>;
@@ -686,6 +719,9 @@ export class MtmIdentityCodec implements IIdentityCodec {
686
719
  // @public
687
720
  export const NON_SEMANTIC_CAPABILITIES: IMemoryRetrieverCapabilities;
688
721
 
722
+ // @public
723
+ export function orderingCompare(orderBy?: IMemoryQuery['orderBy']): (a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>) => number;
724
+
689
725
  // @public
690
726
  export function parseMemoryFile(raw: string, registry: IBodyConverterRegistry): Result<IMemoryRecord<unknown>>;
691
727
 
@@ -698,6 +734,12 @@ export type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {})
698
734
  // @public
699
735
  export type QueryEmbedder = (text: string) => Promise<Result<Float32Array>>;
700
736
 
737
+ // @public
738
+ export function rankCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number;
739
+
740
+ // @public
741
+ export type RankProjector = (record: IMemoryRecord<unknown>) => number;
742
+
701
743
  // @public
702
744
  export function recencyCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number;
703
745
 
@@ -713,13 +755,13 @@ export type ResolutionVerdict = {
713
755
  readonly verdict: 'new';
714
756
  } | {
715
757
  readonly verdict: 'duplicate-of';
716
- readonly target: MemoryId;
758
+ readonly target: IEdgeTarget;
717
759
  } | {
718
760
  readonly verdict: 'supersede';
719
- readonly target: MemoryId;
761
+ readonly target: IEdgeTarget;
720
762
  } | {
721
763
  readonly verdict: 'merge-into';
722
- readonly target: MemoryId;
764
+ readonly target: IEdgeTarget;
723
765
  };
724
766
 
725
767
  // @public
@@ -1,6 +1,13 @@
1
1
  import { Converter, Result } from '@fgv/ts-utils';
2
- import { IEdge, IMemoryEnvelope, IMemoryRecord, IProvenance, ITemporalBlock } from '../types';
2
+ import { IEdge, IEdgeTarget, IMemoryEnvelope, IMemoryRecord, IProvenance, ITemporalBlock } from '../types';
3
3
  import { IBodyConverterRegistry } from './bodyConverterRegistry';
4
+ /**
5
+ * Converter for a scope-qualified {@link IEdgeTarget}. Both `scope` and `id`
6
+ * are required — the whole point of the scoped target is that a bare id is
7
+ * ambiguous across scopes.
8
+ * @public
9
+ */
10
+ export declare const edgeTargetConverter: Converter<IEdgeTarget>;
4
11
  /**
5
12
  * Converter for {@link IProvenance}. Validates the known fields and preserves
6
13
  * any extension keys verbatim (the `[key: string]: unknown` opaque payload),
@@ -1 +1 @@
1
- {"version":3,"file":"envelopeConverter.d.ts","sourceRoot":"","sources":["../../../src/packlets/converters/envelopeConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAc,MAAM,EAAiB,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAW,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvG,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAqCjE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,WAAW,CAUtD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,KAAK,CAU1C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,cAAc,CAMvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,eAAe,CAgBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,CAAC,eAAe,CAAyC,CAAC;AAKvG;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAuBtE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,sBAAsB,GAC/B,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAYhC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAI3F"}
1
+ {"version":3,"file":"envelopeConverter.d.ts","sourceRoot":"","sources":["../../../src/packlets/converters/envelopeConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAc,MAAM,EAAiB,MAAM,eAAe,CAAC;AAE7E,OAAO,EAEL,KAAK,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,WAAW,EACX,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAsBjE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,WAAW,CAGrD,CAAC;AAoBH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,WAAW,CAUtD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,KAAK,CAU1C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,cAAc,CAMvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,eAAe,CAiBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,CAAC,eAAe,CAAyC,CAAC;AAKvG;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAuBtE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,sBAAsB,GAC/B,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAYhC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAI3F"}
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.envelopeYamlConverter = exports.envelopeConverter = exports.temporalConverter = exports.edgeConverter = exports.provenanceConverter = void 0;
7
+ exports.envelopeYamlConverter = exports.envelopeConverter = exports.temporalConverter = exports.edgeConverter = exports.provenanceConverter = exports.edgeTargetConverter = void 0;
8
8
  exports.splitFrontmatter = splitFrontmatter;
9
9
  exports.joinFrontmatter = joinFrontmatter;
10
10
  exports.parseMemoryFile = parseMemoryFile;
@@ -27,16 +27,29 @@ const stringOrNull = ts_utils_1.Converters.oneOf([
27
27
  ts_utils_1.Converters.string,
28
28
  nullConverter
29
29
  ]);
30
+ /**
31
+ * Converter for a scope-qualified {@link IEdgeTarget}. Both `scope` and `id`
32
+ * are required — the whole point of the scoped target is that a bare id is
33
+ * ambiguous across scopes.
34
+ * @public
35
+ */
36
+ exports.edgeTargetConverter = ts_utils_1.Converters.object({
37
+ scope: types_1.Convert.scopeKey,
38
+ id: types_1.Convert.memoryId
39
+ });
30
40
  /**
31
41
  * Converter for the known {@link IProvenance} fields. The full
32
42
  * {@link provenanceConverter} layers extension-key preservation on top.
43
+ * `derivedFrom` is serialized as the nested `{ scope, id }` object (mirroring
44
+ * {@link edgeConverter | edge}'s scope-qualified `target`) so the provenance
45
+ * back-reference is unambiguous across scopes.
33
46
  */
34
47
  const knownProvenanceConverter = ts_utils_1.Converters.object({
35
48
  source: ts_utils_1.Converters.string,
36
49
  by: ts_utils_1.Converters.string.optional(),
37
50
  model: ts_utils_1.Converters.string.optional(),
38
51
  confidence: ts_utils_1.Converters.number.optional(),
39
- derivedFrom: types_1.Convert.memoryId.optional()
52
+ derivedFrom: exports.edgeTargetConverter.optional()
40
53
  }, { optionalFields: ['by', 'model', 'confidence', 'derivedFrom'] });
41
54
  /**
42
55
  * Converter for {@link IProvenance}. Validates the known fields and preserves
@@ -58,7 +71,7 @@ exports.provenanceConverter = ts_utils_1.Converters.generic((from) => knownProve
58
71
  */
59
72
  exports.edgeConverter = ts_utils_1.Converters.object({
60
73
  type: types_1.Convert.linkType,
61
- target: types_1.Convert.memoryId,
74
+ target: exports.edgeTargetConverter,
62
75
  confidence: ts_utils_1.Converters.number.optional(),
63
76
  provenance: exports.provenanceConverter.optional(),
64
77
  valid_at: ts_utils_1.Converters.number.optional(),
@@ -87,10 +100,11 @@ exports.envelopeConverter = ts_utils_1.Converters.object({
87
100
  updated: ts_utils_1.Converters.number,
88
101
  seq: ts_utils_1.Converters.number,
89
102
  contentHash: ts_utils_1.Converters.string,
103
+ rank: ts_utils_1.Converters.number.optional(),
90
104
  provenance: exports.provenanceConverter,
91
105
  temporal: exports.temporalConverter.optional(),
92
106
  embeddingRef: stringOrNull.optional()
93
- }, { optionalFields: ['temporal', 'embeddingRef'] });
107
+ }, { optionalFields: ['rank', 'temporal', 'embeddingRef'] });
94
108
  /**
95
109
  * Converter that parses a YAML frontmatter string into an
96
110
  * {@link IMemoryEnvelope}.
@@ -1 +1 @@
1
- {"version":3,"file":"envelopeConverter.js","sourceRoot":"","sources":["../../../src/packlets/converters/envelopeConverter.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Converter, Converters, Result, fail, succeed } from '@fgv/ts-utils';\nimport { Yaml } from '@fgv/ts-extras';\nimport { Convert, IEdge, IMemoryEnvelope, IMemoryRecord, IProvenance, ITemporalBlock } from '../types';\nimport { IBodyConverterRegistry } from './bodyConverterRegistry';\n\n/** Matches exactly the JSON `null` literal. */\n// eslint-disable-next-line @rushstack/no-new-null -- the envelope nullable fields (invalid_at, embeddingRef) carry meaningful null; design-lock §2.3-2.5\nconst nullConverter: Converter<null> = Converters.generic<null>((from: unknown) =>\n from === null ? succeed(null) : fail('expected null')\n);\n\n/** A nullable epoch-ms value (`number | null`). */\n// eslint-disable-next-line @rushstack/no-new-null -- meaningful null for IEdge/ITemporalBlock.invalid_at; design-lock §2.3-2.4\nconst numberOrNull: Converter<number | null> = Converters.oneOf<number | null>([\n Converters.number,\n nullConverter\n]);\n\n/** A nullable string value (`string | null`). */\n// eslint-disable-next-line @rushstack/no-new-null -- meaningful null for IMemoryEnvelope.embeddingRef; design-lock §2.5\nconst stringOrNull: Converter<string | null> = Converters.oneOf<string | null>([\n Converters.string,\n nullConverter\n]);\n\n/**\n * Converter for the known {@link IProvenance} fields. The full\n * {@link provenanceConverter} layers extension-key preservation on top.\n */\nconst knownProvenanceConverter: Converter<IProvenance> = Converters.object<IProvenance>(\n {\n source: Converters.string,\n by: Converters.string.optional(),\n model: Converters.string.optional(),\n confidence: Converters.number.optional(),\n derivedFrom: Convert.memoryId.optional()\n },\n { optionalFields: ['by', 'model', 'confidence', 'derivedFrom'] }\n);\n\n/**\n * Converter for {@link IProvenance}. Validates the known fields and preserves\n * any extension keys verbatim (the `[key: string]: unknown` opaque payload),\n * so a round-trip never drops consumer-attached data.\n * @public\n */\nexport const provenanceConverter: Converter<IProvenance> = Converters.generic<IProvenance>(\n (from: unknown): Result<IProvenance> =>\n knownProvenanceConverter.convert(from).onSuccess((known) => {\n // `from` is guaranteed to be a non-null object here — the known-field\n // converter only succeeds on objects. Spread the original keys first,\n // then the validated/normalized known fields on top, so extension keys\n // survive while the known fields carry their converted values.\n const merged: IProvenance = { ...(from as Record<string, unknown>), ...known };\n return succeed(merged);\n })\n);\n\n/**\n * Converter for an attributed {@link IEdge}.\n * @public\n */\nexport const edgeConverter: Converter<IEdge> = Converters.object<IEdge>(\n {\n type: Convert.linkType,\n target: Convert.memoryId,\n confidence: Converters.number.optional(),\n provenance: provenanceConverter.optional(),\n valid_at: Converters.number.optional(),\n invalid_at: numberOrNull.optional()\n },\n { optionalFields: ['confidence', 'provenance', 'valid_at', 'invalid_at'] }\n);\n\n/**\n * Converter for the optional {@link ITemporalBlock}.\n * @public\n */\nexport const temporalConverter: Converter<ITemporalBlock> = Converters.object<ITemporalBlock>(\n {\n valid_at: Converters.number.optional(),\n invalid_at: numberOrNull.optional()\n },\n { optionalFields: ['valid_at', 'invalid_at'] }\n);\n\n/**\n * Converter for the invariant {@link IMemoryEnvelope}. Validates a plain\n * object (e.g. parsed YAML frontmatter) into a typed envelope.\n * @public\n */\nexport const envelopeConverter: Converter<IMemoryEnvelope> = Converters.object<IMemoryEnvelope>(\n {\n id: Convert.memoryId,\n entityId: Convert.entityId,\n kind: Convert.kind,\n tags: Converters.arrayOf(Convert.tag),\n links: Converters.arrayOf(edgeConverter),\n created: Converters.number,\n updated: Converters.number,\n seq: Converters.number,\n contentHash: Converters.string,\n provenance: provenanceConverter,\n temporal: temporalConverter.optional(),\n embeddingRef: stringOrNull.optional()\n },\n { optionalFields: ['temporal', 'embeddingRef'] }\n);\n\n/**\n * Converter that parses a YAML frontmatter string into an\n * {@link IMemoryEnvelope}.\n * @public\n */\nexport const envelopeYamlConverter: Converter<IMemoryEnvelope> = Yaml.yamlConverter(envelopeConverter);\n\n/** The frontmatter delimiter line. */\nconst FRONTMATTER_DELIMITER: string = '---';\n\n/**\n * The two parts of a memory file: the YAML frontmatter (between the `---`\n * delimiters) and the markdown body (everything after the closing delimiter).\n * @public\n */\nexport interface IMemoryFileParts {\n /** The raw YAML frontmatter (delimiters stripped). */\n readonly frontmatter: string;\n /** The raw body text following the closing delimiter. */\n readonly body: string;\n}\n\n/**\n * Split a `---\\n<yaml>\\n---\\n<body>` memory file into its frontmatter and\n * body parts. Pure string handling — no external dependency.\n * @public\n */\nexport function splitFrontmatter(raw: string): Result<IMemoryFileParts> {\n // Split on '\\n' and strip a trailing '\\r' per line so CRLF-authored files\n // parse identically to LF — otherwise the '\\r' would ride along into the\n // returned frontmatter (perturbing YAML parsing) and body (corrupting\n // round-trip fidelity).\n const lines: string[] = raw.split('\\n').map((line) => (line.endsWith('\\r') ? line.slice(0, -1) : line));\n if (lines[0].trim() !== FRONTMATTER_DELIMITER) {\n return fail(\"memory file: missing opening frontmatter delimiter '---'\");\n }\n let closeIndex: number = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === FRONTMATTER_DELIMITER) {\n closeIndex = i;\n break;\n }\n }\n if (closeIndex === -1) {\n return fail(\"memory file: missing closing frontmatter delimiter '---'\");\n }\n return succeed({\n frontmatter: lines.slice(1, closeIndex).join('\\n'),\n body: lines.slice(closeIndex + 1).join('\\n')\n });\n}\n\n/**\n * Join a YAML frontmatter string and a body into the canonical\n * `---\\n<yaml>\\n---\\n<body>` memory-file format.\n * @public\n */\nexport function joinFrontmatter(frontmatter: string, body: string): string {\n const normalized: string = frontmatter.endsWith('\\n') ? frontmatter : `${frontmatter}\\n`;\n return `${FRONTMATTER_DELIMITER}\\n${normalized}${FRONTMATTER_DELIMITER}\\n${body}`;\n}\n\n/**\n * Parse a complete memory file into a typed {@link IMemoryRecord}. Splits the\n * frontmatter, validates the envelope, and dispatches the body through the\n * registered Converter for the envelope's kind.\n * @public\n */\nexport function parseMemoryFile(\n raw: string,\n registry: IBodyConverterRegistry\n): Result<IMemoryRecord<unknown>> {\n return splitFrontmatter(raw).onSuccess((parts) =>\n envelopeYamlConverter\n .convert(parts.frontmatter)\n .withErrorFormat((msg) => `memory file: invalid envelope: ${msg}`)\n .onSuccess((envelope) =>\n registry\n .convert(envelope.kind, parts.body)\n .withErrorFormat((msg) => `memory file '${envelope.id}': invalid body: ${msg}`)\n .onSuccess((body) => succeed({ envelope, body }))\n )\n );\n}\n\n/**\n * Serialize an envelope and its rendered body text into a memory file. The\n * envelope is emitted as YAML frontmatter; the body is written verbatim after\n * the closing delimiter.\n * @public\n */\nexport function serializeMemoryFile(envelope: IMemoryEnvelope, body: string): Result<string> {\n return Yaml.yamlStringify(envelope)\n .withErrorFormat((msg) => `memory file '${envelope.id}': failed to serialize envelope: ${msg}`)\n .onSuccess((frontmatter) => succeed(joinFrontmatter(frontmatter, body)));\n}\n"]}
1
+ {"version":3,"file":"envelopeConverter.js","sourceRoot":"","sources":["../../../src/packlets/converters/envelopeConverter.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAiKH,4CAuBC;AAOD,0CAGC;AAQD,0CAeC;AAQD,kDAIC;AAnOD,4CAA6E;AAC7E,8CAAsC;AACtC,oCAQkB;AAGlB,+CAA+C;AAC/C,yJAAyJ;AACzJ,MAAM,aAAa,GAAoB,qBAAU,CAAC,OAAO,CAAO,CAAC,IAAa,EAAE,EAAE,CAChF,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAA,kBAAO,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,eAAI,EAAC,eAAe,CAAC,CACtD,CAAC;AAEF,mDAAmD;AACnD,+HAA+H;AAC/H,MAAM,YAAY,GAA6B,qBAAU,CAAC,KAAK,CAAgB;IAC7E,qBAAU,CAAC,MAAM;IACjB,aAAa;CACd,CAAC,CAAC;AAEH,iDAAiD;AACjD,wHAAwH;AACxH,MAAM,YAAY,GAA6B,qBAAU,CAAC,KAAK,CAAgB;IAC7E,qBAAU,CAAC,MAAM;IACjB,aAAa;CACd,CAAC,CAAC;AAEH;;;;;GAKG;AACU,QAAA,mBAAmB,GAA2B,qBAAU,CAAC,MAAM,CAAc;IACxF,KAAK,EAAE,eAAO,CAAC,QAAQ;IACvB,EAAE,EAAE,eAAO,CAAC,QAAQ;CACrB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,wBAAwB,GAA2B,qBAAU,CAAC,MAAM,CACxE;IACE,MAAM,EAAE,qBAAU,CAAC,MAAM;IACzB,EAAE,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IAChC,KAAK,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IACxC,WAAW,EAAE,2BAAmB,CAAC,QAAQ,EAAE;CAC5C,EACD,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,CACjE,CAAC;AAEF;;;;;GAKG;AACU,QAAA,mBAAmB,GAA2B,qBAAU,CAAC,OAAO,CAC3E,CAAC,IAAa,EAAuB,EAAE,CACrC,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;IACzD,sEAAsE;IACtE,sEAAsE;IACtE,uEAAuE;IACvE,+DAA+D;IAC/D,MAAM,MAAM,mCAAsB,IAAgC,GAAK,KAAK,CAAE,CAAC;IAC/E,OAAO,IAAA,kBAAO,EAAC,MAAM,CAAC,CAAC;AACzB,CAAC,CAAC,CACL,CAAC;AAEF;;;GAGG;AACU,QAAA,aAAa,GAAqB,qBAAU,CAAC,MAAM,CAC9D;IACE,IAAI,EAAE,eAAO,CAAC,QAAQ;IACtB,MAAM,EAAE,2BAAmB;IAC3B,UAAU,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IACxC,UAAU,EAAE,2BAAmB,CAAC,QAAQ,EAAE;IAC1C,QAAQ,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE;CACpC,EACD,EAAE,cAAc,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,CAC3E,CAAC;AAEF;;;GAGG;AACU,QAAA,iBAAiB,GAA8B,qBAAU,CAAC,MAAM,CAC3E;IACE,QAAQ,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE;CACpC,EACD,EAAE,cAAc,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,CAC/C,CAAC;AAEF;;;;GAIG;AACU,QAAA,iBAAiB,GAA+B,qBAAU,CAAC,MAAM,CAC5E;IACE,EAAE,EAAE,eAAO,CAAC,QAAQ;IACpB,QAAQ,EAAE,eAAO,CAAC,QAAQ;IAC1B,IAAI,EAAE,eAAO,CAAC,IAAI;IAClB,IAAI,EAAE,qBAAU,CAAC,OAAO,CAAC,eAAO,CAAC,GAAG,CAAC;IACrC,KAAK,EAAE,qBAAU,CAAC,OAAO,CAAC,qBAAa,CAAC;IACxC,OAAO,EAAE,qBAAU,CAAC,MAAM;IAC1B,OAAO,EAAE,qBAAU,CAAC,MAAM;IAC1B,GAAG,EAAE,qBAAU,CAAC,MAAM;IACtB,WAAW,EAAE,qBAAU,CAAC,MAAM;IAC9B,IAAI,EAAE,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,2BAAmB;IAC/B,QAAQ,EAAE,yBAAiB,CAAC,QAAQ,EAAE;IACtC,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;CACtC,EACD,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,CACzD,CAAC;AAEF;;;;GAIG;AACU,QAAA,qBAAqB,GAA+B,gBAAI,CAAC,aAAa,CAAC,yBAAiB,CAAC,CAAC;AAEvG,sCAAsC;AACtC,MAAM,qBAAqB,GAAW,KAAK,CAAC;AAc5C;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,GAAW;IAC1C,0EAA0E;IAC1E,yEAAyE;IACzE,sEAAsE;IACtE,wBAAwB;IACxB,MAAM,KAAK,GAAa,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACxG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,qBAAqB,EAAE,CAAC;QAC9C,OAAO,IAAA,eAAI,EAAC,0DAA0D,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,UAAU,GAAW,CAAC,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,qBAAqB,EAAE,CAAC;YAC9C,UAAU,GAAG,CAAC,CAAC;YACf,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,IAAA,eAAI,EAAC,0DAA0D,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,IAAA,kBAAO,EAAC;QACb,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAClD,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,WAAmB,EAAE,IAAY;IAC/D,MAAM,UAAU,GAAW,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,CAAC;IACzF,OAAO,GAAG,qBAAqB,KAAK,UAAU,GAAG,qBAAqB,KAAK,IAAI,EAAE,CAAC;AACpF,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,GAAW,EACX,QAAgC;IAEhC,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/C,6BAAqB;SAClB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;SAC1B,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,kCAAkC,GAAG,EAAE,CAAC;SACjE,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE,CACtB,QAAQ;SACL,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC;SAClC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,QAAQ,CAAC,EAAE,oBAAoB,GAAG,EAAE,CAAC;SAC9E,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,kBAAO,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CACpD,CACJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,QAAyB,EAAE,IAAY;IACzE,OAAO,gBAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;SAChC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,QAAQ,CAAC,EAAE,oCAAoC,GAAG,EAAE,CAAC;SAC9F,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAA,kBAAO,EAAC,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Converter, Converters, Result, fail, succeed } from '@fgv/ts-utils';\nimport { Yaml } from '@fgv/ts-extras';\nimport {\n Convert,\n IEdge,\n IEdgeTarget,\n IMemoryEnvelope,\n IMemoryRecord,\n IProvenance,\n ITemporalBlock\n} from '../types';\nimport { IBodyConverterRegistry } from './bodyConverterRegistry';\n\n/** Matches exactly the JSON `null` literal. */\n// eslint-disable-next-line @rushstack/no-new-null -- the envelope nullable fields (invalid_at, embeddingRef) carry meaningful null; design-lock §2.3-2.5\nconst nullConverter: Converter<null> = Converters.generic<null>((from: unknown) =>\n from === null ? succeed(null) : fail('expected null')\n);\n\n/** A nullable epoch-ms value (`number | null`). */\n// eslint-disable-next-line @rushstack/no-new-null -- meaningful null for IEdge/ITemporalBlock.invalid_at; design-lock §2.3-2.4\nconst numberOrNull: Converter<number | null> = Converters.oneOf<number | null>([\n Converters.number,\n nullConverter\n]);\n\n/** A nullable string value (`string | null`). */\n// eslint-disable-next-line @rushstack/no-new-null -- meaningful null for IMemoryEnvelope.embeddingRef; design-lock §2.5\nconst stringOrNull: Converter<string | null> = Converters.oneOf<string | null>([\n Converters.string,\n nullConverter\n]);\n\n/**\n * Converter for a scope-qualified {@link IEdgeTarget}. Both `scope` and `id`\n * are required — the whole point of the scoped target is that a bare id is\n * ambiguous across scopes.\n * @public\n */\nexport const edgeTargetConverter: Converter<IEdgeTarget> = Converters.object<IEdgeTarget>({\n scope: Convert.scopeKey,\n id: Convert.memoryId\n});\n\n/**\n * Converter for the known {@link IProvenance} fields. The full\n * {@link provenanceConverter} layers extension-key preservation on top.\n * `derivedFrom` is serialized as the nested `{ scope, id }` object (mirroring\n * {@link edgeConverter | edge}'s scope-qualified `target`) so the provenance\n * back-reference is unambiguous across scopes.\n */\nconst knownProvenanceConverter: Converter<IProvenance> = Converters.object<IProvenance>(\n {\n source: Converters.string,\n by: Converters.string.optional(),\n model: Converters.string.optional(),\n confidence: Converters.number.optional(),\n derivedFrom: edgeTargetConverter.optional()\n },\n { optionalFields: ['by', 'model', 'confidence', 'derivedFrom'] }\n);\n\n/**\n * Converter for {@link IProvenance}. Validates the known fields and preserves\n * any extension keys verbatim (the `[key: string]: unknown` opaque payload),\n * so a round-trip never drops consumer-attached data.\n * @public\n */\nexport const provenanceConverter: Converter<IProvenance> = Converters.generic<IProvenance>(\n (from: unknown): Result<IProvenance> =>\n knownProvenanceConverter.convert(from).onSuccess((known) => {\n // `from` is guaranteed to be a non-null object here — the known-field\n // converter only succeeds on objects. Spread the original keys first,\n // then the validated/normalized known fields on top, so extension keys\n // survive while the known fields carry their converted values.\n const merged: IProvenance = { ...(from as Record<string, unknown>), ...known };\n return succeed(merged);\n })\n);\n\n/**\n * Converter for an attributed {@link IEdge}.\n * @public\n */\nexport const edgeConverter: Converter<IEdge> = Converters.object<IEdge>(\n {\n type: Convert.linkType,\n target: edgeTargetConverter,\n confidence: Converters.number.optional(),\n provenance: provenanceConverter.optional(),\n valid_at: Converters.number.optional(),\n invalid_at: numberOrNull.optional()\n },\n { optionalFields: ['confidence', 'provenance', 'valid_at', 'invalid_at'] }\n);\n\n/**\n * Converter for the optional {@link ITemporalBlock}.\n * @public\n */\nexport const temporalConverter: Converter<ITemporalBlock> = Converters.object<ITemporalBlock>(\n {\n valid_at: Converters.number.optional(),\n invalid_at: numberOrNull.optional()\n },\n { optionalFields: ['valid_at', 'invalid_at'] }\n);\n\n/**\n * Converter for the invariant {@link IMemoryEnvelope}. Validates a plain\n * object (e.g. parsed YAML frontmatter) into a typed envelope.\n * @public\n */\nexport const envelopeConverter: Converter<IMemoryEnvelope> = Converters.object<IMemoryEnvelope>(\n {\n id: Convert.memoryId,\n entityId: Convert.entityId,\n kind: Convert.kind,\n tags: Converters.arrayOf(Convert.tag),\n links: Converters.arrayOf(edgeConverter),\n created: Converters.number,\n updated: Converters.number,\n seq: Converters.number,\n contentHash: Converters.string,\n rank: Converters.number.optional(),\n provenance: provenanceConverter,\n temporal: temporalConverter.optional(),\n embeddingRef: stringOrNull.optional()\n },\n { optionalFields: ['rank', 'temporal', 'embeddingRef'] }\n);\n\n/**\n * Converter that parses a YAML frontmatter string into an\n * {@link IMemoryEnvelope}.\n * @public\n */\nexport const envelopeYamlConverter: Converter<IMemoryEnvelope> = Yaml.yamlConverter(envelopeConverter);\n\n/** The frontmatter delimiter line. */\nconst FRONTMATTER_DELIMITER: string = '---';\n\n/**\n * The two parts of a memory file: the YAML frontmatter (between the `---`\n * delimiters) and the markdown body (everything after the closing delimiter).\n * @public\n */\nexport interface IMemoryFileParts {\n /** The raw YAML frontmatter (delimiters stripped). */\n readonly frontmatter: string;\n /** The raw body text following the closing delimiter. */\n readonly body: string;\n}\n\n/**\n * Split a `---\\n<yaml>\\n---\\n<body>` memory file into its frontmatter and\n * body parts. Pure string handling — no external dependency.\n * @public\n */\nexport function splitFrontmatter(raw: string): Result<IMemoryFileParts> {\n // Split on '\\n' and strip a trailing '\\r' per line so CRLF-authored files\n // parse identically to LF — otherwise the '\\r' would ride along into the\n // returned frontmatter (perturbing YAML parsing) and body (corrupting\n // round-trip fidelity).\n const lines: string[] = raw.split('\\n').map((line) => (line.endsWith('\\r') ? line.slice(0, -1) : line));\n if (lines[0].trim() !== FRONTMATTER_DELIMITER) {\n return fail(\"memory file: missing opening frontmatter delimiter '---'\");\n }\n let closeIndex: number = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === FRONTMATTER_DELIMITER) {\n closeIndex = i;\n break;\n }\n }\n if (closeIndex === -1) {\n return fail(\"memory file: missing closing frontmatter delimiter '---'\");\n }\n return succeed({\n frontmatter: lines.slice(1, closeIndex).join('\\n'),\n body: lines.slice(closeIndex + 1).join('\\n')\n });\n}\n\n/**\n * Join a YAML frontmatter string and a body into the canonical\n * `---\\n<yaml>\\n---\\n<body>` memory-file format.\n * @public\n */\nexport function joinFrontmatter(frontmatter: string, body: string): string {\n const normalized: string = frontmatter.endsWith('\\n') ? frontmatter : `${frontmatter}\\n`;\n return `${FRONTMATTER_DELIMITER}\\n${normalized}${FRONTMATTER_DELIMITER}\\n${body}`;\n}\n\n/**\n * Parse a complete memory file into a typed {@link IMemoryRecord}. Splits the\n * frontmatter, validates the envelope, and dispatches the body through the\n * registered Converter for the envelope's kind.\n * @public\n */\nexport function parseMemoryFile(\n raw: string,\n registry: IBodyConverterRegistry\n): Result<IMemoryRecord<unknown>> {\n return splitFrontmatter(raw).onSuccess((parts) =>\n envelopeYamlConverter\n .convert(parts.frontmatter)\n .withErrorFormat((msg) => `memory file: invalid envelope: ${msg}`)\n .onSuccess((envelope) =>\n registry\n .convert(envelope.kind, parts.body)\n .withErrorFormat((msg) => `memory file '${envelope.id}': invalid body: ${msg}`)\n .onSuccess((body) => succeed({ envelope, body }))\n )\n );\n}\n\n/**\n * Serialize an envelope and its rendered body text into a memory file. The\n * envelope is emitted as YAML frontmatter; the body is written verbatim after\n * the closing delimiter.\n * @public\n */\nexport function serializeMemoryFile(envelope: IMemoryEnvelope, body: string): Result<string> {\n return Yaml.yamlStringify(envelope)\n .withErrorFormat((msg) => `memory file '${envelope.id}': failed to serialize envelope: ${msg}`)\n .onSuccess((frontmatter) => succeed(joinFrontmatter(frontmatter, body)));\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { Result } from '@fgv/ts-utils';
2
- import { IMemoryRecord, Kind, MemoryId, MemoryScopeKey, Tag } from '../types';
2
+ import { IEdgeTarget, IMemoryRecord, Kind, MemoryScopeKey, Tag } from '../types';
3
3
  /**
4
4
  * The mutation a {@link IMemoryIndex.patch | patch} applies: a record was
5
5
  * written (`'put'`) or removed (`'delete'`).
@@ -55,10 +55,20 @@ export interface IMemoryIndex {
55
55
  /** All records in recency order (most-recently-updated first). */
56
56
  byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
57
57
  /**
58
- * The ids of records whose `links` point AT `target` (inbound edges).
59
- * The seed map for B2 link-traversal.
58
+ * All records ordered by store-computed {@link IMemoryEnvelope.rank} descending,
59
+ * with recency (most-recently-updated, then `seq`) as a tiebreak. Records with
60
+ * an absent `rank` sort LAST (after every ranked record), then by recency among
61
+ * themselves. Serves a bounded top-M ({@link IMemoryEnvelope.rank}-ordered) page
62
+ * from the in-memory index with no full-vault (filesystem) scan.
60
63
  */
61
- backlinks(target: MemoryId): ReadonlyArray<MemoryId>;
64
+ byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
65
+ /**
66
+ * The scope-qualified sources of records whose `links` point AT `target`
67
+ * (inbound edges), keyed on the target's `(scope, id)` address. The seed map
68
+ * for B2 link-traversal; results are {@link IEdgeTarget}s so a caller can feed
69
+ * them straight back in as further traversal seeds.
70
+ */
71
+ backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
62
72
  }
63
73
  /**
64
74
  * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /
@@ -75,10 +85,13 @@ export declare class MemoryIndex implements IMemoryIndex {
75
85
  /** tag → set of composite keys. */
76
86
  private readonly _byTag;
77
87
  /**
78
- * link target id → (source composite key → source id). Keyed by the source's
79
- * `(scope, id)` composite NOT its bare id so two distinct source records
80
- * that share an id across scopes (e.g. `turn-0` in different conversations)
81
- * are tracked independently and removing one never drops the other's edge.
88
+ * canonical target key (`edgeTargetKey`) → (source composite key → source
89
+ * {@link IEdgeTarget}). The OUTER map is keyed on the scope-qualified target's
90
+ * canonical `(scope, id)` string NOT the target's bare id — so an edge to
91
+ * `turn-3` in one conversation is tracked separately from `turn-3` in another.
92
+ * The INNER map is keyed by the source's `(scope, id)` composite so two distinct
93
+ * source records that share an id across scopes are tracked independently and
94
+ * removing one never drops the other's edge.
82
95
  */
83
96
  private readonly _backlinks;
84
97
  private constructor();
@@ -103,19 +116,38 @@ export declare class MemoryIndex implements IMemoryIndex {
103
116
  byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
104
117
  /** {@inheritDoc IMemoryIndex.byRecency} */
105
118
  byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
119
+ /** {@inheritDoc IMemoryIndex.byRank} */
120
+ byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
106
121
  /** {@inheritDoc IMemoryIndex.backlinks} */
107
- backlinks(target: MemoryId): ReadonlyArray<MemoryId>;
122
+ backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
108
123
  /**
109
124
  * Resolve a set of composite keys to their records, ordered
110
125
  * most-recently-updated first (with a `seq` tiebreak so equal-`updated`
111
126
  * records sort deterministically).
112
127
  */
113
128
  private _recencyOrdered;
129
+ /**
130
+ * Resolve a set of composite keys to their records, ordered by
131
+ * {@link IMemoryEnvelope.rank} descending with recency (`updated`, then `seq`)
132
+ * as the tiebreak. Records with an absent `rank` sort LAST, then by recency
133
+ * among themselves. Computed on call (mirrors {@link MemoryIndex._recencyOrdered}) —
134
+ * no incremental rank-ordered view is maintained, matching the recency view's
135
+ * approach; the sort is over the in-memory index, never a filesystem walk.
136
+ */
137
+ private _rankOrdered;
138
+ /**
139
+ * Rank-descending comparator with an absent-`rank`-last rule and a recency
140
+ * (`updated`, then `seq`) tiebreak. Duplicated from the retrieve packlet's
141
+ * `rankCompare` deliberately: the index must not depend on `retrieve` (that
142
+ * package depends on the index), mirroring how `_recencyOrdered` inlines the
143
+ * recency ordering rather than importing `recencyCompare`.
144
+ */
145
+ private static _compareByRank;
114
146
  /** Insert an entry and register all its derived associations. */
115
147
  private _add;
116
148
  /** Remove the entry at `key` (if present) and all its derived associations. */
117
149
  private _remove;
118
- /** Register `sourceId` (keyed by its composite `sourceKey`) as linking at `target`. */
150
+ /** Register `source` (keyed by its composite `sourceKey`) as linking at `target`. */
119
151
  private _addBacklink;
120
152
  /** Drop the backlink from `sourceKey` to `target`, removing the target map when empty. */
121
153
  private _removeBacklink;
@@ -1 +1 @@
1
- {"version":3,"file":"memoryIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/index/memoryIndex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memoryIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/index/memoryIndex.ts"],"names":[],"mappings":"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"}