@soulcraft/brainy 5.0.0 → 5.1.0

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.
@@ -36,7 +36,7 @@
36
36
  * @since Phase 1 - Type-First Implementation
37
37
  */
38
38
  import { BaseStorage } from '../baseStorage.js';
39
- import { TypeUtils, NOUN_TYPE_COUNT, VERB_TYPE_COUNT } from '../../types/graphTypes.js';
39
+ import { NounType, TypeUtils, NOUN_TYPE_COUNT, VERB_TYPE_COUNT } from '../../types/graphTypes.js';
40
40
  import { getShardIdFromUuid } from '../sharding.js';
41
41
  /**
42
42
  * Type-first storage paths
@@ -201,8 +201,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
201
201
  const typeIndex = TypeUtils.getNounIndex(type);
202
202
  this.nounCountsByType[typeIndex]++;
203
203
  this.nounTypeCache.set(noun.id, type);
204
- // Delegate to underlying storage
205
- await this.u.writeObjectToPath(path, noun);
204
+ // COW-aware write (v5.0.1): Use COW helper for branch isolation
205
+ await this.writeObjectToBranch(path, noun);
206
206
  // Periodically save statistics (every 100 saves)
207
207
  if (this.nounCountsByType[typeIndex] % 100 === 0) {
208
208
  await this.saveTypeStatistics();
@@ -216,14 +216,16 @@ export class TypeAwareStorageAdapter extends BaseStorage {
216
216
  const cachedType = this.nounTypeCache.get(id);
217
217
  if (cachedType) {
218
218
  const path = getNounVectorPath(cachedType, id);
219
- return await this.u.readObjectFromPath(path);
219
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
220
+ return await this.readWithInheritance(path);
220
221
  }
221
222
  // Need to search across all types (expensive, but cached after first access)
222
223
  for (let i = 0; i < NOUN_TYPE_COUNT; i++) {
223
224
  const type = TypeUtils.getNounFromIndex(i);
224
225
  const path = getNounVectorPath(type, id);
225
226
  try {
226
- const noun = await this.u.readObjectFromPath(path);
227
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
228
+ const noun = await this.readWithInheritance(path);
227
229
  if (noun) {
228
230
  // Cache the type for next time
229
231
  this.nounTypeCache.set(id, type);
@@ -242,13 +244,14 @@ export class TypeAwareStorageAdapter extends BaseStorage {
242
244
  async getNounsByNounType_internal(nounType) {
243
245
  const type = nounType;
244
246
  const prefix = `entities/nouns/${type}/vectors/`;
245
- // List all files under this type's directory
246
- const paths = await this.u.listObjectsUnderPath(prefix);
247
+ // COW-aware list (v5.0.1): Use COW helper for branch isolation
248
+ const paths = await this.listObjectsInBranch(prefix);
247
249
  // Load all nouns of this type
248
250
  const nouns = [];
249
251
  for (const path of paths) {
250
252
  try {
251
- const noun = await this.u.readObjectFromPath(path);
253
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
254
+ const noun = await this.readWithInheritance(path);
252
255
  if (noun) {
253
256
  nouns.push(noun);
254
257
  // Cache the type
@@ -269,7 +272,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
269
272
  const cachedType = this.nounTypeCache.get(id);
270
273
  if (cachedType) {
271
274
  const path = getNounVectorPath(cachedType, id);
272
- await this.u.deleteObjectFromPath(path);
275
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
276
+ await this.deleteObjectFromBranch(path);
273
277
  // Update counts
274
278
  const typeIndex = TypeUtils.getNounIndex(cachedType);
275
279
  if (this.nounCountsByType[typeIndex] > 0) {
@@ -283,7 +287,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
283
287
  const type = TypeUtils.getNounFromIndex(i);
284
288
  const path = getNounVectorPath(type, id);
285
289
  try {
286
- await this.u.deleteObjectFromPath(path);
290
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
291
+ await this.deleteObjectFromBranch(path);
287
292
  // Update counts
288
293
  if (this.nounCountsByType[i] > 0) {
289
294
  this.nounCountsByType[i]--;
@@ -310,8 +315,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
310
315
  const typeIndex = TypeUtils.getVerbIndex(type);
311
316
  this.verbCountsByType[typeIndex]++;
312
317
  this.verbTypeCache.set(verb.id, type);
313
- // Delegate to underlying storage
314
- await this.u.writeObjectToPath(path, verb);
318
+ // COW-aware write (v5.0.1): Use COW helper for branch isolation
319
+ await this.writeObjectToBranch(path, verb);
315
320
  // Periodically save statistics
316
321
  if (this.verbCountsByType[typeIndex] % 100 === 0) {
317
322
  await this.saveTypeStatistics();
@@ -328,7 +333,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
328
333
  const cachedType = this.verbTypeCache.get(id);
329
334
  if (cachedType) {
330
335
  const path = getVerbVectorPath(cachedType, id);
331
- const verb = await this.u.readObjectFromPath(path);
336
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
337
+ const verb = await this.readWithInheritance(path);
332
338
  return verb;
333
339
  }
334
340
  // Search across all types (only on first access)
@@ -336,7 +342,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
336
342
  const type = TypeUtils.getVerbFromIndex(i);
337
343
  const path = getVerbVectorPath(type, id);
338
344
  try {
339
- const verb = await this.u.readObjectFromPath(path);
345
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
346
+ const verb = await this.readWithInheritance(path);
340
347
  if (verb) {
341
348
  // Cache the type for next time (read from verb.verb field)
342
349
  this.verbTypeCache.set(id, verb.verb);
@@ -353,27 +360,36 @@ export class TypeAwareStorageAdapter extends BaseStorage {
353
360
  * Get verbs by source
354
361
  */
