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

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 (164) 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/linkTraversalRetriever.js +12 -26
  6. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  7. package/dist/packlets/retrieve/recencyRetriever.js +7 -7
  8. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
  9. package/dist/packlets/retrieve/retriever.js +91 -10
  10. package/dist/packlets/retrieve/retriever.js.map +1 -1
  11. package/dist/packlets/retrieve/semanticRetriever.js +16 -16
  12. package/dist/packlets/retrieve/semanticRetriever.js.map +1 -1
  13. package/dist/packlets/retrieve/structuredFilterRetriever.js +7 -7
  14. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  15. package/dist/packlets/retrieve/tagRetriever.js +7 -7
  16. package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
  17. package/dist/packlets/retrieve/temporalRetrievers.js +23 -20
  18. package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
  19. package/dist/packlets/store/coverage.js +6 -0
  20. package/dist/packlets/store/coverage.js.map +1 -0
  21. package/dist/packlets/store/fileTreeMemoryStore.js +221 -79
  22. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  23. package/dist/packlets/store/index.js +4 -0
  24. package/dist/packlets/store/index.js.map +1 -1
  25. package/dist/packlets/store/listSelection.js +36 -0
  26. package/dist/packlets/store/listSelection.js.map +1 -0
  27. package/dist/packlets/store/memoryStore.js +6 -0
  28. package/dist/packlets/store/memoryStore.js.map +1 -0
  29. package/dist/packlets/store/reconcile.js +6 -0
  30. package/dist/packlets/store/reconcile.js.map +1 -0
  31. package/dist/packlets/store/storeCoverage.js +102 -0
  32. package/dist/packlets/store/storeCoverage.js.map +1 -0
  33. package/dist/packlets/store/storeReconcile.js +122 -0
  34. package/dist/packlets/store/storeReconcile.js.map +1 -0
  35. package/dist/packlets/store/vectorMaintenance.js +116 -8
  36. package/dist/packlets/store/vectorMaintenance.js.map +1 -1
  37. package/dist/packlets/store/vectorRecordSource.js +44 -0
  38. package/dist/packlets/store/vectorRecordSource.js.map +1 -0
  39. package/dist/packlets/tools/memoryTools.js +25 -2
  40. package/dist/packlets/tools/memoryTools.js.map +1 -1
  41. package/dist/packlets/types/envelope.js +25 -0
  42. package/dist/packlets/types/envelope.js.map +1 -1
  43. package/dist/packlets/types/index.js +1 -0
  44. package/dist/packlets/types/index.js.map +1 -1
  45. package/dist/packlets/types/recordResolver.js +6 -0
  46. package/dist/packlets/types/recordResolver.js.map +1 -0
  47. package/dist/packlets/types/temporal.js.map +1 -1
  48. package/dist/packlets/vector/inMemoryCosineIndex.js +39 -18
  49. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  50. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +67 -12
  51. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  52. package/dist/packlets/vector/rebuildHelpers.js +38 -0
  53. package/dist/packlets/vector/rebuildHelpers.js.map +1 -0
  54. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  55. package/dist/ts-agent-memory.d.ts +1035 -106
  56. package/lib/packlets/index/memoryIndex.d.ts +118 -27
  57. package/lib/packlets/index/memoryIndex.d.ts.map +1 -1
  58. package/lib/packlets/index/memoryIndex.js +23 -16
  59. package/lib/packlets/index/memoryIndex.js.map +1 -1
  60. package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
  61. package/lib/packlets/ingest/orchestrator.js +13 -1
  62. package/lib/packlets/ingest/orchestrator.js.map +1 -1
  63. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +3 -10
  64. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -1
  65. package/lib/packlets/retrieve/linkTraversalRetriever.js +11 -25
  66. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  67. package/lib/packlets/retrieve/recencyRetriever.d.ts +3 -3
  68. package/lib/packlets/retrieve/recencyRetriever.d.ts.map +1 -1
  69. package/lib/packlets/retrieve/recencyRetriever.js +6 -6
  70. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
  71. package/lib/packlets/retrieve/retriever.d.ts +88 -7
  72. package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
  73. package/lib/packlets/retrieve/retriever.js +94 -9
  74. package/lib/packlets/retrieve/retriever.js.map +1 -1
  75. package/lib/packlets/retrieve/semanticRetriever.d.ts +3 -5
  76. package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -1
  77. package/lib/packlets/retrieve/semanticRetriever.js +15 -15
  78. package/lib/packlets/retrieve/semanticRetriever.js.map +1 -1
  79. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +3 -3
  80. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
  81. package/lib/packlets/retrieve/structuredFilterRetriever.js +6 -6
  82. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  83. package/lib/packlets/retrieve/tagRetriever.d.ts +3 -3
  84. package/lib/packlets/retrieve/tagRetriever.d.ts.map +1 -1
  85. package/lib/packlets/retrieve/tagRetriever.js +6 -6
  86. package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
  87. package/lib/packlets/retrieve/temporalRetrievers.d.ts +7 -5
  88. package/lib/packlets/retrieve/temporalRetrievers.d.ts.map +1 -1
  89. package/lib/packlets/retrieve/temporalRetrievers.js +22 -19
  90. package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
  91. package/lib/packlets/store/coverage.d.ts +102 -0
  92. package/lib/packlets/store/coverage.d.ts.map +1 -0
  93. package/lib/packlets/store/coverage.js +7 -0
  94. package/lib/packlets/store/coverage.js.map +1 -0
  95. package/lib/packlets/store/fileTreeMemoryStore.d.ts +53 -166
  96. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  97. package/lib/packlets/store/fileTreeMemoryStore.js +221 -79
  98. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  99. package/lib/packlets/store/index.d.ts +4 -0
  100. package/lib/packlets/store/index.d.ts.map +1 -1
  101. package/lib/packlets/store/index.js +4 -0
  102. package/lib/packlets/store/index.js.map +1 -1
  103. package/lib/packlets/store/listSelection.d.ts +101 -0
  104. package/lib/packlets/store/listSelection.d.ts.map +1 -0
  105. package/lib/packlets/store/listSelection.js +40 -0
  106. package/lib/packlets/store/listSelection.js.map +1 -0
  107. package/lib/packlets/store/memoryStore.d.ts +237 -0
  108. package/lib/packlets/store/memoryStore.d.ts.map +1 -0
  109. package/lib/packlets/store/memoryStore.js +7 -0
  110. package/lib/packlets/store/memoryStore.js.map +1 -0
  111. package/lib/packlets/store/reconcile.d.ts +82 -0
  112. package/lib/packlets/store/reconcile.d.ts.map +1 -0
  113. package/lib/packlets/store/reconcile.js +7 -0
  114. package/lib/packlets/store/reconcile.js.map +1 -0
  115. package/lib/packlets/store/storeCoverage.d.ts +45 -0
  116. package/lib/packlets/store/storeCoverage.d.ts.map +1 -0
  117. package/lib/packlets/store/storeCoverage.js +105 -0
  118. package/lib/packlets/store/storeCoverage.js.map +1 -0
  119. package/lib/packlets/store/storeReconcile.d.ts +41 -0
  120. package/lib/packlets/store/storeReconcile.d.ts.map +1 -0
  121. package/lib/packlets/store/storeReconcile.js +125 -0
  122. package/lib/packlets/store/storeReconcile.js.map +1 -0
  123. package/lib/packlets/store/vectorMaintenance.d.ts +74 -0
  124. package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -1
  125. package/lib/packlets/store/vectorMaintenance.js +117 -8
  126. package/lib/packlets/store/vectorMaintenance.js.map +1 -1
  127. package/lib/packlets/store/vectorRecordSource.d.ts +36 -0
  128. package/lib/packlets/store/vectorRecordSource.d.ts.map +1 -0
  129. package/lib/packlets/store/vectorRecordSource.js +47 -0
  130. package/lib/packlets/store/vectorRecordSource.js.map +1 -0
  131. package/lib/packlets/tools/memoryTools.d.ts.map +1 -1
  132. package/lib/packlets/tools/memoryTools.js +25 -2
  133. package/lib/packlets/tools/memoryTools.js.map +1 -1
  134. package/lib/packlets/types/envelope.d.ts +24 -2
  135. package/lib/packlets/types/envelope.d.ts.map +1 -1
  136. package/lib/packlets/types/envelope.js +26 -0
  137. package/lib/packlets/types/envelope.js.map +1 -1
  138. package/lib/packlets/types/index.d.ts +1 -0
  139. package/lib/packlets/types/index.d.ts.map +1 -1
  140. package/lib/packlets/types/index.js +1 -0
  141. package/lib/packlets/types/index.js.map +1 -1
  142. package/lib/packlets/types/recordResolver.d.ts +39 -0
  143. package/lib/packlets/types/recordResolver.d.ts.map +1 -0
  144. package/lib/packlets/types/recordResolver.js +7 -0
  145. package/lib/packlets/types/recordResolver.js.map +1 -0
  146. package/lib/packlets/types/temporal.d.ts +26 -6
  147. package/lib/packlets/types/temporal.d.ts.map +1 -1
  148. package/lib/packlets/types/temporal.js.map +1 -1
  149. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +9 -2
  150. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
  151. package/lib/packlets/vector/inMemoryCosineIndex.js +40 -19
  152. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  153. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +6 -3
  154. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
  155. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +66 -11
  156. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  157. package/lib/packlets/vector/rebuildHelpers.d.ts +30 -0
  158. package/lib/packlets/vector/rebuildHelpers.d.ts.map +1 -0
  159. package/lib/packlets/vector/rebuildHelpers.js +42 -0
  160. package/lib/packlets/vector/rebuildHelpers.js.map +1 -0
  161. package/lib/packlets/vector/vectorIndex.d.ts +270 -15
  162. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  163. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  164. package/package.json +7 -7
