cogmem 3.7.2 → 3.7.3

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 (72) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/MEMORY_MODEL.md +1 -1
  3. package/README.md +5 -4
  4. package/RELEASE_CHECKLIST.md +5 -5
  5. package/dist/belief/BeliefStore.d.ts +3 -1
  6. package/dist/belief/BeliefStore.js +10 -2
  7. package/dist/bin/episode.js +107 -16
  8. package/dist/bin/import-support.js +28 -11
  9. package/dist/config/CogmemConfig.d.ts +1 -0
  10. package/dist/config/CogmemConfig.js +45 -0
  11. package/dist/core/MemoryGraph.js +25 -8
  12. package/dist/dream/DreamScheduler.d.ts +6 -1
  13. package/dist/dream/DreamScheduler.js +36 -6
  14. package/dist/engine/CognitiveGraphCompiler.js +1 -1
  15. package/dist/engine/ConsolidationPipeline.js +4 -4
  16. package/dist/engine/DeepWritePromotionPolicy.d.ts +2 -0
  17. package/dist/engine/DeepWritePromotionPolicy.js +25 -4
  18. package/dist/engine/DreamCuratorWorker.d.ts +3 -0
  19. package/dist/engine/DreamCuratorWorker.js +18 -3
  20. package/dist/engine/FactCompiler.js +2 -2
  21. package/dist/entity/EntityGovernanceService.js +1 -1
  22. package/dist/episode/EpisodeActiveScopeGuard.d.ts +3 -0
  23. package/dist/episode/EpisodeActiveScopeGuard.js +46 -0
  24. package/dist/episode/EpisodeAssembler.d.ts +20 -2
  25. package/dist/episode/EpisodeAssembler.js +458 -98
  26. package/dist/episode/EpisodeBoundaryAuditService.d.ts +70 -0
  27. package/dist/episode/EpisodeBoundaryAuditService.js +276 -0
  28. package/dist/episode/EpisodeBoundaryPolicy.d.ts +75 -0
  29. package/dist/episode/EpisodeBoundaryPolicy.js +189 -0
  30. package/dist/episode/EpisodeBoundaryReplayEngine.d.ts +65 -0
  31. package/dist/episode/EpisodeBoundaryReplayEngine.js +272 -0
  32. package/dist/episode/EpisodeImportIdentity.d.ts +1 -0
  33. package/dist/episode/EpisodeImportIdentity.js +1 -0
  34. package/dist/episode/EpisodeInvariantValidator.d.ts +16 -0
  35. package/dist/episode/EpisodeInvariantValidator.js +99 -0
  36. package/dist/episode/EpisodeSplitPlanner.d.ts +89 -0
  37. package/dist/episode/EpisodeSplitPlanner.js +225 -0
  38. package/dist/episode/EpisodeStore.d.ts +67 -2
  39. package/dist/episode/EpisodeStore.js +443 -59
  40. package/dist/episode/EpisodeTypes.d.ts +2 -2
  41. package/dist/episode/TurnRelationClassifier.d.ts +9 -0
  42. package/dist/episode/TurnRelationClassifier.js +42 -12
  43. package/dist/episode/index.d.ts +3 -0
  44. package/dist/episode/index.js +3 -0
  45. package/dist/factory.d.ts +62 -3
  46. package/dist/factory.js +308 -58
  47. package/dist/mcp/CoreMcpTools.js +103 -8
  48. package/dist/migrations/0028_episode_boundary_guardrails.d.ts +3 -0
  49. package/dist/migrations/0028_episode_boundary_guardrails.js +47 -0
  50. package/dist/migrations/0029_episode_active_scope_guard.d.ts +3 -0
  51. package/dist/migrations/0029_episode_active_scope_guard.js +16 -0
  52. package/dist/migrations/0030_memory_event_local_date_source.d.ts +3 -0
  53. package/dist/migrations/0030_memory_event_local_date_source.js +111 -0
  54. package/dist/migrations/0031_episode_boundary_integrity_repair.d.ts +7 -0
  55. package/dist/migrations/0031_episode_boundary_integrity_repair.js +124 -0
  56. package/dist/migrations/SchemaMigrationRunner.d.ts +2 -0
  57. package/dist/migrations/SchemaMigrationRunner.js +46 -15
  58. package/dist/migrations/index.d.ts +6 -1
  59. package/dist/migrations/index.js +15 -1
  60. package/dist/public.d.ts +1 -1
  61. package/dist/public.js +1 -1
  62. package/dist/recall/BrainRecall.js +1 -1
  63. package/dist/store/DeepWriteCandidateStore.d.ts +21 -3
  64. package/dist/store/DeepWriteCandidateStore.js +118 -11
  65. package/dist/store/EntityStore.d.ts +4 -0
  66. package/dist/store/EntityStore.js +24 -12
  67. package/dist/store/EventStore.d.ts +7 -2
  68. package/dist/store/EventStore.js +144 -23
  69. package/dist/store/FactStore.js +6 -5
  70. package/dist/types/ExtensionPoints.d.ts +3 -1
  71. package/dist/types/index.d.ts +1 -0
  72. package/package.json +1 -1