355
362
  async getVerbsBySource_internal(sourceId) {
356
- // v4.8.1 PERFORMANCE FIX: Delegate to underlying storage instead of scanning all files
357
- // Previous implementation was O(total_verbs) - scanned ALL 40 verb types and ALL verb files
358
- // This was the root cause of the 11-version VFS bug (timeouts/zero results)
363
+ // v5.0.1 COW FIX: Use getVerbsWithPagination which is COW-aware
364
+ // Previous v4.8.1 implementation delegated to underlying storage, which bypasses COW!
365
+ // The underlying storage delegates to GraphAdjacencyIndex, which is shared between forks.
366
+ // This caused getRelations() to return 0 results for fork-created relationships.
359
367
  //
360
- // Underlying storage adapters have optimized implementations:
361
- // - FileSystemStorage: Uses getVerbsWithPagination with sourceId filter
362
- // - GcsStorage: Uses batch queries with prefix filtering
363
- // - S3Storage: Uses listObjects with sourceId-based filtering
368
+ // Now we use getVerbsWithPagination with sourceId filter, which:
369
+ // - Searches across all verb types using COW-aware listObjectsInBranch()
370
+ // - Reads verbs using COW-aware readWithInheritance()
371
+ // - Properly isolates fork data from parent
364
372
  //
365
- // Phase 1b TODO: Add graph adjacency index query for O(1) lookups:
366
- // const verbIds = await this.graphIndex?.getOutgoingEdges(sourceId) || []
367
- // return Promise.all(verbIds.map(id => this.getVerb(id)))
368
- return this.underlying.getVerbsBySource(sourceId);
373
+ // Performance: Still efficient because sourceId filter reduces iteration
374
+ const result = await this.getVerbsWithPagination({
375
+ limit: 10000, // High limit to get all verbs for this source
376
+ offset: 0,
377
+ filter: { sourceId }
378
+ });
379
+ return result.items;
369
380
  }
370
381
  /**
371
382
  * Get verbs by target
372
383
  */
373
384
  async getVerbsByTarget_internal(targetId) {
374
- // v4.8.1 PERFORMANCE FIX: Delegate to underlying storage (same as getVerbsBySource fix)
375
- // Previous implementation was O(total_verbs) - scanned ALL 40 verb types and ALL verb files
376
- return this.underlying.getVerbsByTarget(targetId);
385
+ // v5.0.1 COW FIX: Use getVerbsWithPagination which is COW-aware
386
+ // Same fix as getVerbsBySource_internal - delegating to underlying bypasses COW
387
+ const result = await this.getVerbsWithPagination({
388
+ limit: 10000, // High limit to get all verbs for this target
389
+ offset: 0,
390
+ filter: { targetId }
391
+ });
392
+ return result.items;
377
393
  }
