@soulcraft/brainy 6.3.0 → 6.3.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/CHANGELOG.md +21 -0
- package/dist/brainy.d.ts +55 -0
- package/dist/brainy.js +86 -0
- package/dist/versioning/VersionIndex.d.ts +42 -47
- package/dist/versioning/VersionIndex.js +141 -166
- package/dist/versioning/VersionManager.d.ts +12 -6
- package/dist/versioning/VersionManager.js +26 -8
- package/dist/versioning/VersionStorage.d.ts +25 -15
- package/dist/versioning/VersionStorage.js +49 -65
- package/package.json +1 -1
- package/dist/augmentations/KnowledgeAugmentation.d.ts +0 -40
- package/dist/augmentations/KnowledgeAugmentation.js +0 -251
- package/dist/importManager.d.ts +0 -78
- package/dist/importManager.js +0 -267
- package/dist/query/typeInference.d.ts +0 -158
- package/dist/query/typeInference.js +0 -760
- package/dist/storage/adapters/typeAwareStorageAdapter.d.ts +0 -252
- package/dist/storage/adapters/typeAwareStorageAdapter.js +0 -814
- package/dist/types/brainyDataInterface.d.ts +0 -52
- package/dist/types/brainyDataInterface.js +0 -10
- package/dist/vfs/ConceptSystem.d.ts +0 -203
- package/dist/vfs/ConceptSystem.js +0 -545
- package/dist/vfs/EntityManager.d.ts +0 -75
- package/dist/vfs/EntityManager.js +0 -216
- package/dist/vfs/EventRecorder.d.ts +0 -84
- package/dist/vfs/EventRecorder.js +0 -269
- package/dist/vfs/GitBridge.d.ts +0 -167
- package/dist/vfs/GitBridge.js +0 -537
- package/dist/vfs/KnowledgeLayer.d.ts +0 -35
- package/dist/vfs/KnowledgeLayer.js +0 -443
- package/dist/vfs/PersistentEntitySystem.d.ts +0 -165
- package/dist/vfs/PersistentEntitySystem.js +0 -503
- package/dist/vfs/SemanticVersioning.d.ts +0 -105
- package/dist/vfs/SemanticVersioning.js +0 -309
|
@@ -1,31 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* VersionIndex -
|
|
2
|
+
* VersionIndex - Pure Key-Value Version Storage (v6.3.0)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - Uses EntityIdMapper for efficient ID handling
|
|
8
|
-
* - Uses ChunkManager for adaptive chunking
|
|
9
|
-
* - Leverages Roaring Bitmaps for fast set operations
|
|
4
|
+
* Stores version metadata using simple key-value storage:
|
|
5
|
+
* - Version list per entity: __version_meta_{entityId}_{branch}
|
|
6
|
+
* - Content stored separately by VersionStorage
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
16
|
-
* - versionBranch: Branch version was created on
|
|
17
|
-
* - versionNumber: Version number
|
|
18
|
-
* - versionTag: Optional user tag
|
|
19
|
-
* - versionTimestamp: Creation timestamp
|
|
20
|
-
* - versionCommitHash: Commit hash
|
|
8
|
+
* Key Design Decisions:
|
|
9
|
+
* - Versions are NOT entities (no brain.add())
|
|
10
|
+
* - Versions do NOT pollute find() results
|
|
11
|
+
* - Simple O(1) lookups per entity
|
|
12
|
+
* - Versions per entity is typically small (10-1000)
|
|
21
13
|
*
|
|
22
14
|
* NO MOCKS - Production implementation
|
|
23
15
|
*/
|
|
24
16
|
/**
|
|
25
|
-
* VersionIndex -
|
|
17
|
+
* VersionIndex - Pure key-value version metadata storage
|
|
26
18
|
*
|
|
27
|
-
*
|
|
28
|
-
* This
|
|
19
|
+
* Uses simple JSON storage instead of creating entities.
|
|
20
|
+
* This ensures versions never appear in find() results.
|
|
29
21
|
*/
|
|
30
22
|
export class VersionIndex {
|
|
31
23
|
constructor(brain) {
|
|
@@ -34,8 +26,6 @@ export class VersionIndex {
|
|
|
34
26
|
}
|
|
35
27
|
/**
|
|
36
28
|
* Initialize version index
|
|
37
|
-
*
|
|
38
|
-
* No special setup needed - we use existing entity storage and indexes!
|
|
39
29
|
*/
|
|
40
30
|
async initialize() {
|
|
41
31
|
if (this.initialized)
|
|
@@ -45,75 +35,85 @@ export class VersionIndex {
|
|
|
45
35
|
/**
|
|
46
36
|
* Add version to index
|
|
47
37
|
*
|
|
48
|
-
* Stores version
|
|
49
|
-
*
|
|
38
|
+
* Stores version entry in key-value storage.
|
|
39
|
+
* Handles deduplication by content hash.
|
|
50
40
|
*
|
|
51
|
-
* @param version Version metadata
|
|
41
|
+
* @param version Version metadata to store
|
|
52
42
|
*/
|
|
53
43
|
async addVersion(version) {
|
|
54
44
|
await this.initialize();
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
versionContentHash: version.contentHash, // Content hash
|
|
74
|
-
versionAuthor: version.author, // Author
|
|
75
|
-
versionDescription: version.description, // Description
|
|
76
|
-
versionMetadata: version.metadata // Additional metadata
|
|
45
|
+
const key = this.getMetaKey(version.entityId, version.branch);
|
|
46
|
+
const store = await this.loadStore(key) || {
|
|
47
|
+
entityId: version.entityId,
|
|
48
|
+
branch: version.branch,
|
|
49
|
+
versions: []
|
|
50
|
+
};
|
|
51
|
+
// Check for duplicate content hash (deduplication)
|
|
52
|
+
const existing = store.versions.find(v => v.contentHash === version.contentHash);
|
|
53
|
+
if (existing) {
|
|
54
|
+
// Update tag/description if provided on duplicate save
|
|
55
|
+
let updated = false;
|
|
56
|
+
if (version.tag && version.tag !== existing.tag) {
|
|
57
|
+
existing.tag = version.tag;
|
|
58
|
+
updated = true;
|
|
59
|
+
}
|
|
60
|
+
if (version.description && version.description !== existing.description) {
|
|
61
|
+
existing.description = version.description;
|
|
62
|
+
updated = true;
|
|
77
63
|
}
|
|
64
|
+
if (updated) {
|
|
65
|
+
await this.saveStore(key, store);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// Add new version entry
|
|
70
|
+
store.versions.push({
|
|
71
|
+
version: version.version,
|
|
72
|
+
timestamp: version.timestamp,
|
|
73
|
+
contentHash: version.contentHash,
|
|
74
|
+
commitHash: version.commitHash,
|
|
75
|
+
tag: version.tag,
|
|
76
|
+
description: version.description,
|
|
77
|
+
author: version.author
|
|
78
78
|
});
|
|
79
|
+
await this.saveStore(key, store);
|
|
79
80
|
}
|
|
80
81
|
/**
|
|
81
82
|
* Get versions for an entity
|
|
82
83
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* @param query Version query
|
|
84
|
+
* @param query Version query with filters
|
|
86
85
|
* @returns List of versions (newest first)
|
|
87
86
|
*/
|
|
88
87
|
async getVersions(query) {
|
|
89
88
|
await this.initialize();
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
const branch = query.branch || this.brain.currentBranch;
|
|
90
|
+
const key = this.getMetaKey(query.entityId, branch);
|
|
91
|
+
const store = await this.loadStore(key);
|
|
92
|
+
if (!store)
|
|
93
|
+
return [];
|
|
94
|
+
// Convert entries to EntityVersion format
|
|
95
|
+
let versions = store.versions.map(entry => ({
|
|
96
|
+
version: entry.version,
|
|
97
|
+
entityId: store.entityId,
|
|
98
|
+
branch: store.branch,
|
|
99
|
+
timestamp: entry.timestamp,
|
|
100
|
+
contentHash: entry.contentHash,
|
|
101
|
+
commitHash: entry.commitHash || '',
|
|
102
|
+
tag: entry.tag,
|
|
103
|
+
description: entry.description,
|
|
104
|
+
author: entry.author
|
|
105
|
+
}));
|
|
106
|
+
// Apply filters
|
|
98
107
|
if (query.tag) {
|
|
99
|
-
|
|
108
|
+
versions = versions.filter(v => v.tag === query.tag);
|
|
100
109
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Convert entities back to EntityVersion format
|
|
104
|
-
const versions = [];
|
|
105
|
-
for (const entity of results) {
|
|
106
|
-
const version = this.entityToVersion(entity);
|
|
107
|
-
if (version) {
|
|
108
|
-
// Filter by date range if specified
|
|
109
|
-
if (query.startDate && version.timestamp < query.startDate)
|
|
110
|
-
continue;
|
|
111
|
-
if (query.endDate && version.timestamp > query.endDate)
|
|
112
|
-
continue;
|
|
113
|
-
versions.push(version);
|
|
114
|
-
}
|
|
110
|
+
if (query.startDate) {
|
|
111
|
+
versions = versions.filter(v => v.timestamp >= query.startDate);
|
|
115
112
|
}
|
|
116
|
-
|
|
113
|
+
if (query.endDate) {
|
|
114
|
+
versions = versions.filter(v => v.timestamp <= query.endDate);
|
|
115
|
+
}
|
|
116
|
+
// Sort newest first (highest version number first)
|
|
117
117
|
versions.sort((a, b) => b.version - a.version);
|
|
118
118
|
// Apply pagination
|
|
119
119
|
const start = query.offset || 0;
|
|
@@ -129,12 +129,8 @@ export class VersionIndex {
|
|
|
129
129
|
* @returns Version metadata or null
|
|
130
130
|
*/
|
|
131
131
|
async getVersion(entityId, version, branch) {
|
|
132
|
-
await this.
|
|
133
|
-
|
|
134
|
-
const entity = await this.brain.getNounMetadata(versionEntityId);
|
|
135
|
-
if (!entity)
|
|
136
|
-
return null;
|
|
137
|
-
return this.entityToVersion(entity);
|
|
132
|
+
const versions = await this.getVersions({ entityId, branch });
|
|
133
|
+
return versions.find(v => v.version === version) || null;
|
|
138
134
|
}
|
|
139
135
|
/**
|
|
140
136
|
* Get version by tag
|
|
@@ -145,19 +141,8 @@ export class VersionIndex {
|
|
|
145
141
|
* @returns Version metadata or null
|
|
146
142
|
*/
|
|
147
143
|
async getVersionByTag(entityId, tag, branch) {
|
|
148
|
-
await this.
|
|
149
|
-
|
|
150
|
-
const results = await this.brain.searchByMetadata({
|
|
151
|
-
type: 'state',
|
|
152
|
-
_isVersion: true,
|
|
153
|
-
versionEntityId: entityId,
|
|
154
|
-
versionBranch: branch,
|
|
155
|
-
versionTag: tag
|
|
156
|
-
});
|
|
157
|
-
if (results.length === 0)
|
|
158
|
-
return null;
|
|
159
|
-
// Return first match (tags should be unique per entity/branch)
|
|
160
|
-
return this.entityToVersion(results[0]);
|
|
144
|
+
const versions = await this.getVersions({ entityId, branch, tag });
|
|
145
|
+
return versions[0] || null;
|
|
161
146
|
}
|
|
162
147
|
/**
|
|
163
148
|
* Get version count for entity
|
|
@@ -167,15 +152,9 @@ export class VersionIndex {
|
|
|
167
152
|
* @returns Number of versions
|
|
168
153
|
*/
|
|
169
154
|
async getVersionCount(entityId, branch) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
type: 'state',
|
|
174
|
-
_isVersion: true,
|
|
175
|
-
versionEntityId: entityId,
|
|
176
|
-
versionBranch: branch
|
|
177
|
-
});
|
|
178
|
-
return results.length;
|
|
155
|
+
const key = this.getMetaKey(entityId, branch);
|
|
156
|
+
const store = await this.loadStore(key);
|
|
157
|
+
return store?.versions.length || 0;
|
|
179
158
|
}
|
|
180
159
|
/**
|
|
181
160
|
* Remove version from index
|
|
@@ -186,90 +165,86 @@ export class VersionIndex {
|
|
|
186
165
|
*/
|
|
187
166
|
async removeVersion(entityId, version, branch) {
|
|
188
167
|
await this.initialize();
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
*/
|
|
199
|
-
entityToVersion(entity) {
|
|
200
|
-
if (!entity || !entity.metadata)
|
|
201
|
-
return null;
|
|
202
|
-
const m = entity.metadata;
|
|
203
|
-
if (!m.versionEntityId ||
|
|
204
|
-
!m.versionBranch ||
|
|
205
|
-
m.versionNumber === undefined ||
|
|
206
|
-
!m.versionCommitHash ||
|
|
207
|
-
!m.versionContentHash ||
|
|
208
|
-
!m.versionTimestamp) {
|
|
209
|
-
return null;
|
|
168
|
+
const key = this.getMetaKey(entityId, branch);
|
|
169
|
+
const store = await this.loadStore(key);
|
|
170
|
+
if (!store)
|
|
171
|
+
return;
|
|
172
|
+
const initialLength = store.versions.length;
|
|
173
|
+
store.versions = store.versions.filter(v => v.version !== version);
|
|
174
|
+
// Only save if something was removed
|
|
175
|
+
if (store.versions.length < initialLength) {
|
|
176
|
+
await this.saveStore(key, store);
|
|
210
177
|
}
|
|
211
|
-
return {
|
|
212
|
-
version: m.versionNumber,
|
|
213
|
-
entityId: m.versionEntityId,
|
|
214
|
-
branch: m.versionBranch,
|
|
215
|
-
commitHash: m.versionCommitHash,
|
|
216
|
-
timestamp: m.versionTimestamp,
|
|
217
|
-
contentHash: m.versionContentHash,
|
|
218
|
-
tag: m.versionTag,
|
|
219
|
-
description: m.versionDescription,
|
|
220
|
-
author: m.versionAuthor,
|
|
221
|
-
metadata: m.versionMetadata
|
|
222
|
-
};
|
|
223
178
|
}
|
|
224
179
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* Format: _version:{entityId}:{version}:{branch}
|
|
180
|
+
* Clear all versions for an entity
|
|
228
181
|
*
|
|
229
182
|
* @param entityId Entity ID
|
|
230
|
-
* @param version Version number
|
|
231
183
|
* @param branch Branch name
|
|
232
|
-
* @returns
|
|
184
|
+
* @returns Number of versions deleted
|
|
233
185
|
*/
|
|
234
|
-
|
|
235
|
-
|
|
186
|
+
async clearVersions(entityId, branch) {
|
|
187
|
+
const key = this.getMetaKey(entityId, branch);
|
|
188
|
+
const store = await this.loadStore(key);
|
|
189
|
+
if (!store)
|
|
190
|
+
return 0;
|
|
191
|
+
const count = store.versions.length;
|
|
192
|
+
// Delete the store by saving null/empty
|
|
193
|
+
await this.saveStore(key, { entityId, branch, versions: [] });
|
|
194
|
+
return count;
|
|
236
195
|
}
|
|
237
196
|
/**
|
|
238
197
|
* Get all versioned entities (for cleanup/debugging)
|
|
239
198
|
*
|
|
240
|
-
*
|
|
199
|
+
* Note: This is an expensive operation that requires scanning.
|
|
200
|
+
* In the simple key-value approach, we don't maintain a global index.
|
|
201
|
+
* This method returns an empty array - use storage-level scanning if needed.
|
|
202
|
+
*
|
|
203
|
+
* @returns Empty array (not supported in simple approach)
|
|
241
204
|
*/
|
|
242
205
|
async getVersionedEntities() {
|
|
243
|
-
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
_isVersion: true
|
|
248
|
-
});
|
|
249
|
-
// Extract unique entity IDs
|
|
250
|
-
const entityIds = new Set();
|
|
251
|
-
for (const entity of results) {
|
|
252
|
-
const version = this.entityToVersion(entity);
|
|
253
|
-
if (version) {
|
|
254
|
-
entityIds.add(version.entityId);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return Array.from(entityIds);
|
|
206
|
+
// In the simple key-value approach, we don't maintain a global index
|
|
207
|
+
// of all versioned entities. This would require scanning storage.
|
|
208
|
+
// For most use cases, you know which entities you've versioned.
|
|
209
|
+
return [];
|
|
258
210
|
}
|
|
211
|
+
// ============= Private Helpers =============
|
|
259
212
|
/**
|
|
260
|
-
*
|
|
213
|
+
* Generate storage key for version metadata
|
|
261
214
|
*
|
|
262
215
|
* @param entityId Entity ID
|
|
263
216
|
* @param branch Branch name
|
|
264
|
-
* @returns
|
|
217
|
+
* @returns Storage key
|
|
265
218
|
*/
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
219
|
+
getMetaKey(entityId, branch) {
|
|
220
|
+
return `__version_meta_${entityId}_${branch}`;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Load version store from storage
|
|
224
|
+
*
|
|
225
|
+
* @param key Storage key
|
|
226
|
+
* @returns Version store or null
|
|
227
|
+
*/
|
|
228
|
+
async loadStore(key) {
|
|
229
|
+
try {
|
|
230
|
+
const store = await this.brain.storageAdapter.getMetadata(key);
|
|
231
|
+
// Handle empty store
|
|
232
|
+
if (!store || !store.versions)
|
|
233
|
+
return null;
|
|
234
|
+
return store;
|
|
271
235
|
}
|
|
272
|
-
|
|
236
|
+
catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Save version store to storage
|
|
242
|
+
*
|
|
243
|
+
* @param key Storage key
|
|
244
|
+
* @param store Version store
|
|
245
|
+
*/
|
|
246
|
+
async saveStore(key, store) {
|
|
247
|
+
await this.brain.storageAdapter.saveMetadata(key, store);
|
|
273
248
|
}
|
|
274
249
|
}
|
|
275
250
|
//# sourceMappingURL=VersionIndex.js.map
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* VersionManager - Entity-Level Versioning Engine (v5.3.0)
|
|
2
|
+
* VersionManager - Entity-Level Versioning Engine (v5.3.0, v6.3.0 fix)
|
|
3
3
|
*
|
|
4
4
|
* Provides entity-level version control with:
|
|
5
5
|
* - save() - Create entity version
|
|
6
|
-
* - restore() - Restore entity to specific version
|
|
6
|
+
* - restore() - Restore entity to specific version (v6.3.0: now updates all indexes)
|
|
7
7
|
* - list() - List all versions of an entity
|
|
8
8
|
* - compare() - Deep diff between versions
|
|
9
9
|
* - prune() - Remove old versions (retention policies)
|
|
10
10
|
*
|
|
11
|
-
* Architecture:
|
|
12
|
-
* -
|
|
11
|
+
* Architecture (v6.3.0 - Clean Key-Value Storage):
|
|
12
|
+
* - Versions stored as key-value pairs, NOT as entities (no index pollution)
|
|
13
13
|
* - Content-addressable: SHA-256 hashing for deduplication
|
|
14
|
-
* - Space-efficient: Only stores
|
|
14
|
+
* - Space-efficient: Only stores unique content
|
|
15
15
|
* - Branch-aware: Versions tied to current branch
|
|
16
|
+
* - restore() uses brain.update() to refresh ALL indexes (HNSW, metadata, graph)
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
+
* Storage keys:
|
|
19
|
+
* - Version metadata: __version_meta_{entityId}_{branch}
|
|
20
|
+
* - Version content: __system_version_{entityId}_{contentHash}
|
|
21
|
+
*
|
|
22
|
+
* ZERO-CONFIG - Works automatically with existing storage infrastructure.
|
|
23
|
+
* NO MOCKS - Production implementation.
|
|
18
24
|
*/
|
|
19
25
|
import { VersionDiff } from './VersionDiff.js';
|
|
20
26
|
export interface EntityVersion {
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* VersionManager - Entity-Level Versioning Engine (v5.3.0)
|
|
2
|
+
* VersionManager - Entity-Level Versioning Engine (v5.3.0, v6.3.0 fix)
|
|
3
3
|
*
|
|
4
4
|
* Provides entity-level version control with:
|
|
5
5
|
* - save() - Create entity version
|
|
6
|
-
* - restore() - Restore entity to specific version
|
|
6
|
+
* - restore() - Restore entity to specific version (v6.3.0: now updates all indexes)
|
|
7
7
|
* - list() - List all versions of an entity
|
|
8
8
|
* - compare() - Deep diff between versions
|
|
9
9
|
* - prune() - Remove old versions (retention policies)
|
|
10
10
|
*
|
|
11
|
-
* Architecture:
|
|
12
|
-
* -
|
|
11
|
+
* Architecture (v6.3.0 - Clean Key-Value Storage):
|
|
12
|
+
* - Versions stored as key-value pairs, NOT as entities (no index pollution)
|
|
13
13
|
* - Content-addressable: SHA-256 hashing for deduplication
|
|
14
|
-
* - Space-efficient: Only stores
|
|
14
|
+
* - Space-efficient: Only stores unique content
|
|
15
15
|
* - Branch-aware: Versions tied to current branch
|
|
16
|
+
* - restore() uses brain.update() to refresh ALL indexes (HNSW, metadata, graph)
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
+
* Storage keys:
|
|
19
|
+
* - Version metadata: __version_meta_{entityId}_{branch}
|
|
20
|
+
* - Version content: __system_version_{entityId}_{contentHash}
|
|
21
|
+
*
|
|
22
|
+
* ZERO-CONFIG - Works automatically with existing storage infrastructure.
|
|
23
|
+
* NO MOCKS - Production implementation.
|
|
18
24
|
*/
|
|
19
25
|
import { VersionStorage } from './VersionStorage.js';
|
|
20
26
|
import { VersionIndex } from './VersionIndex.js';
|
|
@@ -201,8 +207,20 @@ export class VersionManager {
|
|
|
201
207
|
if (!versionedEntity) {
|
|
202
208
|
throw new Error(`Version data not found for entity ${entityId} version ${version}`);
|
|
203
209
|
}
|
|
204
|
-
//
|
|
205
|
-
|
|
210
|
+
// Extract standard fields vs custom metadata
|
|
211
|
+
// NounMetadata has: noun, data, createdAt, updatedAt, createdBy, service, confidence, weight
|
|
212
|
+
const { noun, data, createdAt, updatedAt, createdBy, service, confidence, weight, ...customMetadata } = versionedEntity;
|
|
213
|
+
// Use brain.update() to restore - this updates ALL indexes (HNSW, metadata, graph)
|
|
214
|
+
// This is critical: saveNounMetadata() only saves to storage without updating indexes
|
|
215
|
+
await this.brain.update({
|
|
216
|
+
id: entityId,
|
|
217
|
+
data: data,
|
|
218
|
+
type: noun,
|
|
219
|
+
metadata: customMetadata,
|
|
220
|
+
confidence: confidence,
|
|
221
|
+
weight: weight,
|
|
222
|
+
merge: false // Replace entirely, don't merge with existing metadata
|
|
223
|
+
});
|
|
206
224
|
return targetVersion;
|
|
207
225
|
}
|
|
208
226
|
/**
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* VersionStorage - Hybrid Storage for Entity Versions (v5.3.0)
|
|
2
|
+
* VersionStorage - Hybrid Storage for Entity Versions (v5.3.0, v6.3.0 fix)
|
|
3
3
|
*
|
|
4
4
|
* Implements content-addressable storage for entity versions:
|
|
5
5
|
* - SHA-256 content hashing for deduplication
|
|
6
|
-
* -
|
|
6
|
+
* - Uses BaseStorage.saveMetadata/getMetadata for storage (v6.3.0)
|
|
7
7
|
* - Integrates with COW commit system
|
|
8
8
|
* - Space-efficient: Only stores unique content
|
|
9
9
|
*
|
|
10
|
-
* Storage structure:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* └── {entityId}.json # Version index (managed by VersionIndex)
|
|
10
|
+
* Storage structure (v6.3.0):
|
|
11
|
+
* Version content is stored using system metadata keys:
|
|
12
|
+
* __system_version_{entityId}_{contentHash}
|
|
13
|
+
*
|
|
14
|
+
* This integrates with BaseStorage's routing which places system keys
|
|
15
|
+
* in the _system/ directory, keeping version data separate from entities.
|
|
17
16
|
*
|
|
18
17
|
* NO MOCKS - Production implementation
|
|
19
18
|
*/
|
|
@@ -64,38 +63,49 @@ export declare class VersionStorage {
|
|
|
64
63
|
*/
|
|
65
64
|
deleteVersion(version: EntityVersion): Promise<void>;
|
|
66
65
|
/**
|
|
67
|
-
* Get version storage
|
|
66
|
+
* Get version storage key
|
|
67
|
+
*
|
|
68
|
+
* Uses __system_ prefix so BaseStorage routes to system storage (_system/ directory)
|
|
69
|
+
* This keeps version data separate from entity data.
|
|
68
70
|
*
|
|
69
71
|
* @param entityId Entity ID
|
|
70
72
|
* @param contentHash Content hash
|
|
71
|
-
* @returns Storage
|
|
73
|
+
* @returns Storage key for version content
|
|
72
74
|
*/
|
|
73
75
|
private getVersionPath;
|
|
74
76
|
/**
|
|
75
77
|
* Check if content exists in storage
|
|
76
78
|
*
|
|
77
|
-
* @param
|
|
79
|
+
* @param key Storage key
|
|
78
80
|
* @returns True if exists
|
|
79
81
|
*/
|
|
80
82
|
private contentExists;
|
|
81
83
|
/**
|
|
82
84
|
* Write version data to storage
|
|
83
85
|
*
|
|
84
|
-
* @param
|
|
86
|
+
* @param key Storage key
|
|
85
87
|
* @param entity Entity data
|
|
86
88
|
*/
|
|
87
89
|
private writeVersionData;
|
|
88
90
|
/**
|
|
89
91
|
* Read version data from storage
|
|
90
92
|
*
|
|
91
|
-
* @param
|
|
93
|
+
* @param key Storage key
|
|
92
94
|
* @returns Entity data
|
|
93
95
|
*/
|
|
94
96
|
private readVersionData;
|
|
95
97
|
/**
|
|
96
98
|
* Delete version data from storage
|
|
97
99
|
*
|
|
98
|
-
*
|
|
100
|
+
* Note: Version content is content-addressed and immutable.
|
|
101
|
+
* Deleting the version index entry (via VersionIndex.removeVersion) is sufficient.
|
|
102
|
+
* The content may be shared with other versions (same contentHash).
|
|
103
|
+
*
|
|
104
|
+
* v6.3.0: We don't actually delete version content to avoid breaking
|
|
105
|
+
* other versions that may reference the same content hash.
|
|
106
|
+
* A separate garbage collection process could clean up unreferenced content.
|
|
107
|
+
*
|
|
108
|
+
* @param key Storage key (unused - kept for API compatibility)
|
|
99
109
|
*/
|
|
100
110
|
private deleteVersionData;
|
|
101
111
|
}
|