@prmichaelsen/remember-mcp 2.8.0 → 3.12.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.
Files changed (250) hide show
  1. package/AGENT.md +296 -250
  2. package/CHANGELOG.md +468 -0
  3. package/README.md +163 -46
  4. package/agent/commands/acp.clarification-create.md +382 -0
  5. package/agent/commands/acp.command-create.md +0 -1
  6. package/agent/commands/acp.design-create.md +0 -1
  7. package/agent/commands/acp.init.md +0 -1
  8. package/agent/commands/acp.package-create.md +0 -1
  9. package/agent/commands/acp.package-info.md +0 -1
  10. package/agent/commands/acp.package-install.md +0 -1
  11. package/agent/commands/acp.package-list.md +0 -1
  12. package/agent/commands/acp.package-publish.md +0 -1
  13. package/agent/commands/acp.package-remove.md +0 -1
  14. package/agent/commands/acp.package-search.md +0 -1
  15. package/agent/commands/acp.package-update.md +0 -1
  16. package/agent/commands/acp.package-validate.md +0 -1
  17. package/agent/commands/acp.pattern-create.md +0 -1
  18. package/agent/commands/acp.plan.md +0 -1
  19. package/agent/commands/acp.proceed.md +0 -1
  20. package/agent/commands/acp.project-create.md +0 -1
  21. package/agent/commands/acp.project-info.md +309 -0
  22. package/agent/commands/acp.project-list.md +0 -1
  23. package/agent/commands/acp.project-remove.md +379 -0
  24. package/agent/commands/acp.project-set.md +0 -1
  25. package/agent/commands/acp.project-update.md +296 -0
  26. package/agent/commands/acp.report.md +0 -1
  27. package/agent/commands/acp.resume.md +0 -1
  28. package/agent/commands/acp.status.md +0 -1
  29. package/agent/commands/acp.sync.md +0 -1
  30. package/agent/commands/acp.task-create.md +17 -10
  31. package/agent/commands/acp.update.md +0 -1
  32. package/agent/commands/acp.validate.md +0 -1
  33. package/agent/commands/acp.version-check-for-updates.md +0 -1
  34. package/agent/commands/acp.version-check.md +0 -1
  35. package/agent/commands/acp.version-update.md +0 -1
  36. package/agent/commands/command.template.md +0 -5
  37. package/agent/commands/git.commit.md +13 -2
  38. package/agent/commands/git.init.md +0 -1
  39. package/agent/design/comment-memory-type.md +2 -2
  40. package/agent/design/local.collaborative-memory-sync.md +265 -0
  41. package/agent/design/local.content-flags.md +210 -0
  42. package/agent/design/local.ghost-persona-system.md +273 -0
  43. package/agent/design/local.group-acl-integration.md +338 -0
  44. package/agent/design/local.memory-acl-schema.md +352 -0
  45. package/agent/design/local.memory-collection-pattern-v2.md +348 -0
  46. package/agent/design/local.moderation-and-space-config.md +257 -0
  47. package/agent/design/local.v2-api-reference.md +621 -0
  48. package/agent/design/local.v2-migration-guide.md +191 -0
  49. package/agent/design/local.v2-usage-examples.md +265 -0
  50. package/agent/design/permissions-storage-architecture.md +11 -3
  51. package/agent/design/soft-delete-system.md +291 -0
  52. package/agent/design/trust-escalation-prevention.md +9 -2
  53. package/agent/design/trust-system-implementation.md +12 -3
  54. package/agent/milestones/milestone-13-soft-delete-system.md +306 -0
  55. package/agent/milestones/milestone-14-memory-collection-v2.md +182 -0
  56. package/agent/milestones/milestone-15-moderation-space-config.md +126 -0
  57. package/agent/package.template.yaml +0 -17
  58. package/agent/progress.yaml +762 -49
  59. package/agent/scripts/acp.common.sh +2 -0
  60. package/agent/scripts/acp.install.sh +15 -85
  61. package/agent/scripts/acp.package-install-optimized.sh +454 -0
  62. package/agent/scripts/acp.package-install.sh +248 -380
  63. package/agent/scripts/acp.package-validate.sh +0 -99
  64. package/agent/scripts/acp.project-info.sh +218 -0
  65. package/agent/scripts/acp.project-remove.sh +302 -0
  66. package/agent/scripts/acp.project-update.sh +296 -0
  67. package/agent/scripts/acp.yaml-parser.sh +128 -10
  68. package/agent/tasks/milestone-14-memory-collection-v2/task-165-core-infrastructure-setup.md +171 -0
  69. package/agent/tasks/milestone-14-memory-collection-v2/task-166-update-remember-publish.md +191 -0
  70. package/agent/tasks/milestone-14-memory-collection-v2/task-167-update-remember-retract.md +186 -0
  71. package/agent/tasks/milestone-14-memory-collection-v2/task-168-implement-remember-revise.md +184 -0
  72. package/agent/tasks/milestone-14-memory-collection-v2/task-169-update-remember-search-space.md +179 -0
  73. package/agent/tasks/milestone-14-memory-collection-v2/task-170-update-remember-create-update.md +139 -0
  74. package/agent/tasks/milestone-14-memory-collection-v2/task-172-performance-testing-optimization.md +161 -0
  75. package/agent/tasks/milestone-14-memory-collection-v2/task-173-documentation-examples.md +258 -0
  76. package/agent/tasks/milestone-15-moderation-space-config/task-174-add-moderation-schema-fields.md +57 -0
  77. package/agent/tasks/milestone-15-moderation-space-config/task-175-create-space-config-service.md +64 -0
  78. package/agent/tasks/milestone-15-moderation-space-config/task-176-wire-moderation-publish-flow.md +45 -0
  79. package/agent/tasks/milestone-15-moderation-space-config/task-177-add-moderation-search-filters.md +70 -0
  80. package/agent/tasks/milestone-15-moderation-space-config/task-178-create-remember-moderate-tool.md +69 -0
  81. package/agent/tasks/milestone-15-moderation-space-config/task-179-documentation-integration-tests.md +58 -0
  82. package/agent/tasks/milestone-16-ghost-system/task-187-ghost-config-firestore.md +41 -0
  83. package/agent/tasks/milestone-16-ghost-system/task-188-trust-filter-integration.md +44 -0
  84. package/agent/tasks/milestone-16-ghost-system/task-189-ghost-memory-filtering.md +43 -0
  85. package/agent/tasks/milestone-16-ghost-system/task-190-ghost-config-tools.md +45 -0
  86. package/agent/tasks/milestone-16-ghost-system/task-191-escalation-firestore.md +38 -0
  87. package/agent/tasks/milestone-16-ghost-system/task-192-documentation-verification.md +39 -0
  88. package/agent/tasks/milestone-7-trust-permissions/task-180-access-result-permission-types.md +69 -0
  89. package/agent/tasks/milestone-7-trust-permissions/task-181-firestore-permissions-access-logs.md +56 -0
  90. package/agent/tasks/milestone-7-trust-permissions/task-182-trust-enforcement-service.md +68 -0
  91. package/agent/tasks/milestone-7-trust-permissions/task-183-access-control-service.md +70 -0
  92. package/agent/tasks/milestone-7-trust-permissions/task-184-permission-tools.md +79 -0
  93. package/agent/tasks/milestone-7-trust-permissions/task-185-wire-trust-into-search-query.md +55 -0
  94. package/agent/tasks/milestone-7-trust-permissions/task-186-documentation-verification.md +56 -0
  95. package/agent/tasks/task-70-add-soft-delete-schema-fields.md +165 -0
  96. package/agent/tasks/task-71-implement-delete-confirmation-flow.md +257 -0
  97. package/agent/tasks/task-72-add-deleted-filter-to-search-tools.md +18 -0
  98. package/agent/tasks/task-73-update-relationship-handling.md +18 -0
  99. package/agent/tasks/task-74-add-unit-tests-soft-delete.md +18 -0
  100. package/agent/tasks/task-75-update-documentation-changelog.md +26 -0
  101. package/agent/tasks/task-76-fix-indexnullstate-schema-bug.md +197 -0
  102. package/dist/collections/composite-ids.d.ts +106 -0
  103. package/dist/collections/core-infrastructure.spec.d.ts +11 -0
  104. package/dist/collections/dot-notation.d.ts +106 -0
  105. package/dist/collections/tracking-arrays.d.ts +176 -0
  106. package/dist/constants/content-types.d.ts +1 -0
  107. package/dist/schema/v2-collections-comments.spec.d.ts +8 -0
  108. package/dist/schema/v2-collections.d.ts +210 -0
  109. package/dist/server-factory.d.ts +15 -0
  110. package/dist/server-factory.js +3261 -1316
  111. package/dist/server.js +2926 -1236
  112. package/dist/services/access-control.d.ts +103 -0
  113. package/dist/services/access-control.spec.d.ts +2 -0
  114. package/dist/services/credentials-provider.d.ts +24 -0
  115. package/dist/services/credentials-provider.spec.d.ts +2 -0
  116. package/dist/services/escalation.service.d.ts +22 -0
  117. package/dist/services/escalation.service.spec.d.ts +2 -0
  118. package/dist/services/ghost-config.service.d.ts +55 -0
  119. package/dist/services/ghost-config.service.spec.d.ts +2 -0
  120. package/dist/services/space-config.service.d.ts +23 -0
  121. package/dist/services/space-config.service.spec.d.ts +2 -0
  122. package/dist/services/trust-enforcement.d.ts +83 -0
  123. package/dist/services/trust-enforcement.spec.d.ts +2 -0
  124. package/dist/services/trust-validator.d.ts +43 -0
  125. package/dist/services/trust-validator.spec.d.ts +2 -0
  126. package/dist/tools/confirm-publish-moderation.spec.d.ts +8 -0
  127. package/dist/tools/confirm.d.ts +8 -1
  128. package/dist/tools/create-memory.d.ts +2 -1
  129. package/dist/tools/create-memory.spec.d.ts +10 -0
  130. package/dist/tools/create-relationship.d.ts +2 -1
  131. package/dist/tools/delete-memory.d.ts +7 -31
  132. package/dist/tools/delete-relationship.d.ts +2 -1
  133. package/dist/tools/deny.d.ts +2 -1
  134. package/dist/tools/find-similar.d.ts +10 -2
  135. package/dist/tools/get-preferences.d.ts +2 -1
  136. package/dist/tools/ghost-config.d.ts +27 -0
  137. package/dist/tools/ghost-config.spec.d.ts +2 -0
  138. package/dist/tools/moderate.d.ts +20 -0
  139. package/dist/tools/moderate.spec.d.ts +5 -0
  140. package/dist/tools/publish.d.ts +11 -3
  141. package/dist/tools/query-memory.d.ts +11 -2
  142. package/dist/tools/query-space.d.ts +4 -1
  143. package/dist/tools/retract.d.ts +29 -0
  144. package/dist/tools/revise.d.ts +45 -0
  145. package/dist/tools/revise.spec.d.ts +8 -0
  146. package/dist/tools/search-memory.d.ts +8 -1
  147. package/dist/tools/search-relationship.d.ts +10 -2
  148. package/dist/tools/search-space.d.ts +25 -5
  149. package/dist/tools/search-space.spec.d.ts +9 -0
  150. package/dist/tools/set-preference.d.ts +2 -1
  151. package/dist/tools/update-memory.d.ts +2 -1
  152. package/dist/tools/update-relationship.d.ts +2 -1
  153. package/dist/types/access-result.d.ts +48 -0
  154. package/dist/types/access-result.spec.d.ts +2 -0
  155. package/dist/types/auth.d.ts +46 -0
  156. package/dist/types/ghost-config.d.ts +36 -0
  157. package/dist/types/memory.d.ts +11 -1
  158. package/dist/types/preferences.d.ts +1 -1
  159. package/dist/types/space-memory.d.ts +3 -0
  160. package/dist/utils/auth-helpers.d.ts +14 -0
  161. package/dist/utils/auth-helpers.spec.d.ts +2 -0
  162. package/dist/utils/test-data-generator.d.ts +124 -0
  163. package/dist/utils/test-data-generator.spec.d.ts +12 -0
  164. package/dist/utils/weaviate-filters.d.ts +19 -0
  165. package/dist/v2-performance.e2e.d.ts +17 -0
  166. package/dist/v2-smoke.e2e.d.ts +14 -0
  167. package/dist/weaviate/client.d.ts +5 -8
  168. package/dist/weaviate/space-schema.d.ts +2 -2
  169. package/docs/performance/v2-benchmarks.md +80 -0
  170. package/jest.e2e.config.js +14 -3
  171. package/package.json +1 -1
  172. package/scripts/.collection-recreation-state.yaml +16 -0
  173. package/scripts/.gitkeep +5 -0
  174. package/scripts/README-collection-recreation.md +224 -0
  175. package/scripts/README.md +51 -0
  176. package/scripts/backup-collections.ts +543 -0
  177. package/scripts/delete-collection.ts +137 -0
  178. package/scripts/migrate-recreate-collections.ts +578 -0
  179. package/scripts/migrate-v1-to-v2.ts +1094 -0
  180. package/scripts/package-lock.json +1113 -0
  181. package/scripts/package.json +27 -0
  182. package/src/collections/composite-ids.ts +193 -0
  183. package/src/collections/core-infrastructure.spec.ts +353 -0
  184. package/src/collections/dot-notation.ts +212 -0
  185. package/src/collections/tracking-arrays.ts +298 -0
  186. package/src/constants/content-types.ts +20 -0
  187. package/src/schema/v2-collections-comments.spec.ts +141 -0
  188. package/src/schema/v2-collections.ts +433 -0
  189. package/src/server-factory.ts +89 -20
  190. package/src/server.ts +45 -17
  191. package/src/services/access-control.spec.ts +383 -0
  192. package/src/services/access-control.ts +291 -0
  193. package/src/services/credentials-provider.spec.ts +22 -0
  194. package/src/services/credentials-provider.ts +34 -0
  195. package/src/services/escalation.service.spec.ts +183 -0
  196. package/src/services/escalation.service.ts +150 -0
  197. package/src/services/ghost-config.service.spec.ts +339 -0
  198. package/src/services/ghost-config.service.ts +219 -0
  199. package/src/services/space-config.service.spec.ts +102 -0
  200. package/src/services/space-config.service.ts +79 -0
  201. package/src/services/trust-enforcement.spec.ts +309 -0
  202. package/src/services/trust-enforcement.ts +197 -0
  203. package/src/services/trust-validator.spec.ts +108 -0
  204. package/src/services/trust-validator.ts +105 -0
  205. package/src/tools/confirm-publish-moderation.spec.ts +240 -0
  206. package/src/tools/confirm.ts +914 -116
  207. package/src/tools/create-memory.spec.ts +126 -0
  208. package/src/tools/create-memory.ts +20 -27
  209. package/src/tools/create-relationship.ts +30 -8
  210. package/src/tools/delete-memory.ts +99 -64
  211. package/src/tools/delete-relationship.ts +15 -6
  212. package/src/tools/deny.ts +8 -1
  213. package/src/tools/find-similar.ts +44 -6
  214. package/src/tools/get-preferences.ts +10 -1
  215. package/src/tools/ghost-config.spec.ts +180 -0
  216. package/src/tools/ghost-config.ts +230 -0
  217. package/src/tools/moderate.spec.ts +277 -0
  218. package/src/tools/moderate.ts +219 -0
  219. package/src/tools/publish.ts +99 -41
  220. package/src/tools/query-memory.ts +44 -9
  221. package/src/tools/query-space.ts +39 -4
  222. package/src/tools/retract.ts +292 -0
  223. package/src/tools/revise.spec.ts +146 -0
  224. package/src/tools/revise.ts +283 -0
  225. package/src/tools/search-memory.ts +46 -10
  226. package/src/tools/search-relationship.ts +30 -7
  227. package/src/tools/search-space.spec.ts +341 -0
  228. package/src/tools/search-space.ts +323 -99
  229. package/src/tools/set-preference.ts +10 -1
  230. package/src/tools/update-memory.ts +24 -5
  231. package/src/tools/update-relationship.ts +10 -1
  232. package/src/types/access-result.spec.ts +193 -0
  233. package/src/types/access-result.ts +62 -0
  234. package/src/types/auth.ts +52 -0
  235. package/src/types/ghost-config.ts +46 -0
  236. package/src/types/memory.ts +20 -1
  237. package/src/types/preferences.ts +2 -2
  238. package/src/types/space-memory.ts +5 -0
  239. package/src/utils/auth-helpers.spec.ts +75 -0
  240. package/src/utils/auth-helpers.ts +25 -0
  241. package/src/utils/test-data-generator.spec.ts +317 -0
  242. package/src/utils/test-data-generator.ts +292 -0
  243. package/src/utils/weaviate-filters.ts +32 -5
  244. package/src/v2-performance.e2e.ts +173 -0
  245. package/src/v2-smoke.e2e.ts +401 -0
  246. package/src/weaviate/client.spec.ts +5 -5
  247. package/src/weaviate/client.ts +55 -35
  248. package/src/weaviate/schema.ts +11 -239
  249. package/src/weaviate/space-schema.spec.ts +28 -25
  250. package/src/weaviate/space-schema.ts +35 -11