378
394
  /**
379
395
  * Get verbs by type (O(1) with type-first paths!)
@@ -383,11 +399,13 @@ export class TypeAwareStorageAdapter extends BaseStorage {
383
399
  async getVerbsByType_internal(verbType) {
384
400
  const type = verbType;
385
401
  const prefix = `entities/verbs/${type}/vectors/`;
386
- const paths = await this.u.listObjectsUnderPath(prefix);
402
+ // COW-aware list (v5.0.1): Use COW helper for branch isolation
403
+ const paths = await this.listObjectsInBranch(prefix);
387
404
  const verbs = [];
388
405
  for (const path of paths) {
389
406
  try {
390
- const hnswVerb = await this.u.readObjectFromPath(path);
407
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
408
+ const hnswVerb = await this.readWithInheritance(path);
391
409
  if (!hnswVerb)
392
410
  continue;
393
411
  // Cache type from HNSWVerb for future O(1) retrievals
@@ -438,7 +456,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
438
456
  const cachedType = this.verbTypeCache.get(id);
439
457
  if (cachedType) {
440
458
  const path = getVerbVectorPath(cachedType, id);
441
- await this.u.deleteObjectFromPath(path);
459
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
460
+ await this.deleteObjectFromBranch(path);
442
461
  const typeIndex = TypeUtils.getVerbIndex(cachedType);
443
462
  if (this.verbCountsByType[typeIndex] > 0) {
444
463
  this.verbCountsByType[typeIndex]--;
@@ -451,7 +470,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
451
470
  const type = TypeUtils.getVerbFromIndex(i);
452
471
  const path = getVerbVectorPath(type, id);
453
472
  try {
454
- await this.u.deleteObjectFromPath(path);
473
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
474
+ await this.deleteObjectFromBranch(path);
455
475
  if (this.verbCountsByType[i] > 0) {
456
476
  this.verbCountsByType[i]--;
457
477
  }
@@ -472,9 +492,9 @@ export class TypeAwareStorageAdapter extends BaseStorage {
472
492
  // Extract and cache the type
473
493
  const type = (metadata.noun || 'thing');
474
494
  this.nounTypeCache.set(id, type);
475
- // Save to type-aware path
495
+ // COW-aware write (v5.0.1): Use COW helper for branch isolation
476
496
  const path = getNounMetadataPath(type, id);
477
- await this.u.writeObjectToPath(path, metadata);
497
+ await this.writeObjectToBranch(path, metadata);
478
498
  }
479
499
  /**
480
500
  * Get noun metadata (override to use type-aware paths)
@@ -484,14 +504,16 @@ export class TypeAwareStorageAdapter extends BaseStorage {
484
504
  const cachedType = this.nounTypeCache.get(id);
485
505
  if (cachedType) {
486
506
  const path = getNounMetadataPath(cachedType, id);
487
- return await this.u.readObjectFromPath(path);
507
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
508
+ return await this.readWithInheritance(path);
488
509
  }
489
510
  // Search across all types
490
511
  for (let i = 0; i < NOUN_TYPE_COUNT; i++) {
491
512
  const type = TypeUtils.getNounFromIndex(i);
492
513
  const path = getNounMetadataPath(type, id);
493
514
  try {
494
- const metadata = await this.u.readObjectFromPath(path);
515
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
516
+ const metadata = await this.readWithInheritance(path);
495
517
  if (metadata) {
496
518
  // Cache the type for next time
497
519
  const metadataType = (metadata.noun || 'thing');
@@ -512,7 +534,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
512
534
  const cachedType = this.nounTypeCache.get(id);
513
535
  if (cachedType) {
514
536
  const path = getNounMetadataPath(cachedType, id);
515
- await this.u.deleteObjectFromPath(path);
537
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
538
+ await this.deleteObjectFromBranch(path);
516
539
  return;
517
540
  }
518
541
  // Search across all types
@@ -520,7 +543,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
520
543
  const type = TypeUtils.getNounFromIndex(i);
521
544
  const path = getNounMetadataPath(type, id);
522
545
  try {
523
- await this.u.deleteObjectFromPath(path);
546
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
547
+ await this.deleteObjectFromBranch(path);
524
548
  return;
525
549
  }
526
550
  catch (error) {
@@ -550,7 +574,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
550
574
  }
551
575
  // Save to type-aware path
552
576
  const path = getVerbMetadataPath(type, id);
553
- await this.u.writeObjectToPath(path, metadata);
577
+ // COW-aware write (v5.0.1): Use COW helper for branch isolation
578
+ await this.writeObjectToBranch(path, metadata);
554
579
  }
555
580
  /**
556
581
  * Get verb metadata (override to use type-aware paths)
@@ -560,14 +585,16 @@ export class TypeAwareStorageAdapter extends BaseStorage {
560
585
  const cachedType = this.verbTypeCache.get(id);
561
586
  if (cachedType) {
562
587
  const path = getVerbMetadataPath(cachedType, id);
563
- return await this.u.readObjectFromPath(path);
588
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
589
+ return await this.readWithInheritance(path);
564
590
  }
565
591
  // Search across all types
566
592
  for (let i = 0; i < VERB_TYPE_COUNT; i++) {
567
593
  const type = TypeUtils.getVerbFromIndex(i);
568
594
  const path = getVerbMetadataPath(type, id);
569
595
  try {
570
- const metadata = await this.u.readObjectFromPath(path);
596
+ // COW-aware read (v5.0.1): Use COW helper for branch isolation
597
+ const metadata = await this.readWithInheritance(path);
571
598
  if (metadata) {
572
599
  // Cache the type for next time
573
600
  this.verbTypeCache.set(id, type);
@@ -587,7 +614,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
587
614
  const cachedType = this.verbTypeCache.get(id);
588
615
  if (cachedType) {
589
616
  const path = getVerbMetadataPath(cachedType, id);
590
- await this.u.deleteObjectFromPath(path);
617
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
618
+ await this.deleteObjectFromBranch(path);
591
619
  return;
592
620
  }
593
621
  // Search across all types
@@ -595,7 +623,8 @@ export class TypeAwareStorageAdapter extends BaseStorage {
595
623
  const type = TypeUtils.getVerbFromIndex(i);
596
624
  const path = getVerbMetadataPath(type, id);
597
625
  try {
598
- await this.u.deleteObjectFromPath(path);
626
+ // COW-aware delete (v5.0.1): Use COW helper for branch isolation
627
+ await this.deleteObjectFromBranch(path);
599
628
  return;
600
629
  }
601
630
  catch (error) {
@@ -742,6 +771,206 @@ export class TypeAwareStorageAdapter extends BaseStorage {
742
771
  }
743
772
  return null;
744
773
  }
774
+ /**
775
+ * Get nouns with pagination (v5.0.1: COW-aware)
776
+ * Required for find() to work with TypeAwareStorage
777
+ */
778
+ async getNounsWithPagination(options) {
779
+ const limit = options.limit || 100;
780
+ const offset = options.offset || 0;
781
+ const filter = options.filter || {};
782
+ // Determine which types to search
783
+ let typesToSearch;
784
+ if (filter.nounType) {
785
+ typesToSearch = Array.isArray(filter.nounType) ? filter.nounType : [filter.nounType];
786
+ }
787
+ else {
788
+ // Search all 31 types
789
+ typesToSearch = [];
790
+ for (let i = 0; i < NOUN_TYPE_COUNT; i++) {
791
+ const type = TypeUtils.getNounFromIndex(i);
792
+ typesToSearch.push(type);
793
+ }
794
+ }
795
+ // Collect all matching nouns across types (COW-aware!)
796
+ const allNouns = [];
797
+ for (const type of typesToSearch) {
798
+ const prefix = `entities/nouns/${type}/vectors/`;
799
+ // COW-aware list with inheritance (v5.0.1): Fork sees parent's nouns too!
800
+ const paths = await this.listObjectsWithInheritance(prefix);
801
+ for (const path of paths) {
802
+ try {
803
+ // COW-aware read with inheritance
804
+ const noun = await this.readWithInheritance(path);
805
+ if (!noun)
806
+ continue;
807
+ // Get metadata separately
808
+ const metadata = await this.getNounMetadata(noun.id);
809
+ if (!metadata)
810
+ continue;
811
+ // Filter by service if specified
812
+ if (filter.service && metadata.service !== filter.service)
813
+ continue;
814
+ // Filter by custom metadata if specified
815
+ if (filter.metadata) {
816
+ let matches = true;
817
+ for (const [key, value] of Object.entries(filter.metadata)) {
818
+ if (metadata[key] !== value) {
819
+ matches = false;
820
+ break;
821
+ }
822
+ }
823
+ if (!matches)
824
+ continue;
825
+ }
826
+ // Extract standard fields from metadata
827
+ const { noun: nounType, createdAt, updatedAt, confidence, weight, service, data, createdBy, ...customMetadata } = metadata;
828
+ // Create HNSWNounWithMetadata (v4.8.0 format)
829
+ const nounWithMetadata = {
830
+ id: noun.id,
831
+ vector: noun.vector,
832
+ connections: noun.connections,
833
+ level: noun.level || 0,
834
+ type: nounType || NounType.Thing,
835
+ createdAt: createdAt || Date.now(),
836
+ updatedAt: updatedAt || Date.now(),
837
+ confidence,
838
+ weight,
839
+ service,
840
+ data,
841
+ createdBy,
842
+ metadata: customMetadata
843
+ };
844
+ allNouns.push(nounWithMetadata);
845
+ }
846
+ catch (error) {
847
+ // Skip entities with errors
848
+ continue;
849
+ }
850
+ }
851
+ }
852
+ // Apply pagination
853
+ const totalCount = allNouns.length;
854
+ const paginatedNouns = allNouns.slice(offset, offset + limit);
855
+ const hasMore = offset + limit < totalCount;
856
+ // Generate cursor if more results exist
857
+ let nextCursor;
858
+ if (hasMore && paginatedNouns.length > 0) {
859
+ nextCursor = paginatedNouns[paginatedNouns.length - 1].id;
860
+ }
861
+ return {
862
+ items: paginatedNouns,
863
+ totalCount,
864
+ hasMore,
865
+ nextCursor
866
+ };
867
+ }
868
+ /**
869
+ * Get verbs with pagination (v5.0.1: COW-aware)
870
+ * Required for GraphAdjacencyIndex rebuild and find() to work
871
+ */
872
+ async getVerbsWithPagination(options) {
873
+ const limit = options.limit || 100;
874
+ const offset = options.offset || 0;
875
+ const filter = options.filter || {};
876
+ // Determine which types to search
877
+ let typesToSearch;
878
+ if (filter.verbType) {
879
+ typesToSearch = Array.isArray(filter.verbType) ? filter.verbType : [filter.verbType];
880
+ }
881
+ else {
882
+ // Search all 40 verb types
883
+ typesToSearch = [];
884
+ for (let i = 0; i < VERB_TYPE_COUNT; i++) {
885
+ const type = TypeUtils.getVerbFromIndex(i);
886
+ typesToSearch.push(type);
887
+ }
888
+ }
889
+ // Collect all matching verbs across types (COW-aware!)
890
+ const allVerbs = [];
891
+ for (const type of typesToSearch) {
892
+ const prefix = `entities/verbs/${type}/vectors/`;
893
+ // COW-aware list with inheritance (v5.0.1): Fork sees parent's verbs too!
894
+ const paths = await this.listObjectsWithInheritance(prefix);
895
+ for (const path of paths) {
896
+ try {
897
+ // COW-aware read with inheritance
898
+ const verb = await this.readWithInheritance(path);
899
+ if (!verb)
900
+ continue;
901
+ // Filter by sourceId if specified
902
+ if (filter.sourceId) {
903
+ const sourceIds = Array.isArray(filter.sourceId) ? filter.sourceId : [filter.sourceId];
904
+ if (!sourceIds.includes(verb.sourceId))
905
+ continue;
906
+ }
907
+ // Filter by targetId if specified
908
+ if (filter.targetId) {
909
+ const targetIds = Array.isArray(filter.targetId) ? filter.targetId : [filter.targetId];
910
+ if (!targetIds.includes(verb.targetId))
911
+ continue;
912
+ }
913
+ // Get metadata separately
914
+ const metadata = await this.getVerbMetadata(verb.id);
915
+ // Filter by service if specified
916
+ if (filter.service && metadata && metadata.service !== filter.service)
917
+ continue;
918
+ // Filter by custom metadata if specified
919
+ if (filter.metadata && metadata) {
920
+ let matches = true;
921
+ for (const [key, value] of Object.entries(filter.metadata)) {
922
+ if (metadata[key] !== value) {
923
+ matches = false;
924
+ break;
925
+ }
926
+ }
927
+ if (!matches)
928
+ continue;
929
+ }
930
+ // Extract standard fields from metadata
931
+ const metadataObj = metadata || {};
932
+ const { createdAt, updatedAt, confidence, weight, service, data, createdBy, ...customMetadata } = metadataObj;
933
+ // Create HNSWVerbWithMetadata (v4.8.0 format)
934
+ const verbWithMetadata = {
935
+ id: verb.id,
936
+ vector: verb.vector,
937
+ connections: verb.connections,
938
+ verb: verb.verb,
939
+ sourceId: verb.sourceId,
940
+ targetId: verb.targetId,
941
+ createdAt: createdAt || Date.now(),
942
+ updatedAt: updatedAt || Date.now(),
943
+ confidence,
944
+ weight,
945
+ service,
946
+ data,
947
+ createdBy,
948
+ metadata: customMetadata
949
+ };
950
+ allVerbs.push(verbWithMetadata);
951
+ }
952
+ catch (error) {
953
+ // Skip verbs with errors
954
+ continue;
955
+ }
956
+ }
957
+ }
958
+ // Apply pagination
959
+ const totalCount = allVerbs.length;
960
+ const paginatedVerbs = allVerbs.slice(offset, offset + limit);
961
+ const hasMore = offset + limit < totalCount;
962
+ // Generate cursor if more results exist
963
+ let nextCursor;
964
+ if (hasMore && paginatedVerbs.length > 0) {
965
+ nextCursor = paginatedVerbs[paginatedVerbs.length - 1].id;
966
+ }
967
+ return {
968
+ items: paginatedVerbs,
969
+ totalCount,
970
+ hasMore,
971
+ nextCursor
972
+ };
973
+ }
745
974
  /**
746
975
  * Save HNSW system data (entry point, max level)
747
976
  */
