@soulcraft/cor 3.0.16 → 3.0.18

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.
@@ -133,6 +133,21 @@ export declare class MetadataIndexManager implements MetadataIndexProvider {
133
133
  * init() (`columnStore.init` / `warmCache` / `lazyLoadCounts`) on shared state.
134
134
  */
135
135
  private epochMigrationPending;
136
+ /**
137
+ * TRUE when {@link wireIdMapper}'s factory CREATED the mmap mapper fresh
138
+ * this open (both `_id_mapper/*` stores were absent). Benign on a truly
139
+ * fresh brain; POISON when durable int-keyed postings survive alongside
140
+ * it (a lost/deleted `_id_mapper/` directory) — every surviving posting
141
+ * references ints the new mapper never assigned, and minting would pair
142
+ * NEW ints against OLD-int postings silently. Detected right after the
143
+ * LSM cold-open; the response is the coordinated full rebuild.
144
+ */
145
+ private idMapperCreatedFresh;
146
+ /** TRUE when the lost-mapper guard fired this open: the coordinated
147
+ * rebuild must complete BEFORE init returns (blocking), because until
148
+ * vector+graph re-mint, their durable state pairs old ints with a
149
+ * mapper that never assigned them — strictly unservable. */
150
+ private lostMapperHeal;
136
151
  private lastFlushTime;
137
152
  private autoFlushThreshold;
138
153
  private dirtyFields;
@@ -563,6 +578,16 @@ export declare class MetadataIndexManager implements MetadataIndexProvider {
563
578
  * same rebuild). Skipped at/above the u32 saturation point of
564
579
  * `getTotalEntityCount` (a saturated count would make equality lie).
565
580
  */
581
+ /**
582
+ * The verified-unpostable allowance for posted-vs-canonical floors: how
583
+ * many canonical noun rows the last COMPLETED rebuild PROVED carry no
584
+ * readable metadata (each verified by direct read at rebuild time, each
585
+ * RE-VERIFIED here so an id that has since gained metadata stops
586
+ * counting). Beyond {@link UNPOSTABLE_ID_CAP} the stamp is count-only
587
+ * and the allowance carries a bounded, logged staleness caveat.
588
+ * Advisory: any fault reads as 0 (may over-heal, never under-detects).
589
+ */
590
+ private verifiedUnpostableAllowance;
566
591
  private detectDerivedStrand;
567
592
  /**
568
593
  * **#72 Phase C.** Build the shared mmap `BinaryIdMapper` from the
@@ -35,6 +35,7 @@ const BUCKETED_INDEX_FIELDS = new Set([
35
35
  import { TypeUtils, NOUN_TYPE_COUNT, VERB_TYPE_COUNT } from '@soulcraft/brainy/types/graphTypes';
36
36
  import { loadNativeModule } from '../native/index.js';
37
37
  import { composeInvariantReport } from './invariantReport.js';
38
+ import { opsLine } from './opsLog.js';
38
39
  import { declareDerivedFamilies, METADATA_FAMILIES } from './derivedFamilies.js';
39
40
  import { openOrCreateBinaryIdMapper } from './binaryIdMapperFactory.js';
40
41
  import { NativeColumnStore } from './NativeColumnStore.js';
@@ -73,6 +74,20 @@ const LSM_MANIFEST_VERSION = 2;
73
74
  * field registry already depends on.
74
75
  */
75
76
  const LSM_MANIFEST_KEY = '__metadata_lsm_manifest__';
77
+ /**
78
+ * Durable stamp of the entities a COMPLETED rebuild verified as
79
+ * unpostable (canonical rows with NO readable metadata — verified by
80
+ * direct read, not invented postings). The strand detector's
81
+ * posted-count floor accounts for them: without this, a fixed cohort of
82
+ * metadata-less canonical rows makes EVERY boot read as stranded and
83
+ * re-triggers a pointless full heal forever (memory-vm's constant-52,
84
+ * CORTEX-RESTART-STRAND 2026-07-13 — four consecutive boots).
85
+ */
86
+ const UNPOSTABLE_STAMP_KEY = '__metadata_verified_unpostable__';
87
+ /** Above this many ids the stamp stores count-only (the boot-time
88
+ * re-verify would stop being cheap); detection then carries a bounded
89
+ * staleness caveat, logged when it engages. */
90
+ const UNPOSTABLE_ID_CAP = 1000;
76
91
  /**
77
92
  * **LSM durability (step 5).** Lower clamp (32 MiB) for the bounded-memtable
78
93
  * size-flush trigger. Even when the dynamic 'metadata' budget is tiny, the
@@ -208,6 +223,21 @@ export class MetadataIndexManager {
208
223
  * init() (`columnStore.init` / `warmCache` / `lazyLoadCounts`) on shared state.
209
224
  */
210
225
  epochMigrationPending = false;
226
+ /**
227
+ * TRUE when {@link wireIdMapper}'s factory CREATED the mmap mapper fresh
228
+ * this open (both `_id_mapper/*` stores were absent). Benign on a truly
229
+ * fresh brain; POISON when durable int-keyed postings survive alongside
230
+ * it (a lost/deleted `_id_mapper/` directory) — every surviving posting
231
+ * references ints the new mapper never assigned, and minting would pair
232
+ * NEW ints against OLD-int postings silently. Detected right after the
233
+ * LSM cold-open; the response is the coordinated full rebuild.
234
+ */
235
+ idMapperCreatedFresh = false;
236
+ /** TRUE when the lost-mapper guard fired this open: the coordinated
237
+ * rebuild must complete BEFORE init returns (blocking), because until
238
+ * vector+graph re-mint, their durable state pairs old ints with a
239
+ * mapper that never assigned them — strictly unservable. */
240
+ lostMapperHeal = false;
211
241
  lastFlushTime = Date.now();
212
242
  autoFlushThreshold = 10;
213
243
  dirtyFields = new Set();
@@ -1109,6 +1139,36 @@ export class MetadataIndexManager {
1109
1139
  // with NO O(N) rebuild. Runs after wireIdMapper (the engine's posting
1110
1140
  // lists reference the mapper's entity ints) and before any read/mutation.
1111
1141
  await this.openLsmEngine();
1142
+ // LOST-MAPPER GUARD (MEMORY-COR-IDMAP-MIGRATION, root-caused
1143
+ // 2026-07-14): the ONE genuinely dangerous open-state — the mmap
1144
+ // mapper was just created EMPTY while durable int-keyed postings
1145
+ // survive. (Empirically: 3.0.x-born brains carry their mapper and
1146
+ // upgrade cleanly; this cell arises from a lost/deleted `_id_mapper/`
1147
+ // directory, e.g. deleter-era damage.) Serving would resolve every
1148
+ // surviving posting through ints the mapper never assigned, and the
1149
+ // 3.0.16 mint would pair NEW ints against OLD-int postings silently.
1150
+ // Response: loud, then the coordinated full rebuild (metadata →
1151
+ // vector → graph under the migration lock) so re-minted ints are
1152
+ // globally consistent; strandDetected is the belt when no
1153
+ // coordinator is wired (raw/test usage) so the metadata leg at least
1154
+ // reports not-ready instead of serving wrong pairings.
1155
+ // The trigger is EMPTINESS, not who-created-it: TWO entry points open
1156
+ // `_id_mapper/*` (this manager and the plugin's entityIdMapper
1157
+ // provider), and whichever runs first re-creates the directories — a
1158
+ // created-fresh flag from one path is blind to the other. An EMPTY
1159
+ // mapper alongside durable postings is the poison regardless of how
1160
+ // it got empty (deleted directory, truncated store).
1161
+ const mapperEmpty = this.native.entityIdMapperSize() === 0;
1162
+ if ((this.idMapperCreatedFresh || mapperEmpty) && this.lsmHasDurableState()) {
1163
+ opsLine(`LOST-MAPPER: _id_mapper/ was recreated EMPTY while durable ` +
1164
+ `int-keyed postings survive — the surviving index state is ` +
1165
+ `unresolvable and would serve WRONG pairings. Forcing the ` +
1166
+ `coordinated full rebuild from canonical (metadata + vector + ` +
1167
+ `graph; ints re-mint consistently).`);
1168
+ this.strandDetected = true;
1169
+ this.epochMigrationPending = true;
1170
+ this.lostMapperHeal = true;
1171
+ }
1112
1172
  // **#18 read-side epoch guard.** AFTER the cortex-2.x legacy gate and the
1113
1173
  // LSM cold-open, classify the brain's derived-index epoch against this
1114
1174
  // build's expectation. The common case (current epoch) is a single tiny
@@ -1144,6 +1204,13 @@ export class MetadataIndexManager {
1144
1204
  prodLog.info('[NativeMetadataIndex] Field registry missing but the LSM engine ' +
1145
1205
  'recovered durable state (SSTables/memtable) — serving from it, ' +
1146
1206
  'NO rebuild.');
1207
+ // DETECTOR COVERAGE (memory-vm 2026-07-14): this early serve
1208
+ // path previously SKIPPED detectDerivedStrand entirely — a
1209
+ // brain with lost postings that also lost its field registry
1210
+ // served the gap SILENTLY (posted < canonical, zero log
1211
+ // lines). The strand check is boot-path-invariant: it runs
1212
+ // here too, with the same verified-unpostable allowance.
1213
+ await this.detectDerivedStrand();
1147
1214
  this.readinessInitialized = true;
1148
1215
  return;
1149
1216
  }
@@ -1221,7 +1288,24 @@ export class MetadataIndexManager {
1221
1288
  this.readinessInitialized = true;
1222
1289
  if (this.epochMigrationPending) {
1223
1290
  this.epochMigrationPending = false;
1224
- this.migrationCoordinatorGetter?.()?.start().catch(() => { });
1291
+ const coordinator = this.migrationCoordinatorGetter?.();
1292
+ if (this.lostMapperHeal) {
1293
+ // Lost-mapper heal BLOCKS init: until vector+graph re-mint, their
1294
+ // durable state pairs old ints with a mapper that never assigned
1295
+ // them — brainy must not get an initialized brain before the
1296
+ // coordinated rebuild completes. (The epoch path below stays
1297
+ // fire-and-forget per the rc.9 lock contract — brainy sees the
1298
+ // stale marker and waits on the lock itself.)
1299
+ this.lostMapperHeal = false;
1300
+ if (coordinator) {
1301
+ await coordinator.start();
1302
+ }
1303
+ // No coordinator (raw/test usage): strandDetected already gates
1304
+ // the metadata leg; the loud LOST-MAPPER ops line stands.
1305
+ }
1306
+ else {
1307
+ coordinator?.start().catch(() => { });
1308
+ }
1225
1309
  }
1226
1310
  }
1227
1311
  /**
@@ -1275,6 +1359,41 @@ export class MetadataIndexManager {
1275
1359
  * same rebuild). Skipped at/above the u32 saturation point of
1276
1360
  * `getTotalEntityCount` (a saturated count would make equality lie).
1277
1361
  */
1362
+ /**
1363
+ * The verified-unpostable allowance for posted-vs-canonical floors: how
1364
+ * many canonical noun rows the last COMPLETED rebuild PROVED carry no
1365
+ * readable metadata (each verified by direct read at rebuild time, each
1366
+ * RE-VERIFIED here so an id that has since gained metadata stops
1367
+ * counting). Beyond {@link UNPOSTABLE_ID_CAP} the stamp is count-only
1368
+ * and the allowance carries a bounded, logged staleness caveat.
1369
+ * Advisory: any fault reads as 0 (may over-heal, never under-detects).
1370
+ */
1371
+ async verifiedUnpostableAllowance() {
1372
+ try {
1373
+ const stamp = (await this.storage.getMetadata(UNPOSTABLE_STAMP_KEY));
1374
+ if (!stamp || typeof stamp.nounCount !== 'number' || stamp.nounCount <= 0)
1375
+ return 0;
1376
+ if (Array.isArray(stamp.nounIds) && stamp.nounIds.length === stamp.nounCount) {
1377
+ const getMeta = this.storage.getNounMetadata;
1378
+ if (typeof getMeta !== 'function')
1379
+ return stamp.nounCount;
1380
+ let stillUnpostable = 0;
1381
+ for (const id of stamp.nounIds) {
1382
+ const md = await getMeta.call(this.storage, id).catch(() => undefined);
1383
+ if (md == null)
1384
+ stillUnpostable++;
1385
+ }
1386
+ return stillUnpostable;
1387
+ }
1388
+ prodLog.warn(`[NativeMetadataIndex] unpostable stamp is count-only ` +
1389
+ `(${stamp.nounCount} > id cap) — the posted-count floor carries its ` +
1390
+ `staleness until the next completed rebuild refreshes it.`);
1391
+ return stamp.nounCount;
1392
+ }
1393
+ catch {
1394
+ return 0;
1395
+ }
1396
+ }
1278
1397
  async detectDerivedStrand() {
1279
1398
  if (!this.lsmEngine || !this.lsmMetaDir)
1280
1399
  return;
@@ -1364,13 +1483,31 @@ export class MetadataIndexManager {
1364
1483
  // smaller than the (1–2 entity) system skew is masked here and
1365
1484
  // falls to the archive census above; the exact invariant (a
1366
1485
  // persisted posted-count stamp) is CORTEX-BILLION-SCALE-SPINE work.
1367
- if (posted < canonical) {
1486
+ //
1487
+ // UNPOSTABLE ALLOWANCE (the constant-52, CORTEX-RESTART-STRAND):
1488
+ // canonical rows with NO readable metadata cannot carry a
1489
+ // posting, and a completed rebuild PROVES which those are (each
1490
+ // verified by direct read) and stamps them. Without the
1491
+ // allowance the same cohort re-flags every boot and re-triggers
1492
+ // a pointless full heal forever. The stamp's ids are RE-VERIFIED
1493
+ // here (an id that has since gained metadata stops counting), so
1494
+ // the floor stays exact; beyond UNPOSTABLE_ID_CAP the stamp is
1495
+ // count-only and the allowance carries a bounded, logged
1496
+ // staleness caveat.
1497
+ const unpostable = await this.verifiedUnpostableAllowance();
1498
+ if (posted + unpostable < canonical) {
1368
1499
  this.strandDetected = true;
1369
1500
  prodLog.error(`[NativeMetadataIndex] STRAND: canonical holds ${canonical} ` +
1370
- `entities but the index has postings for only ${posted}` +
1371
- `${canonical - posted}+ entities are durable in canonical but ` +
1372
- `UNQUERYABLE (lost postings). Reporting not-ready so the ` +
1373
- `cold-open gate rebuilds from canonical.`);
1501
+ `entities but the index has postings for only ${posted}` +
1502
+ (unpostable > 0 ? ` (+${unpostable} verified-unpostable allowance)` : '') +
1503
+ ` ${canonical - posted - unpostable}+ entities are durable in ` +
1504
+ `canonical but UNQUERYABLE (lost postings). Reporting not-ready ` +
1505
+ `so the cold-open gate rebuilds from canonical.`);
1506
+ }
1507
+ else if (unpostable > 0 && posted < canonical) {
1508
+ opsLine(`posted ${posted} < canonical ${canonical} is FULLY explained by ` +
1509
+ `${unpostable} verified metadata-less canonical entities (stamped ` +
1510
+ `by the last completed rebuild) — no strand, no heal.`);
1374
1511
  }
1375
1512
  }
1376
1513
  }
@@ -1401,6 +1538,7 @@ export class MetadataIndexManager {
1401
1538
  idSpace: 'u64',
1402
1539
  });
1403
1540
  this.idMapperNative = handle.mapper;
1541
+ this.idMapperCreatedFresh = handle.created;
1404
1542
  this.native.setIdMapper(handle.mapper);
1405
1543
  }