@@ -104,26 +104,26 @@ export async function testWeaviateConnection(): Promise<boolean> {
104
104
 
105
105
  /**
106
106
  * Sanitize user_id for collection name
107
- * Weaviate collection names must start with uppercase letter and contain only alphanumeric
107
+ * @deprecated v2 uses literal userId no sanitization needed. Kept for migration script only.
108
108
  */
109
109
  export function sanitizeUserId(userId: string): string {
110
110
  // Remove special characters, keep alphanumeric
111
111
  let sanitized = userId.replace(/[^a-zA-Z0-9]/g, '_');
112
-
112
+
113
113
  // If starts with number, prepend underscore
114
114
  if (/^[0-9]/.test(sanitized)) {
115
115
  sanitized = '_' + sanitized;
116
116
  }
117
-
117
+
118
118
  // Ensure starts with uppercase letter
119
119
  return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
120
120
  }
121
121
 
122
122
  /**
123
- * Get collection name for user's memories
123
+ * Get collection name for user's memories (v2 format)
124
124
  */
125
125
  export function getMemoryCollectionName(userId: string): string {
126
- return `Memory_${sanitizeUserId(userId)}`;
126
+ return `Memory_users_${userId}`;
127
127
  }
128
128
 
129
129
  /**
@@ -142,54 +142,67 @@ export function getAuditCollectionName(userId: string): string {
142
142
 
143
143
  /**
144
144
  * List of all memory properties to fetch
145
- * Centralized to ensure consistency across all tools
146
- */
147
- /**
148
- * List of all memory properties to fetch
149
- * Matches the actual Weaviate schema properties exactly
145
+ * Centralized to ensure consistency across all tools.
146
+ * Includes both v2 canonical names and v1 compat names.
150
147
  */
151
148
  export const ALL_MEMORY_PROPERTIES = [
152
149
  // Core identity
153
150
  'user_id',
154
151
  'doc_type',
155
-
152
+
156
153
  // Memory fields
157
154
  'content',
155
+ 'content_type', // v2 canonical
158
156
  'title',
159
157
  'summary',
160
- 'type',
161
-
158
+ 'type', // v1 compat (v2: content_type)
159
+
162
160
  // Scoring fields
163
161
  'weight',
164
162
  'base_weight',
165
- 'trust',
163
+ 'trust_score', // v2 canonical
164
+ 'trust', // v1 compat (v2: trust_score)
166
165
  'confidence',
167
166
  'computed_weight',
168
-
169
- // Location fields (flattened)
167
+
168
+ // Location fields (v2)
169
+ 'location_name',
170
+ 'location_lat', // v2 canonical
171
+ 'location_lon', // v2 canonical
172
+ // Location fields (v1 compat)
170
173
  'location_gps_lat',
171
174
  'location_gps_lng',
172
175
  'location_address',
173
176
  'location_city',
174
177
  'location_country',
175
178
  'location_source',
176
-
179
+
177
180
  // Locale fields
178
181
  'locale_language',
179
182
  'locale_timezone',
180
-
181
- // Context fields (flattened)
183
+
184
+ // Context fields
182
185
  'context_conversation_id',
183
186
  'context_summary',
184
187
  'context_timestamp',
185
-
186
- // Relationships
188
+ 'context_app',
189
+ 'context_url',
190
+
191
+ // Relationships (v2)
192
+ 'relationship_ids', // v2 canonical
193
+ 'related_memory_ids', // v2 canonical
194
+ // Relationships (v1 compat)
187
195
  'relationships',
188
-
196
+ 'memory_ids',
197
+ // Common relationship fields
198
+ 'relationship_type',
199
+ 'observation',
200
+ 'strength',
201
+
189
202
  // Access tracking
190
203
  'access_count',
191
204
  'last_accessed_at',
192
-
205
+
193
206
  // Metadata
194
207
  'tags',
195
208
  'references',
@@ -197,27 +210,34 @@ export const ALL_MEMORY_PROPERTIES = [
197
210
  'updated_at',
198
211
  'version',
199
212
  'template_id',
200
-
201
- // Relationship-specific fields
202
- 'memory_ids',
203
- 'relationship_type',
204
- 'observation',
205
- 'strength',
206
-
213
+
214
+ // Tracking arrays (v2)
215
+ 'space_ids',
216
+ 'group_ids',
217
+
207
218
  // Comment/threading fields
208
219
  'parent_id',
209
220
  'thread_root_id',
210
221
  'moderation_flags',
211
-
212
- // Space/publishing fields (for Memory_public collection)
213
- 'spaces',
214
- 'space_id',
222
+
223
+ // Space/publishing fields
224
+ 'spaces', // legacy
225
+ 'space_id', // legacy
215
226
  'author_id',
216
227
  'ghost_id',
217
228
  'attribution',
218
229
  'published_at',
219
230
  'discovery_count',
220
- 'space_memory_id',
231
+ 'space_memory_id', // legacy
232
+ 'original_memory_id',
233
+ 'revised_at',
234
+ 'revision_count',
235
+ 'revision_history',
236
+
237
+ // Soft delete fields
238
+ 'deleted_at',
239
+ 'deleted_by',
240
+ 'deletion_reason',
221
241
  ] as const;
222
242
 
223
243
  /**
@@ -4,9 +4,10 @@
4
4
  */
5
5
 
6
6
  import weaviate, { WeaviateClient } from 'weaviate-client';
7
- import { getWeaviateClient, sanitizeUserId } from './client.js';
7
+ import { getWeaviateClient } from './client.js';
8
8
  import { config } from '../config.js';
9
9
  import { logger } from '../utils/logger.js';
10
+ import { createUserCollectionSchema } from '../schema/v2-collections.js';
10
11
 
11
12
  /**
12
13
  * Create Memory collection schema for a user
@@ -21,7 +22,7 @@ import { logger } from '../utils/logger.js';
21
22
  */
22
23
  export async function createMemoryCollection(userId: string): Promise<void> {
23
24
  const client = getWeaviateClient();
24
- const collectionName = `Memory_${sanitizeUserId(userId)}`;
25
+ const collectionName = `Memory_users_${userId}`;
25
26
 
26
27
  // Check if collection already exists
27
28
  const exists = await client.collections.exists(collectionName);
@@ -38,238 +39,9 @@ export async function createMemoryCollection(userId: string): Promise<void> {
38
39
  collectionName,
39
40
  });
40
41
 
41
- // Create collection with schema
42
- await client.collections.create({
43
- name: collectionName,
44
-
45
- // Vectorizer configuration
46
- vectorizers: weaviate.configure.vectorizer.text2VecOpenAI({
47
- model: 'text-embedding-3-small',
48
- // Vectorize content, title, summary, and observation for semantic search
49
- // Note: title and summary are optional fields
50
- sourceProperties: ['content', 'title', 'summary', 'observation'],
51
- }),
52
-
53
- properties: [
54
- // Discriminator
55
- {
56
- name: 'doc_type',
57
- dataType: 'text' as any,
58
- description: 'Document type: "memory" or "relationship"',
59
- },
60
-
61
- // Core identity
62
- {
63
- name: 'user_id',
64
- dataType: 'text' as any,
65
- description: 'User who owns this document',
66
- },
67
-
68
- // Memory fields
69
- {
70
- name: 'content',
71
- dataType: 'text' as any,
72
- description: 'Main memory content (vectorized)',
73
- },
74
- {
75
- name: 'title',
76
- dataType: 'text' as any,
77
- description: 'Optional short title',
78
- },
79
- {
80
- name: 'summary',
81
- dataType: 'text' as any,
82
- description: 'Optional brief summary',
83
- },
84
- {
85
- name: 'type',
86
- dataType: 'text' as any,
87
- description: 'Content type (note, event, person, etc.)',
88
- },
89
-
90
- // Scoring fields
91
- {
92
- name: 'weight',
93
- dataType: 'number' as any,
94
- description: 'Significance/priority (0-1)',
95
- },
96
- {
97
- name: 'trust',
98
- dataType: 'number' as any,
99
- description: 'Access control level (0-1)',
100
- },
101
- {
102
- name: 'confidence',
103
- dataType: 'number' as any,
104
- description: 'System confidence in accuracy (0-1)',
105
- },
106
-
107
- // Location fields (flattened for Weaviate)
108
- {
109
- name: 'location_gps_lat',
110
- dataType: 'number' as any,
111
- description: 'GPS latitude',
112
- },
113
- {
114
- name: 'location_gps_lng',
115
- dataType: 'number' as any,
116
- description: 'GPS longitude',
117
- },
118
- {
119
- name: 'location_address',
120
- dataType: 'text' as any,
121
- description: 'Formatted address',
122
- },
123
- {
124
- name: 'location_city',
125
- dataType: 'text' as any,
126
- description: 'City name',
127
- },
128
- {
129
- name: 'location_country',
130
- dataType: 'text' as any,
131
- description: 'Country name',
132
- },
133
- {
134
- name: 'location_source',
135
- dataType: 'text' as any,
136
- description: 'Location source (gps, ip, manual, etc.)',
137
- },
138
-
139
- // Locale fields
140
- {
141
- name: 'locale_language',
142
- dataType: 'text' as any,
143
- description: 'Language code (e.g., en, es, fr)',
144
- },
145
- {
146
- name: 'locale_timezone',
147
- dataType: 'text' as any,
148
- description: 'Timezone (e.g., America/Los_Angeles)',
149
- },
150
-
151
- // Context fields
152
- {
153
- name: 'context_conversation_id',
154
- dataType: 'text' as any,
155
- description: 'Conversation ID',
156
- },
157
- {
158
- name: 'context_summary',
159
- dataType: 'text' as any,
160
- description: 'Brief context summary',
161
- },
162
- {
163
- name: 'context_timestamp',
164
- dataType: 'date' as any,
165
- description: 'Context timestamp',
166
- },
167
-
168
- // Relationships
169
- {
170
- name: 'relationships',
171
- dataType: 'text[]' as any,
172
- description: 'Array of relationship IDs',
173
- },
174
-
175
- // Access tracking
176
- {
177
- name: 'access_count',
178
- dataType: 'number' as any,
179
- description: 'Total times accessed',
180
- },
181
- {
182
- name: 'last_accessed_at',
183
- dataType: 'date' as any,
184
- description: 'Most recent access timestamp',
185
- },
186
-
187
- // Metadata
188
- {
189
- name: 'tags',
190
- dataType: 'text[]' as any,
191
- description: 'Tags for organization',
192
- },
193
- {
194
- name: 'references',
195
- dataType: 'text[]' as any,
196
- description: 'Source URLs',
197
- },
198
- {
199
- name: 'created_at',
200
- dataType: 'date' as any,
201
- description: 'Creation timestamp',
202
- },
203
- {
204
- name: 'updated_at',
205
- dataType: 'date' as any,
206
- description: 'Last update timestamp',
207
- },
208
- {
209
- name: 'version',
210
- dataType: 'number' as any,
211
- description: 'Version number',
212
- },
213
-
214
- // Template fields
215
- {
216
- name: 'template_id',
217
- dataType: 'text' as any,
218
- description: 'Template ID if using template',
219
- },
220
-
221
- // Relationship-specific fields
222
- {
223
- name: 'memory_ids',
224
- dataType: 'text[]' as any,
225
- description: 'Connected memory IDs (for relationships)',
226
- },
227
- {
228
- name: 'relationship_type',
229
- dataType: 'text' as any,
230
- description: 'Relationship type (for relationships)',
231
- },
232
- {
233
- name: 'observation',
234
- dataType: 'text' as any,
235
- description: 'Relationship observation (vectorized)',
236
- },
237
- {
238
- name: 'strength',
239
- dataType: 'number' as any,
240
- description: 'Relationship strength (0-1)',
241
- },
242
-
243
- // Computed fields
244
- {
245
- name: 'base_weight',
246
- dataType: 'number' as any,
247
- description: 'User-specified weight',
248
- },
249
- {
250
- name: 'computed_weight',
251
- dataType: 'number' as any,
252
- description: 'Calculated effective weight',
253
- },
254
-
255
- // Comment/threading fields (for threaded discussions in shared spaces)
256
- {
257
- name: 'parent_id',
258
- dataType: 'text' as any,
259
- description: 'ID of parent memory or comment (for threading)',
260
- },
261
- {
262
- name: 'thread_root_id',
263
- dataType: 'text' as any,
264
- description: 'Root memory ID for fetching entire thread',
265
- },
266
- {
267
- name: 'moderation_flags',
268
- dataType: 'text[]' as any,
269
- description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")',
270
- },
271
- ],
272
- });
42
+ // Create collection using v2 schema
43
+ const schema = createUserCollectionSchema(userId);
44
+ await client.collections.create(schema);
273
45
 
274
46
  logger.info('Memory collection created successfully', {
275
47
  module: 'weaviate-schema',
@@ -282,10 +54,10 @@ export async function createMemoryCollection(userId: string): Promise<void> {
282
54
  */
283
55
  export async function ensureMemoryCollection(userId: string): Promise<void> {
284
56
  const client = getWeaviateClient();
285
- const collectionName = `Memory_${sanitizeUserId(userId)}`;
57
+ const collectionName = `Memory_users_${userId}`;
286
58
 
287
59
  const exists = await client.collections.exists(collectionName);
288
-
60
+
289
61
  if (!exists) {
290
62
  await createMemoryCollection(userId);
291
63
  }
@@ -296,7 +68,7 @@ export async function ensureMemoryCollection(userId: string): Promise<void> {
296
68
  */
297
69
  export function getMemoryCollection(userId: string) {
298
70
  const client = getWeaviateClient();
299
- const collectionName = `Memory_${sanitizeUserId(userId)}`;
71
+ const collectionName = `Memory_users_${userId}`;
300
72
  return client.collections.get(collectionName);
301
73
  }
302
74
 
@@ -305,10 +77,10 @@ export function getMemoryCollection(userId: string) {
305
77
  */
306
78
  export async function deleteMemoryCollection(userId: string): Promise<void> {
307
79
  const client = getWeaviateClient();
308
- const collectionName = `Memory_${sanitizeUserId(userId)}`;
80
+ const collectionName = `Memory_users_${userId}`;
309
81
 
310
82
  const exists = await client.collections.exists(collectionName);
311
-
83
+
312
84
  if (exists) {
313
85
  await client.collections.delete(collectionName);
314
86
  logger.info('Memory collection deleted', {
@@ -119,22 +119,25 @@ describe('Space Schema Utilities', () => {
119
119
  expect(createCall.vectorizers).toBeDefined();
120
120
  expect(createCall.properties).toBeDefined();
121
121
  expect(createCall.properties.length).toBeGreaterThan(20); // Should have many properties
122
-
122
+
123
123
  // Check for space-specific properties
124
124
  const propertyNames = createCall.properties.map((p: any) => p.name);
125
- expect(propertyNames).toContain('spaces'); // New array field
126
- expect(propertyNames).toContain('space_id');
125
+ expect(propertyNames).toContain('spaces'); // legacy multi-space array field
127
126
  expect(propertyNames).toContain('author_id');
128
127
  expect(propertyNames).toContain('ghost_id');
129
128
  expect(propertyNames).toContain('published_at');
130
129
  expect(propertyNames).toContain('discovery_count');
131
130
  expect(propertyNames).toContain('attribution');
131
+ // Soft delete fields
132
+ expect(propertyNames).toContain('deleted_at');
133
+ expect(propertyNames).toContain('deleted_by');
134
+ expect(propertyNames).toContain('deletion_reason');
132
135
  });
133
136
  });
134
137
 
135
- describe('Unified Public Collection', () => {
136
- it('should create Memory_public collection', async () => {
137
- const mockCollection = { name: 'Memory_public' };
138
+ describe('Unified Public Collection (v2: Memory_spaces_public)', () => {
139
+ it('should create Memory_spaces_public collection', async () => {
140
+ const mockCollection = { name: 'Memory_spaces_public' };
138
141
  (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(false);
139
142
  (mockWeaviateClient.collections.create as jest.Mock).mockResolvedValue(undefined);
140
143
  (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue(mockCollection);
@@ -142,25 +145,25 @@ describe('Space Schema Utilities', () => {
142
145
  const result = await ensurePublicCollection(mockWeaviateClient);
143
146
 
144
147
  expect(result).toBe(mockCollection);
145
- expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_public');
148
+ expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_spaces_public');
146
149
  expect(mockWeaviateClient.collections.create).toHaveBeenCalled();
147
- expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_public');
150
+ expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_spaces_public');
148
151
  });
149
152
 
150
- it('should return existing Memory_public if it exists', async () => {
151
- const mockCollection = { name: 'Memory_public' };
153
+ it('should return existing Memory_spaces_public if it exists', async () => {
154
+ const mockCollection = { name: 'Memory_spaces_public' };
152
155
  (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(true);
153
156
  (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue(mockCollection);
154
157
 
155
158
  const result = await ensurePublicCollection(mockWeaviateClient);
156
159
 
157
160
  expect(result).toBe(mockCollection);
158
- expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_public');
159
- expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_public');
161
+ expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_spaces_public');
162
+ expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_spaces_public');
160
163
  expect(mockWeaviateClient.collections.create).not.toHaveBeenCalled();
161
164
  });
162
165
 
163
- it('should have spaces array field in schema', async () => {
166
+ it('should use v2 schema with space_ids array field', async () => {
164
167
  (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(false);
165
168
  (mockWeaviateClient.collections.create as jest.Mock).mockResolvedValue(undefined);
166
169
  (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue({});
@@ -168,19 +171,19 @@ describe('Space Schema Utilities', () => {
168
171
  await ensurePublicCollection(mockWeaviateClient);
169
172
 
170
173
  const createCall = (mockWeaviateClient.collections.create as jest.Mock).mock.calls[0][0];
174
+ expect(createCall.name).toBe('Memory_spaces_public');
175
+
171
176
  const propertyNames = createCall.properties.map((p: any) => p.name);
172
-
173
- // Verify spaces array field exists
174
- expect(propertyNames).toContain('spaces');
175
-
176
- // Find spaces property and verify it's an array
177
- const spacesProperty = createCall.properties.find((p: any) => p.name === 'spaces');
178
- expect(spacesProperty).toBeDefined();
179
- expect(spacesProperty.dataType).toBe('text[]');
180
- });
181
-
182
- it('should verify PUBLIC_COLLECTION_NAME constant', () => {
183
- expect(PUBLIC_COLLECTION_NAME).toBe('Memory_public');
177
+ // v2 tracking arrays
178
+ expect(propertyNames).toContain('space_ids');
179
+ expect(propertyNames).toContain('group_ids');
180
+ // v2 revision fields
181
+ expect(propertyNames).toContain('revision_count');
182
+ expect(propertyNames).toContain('revised_at');
183
+ });
184
+
185
+ it('should verify PUBLIC_COLLECTION_NAME constant is v2 format', () => {
186
+ expect(PUBLIC_COLLECTION_NAME).toBe('Memory_spaces_public');
184
187
  });
185
188
  });
186
189
  });
@@ -9,11 +9,12 @@ import weaviate, { type WeaviateClient, type Collection } from 'weaviate-client'
9
9
  import { config } from '../config.js';
10
10
  import { SUPPORTED_SPACES, type SpaceId } from '../types/space-memory.js';
11
11
  import { logger } from '../utils/logger.js';
12
+ import { createSpaceCollectionSchema } from '../schema/v2-collections.js';
12
13
 
13
14
  /**
14
- * Unified public collection name for all public spaces
15
+ * Unified public collection name for all public spaces (v2)
15
16
  */
16
- export const PUBLIC_COLLECTION_NAME = 'Memory_public';
17
+ export const PUBLIC_COLLECTION_NAME = 'Memory_spaces_public';
17
18
 
18
19
  /**
19
20
  * Get collection name for a space
@@ -102,6 +103,12 @@ async function createSpaceCollection(
102
103
  sourceProperties: ['content', 'title', 'summary', 'observation'],
103
104
  }),
104
105
 
106
+ // Inverted index configuration
107
+ // indexNullState: true is required for filtering on null values (e.g., deleted_at IS NULL)
108
+ invertedIndex: weaviate.configure.invertedIndex({
109
+ indexNullState: true,
110
+ }),
111
+
105
112
  properties: [
106
113
  // Discriminator
107
114
  {
@@ -116,11 +123,6 @@ async function createSpaceCollection(
116
123
  dataType: 'text[]' as any,
117
124
  description: 'Spaces this memory is published to (e.g., ["the_void", "dogs"])',
118
125
  },
119
- {
120
- name: 'space_id',
121
- dataType: 'text' as any,
122
- description: 'DEPRECATED: Use spaces array instead. Will be removed in v3.0.0.',
123
- },
124
126
  {
125
127
  name: 'author_id',
126
128
  dataType: 'text' as any,
@@ -361,6 +363,23 @@ async function createSpaceCollection(
361
363
  dataType: 'text[]' as any,
362
364
  description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")',
363
365
  },
366
+
367
+ // Soft delete fields
368
+ {
369
+ name: 'deleted_at',
370
+ dataType: 'date' as any,
371
+ description: 'Timestamp when memory was soft-deleted (null = not deleted)',
372
+ },
373
+ {
374
+ name: 'deleted_by',
375
+ dataType: 'text' as any,
376
+ description: 'User ID who deleted the memory',
377
+ },
378
+ {
379
+ name: 'deletion_reason',
380
+ dataType: 'text' as any,
381
+ description: 'Optional reason for deletion',
382
+ },
364
383
  ],
365
384
  });
366
385
 
@@ -386,11 +405,16 @@ export async function ensurePublicCollection(
386
405
 
387
406
  // Check if collection exists
388
407
  const exists = await client.collections.exists(collectionName);
389
-
408
+
390
409
  if (!exists) {
391
- // Create with proper vectorizer configuration
392
- // Use 'public' as spaceId to trigger PUBLIC_COLLECTION_NAME
393
- await createSpaceCollection(client, 'public');
410
+ // Create using v2 schema
411
+ const schema = createSpaceCollectionSchema();
412
+ await client.collections.create(schema);
413
+
414
+ logger.info('Public space collection created', {
415
+ module: 'weaviate-space-schema',
416
+ collectionName,
417
+ });
394
418
  }
395
419
 
396
420
  return client.collections.get(collectionName);