@soulcraft/cor 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +328 -0
- package/dist/aggregation/NativeAggregationEngine.d.ts +118 -0
- package/dist/aggregation/NativeAggregationEngine.js +186 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +236 -0
- package/dist/graph/GraphAccelerationAdapter.d.ts +153 -0
- package/dist/graph/GraphAccelerationAdapter.js +326 -0
- package/dist/graph/NativeGraphAdjacencyIndex.d.ts +286 -0
- package/dist/graph/NativeGraphAdjacencyIndex.js +944 -0
- package/dist/hnsw/AdaptiveDiskAnnModeSelector.d.ts +187 -0
- package/dist/hnsw/AdaptiveDiskAnnModeSelector.js +313 -0
- package/dist/hnsw/NativeDiskAnnWrapper.d.ts +489 -0
- package/dist/hnsw/NativeDiskAnnWrapper.js +1456 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +29 -0
- package/dist/legacyLayoutGuard.d.ts +93 -0
- package/dist/legacyLayoutGuard.js +237 -0
- package/dist/license/constants.d.ts +30 -0
- package/dist/license/constants.js +30 -0
- package/dist/license/onlineValidator.d.ts +43 -0
- package/dist/license/onlineValidator.js +225 -0
- package/dist/license/types.d.ts +39 -0
- package/dist/license/types.js +5 -0
- package/dist/license.d.ts +64 -0
- package/dist/license.js +165 -0
- package/dist/migration/MigrationCoordinator.d.ts +171 -0
- package/dist/migration/MigrationCoordinator.js +249 -0
- package/dist/migration/indexEpochGuard.d.ts +163 -0
- package/dist/migration/indexEpochGuard.js +202 -0
- package/dist/native/NativeEmbeddingEngine.d.ts +79 -0
- package/dist/native/NativeEmbeddingEngine.js +318 -0
- package/dist/native/NativeRoaringBitmap32.d.ts +114 -0
- package/dist/native/NativeRoaringBitmap32.js +221 -0
- package/dist/native/ffi.d.ts +20 -0
- package/dist/native/ffi.js +48 -0
- package/dist/native/idMapperTestSupport.d.ts +67 -0
- package/dist/native/idMapperTestSupport.js +112 -0
- package/dist/native/index.d.ts +49 -0
- package/dist/native/index.js +87 -0
- package/dist/native/napi.d.ts +21 -0
- package/dist/native/napi.js +88 -0
- package/dist/native/types.d.ts +1298 -0
- package/dist/native/types.js +16 -0
- package/dist/plugin.d.ts +50 -0
- package/dist/plugin.js +388 -0
- package/dist/providerContracts.d.ts +277 -0
- package/dist/providerContracts.js +38 -0
- package/dist/resource/OsMemoryProbe.d.ts +175 -0
- package/dist/resource/OsMemoryProbe.js +206 -0
- package/dist/resource/ResourceManager.d.ts +491 -0
- package/dist/resource/ResourceManager.js +960 -0
- package/dist/utils/ColumnManifest.d.ts +97 -0
- package/dist/utils/ColumnManifest.js +129 -0
- package/dist/utils/NativeColumnStore.d.ts +284 -0
- package/dist/utils/NativeColumnStore.js +685 -0
- package/dist/utils/NativeMetadataIndex.d.ts +882 -0
- package/dist/utils/NativeMetadataIndex.js +2631 -0
- package/dist/utils/NativeUnifiedCache.d.ts +87 -0
- package/dist/utils/NativeUnifiedCache.js +273 -0
- package/dist/utils/binaryIdMapperFactory.d.ts +59 -0
- package/dist/utils/binaryIdMapperFactory.js +94 -0
- package/dist/utils/collation.d.ts +30 -0
- package/dist/utils/collation.js +40 -0
- package/dist/utils/columnStoreTypes.d.ts +161 -0
- package/dist/utils/columnStoreTypes.js +29 -0
- package/dist/utils/nativeBinaryEntityIdMapper.d.ts +211 -0
- package/dist/utils/nativeBinaryEntityIdMapper.js +381 -0
- package/dist/utils/nativeEntityIdMapper.d.ts +111 -0
- package/dist/utils/nativeEntityIdMapper.js +170 -0
- package/docs/ADR-002-diskann-100-percent-rust.md +294 -0
- package/docs/ADR-003-semantic-time-travel.md +100 -0
- package/docs/aggregation.md +251 -0
- package/docs/comparison.md +162 -0
- package/docs/deployment-limits.md +87 -0
- package/docs/diskann.md +184 -0
- package/docs/migration-3.0.md +396 -0
- package/docs/performance-budget.md +274 -0
- package/docs/performance.md +117 -0
- package/docs/scaling.md +439 -0
- package/docs/snapshot-safety.md +246 -0
- package/docs/u64-id-space.md +214 -0
- package/docs/verification-report.md +670 -0
- package/native/brainy-native.node +0 -0
- package/native/index.d.ts +3916 -0
- package/package.json +92 -0
- package/scripts/migrate-cortex-2x-to-3x.mjs +970 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providerContracts
|
|
3
|
+
* @description Cor-local copies of brainy's provider contracts — the EXACT
|
|
4
|
+
* method/property surface brainy calls on each native provider cor registers.
|
|
5
|
+
*
|
|
6
|
+
* Cor's wrappers `implements` these, so dropping or drifting a member brainy
|
|
7
|
+
* depends on becomes a compile error here (not a runtime crash when the code
|
|
8
|
+
* path first runs with cor active). This is the compile-time half of the
|
|
9
|
+
* provider-parity guarantee; `scripts/check-brainy-compat.mjs` is the runtime
|
|
10
|
+
* half (it instantiates each provider and asserts the same surface).
|
|
11
|
+
*
|
|
12
|
+
* ## Why a local copy
|
|
13
|
+
*
|
|
14
|
+
* These interfaces are exported from brainy's `@soulcraft/brainy/plugin`
|
|
15
|
+
* entrypoint, but only from the brainy release that ships alongside cor
|
|
16
|
+
* 2.3.0 — they are NOT in published brainy 7.24.0, which cor currently
|
|
17
|
+
* builds against. So cor keeps a local copy (exactly as it already does for
|
|
18
|
+
* `ColumnStoreProvider` and `EntityIdMapperLike` in {@link module:utils/columnStoreTypes}
|
|
19
|
+
* and for the collation routine — see `docs/ADR-001`). The copies MUST stay in
|
|
20
|
+
* lockstep with brainy's `src/plugin.ts`. When cor bumps its brainy
|
|
21
|
+
* dependency to the release that exports them, replace this file's interface
|
|
22
|
+
* bodies with re-exports from `@soulcraft/brainy/plugin`:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* export type {
|
|
26
|
+
* MetadataIndexProvider, GraphIndexProvider, HnswProvider,
|
|
27
|
+
* EntityIdMapperProvider, CacheProvider,
|
|
28
|
+
* } from '@soulcraft/brainy/plugin'
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* `AggregationProvider` is intentionally absent here: it is already a published
|
|
32
|
+
* export of brainy 7.24.0, so `NativeAggregationProvider` implements it directly
|
|
33
|
+
* from `@soulcraft/brainy`. `ColumnStoreProvider` likewise lives in
|
|
34
|
+
* {@link module:utils/columnStoreTypes} (its bitmap types reference cor's
|
|
35
|
+
* binary-compatible `RoaringBitmap32`).
|
|
36
|
+
*/
|
|
37
|
+
import type { Vector, VectorDocument, GraphVerb, NounType, VerbType } from '@soulcraft/brainy';
|
|
38
|
+
import type { ColumnStoreProvider } from './utils/columnStoreTypes.js';
|
|
39
|
+
/**
|
|
40
|
+
* @description The `'metadataIndex'` provider contract — the surface brainy
|
|
41
|
+
* calls via `this.metadataIndex.*` (plus the transactional add/remove
|
|
42
|
+
* operations). Mirror of brainy's `MetadataIndexProvider`.
|
|
43
|
+
*/
|
|
44
|
+
export interface MetadataIndexProvider {
|
|
45
|
+
init(): Promise<void>;
|
|
46
|
+
flush(): Promise<void>;
|
|
47
|
+
rebuild(): Promise<void>;
|
|
48
|
+
addToIndex(id: string, entityOrMetadata: any, skipFlush?: boolean, deferWrites?: boolean): Promise<void>;
|
|
49
|
+
removeFromIndex(id: string, metadata?: any): Promise<void>;
|
|
50
|
+
getIds(field: string, value: any): Promise<string[]>;
|
|
51
|
+
getIdsForFilter(filter: any, opts?: {
|
|
52
|
+
limit?: number;
|
|
53
|
+
offset?: number;
|
|
54
|
+
}): Promise<string[]>;
|
|
55
|
+
getIdsForTextQuery(query: string): Promise<Array<{
|
|
56
|
+
id: string;
|
|
57
|
+
matchCount: number;
|
|
58
|
+
}>>;
|
|
59
|
+
getSortedIdsForFilter(filter: any, orderBy: string, order?: 'asc' | 'desc', topK?: number): Promise<string[]>;
|
|
60
|
+
getFilterValues(field: string): Promise<string[]>;
|
|
61
|
+
getFilterFields(): Promise<string[]>;
|
|
62
|
+
getFieldValueForEntity(entityId: string, field: string): Promise<any>;
|
|
63
|
+
getFieldsForType(nounType: NounType): Promise<Array<{
|
|
64
|
+
field: string;
|
|
65
|
+
affinity: number;
|
|
66
|
+
occurrences: number;
|
|
67
|
+
totalEntities: number;
|
|
68
|
+
}>>;
|
|
69
|
+
getFieldStatistics(): Promise<Map<string, unknown>>;
|
|
70
|
+
getFieldsWithCardinality(): Promise<Array<{
|
|
71
|
+
field: string;
|
|
72
|
+
cardinality: number;
|
|
73
|
+
distribution: string;
|
|
74
|
+
}>>;
|
|
75
|
+
getOptimalQueryPlan(filters: Record<string, any>): Promise<unknown>;
|
|
76
|
+
/** Report which index path a `where` clause on `field` will hit (drives `brain.explain()`). */
|
|
77
|
+
explainField(field: string): Promise<{
|
|
78
|
+
path: 'column-store' | 'sparse-chunked' | 'none';
|
|
79
|
+
notes?: string;
|
|
80
|
+
}>;
|
|
81
|
+
getCountForCriteria(field: string, value: any): Promise<number>;
|
|
82
|
+
getEntityCountByType(type: string): number;
|
|
83
|
+
getEntityCountByTypeEnum(type: NounType): number;
|
|
84
|
+
getTotalEntityCount(): number;
|
|
85
|
+
getAllEntityCounts(): Map<string, number>;
|
|
86
|
+
getTopNounTypes(n: number): NounType[];
|
|
87
|
+
getTopVerbTypes(n: number): VerbType[];
|
|
88
|
+
getAllNounTypeCounts(): Map<NounType, number>;
|
|
89
|
+
getAllVerbTypeCounts(): Map<VerbType, number>;
|
|
90
|
+
getAllVFSEntityCounts(): Promise<Map<string, number>>;
|
|
91
|
+
detectAndRepairCorruption(): Promise<void>;
|
|
92
|
+
validateConsistency(): Promise<{
|
|
93
|
+
healthy: boolean;
|
|
94
|
+
avgEntriesPerEntity: number;
|
|
95
|
+
entityCount: number;
|
|
96
|
+
indexEntryCount: number;
|
|
97
|
+
recommendation: string | null;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* O(1)-ish cross-bucket consistency probe. Brainy rc.6+ calls this ONCE on
|
|
101
|
+
* the first read; on `false` it runs `detectAndRepairCorruption()`. Returns
|
|
102
|
+
* `true` if healthy (or indeterminate), `false` if a cross-bucket phantom is
|
|
103
|
+
* sampled. Best-effort — never throws into the read path.
|
|
104
|
+
*/
|
|
105
|
+
probeConsistency(): Promise<boolean>;
|
|
106
|
+
tokenize(text: string): string[];
|
|
107
|
+
extractTextContent(data: any): string;
|
|
108
|
+
getStats(): Promise<{
|
|
109
|
+
totalEntries: number;
|
|
110
|
+
totalIds: number;
|
|
111
|
+
fieldsIndexed: string[];
|
|
112
|
+
lastRebuild: number;
|
|
113
|
+
indexSize: number;
|
|
114
|
+
}>;
|
|
115
|
+
/** The shared UUID ↔ int mapper. Brainy reads `.getUuid(intId)` off the result. */
|
|
116
|
+
getIdMapper(): {
|
|
117
|
+
getUuid(intId: number): string | undefined;
|
|
118
|
+
};
|
|
119
|
+
/** The column store the coordinator delegates `where`/`orderBy` to. */
|
|
120
|
+
readonly columnStore: ColumnStoreProvider;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @description The `'graphIndex'` provider contract — the surface brainy calls
|
|
124
|
+
* via `this.graphIndex.*` (some optional-chained). Mirror of brainy's
|
|
125
|
+
* `GraphIndexProvider`.
|
|
126
|
+
*
|
|
127
|
+
* **Cor 3.0 Piece D**: entity ids cross as `bigint` (the canonical u64
|
|
128
|
+
* from brainy's `BinaryIdMapper`). Verb-ids likewise cross as `bigint`
|
|
129
|
+
* (the verb-int interned via cor's `verb_id_namespace`). Brainy 8.0
|
|
130
|
+
* owns UUID ↔ int conversion on its side via the same `BinaryIdMapper`
|
|
131
|
+
* it already maintains. The legacy string-id surface is retired —
|
|
132
|
+
* brainy 7.x consumers will not work against this contract.
|
|
133
|
+
*/
|
|
134
|
+
export interface GraphIndexProvider {
|
|
135
|
+
/** `false` until the index has loaded; brainy probes this before fast paths. */
|
|
136
|
+
readonly isInitialized: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Eagerly cold-load the durable graph (the four u64 LSM trees) from
|
|
139
|
+
* persistence. Brainy 8.0 (#36) awaits this right after
|
|
140
|
+
* `metadataIndex.init()` and BEFORE consulting {@link isReady}, so the
|
|
141
|
+
* rebuild gate reads an honest readiness signal. Idempotent and a no-op
|
|
142
|
+
* for an in-memory (no `persistence_dir`) index. Mirrors
|
|
143
|
+
* {@link MetadataIndexProvider.init}.
|
|
144
|
+
*/
|
|
145
|
+
init(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether the graph's edges are loaded and queryable WITHOUT a rebuild —
|
|
148
|
+
* brainy's rebuild gate (#36). `true` once the durable cold-load restored
|
|
149
|
+
* the adjacency (so brainy SKIPS its O(E) rebuild-from-storage), or while
|
|
150
|
+
* live edges sit in a memtable. Edges-loaded semantics ONLY — never gated
|
|
151
|
+
* on the verb-id membership walk. Synchronous (no await).
|
|
152
|
+
*/
|
|
153
|
+
isReady(): boolean;
|
|
154
|
+
getNeighbors(id: bigint, optionsOrDirection?: {
|
|
155
|
+
direction?: 'in' | 'out' | 'both';
|
|
156
|
+
limit?: number;
|
|
157
|
+
offset?: number;
|
|
158
|
+
} | 'in' | 'out' | 'both'): Promise<bigint[]>;
|
|
159
|
+
getVerbIdsBySource(sourceInt: bigint, options?: {
|
|
160
|
+
limit?: number;
|
|
161
|
+
offset?: number;
|
|
162
|
+
}): Promise<bigint[]>;
|
|
163
|
+
getVerbIdsByTarget(targetInt: bigint, options?: {
|
|
164
|
+
limit?: number;
|
|
165
|
+
offset?: number;
|
|
166
|
+
}): Promise<bigint[]>;
|
|
167
|
+
/** Resolve interned verb ints back to verb-id strings (null per missing int).
|
|
168
|
+
* brainy hard-calls this to hydrate edge verb-ids; mirrored here so the
|
|
169
|
+
* `implements` guard catches any future drift on it. (#79 cluster C.) */
|
|
170
|
+
verbIntsToIds(verbInts: bigint[]): Promise<(string | null)[]>;
|
|
171
|
+
getVerbsBatchCached(verbIds: string[]): Promise<Map<string, GraphVerb>>;
|
|
172
|
+
rebuild(): Promise<void>;
|
|
173
|
+
flush(): Promise<void>;
|
|
174
|
+
close(): Promise<void>;
|
|
175
|
+
size(): number;
|
|
176
|
+
getStats(): {
|
|
177
|
+
totalRelationships: number;
|
|
178
|
+
sourceNodes: number;
|
|
179
|
+
targetNodes: number;
|
|
180
|
+
memoryUsage: number;
|
|
181
|
+
lastRebuild: number;
|
|
182
|
+
rebuildTime: number;
|
|
183
|
+
};
|
|
184
|
+
getRelationshipStats(): {
|
|
185
|
+
totalRelationships: number;
|
|
186
|
+
relationshipsByType: Record<string, number>;
|
|
187
|
+
uniqueSourceNodes: number;
|
|
188
|
+
uniqueTargetNodes: number;
|
|
189
|
+
totalNodes: number;
|
|
190
|
+
};
|
|
191
|
+
getRelationshipCountByType(type: string): number;
|
|
192
|
+
getTotalRelationshipCount(): number;
|
|
193
|
+
getAllRelationshipCounts(): Map<string, number>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* @description The object returned by the `'vector'` provider factory
|
|
197
|
+
* — the surface brainy hard-calls via `this.index.*` plus the
|
|
198
|
+
* transactional add/remove operations. Mirror of brainy 8.0's
|
|
199
|
+
* `VectorIndexProvider`.
|
|
200
|
+
*
|
|
201
|
+
* Cor's implementation is [[`NativeDiskAnnWrapper`]] (Adaptive
|
|
202
|
+
* DiskANN). Brainy 8.0 keeps its own pure-JS HNSW for the standalone
|
|
203
|
+
* open-source path (~10 M entities) — the contract name is shared
|
|
204
|
+
* vocabulary so brainy can swap implementations transparently.
|
|
205
|
+
*
|
|
206
|
+
* `enableCOW`, `getItem`, and `setPersistMode` are intentionally
|
|
207
|
+
* absent: brainy feature-detects each (`typeof x === 'function'`),
|
|
208
|
+
* so they are optional, not part of the required contract.
|
|
209
|
+
*/
|
|
210
|
+
export interface VectorIndexProvider {
|
|
211
|
+
addItem(item: VectorDocument): Promise<string>;
|
|
212
|
+
removeItem(id: string): Promise<boolean>;
|
|
213
|
+
search(queryVector: Vector, k?: number, filter?: (id: string) => Promise<boolean>, options?: {
|
|
214
|
+
rerank?: {
|
|
215
|
+
multiplier: number;
|
|
216
|
+
};
|
|
217
|
+
candidateIds?: string[];
|
|
218
|
+
/**
|
|
219
|
+
* **Predicate pushdown (#10).** The metadata∩graph universe (entity
|
|
220
|
+
* UUIDs) brainy's `find()` has already computed for this query. When
|
|
221
|
+
* supplied and selective, cor pushes it INTO the native beam walk
|
|
222
|
+
* (collect only allowed slots, walk wider) instead of post-filtering —
|
|
223
|
+
* far higher recall on selective filters. brainy feature-detects this:
|
|
224
|
+
* passing `allowedIds` is optional and a provider may ignore it (the
|
|
225
|
+
* pure-JS path falls back to `filter`). Coordinate the matching
|
|
226
|
+
* addition to brainy 8.0's `VectorIndexProvider.search` contract +
|
|
227
|
+
* `find()` wiring via PLATFORM-HANDOFF (CTX-PUSHDOWN-ALLOWEDIDS).
|
|
228
|
+
*/
|
|
229
|
+
allowedIds?: ReadonlySet<string>;
|
|
230
|
+
}): Promise<Array<[string, number]>>;
|
|
231
|
+
size(): number;
|
|
232
|
+
clear(): void;
|
|
233
|
+
rebuild(options?: any): Promise<void>;
|
|
234
|
+
flush(): Promise<number>;
|
|
235
|
+
getPersistMode(): 'immediate' | 'deferred';
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* @description The `'entityIdMapper'` provider contract — a drop-in for brainy's
|
|
239
|
+
* `EntityIdMapper`. Injected into brainy's TypeScript `MetadataIndexManager`
|
|
240
|
+
* when a native metadata index is not also registered; that coordinator calls
|
|
241
|
+
* this full surface (incl. `getAllIntIds`, the all-ids universe brainy uses for
|
|
242
|
+
* negation / `exists:false` filters). Mirror of brainy's `EntityIdMapperProvider`.
|
|
243
|
+
*/
|
|
244
|
+
export interface EntityIdMapperProvider {
|
|
245
|
+
init(): Promise<void>;
|
|
246
|
+
getOrAssign(uuid: string): number;
|
|
247
|
+
getUuid(intId: number): string | undefined;
|
|
248
|
+
getInt(uuid: string): number | undefined;
|
|
249
|
+
remove(uuid: string): boolean;
|
|
250
|
+
flush(): Promise<void>;
|
|
251
|
+
clear(): Promise<void>;
|
|
252
|
+
getAllIntIds(): number[];
|
|
253
|
+
intsIterableToUuids(ints: Iterable<number>): string[];
|
|
254
|
+
readonly size: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* @description Vector-index cache category union. Four hot working-
|
|
258
|
+
* set slices brainy + cor coordinate cache budget across:
|
|
259
|
+
* `'vectors'` (graph hops + PQ codes pages), `'metadata'` (LSM block
|
|
260
|
+
* cache), `'embedding'` (embedding model cache), and `'other'`
|
|
261
|
+
* (catch-all).
|
|
262
|
+
*/
|
|
263
|
+
export type CacheCategory = 'vectors' | 'metadata' | 'embedding' | 'other';
|
|
264
|
+
/**
|
|
265
|
+
* @description The `'cache'` provider contract — a drop-in for
|
|
266
|
+
* brainy's `UnifiedCache`. Brainy installs it as the global cache
|
|
267
|
+
* (`setGlobalCache`) and calls this surface via `getGlobalCache()`.
|
|
268
|
+
* Mirror of brainy's `CacheProvider`.
|
|
269
|
+
*/
|
|
270
|
+
export interface CacheProvider {
|
|
271
|
+
getSync(key: string): any | undefined;
|
|
272
|
+
set(key: string, data: any, type: CacheCategory, size: number, rebuildCost?: number): void;
|
|
273
|
+
delete(key: string): boolean;
|
|
274
|
+
deleteByPrefix(prefix: string): number;
|
|
275
|
+
clear(type?: CacheCategory): void;
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=providerContracts.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providerContracts
|
|
3
|
+
* @description Cor-local copies of brainy's provider contracts — the EXACT
|
|
4
|
+
* method/property surface brainy calls on each native provider cor registers.
|
|
5
|
+
*
|
|
6
|
+
* Cor's wrappers `implements` these, so dropping or drifting a member brainy
|
|
7
|
+
* depends on becomes a compile error here (not a runtime crash when the code
|
|
8
|
+
* path first runs with cor active). This is the compile-time half of the
|
|
9
|
+
* provider-parity guarantee; `scripts/check-brainy-compat.mjs` is the runtime
|
|
10
|
+
* half (it instantiates each provider and asserts the same surface).
|
|
11
|
+
*
|
|
12
|
+
* ## Why a local copy
|
|
13
|
+
*
|
|
14
|
+
* These interfaces are exported from brainy's `@soulcraft/brainy/plugin`
|
|
15
|
+
* entrypoint, but only from the brainy release that ships alongside cor
|
|
16
|
+
* 2.3.0 — they are NOT in published brainy 7.24.0, which cor currently
|
|
17
|
+
* builds against. So cor keeps a local copy (exactly as it already does for
|
|
18
|
+
* `ColumnStoreProvider` and `EntityIdMapperLike` in {@link module:utils/columnStoreTypes}
|
|
19
|
+
* and for the collation routine — see `docs/ADR-001`). The copies MUST stay in
|
|
20
|
+
* lockstep with brainy's `src/plugin.ts`. When cor bumps its brainy
|
|
21
|
+
* dependency to the release that exports them, replace this file's interface
|
|
22
|
+
* bodies with re-exports from `@soulcraft/brainy/plugin`:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* export type {
|
|
26
|
+
* MetadataIndexProvider, GraphIndexProvider, HnswProvider,
|
|
27
|
+
* EntityIdMapperProvider, CacheProvider,
|
|
28
|
+
* } from '@soulcraft/brainy/plugin'
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* `AggregationProvider` is intentionally absent here: it is already a published
|
|
32
|
+
* export of brainy 7.24.0, so `NativeAggregationProvider` implements it directly
|
|
33
|
+
* from `@soulcraft/brainy`. `ColumnStoreProvider` likewise lives in
|
|
34
|
+
* {@link module:utils/columnStoreTypes} (its bitmap types reference cor's
|
|
35
|
+
* binary-compatible `RoaringBitmap32`).
|
|
36
|
+
*/
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=providerContracts.js.map
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module resource/OsMemoryProbe
|
|
3
|
+
* @description OS-level memory observer for the cor 3.0 **Adaptive
|
|
4
|
+
* DiskANN** mode selector (Piece J of the cor 3.0 plan).
|
|
5
|
+
*
|
|
6
|
+
* The {@link ResourceManager} already observes the V8 heap and a
|
|
7
|
+
* coarse system-RSS pressure ratio (Piece 8). What it didn't have
|
|
8
|
+
* was a read on the kernel's `MemAvailable` figure — the metric the
|
|
9
|
+
* Linux kernel computes as "how much physical RAM can a new
|
|
10
|
+
* allocation claim without swapping," factoring in reclaimable page
|
|
11
|
+
* cache and slab. That's the right signal for the adaptive selector
|
|
12
|
+
* to pick a DiskANN open mode in multi-tenant scenarios where a
|
|
13
|
+
* shared box runs many brainy+cor instances: each instance's
|
|
14
|
+
* `os.freemem()` undercounts available memory (it reports MemFree,
|
|
15
|
+
* not MemAvailable), so a naïve `freemem`-based check would push
|
|
16
|
+
* the selector toward OnDisk hints even when there's plenty of
|
|
17
|
+
* reclaimable cache available.
|
|
18
|
+
*
|
|
19
|
+
* ## Surface
|
|
20
|
+
*
|
|
21
|
+
* - {@link parseMeminfo} — pure parser; fixture-friendly.
|
|
22
|
+
* - {@link OsMemoryProbe} — readers + caching wrapper. Dependency-
|
|
23
|
+
* injected so tests can simulate Linux on macOS and exercise the
|
|
24
|
+
* `MemAvailable` missing branch without touching the real
|
|
25
|
+
* `/proc/meminfo`.
|
|
26
|
+
*
|
|
27
|
+
* ## Why a cache
|
|
28
|
+
*
|
|
29
|
+
* `/proc/meminfo` reads cost ~10 μs of syscall time — not free, but
|
|
30
|
+
* also not worth re-reading on every single call. The 250 ms cache
|
|
31
|
+
* is comfortably below the 5 s pressure-tick cadence and the 30 s
|
|
32
|
+
* rebalance cadence the ResourceManager already runs, so any
|
|
33
|
+
* meaningful pressure event lands on a fresh read.
|
|
34
|
+
*
|
|
35
|
+
* ## Non-Linux fallback
|
|
36
|
+
*
|
|
37
|
+
* On macOS and Windows there is no `/proc/meminfo`. The probe falls
|
|
38
|
+
* back to `os.totalmem()` + `os.freemem()` and marks the snapshot
|
|
39
|
+
* `source: 'os-fallback'` so callers can degrade gracefully (the
|
|
40
|
+
* adaptive selector currently treats fallback snapshots as
|
|
41
|
+
* "available bytes is conservative, prefer Hybrid over OnDisk").
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Snapshot of OS-level memory state at observation time. All byte
|
|
45
|
+
* fields are in absolute bytes (the on-disk units in `/proc/meminfo`
|
|
46
|
+
* are KiB; the parser converts).
|
|
47
|
+
*/
|
|
48
|
+
export interface OsMemorySnapshot {
|
|
49
|
+
/**
|
|
50
|
+
* Total physical RAM on the machine — the `MemTotal` line in
|
|
51
|
+
* `/proc/meminfo`, or `os.totalmem()` on non-Linux fallback.
|
|
52
|
+
*/
|
|
53
|
+
totalBytes: number;
|
|
54
|
+
/**
|
|
55
|
+
* Memory the kernel reports as available for new allocations
|
|
56
|
+
* without swapping. On Linux ≥ 3.14, this is the `MemAvailable`
|
|
57
|
+
* line — accounts for reclaimable page cache + slab. On older
|
|
58
|
+
* kernels and on the os-fallback path, falls back to
|
|
59
|
+
* {@link freeBytes}.
|
|
60
|
+
*
|
|
61
|
+
* This is the load-bearing field for the Adaptive DiskANN mode
|
|
62
|
+
* selector: it answers "can this brain afford to keep PQ codes
|
|
63
|
+
* RAM-resident?".
|
|
64
|
+
*/
|
|
65
|
+
availableBytes: number;
|
|
66
|
+
/**
|
|
67
|
+
* Physically free memory — the `MemFree` line in `/proc/meminfo`,
|
|
68
|
+
* or `os.freemem()` on non-Linux fallback. Smaller than
|
|
69
|
+
* {@link availableBytes} on a healthy Linux system because it
|
|
70
|
+
* excludes reclaimable page cache.
|
|
71
|
+
*/
|
|
72
|
+
freeBytes: number;
|
|
73
|
+
/**
|
|
74
|
+
* `1 - (availableBytes / totalBytes)` clamped to `[0, 1]`. A high
|
|
75
|
+
* pressure score means little headroom for new allocations; the
|
|
76
|
+
* adaptive selector uses this as the primary mode-down signal.
|
|
77
|
+
*/
|
|
78
|
+
pressureScore: number;
|
|
79
|
+
/**
|
|
80
|
+
* `'proc-meminfo'` when the values came from a successful
|
|
81
|
+
* `/proc/meminfo` read; `'os-fallback'` when the probe degraded
|
|
82
|
+
* to `os.totalmem()`/`os.freemem()`. Surface for diagnostics —
|
|
83
|
+
* a fallback snapshot is a hint that the deployment is on macOS
|
|
84
|
+
* or Windows.
|
|
85
|
+
*/
|
|
86
|
+
source: 'proc-meminfo' | 'os-fallback';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Subset of `/proc/meminfo` lines the probe cares about. Returned by
|
|
90
|
+
* {@link parseMeminfo} so the snapshot composition stays unit-
|
|
91
|
+
* testable.
|
|
92
|
+
*/
|
|
93
|
+
export interface MeminfoFields {
|
|
94
|
+
totalKib?: number;
|
|
95
|
+
availableKib?: number;
|
|
96
|
+
freeKib?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse a `/proc/meminfo` text blob and extract the three fields the
|
|
100
|
+
* probe needs. Pure function — no I/O, fully deterministic, the
|
|
101
|
+
* only thing fixture tests need to cover.
|
|
102
|
+
*
|
|
103
|
+
* Returns `null` only when `MemTotal` is missing, which would mean
|
|
104
|
+
* the input isn't `/proc/meminfo` at all (every Linux kernel since
|
|
105
|
+
* the file existed has emitted it). Missing `MemAvailable` or
|
|
106
|
+
* `MemFree` is normal on old or specialised kernels and is left for
|
|
107
|
+
* the snapshot composer to handle.
|
|
108
|
+
*/
|
|
109
|
+
export declare function parseMeminfo(text: string): MeminfoFields | null;
|
|
110
|
+
/**
|
|
111
|
+
* Build an {@link OsMemorySnapshot} from the parsed `/proc/meminfo`
|
|
112
|
+
* fields. Visible for tests; production callers use
|
|
113
|
+
* {@link OsMemoryProbe.snapshot}.
|
|
114
|
+
*/
|
|
115
|
+
export declare function snapshotFromMeminfo(fields: MeminfoFields): OsMemorySnapshot;
|
|
116
|
+
/**
|
|
117
|
+
* Build the os-fallback snapshot from Node's `os` module. Visible
|
|
118
|
+
* for tests; production callers use {@link OsMemoryProbe.snapshot}.
|
|
119
|
+
*/
|
|
120
|
+
export declare function snapshotFromOs(): OsMemorySnapshot;
|
|
121
|
+
/**
|
|
122
|
+
* Optional config for {@link OsMemoryProbe}. All fields are mainly
|
|
123
|
+
* for tests — production callers construct with defaults.
|
|
124
|
+
*/
|
|
125
|
+
export interface OsMemoryProbeOptions {
|
|
126
|
+
/**
|
|
127
|
+
* Cache TTL in milliseconds. The snapshot is reused for repeated
|
|
128
|
+
* calls within this window. Default 250 ms — comfortably below
|
|
129
|
+
* the ResourceManager's 5 s pressure-tick.
|
|
130
|
+
*/
|
|
131
|
+
cacheMs?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Override the `/proc/meminfo` reader. Tests inject custom text
|
|
134
|
+
* to exercise the parser's edge cases without touching the real
|
|
135
|
+
* filesystem.
|
|
136
|
+
*/
|
|
137
|
+
procReader?: () => string | null;
|
|
138
|
+
/**
|
|
139
|
+
* Override the os-fallback snapshot generator. Tests use this to
|
|
140
|
+
* pin the fallback shape without depending on the host's actual
|
|
141
|
+
* `os.totalmem()` reading.
|
|
142
|
+
*/
|
|
143
|
+
osFallback?: () => OsMemorySnapshot;
|
|
144
|
+
/**
|
|
145
|
+
* Override the wall clock used for cache expiry. Tests pass a
|
|
146
|
+
* controllable timestamp source to assert cache behaviour
|
|
147
|
+
* deterministically.
|
|
148
|
+
*/
|
|
149
|
+
now?: () => number;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Cached `/proc/meminfo` observer. Wire one instance into the
|
|
153
|
+
* {@link ResourceManager}; the adaptive DiskANN selector (Piece I)
|
|
154
|
+
* will read `snapshot()` at brain-open time.
|
|
155
|
+
*/
|
|
156
|
+
export declare class OsMemoryProbe {
|
|
157
|
+
private readonly cacheMs;
|
|
158
|
+
private readonly procReader;
|
|
159
|
+
private readonly osFallback;
|
|
160
|
+
private readonly now;
|
|
161
|
+
private cached;
|
|
162
|
+
constructor(options?: OsMemoryProbeOptions);
|
|
163
|
+
/**
|
|
164
|
+
* Latest memory snapshot. Cached for {@link OsMemoryProbeOptions.cacheMs}
|
|
165
|
+
* milliseconds; calls inside the window reuse the cached value.
|
|
166
|
+
*/
|
|
167
|
+
snapshot(): OsMemorySnapshot;
|
|
168
|
+
/**
|
|
169
|
+
* Invalidate the cache so the next {@link snapshot} call performs
|
|
170
|
+
* a fresh read. Used by tests; production callers shouldn't need
|
|
171
|
+
* this because the cache TTL is short.
|
|
172
|
+
*/
|
|
173
|
+
invalidate(): void;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=OsMemoryProbe.d.ts.map
|