@@ -1,5 +1,5 @@
1
1
  import { Result } from '@fgv/ts-utils';
2
- import { IEdgeTarget, IMemoryRecord, Kind, MemoryScopeKey, Tag } from '../types';
2
+ import { IEdgeTarget, IMemoryEnvelope, 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'`).
@@ -21,6 +21,32 @@ export interface IIndexedMemoryRecord {
21
21
  /** The memory record itself. */
22
22
  readonly record: IMemoryRecord<unknown>;
23
23
  }
24
+ /**
25
+ * What the index HOLDS and what every index read returns: a record's scope and
26
+ * its {@link IMemoryEnvelope}, and **no body**.
27
+ *
28
+ * @remarks
29
+ * The index is a derived *selection* structure, and selection has never needed a
30
+ * body — every filter the store and the retrievers apply reads envelope fields
31
+ * (`scope` / `kind` / `tags` / `contentHash` / `provenance` / `links` /
32
+ * `temporal` / `updated` / `seq` / `rank`). Returning whole records made every
33
+ * conforming index hold every body by construction, which was the store's
34
+ * resident-memory ceiling; returning envelopes removes it from the contract
35
+ * rather than from one implementation.
36
+ *
37
+ * A caller that needs the body **materializes it explicitly** — through
38
+ * {@link IMemoryStore.getById}, or an `IMemoryRecordResolver` where one is
39
+ * wired. That is deliberately visible: a lazy `body` getter would have kept
40
+ * every call site compiling while turning a memory read into a file read behind
41
+ * an unchanged type, which is a silent performance cliff rather than a migration.
42
+ * @public
43
+ */
44
+ export interface IIndexedMemoryEntry {
45
+ /** The scope the record is stored under. */
46
+ readonly scope: MemoryScopeKey;
47
+ /** The record's envelope. No body — see the remarks. */
48
+ readonly envelope: IMemoryEnvelope;
49
+ }
24
50
  /**
25
51
  * The derived, in-memory secondary indexes the store maintains over its
26
52
  * records. Never the source of truth — the FileTree is. The index is fully
@@ -28,40 +54,98 @@ export interface IIndexedMemoryRecord {
28
54
  * patched incrementally on every write ({@link IMemoryIndex.patch}).
29
55
  *
30
56
  * @remarks
31
- * B1 builds the maps; link-traversal BFS over {@link IMemoryIndex.backlinks}
32
- * is B2. The accessors return records (not bare ids) so the B2 retrievers can
33
- * consume them directly.
57
+ * Every read returns the projected {@link IIndexedMemoryEntry} scope and
58
+ * envelope, no body. See that type for why.
59
+ *
60
+ * **The conformance rule: an index is a derived, COMPLETE, FAITHFUL projection
61
+ * of the vault.** An implementation may change *where* entries are stored and
62
+ * *how* they are looked up; it may not change *which* entries exist or *what any
63
+ * envelope says*. Concretely, {@link IMemoryIndex.entries} must return exactly
64
+ * one entry per record the store has written and not deleted, and each entry's
65
+ * envelope must be the one the store patched in.
66
+ *
67
+ * An index that filters, truncates, deduplicates, or synthesizes entries is not
68
+ * a conforming implementation, and the reason is not tidiness: **the store's
69
+ * write path derives from these reads** — content-hash dedup, write-policy
70
+ * admission cohorts, and temporal version histories all read the index. An index
71
+ * that hides an entry does not merely hide it from queries; it changes what the
72
+ * next write does. That is why the previous guidance said only a faithful
73
+ * delegating decorator was safe to inject. This invariant is what that guidance
74
+ * was reaching for, stated so that a genuinely different implementation (a
75
+ * SQLite-backed index, a lazily-paged one) is permitted while the reshaping that
76
+ * was the actual hazard stays out.
77
+ *
78
+ * **Ordering is NOT part of the contract.** {@link IMemoryIndex.entries} may
79
+ * return entries in any order and callers that need one sort explicitly. Note
80
+ * this is a *behavioural* freedom the compiler cannot police: the bundled
81
+ * {@link MemoryIndex} iterates a `Map` and so returns insertion order, which is
82
+ * stable and observable, so code that came to rely on it keeps compiling and
83
+ * changes results. The ordered accessors ({@link IMemoryIndex.byRecency},
84
+ * {@link IMemoryIndex.byRank}, and the recency-ordered `byKind` / `byTag`) are
85
+ * the supported way to ask for an order.
34
86
  * @public
35
87
  */
36
88
  export interface IMemoryIndex {
37
89
  /**
38
- * Replace the entire index from a full set of records (a store walk).
39
- * @returns The number of records indexed.
90
+ * Replace the entire index from a full set of entries (a store walk).
91
+ *
92
+ * @remarks
93
+ * Takes the **projected** {@link IIndexedMemoryEntry} form, not whole records,
94
+ * and the distinction is load-bearing rather than cosmetic: **`patch` writes,
95
+ * `rebuild` reads.** A rebuild is a whole-vault read that happens to terminate
96
+ * in the index, so requiring whole records here would force every caller — the
97
+ * store's own open path included — to materialize N bodies purely to feed a
98
+ * structure that projects the envelope back out and discards them. `patch`
99
+ * keeps whole records because it carries exactly one, which its caller already
100
+ * holds.
101
+ *
102
+ * @returns The number of entries indexed.
40
103
  */
41
- rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;
104
+ rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number>;
42
105
  /**
43
106
  * Apply a single incremental change. `'put'` inserts or replaces the entry
44
107
  * at its `(scope, id)` key (removing any prior associations first); `'delete'`
45
108
  * removes it.
109
+ *
110
+ * @remarks
111
+ * Takes the whole record — see {@link IMemoryIndex.rebuild} for why this one
112
+ * does and that one does not. It costs nothing (the caller is mid-write and
113
+ * holds the record already) and it is the single point at which an index
114
+ * maintaining a body-derived view could observe content without a re-read.
115
+ * What is *held* is still only the projection.
116
+ *
46
117
  * @returns The entry that was applied.
47
118
  */
48
119
  patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;
49
- /** Every indexed entry (scope + record). Primary read surface for the store. */
50
- entries(): ReadonlyArray<IIndexedMemoryRecord>;
51
- /** Records of the given kind, in recency order (most-recently-updated first). */
52
- byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
53
- /** Records carrying the given tag, in recency order. */
54
- byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
55
- /** All records in recency order (most-recently-updated first). */
56
- byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
120
+ /** Every indexed entry (scope + envelope). Primary read surface for the store. */
121
+ entries(): ReadonlyArray<IIndexedMemoryEntry>;
57
122
  /**
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
123
+ * The entry at a scope-qualified address, or `undefined` if none.
124
+ *
125
+ * @remarks
126
+ * On the contract because its absence made every caller that wanted **one**
127
+ * entry rebuild a map of **all** of them: both `SemanticRetriever` (resolving
128
+ * at most `topK` hits) and `LinkTraversalRetriever` (resolving a BFS frontier)
129
+ * built a full-index `Map` per query for want of this. The index already keys
130
+ * on `(scope, id)` internally, so this exposes a lookup it was doing anyway.
131
+ */
132
+ get(target: IEdgeTarget): IIndexedMemoryEntry | undefined;
133
+ /** Entries of the given kind, in recency order (most-recently-updated first). */
134
+ byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry>;
135
+ /** Entries carrying the given tag, in recency order. */
136
+ byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry>;
137
+ /** All entries in recency order (most-recently-updated first). */
138
+ byRecency(): ReadonlyArray<IIndexedMemoryEntry>;
139
+ /**
140
+ * All entries ordered by store-computed {@link IMemoryEnvelope.rank} descending,
141
+ * with recency (most-recently-updated, then `seq`) as a tiebreak. Entries with
142
+ * an absent `rank` sort LAST (after every ranked entry), then by recency among
61
143
  * themselves. Serves a bounded top-M ({@link IMemoryEnvelope.rank}-ordered) page
62
- * from the in-memory index with no full-vault (filesystem) scan.
144
+ * from the in-memory index with no full-vault (filesystem) scan — and since the
145
+ * page is envelope-only, a caller taking the top M materializes M bodies rather
146
+ * than the vault.
63
147
  */
64
- byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
148
+ byRank(): ReadonlyArray<IIndexedMemoryEntry>;
65
149
  /**
66
150
  * The scope-qualified sources of records whose `links` point AT `target`
67
151
  * (inbound edges), keyed on the target's `(scope, id)` address. The seed map
@@ -78,7 +162,10 @@ export interface IMemoryIndex {
78
162
  * @public
79
163
  */
80
164
  export declare class MemoryIndex implements IMemoryIndex {
81
- /** Primary store: `(scope, id)` composite key → indexed entry. */
165
+ /**
166
+ * Primary store: `(scope, id)` composite key → indexed entry. Holds the
167
+ * PROJECTED form, so the index never retains a body.
168
+ */
82
169
  private readonly _byKey;
83
170
  /** kind → set of composite keys. */
84
171
  private readonly _byKind;
@@ -105,19 +192,21 @@ export declare class MemoryIndex implements IMemoryIndex {
105
192
  */
106
193
  private static _keyOf;
107
194
  /** {@inheritDoc IMemoryIndex.rebuild} */
108
- rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;
195
+ rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number>;
109
196
  /** {@inheritDoc IMemoryIndex.patch} */
110
197
  patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;
111
198
  /** {@inheritDoc IMemoryIndex.entries} */
112
- entries(): ReadonlyArray<IIndexedMemoryRecord>;
199
+ entries(): ReadonlyArray<IIndexedMemoryEntry>;
200
+ /** {@inheritDoc IMemoryIndex.get} */
201
+ get(target: IEdgeTarget): IIndexedMemoryEntry | undefined;
113
202
  /** {@inheritDoc IMemoryIndex.byKind} */
114
- byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;
203
+ byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry>;
115
204
  /** {@inheritDoc IMemoryIndex.byTag} */
116
- byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;
205
+ byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry>;
117
206
  /** {@inheritDoc IMemoryIndex.byRecency} */
118
- byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;
207
+ byRecency(): ReadonlyArray<IIndexedMemoryEntry>;
119
208
  /** {@inheritDoc IMemoryIndex.byRank} */
120
- byRank(): ReadonlyArray<IMemoryRecord<unknown>>;
209
+ byRank(): ReadonlyArray<IIndexedMemoryEntry>;
121
210
  /** {@inheritDoc IMemoryIndex.backlinks} */
122
211
  backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;
123
212
  /**
@@ -135,6 +224,8 @@ export declare class MemoryIndex implements IMemoryIndex {
135
224
  * approach; the sort is over the in-memory index, never a filesystem walk.
136
225
  */
137
226
  private _rankOrdered;
227
+ /** Resolve composite keys to their entries, skipping any that are absent. */
228
+ private static _resolve;
138
229
  /**
139
230
  * Rank-descending comparator with an absent-`rank`-last rule and a recency
140
231
  * (`updated`, then `seq`) tiebreak. Duplicated from the retrieve packlet's
@@ -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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"}
@@ -9,6 +9,10 @@ const ts_utils_1 = require("@fgv/ts-utils");
9
9
  const types_1 = require("../types");
10
10
  /** Shared empty key set for `byKind` / `byTag` misses (avoids per-call allocation). */
11
11
  const EMPTY_KEY_SET = new Set();
12
+ /** Project the write-side whole-record form onto the held/read entry form. */
13
+ function toEntry(entry) {
14
+ return { scope: entry.scope, envelope: entry.record.envelope };
15
+ }
12
16
  /**
13
17
  * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /
14
18
  * `byTag` / `byRecency` / `backlinks` views incrementally; a `'put'` for an
@@ -54,7 +58,9 @@ class MemoryIndex {
54
58
  // changes kind/tags/links cannot strand a stale reference.
55
59
  this._remove(key);
56
60
  if (op === 'put') {
57
- this._add(entry);
61
+ // Projected on the way in: the caller's record is used for its envelope and
62
+ // the body is not retained.
63
+ this._add(toEntry(entry));
58
64
  }
59
65
  return (0, ts_utils_1.succeed)(entry);
60
66
  }
@@ -62,6 +68,10 @@ class MemoryIndex {
62
68
  entries() {
63
69
  return Array.from(this._byKey.values());
64
70
  }
71
+ /** {@inheritDoc IMemoryIndex.get} */
72
+ get(target) {
73
+ return this._byKey.get((0, types_1.edgeTargetKey)(target));
74
+ }
65
75
  /** {@inheritDoc IMemoryIndex.byKind} */
66
76
  byKind(kind) {
67
77
  var _a;
@@ -91,14 +101,7 @@ class MemoryIndex {
91
101
  * records sort deterministically).
92
102
  */
93
103
  _recencyOrdered(keys) {
94
- const records = [];
95
- for (const key of keys) {
96
- const entry = this._byKey.get(key);
97
- if (entry !== undefined) {
98
- records.push(entry.record);
99
- }
100
- }
101
- return records.sort((a, b) => {
104
+ return MemoryIndex._resolve(this._byKey, keys).sort((a, b) => {
102
105
  const byUpdated = b.envelope.updated - a.envelope.updated;
103
106
  return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;
104
107
  });
@@ -112,14 +115,18 @@ class MemoryIndex {
112
115
  * approach; the sort is over the in-memory index, never a filesystem walk.
113
116
  */
114
117
  _rankOrdered(keys) {
115
- const records = [];
118
+ return MemoryIndex._resolve(this._byKey, keys).sort(MemoryIndex._compareByRank);
119
+ }
120
+ /** Resolve composite keys to their entries, skipping any that are absent. */
121
+ static _resolve(byKey, keys) {
122
+ const entries = [];
116
123
  for (const key of keys) {
117
- const entry = this._byKey.get(key);
124
+ const entry = byKey.get(key);
118
125
  if (entry !== undefined) {
119
- records.push(entry.record);
126
+ entries.push(entry);
120
127
  }
121
128
  }
122
- return records.sort(MemoryIndex._compareByRank);
129
+ return entries;
123
130
  }
124
131
  /**
125
132
  * Rank-descending comparator with an absent-`rank`-last rule and a recency
@@ -146,8 +153,8 @@ class MemoryIndex {
146
153
  }
147
154
  /** Insert an entry and register all its derived associations. */
148
155
  _add(entry) {
149
- const key = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);
150
- const envelope = entry.record.envelope;
156
+ const key = MemoryIndex._keyOf(entry.scope, entry.envelope.id);
157
+ const envelope = entry.envelope;
151
158
  this._byKey.set(key, entry);
152
159
  this._addToSetMap(this._byKind, envelope.kind, key);
153
160
  for (const tag of envelope.tags) {
@@ -163,7 +170,7 @@ class MemoryIndex {
163
170
  if (entry === undefined) {
164
171
  return;
165
172
  }
166
- const envelope = entry.record.envelope;
173
+ const envelope = entry.envelope;
167
174
  this._byKey.delete(key);
168
175
  this._removeFromSetMap(this._byKind, envelope.kind, key);
169
176
  for (const tag of envelope.tags) {
@@ -1 +1 @@
1
- {"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../../../src/packlets/index/memoryIndex.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IEdgeTarget, IMemoryRecord, Kind, MemoryId, MemoryScopeKey, Tag, edgeTargetKey } from '../types';\n\n/**\n * The mutation a {@link IMemoryIndex.patch | patch} applies: a record was\n * written (`'put'`) or removed (`'delete'`).\n * @public\n */\nexport type MemoryIndexPatchOp = 'put' | 'delete';\n\n/** Shared empty key set for `byKind` / `byTag` misses (avoids per-call allocation). */\nconst EMPTY_KEY_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * A memory record paired with the {@link MemoryScopeKey | scope} it lives\n * under. The scope is not carried on the {@link IMemoryEnvelope} (it is derived\n * from the entity id by the codec), so the store threads it alongside the\n * record when patching or rebuilding the index. The `(scope, id)` pair is the\n * index's primary key, keeping records distinct across scopes that reuse a\n * filename stem (e.g. `turn-0` under different conversations in Phase C).\n * @public\n */\nexport interface IIndexedMemoryRecord {\n /** The scope the record is stored under. */\n readonly scope: MemoryScopeKey;\n /** The memory record itself. */\n readonly record: IMemoryRecord<unknown>;\n}\n\n/**\n * The derived, in-memory secondary indexes the store maintains over its\n * records. Never the source of truth — the FileTree is. The index is fully\n * rebuildable from a walk of the store ({@link IMemoryIndex.rebuild}) and is\n * patched incrementally on every write ({@link IMemoryIndex.patch}).\n *\n * @remarks\n * B1 builds the maps; link-traversal BFS over {@link IMemoryIndex.backlinks}\n * is B2. The accessors return records (not bare ids) so the B2 retrievers can\n * consume them directly.\n * @public\n */\nexport interface IMemoryIndex {\n /**\n * Replace the entire index from a full set of records (a store walk).\n * @returns The number of records indexed.\n */\n rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;\n\n /**\n * Apply a single incremental change. `'put'` inserts or replaces the entry\n * at its `(scope, id)` key (removing any prior associations first); `'delete'`\n * removes it.\n * @returns The entry that was applied.\n */\n patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;\n\n /** Every indexed entry (scope + record). Primary read surface for the store. */\n entries(): ReadonlyArray<IIndexedMemoryRecord>;\n\n /** Records of the given kind, in recency order (most-recently-updated first). */\n byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /** Records carrying the given tag, in recency order. */\n byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /** All records in recency order (most-recently-updated first). */\n byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /**\n * All records ordered by store-computed {@link IMemoryEnvelope.rank} descending,\n * with recency (most-recently-updated, then `seq`) as a tiebreak. Records with\n * an absent `rank` sort LAST (after every ranked record), then by recency among\n * themselves. Serves a bounded top-M ({@link IMemoryEnvelope.rank}-ordered) page\n * from the in-memory index with no full-vault (filesystem) scan.\n */\n byRank(): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /**\n * The scope-qualified sources of records whose `links` point AT `target`\n * (inbound edges), keyed on the target's `(scope, id)` address. The seed map\n * for B2 link-traversal; results are {@link IEdgeTarget}s so a caller can feed\n * them straight back in as further traversal seeds.\n */\n backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;\n}\n\n/**\n * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /\n * `byTag` / `byRecency` / `backlinks` views incrementally; a `'put'` for an\n * already-indexed key first removes the prior entry's associations so a changed\n * kind / tag / link set never leaves a stale reference behind.\n * @public\n */\nexport class MemoryIndex implements IMemoryIndex {\n /** Primary store: `(scope, id)` composite key → indexed entry. */\n private readonly _byKey: Map<string, IIndexedMemoryRecord>;\n /** kind → set of composite keys. */\n private readonly _byKind: Map<Kind, Set<string>>;\n /** tag → set of composite keys. */\n private readonly _byTag: Map<Tag, Set<string>>;\n /**\n * canonical target key (`edgeTargetKey`) → (source composite key → source\n * {@link IEdgeTarget}). The OUTER map is keyed on the scope-qualified target's\n * canonical `(scope, id)` string — NOT the target's bare id — so an edge to\n * `turn-3` in one conversation is tracked separately from `turn-3` in another.\n * The INNER map is keyed by the source's `(scope, id)` composite so two distinct\n * source records that share an id across scopes are tracked independently and\n * removing one never drops the other's edge.\n */\n private readonly _backlinks: Map<string, Map<string, IEdgeTarget>>;\n\n private constructor() {\n this._byKey = new Map<string, IIndexedMemoryRecord>();\n this._byKind = new Map<Kind, Set<string>>();\n this._byTag = new Map<Tag, Set<string>>();\n this._backlinks = new Map<string, Map<string, IEdgeTarget>>();\n }\n\n /** Family-convention factory. */\n public static create(): Result<MemoryIndex> {\n return succeed(new MemoryIndex());\n }\n\n /**\n * The composite primary key for an entry: scope + id, NUL-separated. NUL\n * is excluded from both components (scope segments pass\n * `assertPortableFilenameStem`; `MemoryId` is portable-filename-safe), so it\n * is a collision-proof separator across every scope/id pair the codecs produce.\n */\n private static _keyOf(scope: MemoryScopeKey, id: MemoryId): string {\n return edgeTargetKey({ scope, id });\n }\n\n /** {@inheritDoc IMemoryIndex.rebuild} */\n public rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number> {\n this._byKey.clear();\n this._byKind.clear();\n this._byTag.clear();\n this._backlinks.clear();\n for (const entry of entries) {\n this._add(entry);\n }\n return succeed(this._byKey.size);\n }\n\n /** {@inheritDoc IMemoryIndex.patch} */\n public patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord> {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);\n // Always drop any prior associations for this key first, so a 'put' that\n // changes kind/tags/links cannot strand a stale reference.\n this._remove(key);\n if (op === 'put') {\n this._add(entry);\n }\n return succeed(entry);\n }\n\n /** {@inheritDoc IMemoryIndex.entries} */\n public entries(): ReadonlyArray<IIndexedMemoryRecord> {\n return Array.from(this._byKey.values());\n }\n\n /** {@inheritDoc IMemoryIndex.byKind} */\n public byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byKind.get(kind) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byTag} */\n public byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byTag.get(tag) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byRecency} */\n public byRecency(): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byKey.keys());\n }\n\n /** {@inheritDoc IMemoryIndex.byRank} */\n public byRank(): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._rankOrdered(this._byKey.keys());\n }\n\n /** {@inheritDoc IMemoryIndex.backlinks} */\n public backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget> {\n const sources: Map<string, IEdgeTarget> | undefined = this._backlinks.get(edgeTargetKey(target));\n return sources === undefined ? [] : Array.from(sources.values());\n }\n\n /**\n * Resolve a set of composite keys to their records, ordered\n * most-recently-updated first (with a `seq` tiebreak so equal-`updated`\n * records sort deterministically).\n */\n private _recencyOrdered(keys: Iterable<string>): ReadonlyArray<IMemoryRecord<unknown>> {\n const records: IMemoryRecord<unknown>[] = [];\n for (const key of keys) {\n const entry: IIndexedMemoryRecord | undefined = this._byKey.get(key);\n if (entry !== undefined) {\n records.push(entry.record);\n }\n }\n return records.sort((a, b) => {\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n });\n }\n\n /**\n * Resolve a set of composite keys to their records, ordered by\n * {@link IMemoryEnvelope.rank} descending with recency (`updated`, then `seq`)\n * as the tiebreak. Records with an absent `rank` sort LAST, then by recency\n * among themselves. Computed on call (mirrors {@link MemoryIndex._recencyOrdered}) —\n * no incremental rank-ordered view is maintained, matching the recency view's\n * approach; the sort is over the in-memory index, never a filesystem walk.\n */\n private _rankOrdered(keys: Iterable<string>): ReadonlyArray<IMemoryRecord<unknown>> {\n const records: IMemoryRecord<unknown>[] = [];\n for (const key of keys) {\n const entry: IIndexedMemoryRecord | undefined = this._byKey.get(key);\n if (entry !== undefined) {\n records.push(entry.record);\n }\n }\n return records.sort(MemoryIndex._compareByRank);\n }\n\n /**\n * Rank-descending comparator with an absent-`rank`-last rule and a recency\n * (`updated`, then `seq`) tiebreak. Duplicated from the retrieve packlet's\n * `rankCompare` deliberately: the index must not depend on `retrieve` (that\n * package depends on the index), mirroring how `_recencyOrdered` inlines the\n * recency ordering rather than importing `recencyCompare`.\n */\n private static _compareByRank(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number {\n const ra: number | undefined = a.envelope.rank;\n const rb: number | undefined = b.envelope.rank;\n // Absent rank sorts last; two absent ranks fall through to the recency tiebreak.\n if (ra === undefined && rb !== undefined) {\n return 1;\n }\n if (rb === undefined && ra !== undefined) {\n return -1;\n }\n if (ra !== undefined && rb !== undefined && ra !== rb) {\n return rb - ra;\n }\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n }\n\n /** Insert an entry and register all its derived associations. */\n private _add(entry: IIndexedMemoryRecord): void {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);\n const envelope: IMemoryRecord<unknown>['envelope'] = entry.record.envelope;\n this._byKey.set(key, entry);\n this._addToSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._addToSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._addBacklink(edge.target, key, { scope: entry.scope, id: envelope.id });\n }\n }\n\n /** Remove the entry at `key` (if present) and all its derived associations. */\n private _remove(key: string): void {\n const entry: IIndexedMemoryRecord | undefined = this._byKey.get(key);\n if (entry === undefined) {\n return;\n }\n const envelope: IMemoryRecord<unknown>['envelope'] = entry.record.envelope;\n this._byKey.delete(key);\n this._removeFromSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._removeFromSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._removeBacklink(edge.target, key);\n }\n }\n\n /** Register `source` (keyed by its composite `sourceKey`) as linking at `target`. */\n private _addBacklink(target: IEdgeTarget, sourceKey: string, source: IEdgeTarget): void {\n const targetKey: string = edgeTargetKey(target);\n const existing: Map<string, IEdgeTarget> | undefined = this._backlinks.get(targetKey);\n if (existing === undefined) {\n this._backlinks.set(targetKey, new Map<string, IEdgeTarget>([[sourceKey, source]]));\n } else {\n existing.set(sourceKey, source);\n }\n }\n\n /** Drop the backlink from `sourceKey` to `target`, removing the target map when empty. */\n private _removeBacklink(target: IEdgeTarget, sourceKey: string): void {\n const targetKey: string = edgeTargetKey(target);\n const existing: Map<string, IEdgeTarget> | undefined = this._backlinks.get(targetKey);\n if (existing === undefined) {\n return;\n }\n existing.delete(sourceKey);\n if (existing.size === 0) {\n this._backlinks.delete(targetKey);\n }\n }\n\n /** Add `member` to the set at `mapKey`, creating the set on first use. */\n private _addToSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n map.set(mapKey, new Set<M>([member]));\n } else {\n existing.add(member);\n }\n }\n\n /** Remove `member` from the set at `mapKey`, dropping the set when empty. */\n private _removeFromSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n return;\n }\n existing.delete(member);\n if (existing.size === 0) {\n map.delete(mapKey);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../../../src/packlets/index/memoryIndex.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport {\n IEdgeTarget,\n IMemoryEnvelope,\n IMemoryRecord,\n Kind,\n MemoryId,\n MemoryScopeKey,\n Tag,\n edgeTargetKey\n} from '../types';\n\n/**\n * The mutation a {@link IMemoryIndex.patch | patch} applies: a record was\n * written (`'put'`) or removed (`'delete'`).\n * @public\n */\nexport type MemoryIndexPatchOp = 'put' | 'delete';\n\n/** Shared empty key set for `byKind` / `byTag` misses (avoids per-call allocation). */\nconst EMPTY_KEY_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * A memory record paired with the {@link MemoryScopeKey | scope} it lives\n * under. The scope is not carried on the {@link IMemoryEnvelope} (it is derived\n * from the entity id by the codec), so the store threads it alongside the\n * record when patching or rebuilding the index. The `(scope, id)` pair is the\n * index's primary key, keeping records distinct across scopes that reuse a\n * filename stem (e.g. `turn-0` under different conversations in Phase C).\n * @public\n */\nexport interface IIndexedMemoryRecord {\n /** The scope the record is stored under. */\n readonly scope: MemoryScopeKey;\n /** The memory record itself. */\n readonly record: IMemoryRecord<unknown>;\n}\n\n/**\n * What the index HOLDS and what every index read returns: a record's scope and\n * its {@link IMemoryEnvelope}, and **no body**.\n *\n * @remarks\n * The index is a derived *selection* structure, and selection has never needed a\n * body — every filter the store and the retrievers apply reads envelope fields\n * (`scope` / `kind` / `tags` / `contentHash` / `provenance` / `links` /\n * `temporal` / `updated` / `seq` / `rank`). Returning whole records made every\n * conforming index hold every body by construction, which was the store's\n * resident-memory ceiling; returning envelopes removes it from the contract\n * rather than from one implementation.\n *\n * A caller that needs the body **materializes it explicitly** — through\n * {@link IMemoryStore.getById}, or an `IMemoryRecordResolver` where one is\n * wired. That is deliberately visible: a lazy `body` getter would have kept\n * every call site compiling while turning a memory read into a file read behind\n * an unchanged type, which is a silent performance cliff rather than a migration.\n * @public\n */\nexport interface IIndexedMemoryEntry {\n /** The scope the record is stored under. */\n readonly scope: MemoryScopeKey;\n /** The record's envelope. No body — see the remarks. */\n readonly envelope: IMemoryEnvelope;\n}\n\n/** Project the write-side whole-record form onto the held/read entry form. */\nfunction toEntry(entry: IIndexedMemoryRecord): IIndexedMemoryEntry {\n return { scope: entry.scope, envelope: entry.record.envelope };\n}\n\n/**\n * The derived, in-memory secondary indexes the store maintains over its\n * records. Never the source of truth — the FileTree is. The index is fully\n * rebuildable from a walk of the store ({@link IMemoryIndex.rebuild}) and is\n * patched incrementally on every write ({@link IMemoryIndex.patch}).\n *\n * @remarks\n * Every read returns the projected {@link IIndexedMemoryEntry} — scope and\n * envelope, no body. See that type for why.\n *\n * **The conformance rule: an index is a derived, COMPLETE, FAITHFUL projection\n * of the vault.** An implementation may change *where* entries are stored and\n * *how* they are looked up; it may not change *which* entries exist or *what any\n * envelope says*. Concretely, {@link IMemoryIndex.entries} must return exactly\n * one entry per record the store has written and not deleted, and each entry's\n * envelope must be the one the store patched in.\n *\n * An index that filters, truncates, deduplicates, or synthesizes entries is not\n * a conforming implementation, and the reason is not tidiness: **the store's\n * write path derives from these reads** — content-hash dedup, write-policy\n * admission cohorts, and temporal version histories all read the index. An index\n * that hides an entry does not merely hide it from queries; it changes what the\n * next write does. That is why the previous guidance said only a faithful\n * delegating decorator was safe to inject. This invariant is what that guidance\n * was reaching for, stated so that a genuinely different implementation (a\n * SQLite-backed index, a lazily-paged one) is permitted while the reshaping that\n * was the actual hazard stays out.\n *\n * **Ordering is NOT part of the contract.** {@link IMemoryIndex.entries} may\n * return entries in any order and callers that need one sort explicitly. Note\n * this is a *behavioural* freedom the compiler cannot police: the bundled\n * {@link MemoryIndex} iterates a `Map` and so returns insertion order, which is\n * stable and observable, so code that came to rely on it keeps compiling and\n * changes results. The ordered accessors ({@link IMemoryIndex.byRecency},\n * {@link IMemoryIndex.byRank}, and the recency-ordered `byKind` / `byTag`) are\n * the supported way to ask for an order.\n * @public\n */\nexport interface IMemoryIndex {\n /**\n * Replace the entire index from a full set of entries (a store walk).\n *\n * @remarks\n * Takes the **projected** {@link IIndexedMemoryEntry} form, not whole records,\n * and the distinction is load-bearing rather than cosmetic: **`patch` writes,\n * `rebuild` reads.** A rebuild is a whole-vault read that happens to terminate\n * in the index, so requiring whole records here would force every caller — the\n * store's own open path included — to materialize N bodies purely to feed a\n * structure that projects the envelope back out and discards them. `patch`\n * keeps whole records because it carries exactly one, which its caller already\n * holds.\n *\n * @returns The number of entries indexed.\n */\n rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number>;\n\n /**\n * Apply a single incremental change. `'put'` inserts or replaces the entry\n * at its `(scope, id)` key (removing any prior associations first); `'delete'`\n * removes it.\n *\n * @remarks\n * Takes the whole record — see {@link IMemoryIndex.rebuild} for why this one\n * does and that one does not. It costs nothing (the caller is mid-write and\n * holds the record already) and it is the single point at which an index\n * maintaining a body-derived view could observe content without a re-read.\n * What is *held* is still only the projection.\n *\n * @returns The entry that was applied.\n */\n patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;\n\n /** Every indexed entry (scope + envelope). Primary read surface for the store. */\n entries(): ReadonlyArray<IIndexedMemoryEntry>;\n\n /**\n * The entry at a scope-qualified address, or `undefined` if none.\n *\n * @remarks\n * On the contract because its absence made every caller that wanted **one**\n * entry rebuild a map of **all** of them: both `SemanticRetriever` (resolving\n * at most `topK` hits) and `LinkTraversalRetriever` (resolving a BFS frontier)\n * built a full-index `Map` per query for want of this. The index already keys\n * on `(scope, id)` internally, so this exposes a lookup it was doing anyway.\n */\n get(target: IEdgeTarget): IIndexedMemoryEntry | undefined;\n\n /** Entries of the given kind, in recency order (most-recently-updated first). */\n byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry>;\n\n /** Entries carrying the given tag, in recency order. */\n byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry>;\n\n /** All entries in recency order (most-recently-updated first). */\n byRecency(): ReadonlyArray<IIndexedMemoryEntry>;\n\n /**\n * All entries ordered by store-computed {@link IMemoryEnvelope.rank} descending,\n * with recency (most-recently-updated, then `seq`) as a tiebreak. Entries with\n * an absent `rank` sort LAST (after every ranked entry), then by recency among\n * themselves. Serves a bounded top-M ({@link IMemoryEnvelope.rank}-ordered) page\n * from the in-memory index with no full-vault (filesystem) scan — and since the\n * page is envelope-only, a caller taking the top M materializes M bodies rather\n * than the vault.\n */\n byRank(): ReadonlyArray<IIndexedMemoryEntry>;\n\n /**\n * The scope-qualified sources of records whose `links` point AT `target`\n * (inbound edges), keyed on the target's `(scope, id)` address. The seed map\n * for B2 link-traversal; results are {@link IEdgeTarget}s so a caller can feed\n * them straight back in as further traversal seeds.\n */\n backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget>;\n}\n\n/**\n * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /\n * `byTag` / `byRecency` / `backlinks` views incrementally; a `'put'` for an\n * already-indexed key first removes the prior entry's associations so a changed\n * kind / tag / link set never leaves a stale reference behind.\n * @public\n */\nexport class MemoryIndex implements IMemoryIndex {\n /**\n * Primary store: `(scope, id)` composite key → indexed entry. Holds the\n * PROJECTED form, so the index never retains a body.\n */\n private readonly _byKey: Map<string, IIndexedMemoryEntry>;\n /** kind → set of composite keys. */\n private readonly _byKind: Map<Kind, Set<string>>;\n /** tag → set of composite keys. */\n private readonly _byTag: Map<Tag, Set<string>>;\n /**\n * canonical target key (`edgeTargetKey`) → (source composite key → source\n * {@link IEdgeTarget}). The OUTER map is keyed on the scope-qualified target's\n * canonical `(scope, id)` string — NOT the target's bare id — so an edge to\n * `turn-3` in one conversation is tracked separately from `turn-3` in another.\n * The INNER map is keyed by the source's `(scope, id)` composite so two distinct\n * source records that share an id across scopes are tracked independently and\n * removing one never drops the other's edge.\n */\n private readonly _backlinks: Map<string, Map<string, IEdgeTarget>>;\n\n private constructor() {\n this._byKey = new Map<string, IIndexedMemoryEntry>();\n this._byKind = new Map<Kind, Set<string>>();\n this._byTag = new Map<Tag, Set<string>>();\n this._backlinks = new Map<string, Map<string, IEdgeTarget>>();\n }\n\n /** Family-convention factory. */\n public static create(): Result<MemoryIndex> {\n return succeed(new MemoryIndex());\n }\n\n /**\n * The composite primary key for an entry: scope + id, NUL-separated. NUL\n * is excluded from both components (scope segments pass\n * `assertPortableFilenameStem`; `MemoryId` is portable-filename-safe), so it\n * is a collision-proof separator across every scope/id pair the codecs produce.\n */\n private static _keyOf(scope: MemoryScopeKey, id: MemoryId): string {\n return edgeTargetKey({ scope, id });\n }\n\n /** {@inheritDoc IMemoryIndex.rebuild} */\n public rebuild(entries: ReadonlyArray<IIndexedMemoryEntry>): Result<number> {\n this._byKey.clear();\n this._byKind.clear();\n this._byTag.clear();\n this._backlinks.clear();\n for (const entry of entries) {\n this._add(entry);\n }\n return succeed(this._byKey.size);\n }\n\n /** {@inheritDoc IMemoryIndex.patch} */\n public patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord> {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);\n // Always drop any prior associations for this key first, so a 'put' that\n // changes kind/tags/links cannot strand a stale reference.\n this._remove(key);\n if (op === 'put') {\n // Projected on the way in: the caller's record is used for its envelope and\n // the body is not retained.\n this._add(toEntry(entry));\n }\n return succeed(entry);\n }\n\n /** {@inheritDoc IMemoryIndex.entries} */\n public entries(): ReadonlyArray<IIndexedMemoryEntry> {\n return Array.from(this._byKey.values());\n }\n\n /** {@inheritDoc IMemoryIndex.get} */\n public get(target: IEdgeTarget): IIndexedMemoryEntry | undefined {\n return this._byKey.get(edgeTargetKey(target));\n }\n\n /** {@inheritDoc IMemoryIndex.byKind} */\n public byKind(kind: Kind): ReadonlyArray<IIndexedMemoryEntry> {\n return this._recencyOrdered(this._byKind.get(kind) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byTag} */\n public byTag(tag: Tag): ReadonlyArray<IIndexedMemoryEntry> {\n return this._recencyOrdered(this._byTag.get(tag) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byRecency} */\n public byRecency(): ReadonlyArray<IIndexedMemoryEntry> {\n return this._recencyOrdered(this._byKey.keys());\n }\n\n /** {@inheritDoc IMemoryIndex.byRank} */\n public byRank(): ReadonlyArray<IIndexedMemoryEntry> {\n return this._rankOrdered(this._byKey.keys());\n }\n\n /** {@inheritDoc IMemoryIndex.backlinks} */\n public backlinks(target: IEdgeTarget): ReadonlyArray<IEdgeTarget> {\n const sources: Map<string, IEdgeTarget> | undefined = this._backlinks.get(edgeTargetKey(target));\n return sources === undefined ? [] : Array.from(sources.values());\n }\n\n /**\n * Resolve a set of composite keys to their records, ordered\n * most-recently-updated first (with a `seq` tiebreak so equal-`updated`\n * records sort deterministically).\n */\n private _recencyOrdered(keys: Iterable<string>): ReadonlyArray<IIndexedMemoryEntry> {\n return MemoryIndex._resolve(this._byKey, keys).sort((a, b) => {\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n });\n }\n\n /**\n * Resolve a set of composite keys to their records, ordered by\n * {@link IMemoryEnvelope.rank} descending with recency (`updated`, then `seq`)\n * as the tiebreak. Records with an absent `rank` sort LAST, then by recency\n * among themselves. Computed on call (mirrors {@link MemoryIndex._recencyOrdered}) —\n * no incremental rank-ordered view is maintained, matching the recency view's\n * approach; the sort is over the in-memory index, never a filesystem walk.\n */\n private _rankOrdered(keys: Iterable<string>): ReadonlyArray<IIndexedMemoryEntry> {\n return MemoryIndex._resolve(this._byKey, keys).sort(MemoryIndex._compareByRank);\n }\n\n /** Resolve composite keys to their entries, skipping any that are absent. */\n private static _resolve(\n byKey: ReadonlyMap<string, IIndexedMemoryEntry>,\n keys: Iterable<string>\n ): IIndexedMemoryEntry[] {\n const entries: IIndexedMemoryEntry[] = [];\n for (const key of keys) {\n const entry: IIndexedMemoryEntry | undefined = byKey.get(key);\n if (entry !== undefined) {\n entries.push(entry);\n }\n }\n return entries;\n }\n\n /**\n * Rank-descending comparator with an absent-`rank`-last rule and a recency\n * (`updated`, then `seq`) tiebreak. Duplicated from the retrieve packlet's\n * `rankCompare` deliberately: the index must not depend on `retrieve` (that\n * package depends on the index), mirroring how `_recencyOrdered` inlines the\n * recency ordering rather than importing `recencyCompare`.\n */\n private static _compareByRank(a: IIndexedMemoryEntry, b: IIndexedMemoryEntry): number {\n const ra: number | undefined = a.envelope.rank;\n const rb: number | undefined = b.envelope.rank;\n // Absent rank sorts last; two absent ranks fall through to the recency tiebreak.\n if (ra === undefined && rb !== undefined) {\n return 1;\n }\n if (rb === undefined && ra !== undefined) {\n return -1;\n }\n if (ra !== undefined && rb !== undefined && ra !== rb) {\n return rb - ra;\n }\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n }\n\n /** Insert an entry and register all its derived associations. */\n private _add(entry: IIndexedMemoryEntry): void {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.envelope.id);\n const envelope: IMemoryEnvelope = entry.envelope;\n this._byKey.set(key, entry);\n this._addToSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._addToSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._addBacklink(edge.target, key, { scope: entry.scope, id: envelope.id });\n }\n }\n\n /** Remove the entry at `key` (if present) and all its derived associations. */\n private _remove(key: string): void {\n const entry: IIndexedMemoryEntry | undefined = this._byKey.get(key);\n if (entry === undefined) {\n return;\n }\n const envelope: IMemoryEnvelope = entry.envelope;\n this._byKey.delete(key);\n this._removeFromSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._removeFromSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._removeBacklink(edge.target, key);\n }\n }\n\n /** Register `source` (keyed by its composite `sourceKey`) as linking at `target`. */\n private _addBacklink(target: IEdgeTarget, sourceKey: string, source: IEdgeTarget): void {\n const targetKey: string = edgeTargetKey(target);\n const existing: Map<string, IEdgeTarget> | undefined = this._backlinks.get(targetKey);\n if (existing === undefined) {\n this._backlinks.set(targetKey, new Map<string, IEdgeTarget>([[sourceKey, source]]));\n } else {\n existing.set(sourceKey, source);\n }\n }\n\n /** Drop the backlink from `sourceKey` to `target`, removing the target map when empty. */\n private _removeBacklink(target: IEdgeTarget, sourceKey: string): void {\n const targetKey: string = edgeTargetKey(target);\n const existing: Map<string, IEdgeTarget> | undefined = this._backlinks.get(targetKey);\n if (existing === undefined) {\n return;\n }\n existing.delete(sourceKey);\n if (existing.size === 0) {\n this._backlinks.delete(targetKey);\n }\n }\n\n /** Add `member` to the set at `mapKey`, creating the set on first use. */\n private _addToSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n map.set(mapKey, new Set<M>([member]));\n } else {\n existing.add(member);\n }\n }\n\n /** Remove `member` from the set at `mapKey`, dropping the set when empty. */\n private _removeFromSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n return;\n }\n existing.delete(member);\n if (existing.size === 0) {\n map.delete(mapKey);\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/packlets/ingest/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/packlets/ingest/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.MemoryIngestOrchestrator = exports.DEFAULT_SIMILARITY_TOP_K = exports.DEFAULT_SIMILARITY_THRESHOLD = exports.CONTRADICTS_LINK_TYPE = exports.HOST_INGEST_PROVENANCE_SOURCE = void 0;
8
8
  const ts_utils_1 = require("@fgv/ts-utils");
9
9
  const types_1 = require("../types");
10
+ const store_1 = require("../store");
10
11
  const cycleGuard_1 = require("./cycleGuard");
11
12
  /**
12
13
  * The provenance source stamped on every record the ingest pipeline writes.
@@ -92,7 +93,18 @@ class MemoryIngestOrchestrator {
92
93
  async _processCandidates(item, candidates) {
93
94
  // Snapshot the store once; stage-4 resolution and the cycle guard reason over
94
95
  // the pre-ingest state.
95
- const snapshotResult = await this._store.list();
96
+ //
97
+ // DECLARED, not optimized. This reads every body in the vault on EVERY
98
+ // ingested item, and `scanEveryRecord()` is how the store now makes a caller
99
+ // say so out loud. Most of what the snapshot is used for downstream — edge
100
+ // target existence, the cycle guard's link walk, scoped-address keying — is
101
+ // envelope-only work that `listEntries()` would serve without reading a
102
+ // single file; only stage-4 layer-1's exact `{ kind, body }` match needs
103
+ // bodies, and it needs them for candidates rather than for the whole vault.
104
+ // Converting this is its own stream (`agent-memory-ingest-snapshot`), because
105
+ // it is on the write path with its own risk surface. Until then the cost is
106
+ // at least visible and greppable rather than implied.
107
+ const snapshotResult = await this._store.list((0, store_1.scanEveryRecord)());
96
108
  if (snapshotResult.isFailure()) {
97
109
  return (0, ts_utils_1.fail)(`ingest '${item.id}': failed to snapshot store: ${snapshotResult.message}`);
98
110
  }