@@ -3,7 +3,7 @@ import { createHash, randomUUID } from 'crypto';
3
3
  const MEMORY_EVENT_COLUMNS = `
4
4
  event_id, global_seq, stream_id, stream_type, event_type, raw_event_type, event_version, project_id,
5
5
  workspace_id, actor_id, causation_id, correlation_id, source_neuron_id, source_id,
6
- content_hash, thread_id, session_id, local_date, thread_seq, turn_id, turn_seq,
6
+ content_hash, thread_id, session_id, local_date, local_date_source, thread_seq, turn_id, turn_seq,
7
7
  event_ordinal, role, parent_event_id, prev_event_id, next_event_id, causality_type,
8
8
  source_offset, line_start, line_end, char_start, char_end, ordering_confidence,
9
9
  occurred_at, payload_json, payload_hash, created_at
@@ -11,9 +11,16 @@ const MEMORY_EVENT_COLUMNS = `
11
11
  export class EventStore {
12
12
  encryptionProvider;
13
13
  db;
14
+ ownsDb = true;
14
15
  constructor(dbPath = ':memory:', encryptionProvider) {
15
16
  this.encryptionProvider = encryptionProvider;
16
- this.db = new Database(dbPath);
17
+ if (dbPath instanceof Database) {
18
+ this.db = dbPath;
19
+ this.ownsDb = false;
20
+ }
21
+ else {
22
+ this.db = new Database(dbPath);
23
+ }
17
24
  this.initializeSchema();
18
25
  }
19
26
  initializeSchema() {
@@ -37,6 +44,7 @@ export class EventStore {
37
44
  thread_id TEXT,
38
45
  session_id TEXT,
39
46
  local_date TEXT,
47
+ local_date_source TEXT NOT NULL DEFAULT 'legacy_unknown',
40
48
  thread_seq INTEGER,
41
49
  turn_id TEXT,
42
50
  turn_seq INTEGER,
@@ -115,6 +123,7 @@ export class EventStore {
115
123
  addColumn('thread_id', 'thread_id TEXT');
116
124
  addColumn('session_id', 'session_id TEXT');
117
125
  addColumn('local_date', 'local_date TEXT');
126
+ addColumn('local_date_source', "local_date_source TEXT NOT NULL DEFAULT 'legacy_unknown'");
118
127
  addColumn('thread_seq', 'thread_seq INTEGER');
119
128
  addColumn('turn_id', 'turn_id TEXT');
120
129
  addColumn('turn_seq', 'turn_seq INTEGER');
@@ -134,6 +143,17 @@ export class EventStore {
134
143
  this.db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_events_thread_order ON memory_events(thread_id, thread_seq, event_ordinal, global_seq);`);
135
144
  this.db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_events_parent ON memory_events(parent_event_id);`);
136
145
  this.db.exec(`
146
+ CREATE TABLE IF NOT EXISTS import_source_anchors (
147
+ project_id TEXT NOT NULL,
148
+ source_id TEXT NOT NULL,
149
+ import_anchor TEXT NOT NULL,
150
+ event_id TEXT NOT NULL UNIQUE,
151
+ content_hash TEXT NOT NULL,
152
+ created_at INTEGER NOT NULL,
153
+ PRIMARY KEY (project_id, source_id, import_anchor)
154
+ );
155
+ `);
156
+ this.db.exec(`
137
157
  CREATE VIRTUAL TABLE IF NOT EXISTS memory_events_fts USING fts5(
138
158
  event_id UNINDEXED,
139
159
  text,
@@ -149,9 +169,11 @@ export class EventStore {
149
169
  `);
150
170
  this.rebuildRawEventFtsIfNeeded();
151
171
  }
152
- append(input) {
172
+ append(input, retry = 0) {
153
173
  const eventVersion = input.eventVersion ?? this.getNextEventVersion(input.streamId);
154
174
  const occurredAt = input.occurredAt ?? Date.now();
175
+ if (!Number.isFinite(occurredAt) || Math.abs(occurredAt) > 8_640_000_000_000_000)
176
+ throw new Error('invalid_event_timestamp');
155
177
  const payloadJson = JSON.stringify(input.payload);
156
178
  const storedPayloadJson = this.encodePayload(payloadJson);
157
179
  const payloadHash = createHash('sha256').update(payloadJson).digest('hex');
@@ -159,6 +181,14 @@ export class EventStore {
159
181
  const threadSeq = input.threadSeq ?? (threadId ? this.getNextThreadSeq(threadId) : undefined);
160
182
  const globalSeq = this.getNextGlobalSeq();
161
183
  const createdAt = Date.now();
184
+ const localDateSource = input.localDateSource ?? (input.localDate ? 'explicit' : 'generated_utc');
185
+ if (localDateSource !== 'explicit' && localDateSource !== 'generated_utc' && localDateSource !== 'legacy_unknown')
186
+ throw new Error('invalid_local_date_source');
187
+ if (localDateSource === 'explicit' && !input.localDate)
188
+ throw new Error('explicit_local_date_required');
189
+ const generatedUtcDate = new Date(occurredAt).toISOString().slice(0, 10);
190
+ if (localDateSource === 'generated_utc' && input.localDate && input.localDate !== generatedUtcDate)
191
+ throw new Error('generated_utc_local_date_mismatch');
162
192
  const event = {
163
193
  eventId: input.eventId || `evt-${randomUUID()}`,
164
194
  globalSeq,
@@ -178,6 +208,7 @@ export class EventStore {
178
208
  threadId,
179
209
  sessionId: input.sessionId,
180
210
  localDate: input.localDate ?? new Date(occurredAt).toISOString().slice(0, 10),
211
+ localDateSource,
181
212
  threadSeq,
182
213
  turnId: input.turnId,
183
214
  turnSeq: input.turnSeq,
@@ -192,25 +223,80 @@ export class EventStore {
192
223
  lineEnd: input.lineEnd,
193
224
  charStart: input.charStart,
194
225
  charEnd: input.charEnd,
195
- orderingConfidence: input.orderingConfidence ?? (threadSeq || input.eventOrdinal ? 'high' : 'low'),
226
+ orderingConfidence: input.orderingConfidence ?? (threadSeq !== undefined || input.eventOrdinal !== undefined || input.sourceOffset !== undefined || input.lineStart !== undefined ? 'high' : 'low'),
196
227
  occurredAt,
197
228
  payload: input.payload,
198
229
  payloadHash,
199
230
  createdAt,
200
231
  ingestedAt: createdAt
201
232
  };
202
- this.db.prepare(`
233
+ const insert = () => this.db.prepare(`
203
234
  INSERT INTO memory_events (
204
235
  event_id, global_seq, stream_id, stream_type, event_type, raw_event_type, event_version, project_id,
205
236
  workspace_id, actor_id, causation_id, correlation_id, source_neuron_id, source_id,
206
- content_hash, thread_id, session_id, local_date, thread_seq, turn_id, turn_seq,
237
+ content_hash, thread_id, session_id, local_date, local_date_source, thread_seq, turn_id, turn_seq,
207
238
  event_ordinal, role, parent_event_id, prev_event_id, next_event_id, causality_type,
208
239
  source_offset, line_start, line_end, char_start, char_end, ordering_confidence,
209
240
  occurred_at, payload_json, payload_hash, created_at
210
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
211
- `).run(event.eventId, event.globalSeq ?? null, event.streamId, event.streamType, event.eventType, event.rawEventType || null, event.eventVersion, event.projectId || null, event.workspaceId || null, event.actorId || null, event.causationId || null, event.correlationId || null, event.sourceNeuronId || null, event.sourceId || null, event.contentHash || null, event.threadId || null, event.sessionId || null, event.localDate || null, event.threadSeq || null, event.turnId || null, event.turnSeq || null, event.eventOrdinal || null, event.role || null, event.parentEventId || null, event.prevEventId || null, event.nextEventId || null, event.causalityType || null, event.sourceOffset || null, event.lineStart || null, event.lineEnd || null, event.charStart || null, event.charEnd || null, event.orderingConfidence || null, event.occurredAt, storedPayloadJson, event.payloadHash, event.createdAt);
212
- this.upsertRawEventFts(event);
213
- return event;
241
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
242
+ `).run(event.eventId, event.globalSeq ?? null, event.streamId, event.streamType, event.eventType, event.rawEventType || null, event.eventVersion, event.projectId || null, event.workspaceId || null, event.actorId || null, event.causationId || null, event.correlationId || null, event.sourceNeuronId || null, event.sourceId || null, event.contentHash || null, event.threadId || null, event.sessionId || null, event.localDate || null, event.localDateSource || 'legacy_unknown', event.threadSeq ?? null, event.turnId || null, event.turnSeq ?? null, event.eventOrdinal ?? null, event.role || null, event.parentEventId || null, event.prevEventId || null, event.nextEventId || null, event.causalityType || null, event.sourceOffset ?? null, event.lineStart ?? null, event.lineEnd ?? null, event.charStart ?? null, event.charEnd ?? null, event.orderingConfidence || null, event.occurredAt, storedPayloadJson, event.payloadHash, event.createdAt);
243
+ try {
244
+ this.db.transaction(() => {
245
+ insert();
246
+ this.upsertImportAnchor(event);
247
+ this.upsertRawEventFts(event);
248
+ })();
249
+ return event;
250
+ }
251
+ catch (error) {
252
+ const message = error instanceof Error ? error.message : String(error);
253
+ const streamConflict = /UNIQUE constraint failed: memory_events\.(stream_id|global_seq)/.test(message);
254
+ const anchorConflict = message === 'import_anchor_already_exists';
255
+ const autoEventVersion = input.eventVersion === undefined;
256
+ const autoThreadSeq = input.threadSeq === undefined;
257
+ if ((streamConflict || message.includes('database is locked')) && autoEventVersion && retry < 5) {
258
+ return this.append({ ...input, eventVersion: undefined, threadSeq: autoThreadSeq ? undefined : input.threadSeq }, retry + 1);
259
+ }
260
+ if (!anchorConflict)
261
+ throw error;
262
+ const metadata = event.payload?.metadata;
263
+ const anchor = typeof metadata?.importAnchor === 'string' ? metadata.importAnchor : undefined;
264
+ const existing = anchor && event.projectId && event.sourceId
265
+ ? this.findImportedEventAnchor(event.projectId, event.sourceId, anchor)
266
+ : null;
267
+ if (!existing)
268
+ throw error;
269
+ if (existing.contentHash !== event.contentHash)
270
+ throw new Error(`import_anchor_content_conflict:${anchor}`);
271
+ return existing;
272
+ }
273
+ }
274
+ upsertImportAnchor(event) {
275
+ const metadata = event.payload?.metadata;
276
+ const anchor = typeof metadata?.importAnchor === 'string' ? metadata.importAnchor : undefined;
277
+ if (!anchor || !event.projectId || !event.sourceId || !event.contentHash)
278
+ return;
279
+ this.db.prepare(`
280
+ INSERT INTO import_source_anchors (project_id, source_id, import_anchor, event_id, content_hash, created_at)
281
+ VALUES (?, ?, ?, ?, ?, ?)
282
+ ON CONFLICT(project_id, source_id, import_anchor) DO NOTHING
283
+ `).run(event.projectId, event.sourceId, anchor, event.eventId, event.contentHash, event.createdAt);
284
+ const inserted = this.db.prepare(`SELECT event_id FROM import_source_anchors WHERE project_id = ? AND source_id = ? AND import_anchor = ?`)
285
+ .get(event.projectId, event.sourceId, anchor);
286
+ if (inserted?.event_id !== event.eventId) {
287
+ const existingEvent = inserted?.event_id
288
+ ? this.db.prepare(`SELECT 1 FROM memory_events WHERE event_id = ?`).get(inserted.event_id)
289
+ : null;
290
+ if (!existingEvent) {
291
+ this.db.prepare(`
292
+ UPDATE import_source_anchors
293
+ SET event_id = ?, content_hash = ?, created_at = ?
294
+ WHERE project_id = ? AND source_id = ? AND import_anchor = ?
295
+ `).run(event.eventId, event.contentHash, event.createdAt, event.projectId, event.sourceId, anchor);
296
+ return;
297
+ }
298
+ throw new Error('import_anchor_already_exists');
299
+ }
214
300
  }
215
301
  getNextGlobalSeq() {
216
302
  const row = this.db.prepare(`
@@ -249,9 +335,18 @@ export class EventStore {
249
335
  FROM memory_events
250
336
  WHERE (? IS NULL OR occurred_at > ?)
251
337
  ORDER BY COALESCE(global_seq, 0) ASC, occurred_at ASC, event_id ASC
252
- `).all(lastEventTime || null, lastEventTime || null);
338
+ `).all(lastEventTime ?? null, lastEventTime ?? null);
253
339
  return rows.map((row) => this.mapRow(row));
254
340
  }
341
+ findImportedEventAnchor(projectId, sourceId, importAnchor) {
342
+ const row = this.db.prepare(`
343
+ SELECT ${qualifiedMemoryEventColumns('e')}
344
+ FROM import_source_anchors a
345
+ JOIN memory_events e ON e.event_id = a.event_id
346
+ WHERE a.project_id = ? AND a.source_id = ? AND a.import_anchor = ?
347
+ `).get(projectId, sourceId, importAnchor);
348
+ return row ? this.mapRow(row) : null;
349
+ }
255
350
  getLatestEvent() {
256
351
  const row = this.db.prepare(`
257
352
  SELECT ${MEMORY_EVENT_COLUMNS}
@@ -430,9 +525,10 @@ export class EventStore {
430
525
  conditions.push('local_date = ?');
431
526
  params.push(options.localDate);
432
527
  }
433
- const limitSql = options.limit ? 'LIMIT ?' : '';
434
- if (options.limit)
435
- params.push(options.limit);
528
+ const boundedLimit = options.limit === undefined ? undefined : Math.max(1, Math.min(Math.trunc(options.limit), 10_000));
529
+ const limitSql = boundedLimit === undefined ? '' : 'LIMIT ?';
530
+ if (boundedLimit !== undefined)
531
+ params.push(boundedLimit);
436
532
  const rows = this.db.prepare(`
437
533
  SELECT ${MEMORY_EVENT_COLUMNS}
438
534
  FROM memory_events
@@ -564,7 +660,8 @@ export class EventStore {
564
660
  `).run(checkpoint.projectionName, checkpoint.lastEventId || null, checkpoint.lastEventTime || null, checkpoint.lastRebuildAt || null, checkpoint.lastFullCount, checkpoint.lastChecksum || null, checkpoint.status, checkpoint.metadata ? JSON.stringify(checkpoint.metadata) : null);
565
661
  }
566
662
  close() {
567
- this.db.close();
663
+ if (this.ownsDb)
664
+ this.db.close();
568
665
  }
569
666
  mapRow(row) {
570
667
  return {
@@ -586,20 +683,21 @@ export class EventStore {
586
683
  threadId: row.thread_id || (row.stream_type === 'thread' ? row.stream_id : undefined),
587
684
  sessionId: row.session_id || undefined,
588
685
  localDate: row.local_date || undefined,
589
- threadSeq: row.thread_seq || undefined,
686
+ localDateSource: row.local_date_source || legacyLocalDateSource(row.payload_json),
687
+ threadSeq: row.thread_seq ?? undefined,
590
688
  turnId: row.turn_id || undefined,
591
- turnSeq: row.turn_seq || undefined,
592
- eventOrdinal: row.event_ordinal || undefined,
689
+ turnSeq: row.turn_seq ?? undefined,
690
+ eventOrdinal: row.event_ordinal ?? undefined,
593
691
  role: row.role || undefined,
594
692
  parentEventId: row.parent_event_id || undefined,
595
693
  prevEventId: row.prev_event_id || undefined,
596
694
  nextEventId: row.next_event_id || undefined,
597
695
  causalityType: row.causality_type || undefined,
598
- sourceOffset: row.source_offset || undefined,
599
- lineStart: row.line_start || undefined,
600
- lineEnd: row.line_end || undefined,
601
- charStart: row.char_start || undefined,
602
- charEnd: row.char_end || undefined,
696
+ sourceOffset: row.source_offset ?? undefined,
697
+ lineStart: row.line_start ?? undefined,
698
+ lineEnd: row.line_end ?? undefined,
699
+ charStart: row.char_start ?? undefined,
700
+ charEnd: row.char_end ?? undefined,
603
701
  orderingConfidence: row.ordering_confidence || undefined,
604
702
  occurredAt: row.occurred_at,
605
703
  payload: JSON.parse(this.decodePayload(row.payload_json)),
@@ -720,6 +818,29 @@ export class EventStore {
720
818
  return this.encryptionProvider?.decrypt(payloadJson) ?? payloadJson;
721
819
  }
722
820
  }
821
+ function qualifiedMemoryEventColumns(alias) {
822
+ return MEMORY_EVENT_COLUMNS.split(',').map((column) => `${alias}.${column.trim()}`).join(', ');
823
+ }
723
824
  function escapeSqlLike(value) {
724
825
  return value.replace(/[\\%_]/g, (character) => `\\${character}`);
725
826
  }
827
+ function validCalendarDate(value) {
828
+ if (!/^\d{4}-\d{2}-\d{2}$/u.test(value))
829
+ return false;
830
+ const [year, month, day] = value.split('-').map(Number);
831
+ const date = new Date(Date.UTC(year, month - 1, day));
832
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
833
+ }
834
+ function legacyLocalDateSource(payloadJson) {
835
+ try {
836
+ const payload = JSON.parse(payloadJson);
837
+ if (payload.metadata?.localDateSource === 'event_store_utc_default')
838
+ return 'generated_utc';
839
+ if (payload.metadata?.localDateSource === 'explicit')
840
+ return 'explicit';
841
+ }
842
+ catch {
843
+ return 'legacy_unknown';
844
+ }
845
+ return 'legacy_unknown';
846
+ }
@@ -122,7 +122,7 @@ export class FactStore {
122
122
  const rows = this.db.prepare(`
123
123
  SELECT *
124
124
  FROM facts
125
- WHERE neuron_id IN (${placeholders})
125
+ WHERE neuron_id IN (${placeholders}) AND status IN ('provisional', 'provisional_enriched', 'verified')
126
126
  ORDER BY valid_from DESC, fact_id DESC
127
127
  LIMIT ?
128
128
  `).all(...neuronIds, limit);
@@ -139,14 +139,15 @@ export class FactStore {
139
139
  SELECT *
140
140
  FROM facts
141
141
  WHERE entity_id IN (${entityPlaceholders})
142
+ AND status IN ('provisional', 'provisional_enriched', 'verified')
142
143
  AND predicate_family IN (${predicateFamilies.map(() => '?').join(', ')})
143
144
  ORDER BY valid_from DESC, fact_id DESC
144
145
  LIMIT ?
145
146
  `).all(...entityIds, ...predicateFamilies, limit)
146
147
  : this.db.prepare(`
147
- SELECT *
148
- FROM facts
149
- WHERE entity_id IN (${entityPlaceholders})
148
+ SELECT *
149
+ FROM facts
150
+ WHERE entity_id IN (${entityPlaceholders}) AND status IN ('provisional', 'provisional_enriched', 'verified')
150
151
  ORDER BY valid_from DESC, fact_id DESC
151
152
  LIMIT ?
152
153
  `).all(...entityIds, limit);
@@ -159,7 +160,7 @@ export class FactStore {
159
160
  const rows = this.db.prepare(`
160
161
  SELECT DISTINCT neuron_id
161
162
  FROM facts
162
- WHERE entity_id IN (${placeholders})
163
+ WHERE entity_id IN (${placeholders}) AND status IN ('provisional', 'provisional_enriched', 'verified')
163
164
  ORDER BY valid_from DESC
164
165
  LIMIT ?
165
166
  `).all(...entityIds, limit);
@@ -106,9 +106,11 @@ export interface GraphEdgeRecordLike {
106
106
  status?: string;
107
107
  }
108
108
  export interface GraphEdgeStoreLike {
109
+ getDatabase(): import('bun:sqlite').default;
109
110
  list?(options?: unknown): GraphEdgeRecordLike[];
110
111
  listActiveNeighborEdges?(entityIds: string[], edgeTypes?: string[], limit?: number): GraphEdgeRecordLike[];
111
- appendEdge?(input: unknown): GraphEdgeRecordLike;
112
+ appendEdge(input: unknown): GraphEdgeRecordLike;
113
+ invalidateEdge(edgeRecordId: string, metadata?: Record<string, unknown>): boolean;
112
114
  }
113
115
  export interface ProposalLedgerLike {
114
116
  append?(items: unknown[]): void;
@@ -277,6 +277,7 @@ export interface MemoryEvent<TPayload = Record<string, unknown>> {
277
277
  threadId?: string;
278
278
  sessionId?: string;
279
279
  localDate?: string;
280
+ localDateSource?: 'explicit' | 'generated_utc' | 'legacy_unknown';
280
281
  threadSeq?: number;
281
282
  turnId?: string;
282
283
  turnSeq?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cogmem",
3
3
 
4
- "version": "3.7.2",
4
+ "version": "3.7.3",
5
5
 
6
6
  "type": "module",
7
7
  "description": "cogmem — agent-native memory kernel for a single local-first AI agent",