@@ -73,19 +73,62 @@ export declare abstract class BaseStorage extends BaseStorageAdapter {
73
73
  * Ensure the storage adapter is initialized
74
74
  */
75
75
  protected ensureInitialized(): Promise<void>;
76
+ /**
77
+ * Lightweight COW enablement - just enables branch-scoped paths
78
+ * Called during init() to ensure all data is stored with branch prefixes from the start
79
+ * RefManager/BlobStorage/CommitLog are lazy-initialized on first fork()
80
+ * @param branch - Branch name to use (default: 'main')
81
+ */
82
+ enableCOWLightweight(branch?: string): void;
76
83
  /**
77
84
  * Initialize COW (Copy-on-Write) support
78
85
  * Creates RefManager and BlobStorage for instant fork() capability
79
86
  *
87
+ * v5.0.1: Now called automatically by storageFactory (zero-config)
88
+ *
80
89
  * @param options - COW initialization options
81
90
  * @param options.branch - Initial branch name (default: 'main')
82
91
  * @param options.enableCompression - Enable zstd compression for blobs (default: true)
83
92
  * @returns Promise that resolves when COW is initialized
84
93
  */
85
- protected initializeCOW(options?: {
94
+ initializeCOW(options?: {
86
95
  branch?: string;
87
96
  enableCompression?: boolean;
88
97
  }): Promise<void>;
98
+ /**
99
+ * Resolve branch-scoped path for COW isolation
100
+ * @protected - Available to subclasses for COW implementation
101
+ */
102
+ protected resolveBranchPath(basePath: string, branch?: string): string;
103
+ /**
104
+ * Write object to branch-specific path (COW layer)
105
+ * @protected - Available to subclasses for COW implementation
106
+ */
107
+ protected writeObjectToBranch(path: string, data: any, branch?: string): Promise<void>;
108
+ /**
109
+ * Read object with inheritance from parent branches (COW layer)
110
+ * Tries current branch first, then walks commit history
111
+ * @protected - Available to subclasses for COW implementation
112
+ */
113
+ protected readWithInheritance(path: string, branch?: string): Promise<any | null>;
114
+ /**
115
+ * Delete object from branch-specific path (COW layer)
116
+ * @protected - Available to subclasses for COW implementation
117
+ */
118
+ protected deleteObjectFromBranch(path: string, branch?: string): Promise<void>;
119
+ /**
120
+ * List objects under path in branch (COW layer)
121
+ * @protected - Available to subclasses for COW implementation
122
+ */
123
+ protected listObjectsInBranch(prefix: string, branch?: string): Promise<string[]>;
124
+ /**
125
+ * List objects with inheritance (v5.0.1)
126
+ * Lists objects from current branch AND main branch, returns unique paths
127
+ * This enables fork to see parent's data in pagination operations
128
+ *
129
+ * Simplified approach: All branches inherit from main
130
+ */
131
+ protected listObjectsWithInheritance(prefix: string, branch?: string): Promise<string[]>;
89
132
  /**
90
133
  * Save a noun to storage (v4.0.0: vector only, metadata saved separately)
91
134
  * @param noun Pure HNSW vector data (no metadata)