1406
1544
  async loadFieldRegistry() {
@@ -2401,15 +2539,23 @@ export class MetadataIndexManager {
2401
2539
  for (const t of Object.values(NounType)) {
2402
2540
  posted += this.native.getEntityCountByType(t);
2403
2541
  }
2542
+ // Same verified-unpostable allowance as the strand detector — a
2543
+ // metadata-less canonical row (proven by the last completed
2544
+ // rebuild) cannot carry a posting and must not read as damage
2545
+ // here either, or brainy's repairIndex loops the same heal the
2546
+ // detector fix just broke.
2547
+ const unpostable = await this.verifiedUnpostableAllowance();
2548
+ const floor = posted + unpostable;
2404
2549
  return {
2405
2550
  name: 'posted-count-floor',
2406
- holds: posted >= canonical,
2407
- detail: posted >= canonical
2408
- ? `posted ${posted} ≥ canonical ${canonical}`
2551
+ holds: floor >= canonical,
2552
+ detail: floor >= canonical
2553
+ ? `posted ${posted}${unpostable > 0 ? ` (+${unpostable} verified-unpostable)` : ''} ≥ canonical ${canonical}`
2409
2554
  : `canonical holds ${canonical} entities but only ${posted} are ` +
2410
- `posted ${canonical - posted} durable-but-unqueryable`,
2555
+ `posted (${unpostable} verified-unpostable allowed) — ` +
2556
+ `${canonical - floor} durable-but-unqueryable`,
2411
2557
  expected: canonical,
2412
- actual: posted,
2558
+ actual: floor,
2413
2559
  heal: 'rebuild',
2414
2560
  };
2415
2561
  },
@@ -2904,11 +3050,11 @@ export class MetadataIndexManager {
2904
3050
  'function';
2905
3051
  if (bulkCapable)
2906
3052
  this.lsmEngine.setBulkLoad(true);
2907
- let totalNounsProcessed;
2908
- let totalVerbsProcessed;
3053
+ let nounResult;
3054
+ let verbResult;
2909
3055
  try {
2910
- totalNounsProcessed = await this.rebuildEntityMetadata('noun');
2911
- totalVerbsProcessed = await this.rebuildEntityMetadata('verb');
3056
+ nounResult = await this.rebuildEntityMetadata('noun');
3057
+ verbResult = await this.rebuildEntityMetadata('verb');
2912
3058
  }
2913
3059
  finally {
2914
3060
  // Leaving bulk mode performs the walk's single durability point
@@ -2922,7 +3068,22 @@ export class MetadataIndexManager {
2922
3068
  this.isRebuilding = false;
2923
3069
  await this.flushRebuildDirty();
2924
3070
  await this.flush();
2925
- prodLog.info(`Metadata index rebuild completed! Processed ${totalNounsProcessed} nouns and ${totalVerbsProcessed} verbs`);
3071
+ // Persist what this COMPLETED walk PROVED unpostable (each id
3072
+ // verified by direct canonical read) so the next boot's strand
3073
+ // detector uses the honest floor instead of re-flagging the same
3074
+ // cohort forever. Refreshed on every completed rebuild; an empty
3075
+ // set clears the stamp.
3076
+ await this.storage.saveMetadata(UNPOSTABLE_STAMP_KEY, {
3077
+ nounCount: nounResult.noMetadata,
3078
+ nounIds: nounResult.noMetadataIds,
3079
+ verbCount: verbResult.noMetadata,
3080
+ verifiedAt: Date.now(),
3081
+ });
3082
+ opsLine(`Metadata index rebuild completed! Processed ${nounResult.processed} nouns and ` +
3083
+ `${verbResult.processed} verbs` +
3084
+ (nounResult.noMetadata > 0
3085
+ ? ` (${nounResult.noMetadata} canonical noun(s) verified metadata-less — stamped for the strand detector)`
3086
+ : ''));
2926
3087
  // A completed rebuild re-posted every canonical entity into a freshly
2927
3088
  // re-opened engine (reopenLsmEngineFresh wiped the stale shard set) —
2928
3089
  // any cold-open strand verdict is now satisfied.
@@ -2950,6 +3111,7 @@ export class MetadataIndexManager {
2950
3111
  let processed = 0;
2951
3112
  let sinceFlush = 0;
2952
3113
  let noMetadata = 0;
3114
+ const noMetadataIds = [];
2953
3115
  // Heal observability (CORTEX-RESTART-STRAND, memory's ask): a rebuild
2954
3116
  // must never be silent for minutes — the operator cannot distinguish
2955
3117
  // converging from stuck. Every 500 posted entities logs progress with
@@ -2990,8 +3152,8 @@ export class MetadataIndexManager {
2990
3152
  if (processed - lastProgressAt >= 500) {
2991
3153
  lastProgressAt = processed;
2992
3154
  const elapsedS = (Date.now() - startedAt) / 1000;
2993
- prodLog.info(`[NativeMetadataIndex] rebuild(${kind}): ${processed} posted ` +
2994
- `in ${elapsedS.toFixed(1)}s (${(processed / Math.max(elapsedS, 0.001)).toFixed(0)}/s)`);
3155
+ opsLine(`rebuild(${kind}): ${processed} posted in ${elapsedS.toFixed(1)}s ` +
3156
+ `(${(processed / Math.max(elapsedS, 0.001)).toFixed(0)}/s)`);
2995
3157
  }
2996
3158
  if (++sinceFlush >= 5000) {
2997
3159
  await this.flushRebuildDirty();
@@ -3000,22 +3162,25 @@ export class MetadataIndexManager {
3000
3162
  }
3001
3163
  else {
3002
3164
  noMetadata++;
3165
+ if (noMetadataIds.length < UNPOSTABLE_ID_CAP)
3166
+ noMetadataIds.push(it.id);
3003
3167
  }
3004
3168
  }
3005
3169
  hasMore = page.hasMore;
3006
3170
  await this.yieldToEventLoop();
3007
3171
  }
3008
3172
  const totalS = (Date.now() - startedAt) / 1000;
3009
- prodLog.info(`[NativeMetadataIndex] rebuild(${kind}): COMPLETE — ${processed} posted ` +
3173
+ opsLine(`rebuild(${kind}): COMPLETE — ${processed} posted ` +
3010
3174
  `in ${totalS.toFixed(1)}s (${(processed / Math.max(totalS, 0.001)).toFixed(0)}/s)` +
3011
3175
  (noMetadata > 0 ? `, ${noMetadata} without metadata` : ''));
3012
3176
  if (noMetadata > 0) {
3013
- prodLog.warn(`[NativeMetadataIndex] rebuild(${kind}): ${noMetadata} enumerated ` +
3177
+ opsLine(`rebuild(${kind}): ${noMetadata} enumerated ` +
3014
3178
  `entit${noMetadata === 1 ? 'y' : 'ies'} carried no canonical ` +
3015
3179
  `metadata (verified by direct read) and were not indexed — ` +
3016
- `expected only for metadata-less legacy records.`);
3180
+ `expected only for metadata-less legacy records. First ids: ` +
3181
+ noMetadataIds.slice(0, 10).join(', '));
3017
3182
  }
3018
- return processed;
3183
+ return { processed, noMetadata, noMetadataIds };
3019
3184
  }
3020
3185
  /**
3021
3186
  * Rebuild-path verify-read for a single entity's canonical metadata.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @module utils/opsLog
3
+ * @description The always-visible operational channel (CORTEX-RESTART-STRAND,
4
+ * 2026-07-14). brainy's prodLog defaults to ERROR level in production, which
5
+ * silenced ALL heal narration on memory-vm — an operator could not tell a
6
+ * converging heal from a hang until BRAINY_LOG_LEVEL=info was set by hand.
7
+ * Index lifecycle events (heal start / progress / completion, verified
8
+ * anomaly accounting) are OPERATIONAL, not debug: they must reach the
9
+ * journal regardless of logger configuration, exactly like the version
10
+ * banner. One writer, `console.error`, `[cor]`-prefixed — never routed
11
+ * through prodLog (no duplicate lines on boxes that set info-level).
12
+ */
13
+ /** Emit one always-visible operational line. */
14
+ export declare function opsLine(message: string): void;
15
+ //# sourceMappingURL=opsLog.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @module utils/opsLog
3
+ * @description The always-visible operational channel (CORTEX-RESTART-STRAND,
4
+ * 2026-07-14). brainy's prodLog defaults to ERROR level in production, which
5
+ * silenced ALL heal narration on memory-vm — an operator could not tell a
6
+ * converging heal from a hang until BRAINY_LOG_LEVEL=info was set by hand.
7
+ * Index lifecycle events (heal start / progress / completion, verified
8
+ * anomaly accounting) are OPERATIONAL, not debug: they must reach the
9
+ * journal regardless of logger configuration, exactly like the version
10
+ * banner. One writer, `console.error`, `[cor]`-prefixed — never routed
11
+ * through prodLog (no duplicate lines on boxes that set info-level).
12
+ */
13
+ /** Emit one always-visible operational line. */
14
+ export function opsLine(message) {
15
+ console.error(`[cor] ${message}`);
16
+ }
17
+ //# sourceMappingURL=opsLog.js.map
package/dist/version.d.ts CHANGED
@@ -11,5 +11,5 @@
11
11
  * `check:brainy`-style drift between the two fails the release.
12
12
  */
13
13
  /** The @soulcraft/cor version this build was cut from. */
14
- export declare const COR_VERSION = "3.0.16";
14
+ export declare const COR_VERSION = "3.0.18";
15
15
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -11,5 +11,5 @@
11
11
  * `check:brainy`-style drift between the two fails the release.
12
12
  */
13
13
  /** The @soulcraft/cor version this build was cut from. */
14
- export const COR_VERSION = '3.0.16';
14
+ export const COR_VERSION = '3.0.18';
15
15
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/cor",
3
- "version": "3.0.16",
3
+ "version": "3.0.18",
4
4
  "description": "Native Rust acceleration for Brainy — SIMD distance, vector quantization, zero-copy mmap, native embeddings. Free tier for storage, Pro license for compute acceleration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",