noormme 1.2.0 → 1.2.2

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 (165) hide show
  1. package/README.md +60 -6
  2. package/dist/cjs/agentic/ActionJournal.d.ts +5 -2
  3. package/dist/cjs/agentic/ActionJournal.js +13 -5
  4. package/dist/cjs/agentic/CapabilityManager.d.ts +7 -0
  5. package/dist/cjs/agentic/CapabilityManager.js +84 -7
  6. package/dist/cjs/agentic/CognitiveRepository.js +3 -6
  7. package/dist/cjs/agentic/Cortex.d.ts +4 -0
  8. package/dist/cjs/agentic/Cortex.js +38 -17
  9. package/dist/cjs/agentic/EpisodicMemory.d.ts +5 -1
  10. package/dist/cjs/agentic/EpisodicMemory.js +11 -4
  11. package/dist/cjs/agentic/PersonaManager.js +37 -31
  12. package/dist/cjs/agentic/PolicyEnforcer.d.ts +6 -1
  13. package/dist/cjs/agentic/PolicyEnforcer.js +74 -17
  14. package/dist/cjs/agentic/ResourceMonitor.d.ts +9 -0
  15. package/dist/cjs/agentic/ResourceMonitor.js +36 -2
  16. package/dist/cjs/agentic/SessionManager.js +24 -17
  17. package/dist/cjs/agentic/VectorIndexer.d.ts +1 -0
  18. package/dist/cjs/agentic/VectorIndexer.js +26 -17
  19. package/dist/cjs/agentic/improvement/AblationEngine.d.ts +4 -6
  20. package/dist/cjs/agentic/improvement/AblationEngine.js +57 -37
  21. package/dist/cjs/agentic/improvement/ActionRefiner.js +30 -14
  22. package/dist/cjs/agentic/improvement/ConflictResolver.d.ts +3 -1
  23. package/dist/cjs/agentic/improvement/ConflictResolver.js +59 -47
  24. package/dist/cjs/agentic/improvement/CortexJanitor.js +11 -0
  25. package/dist/cjs/agentic/improvement/CuriosityEngine.d.ts +1 -1
  26. package/dist/cjs/agentic/improvement/CuriosityEngine.js +48 -21
  27. package/dist/cjs/agentic/improvement/EvolutionRitual.js +26 -14
  28. package/dist/cjs/agentic/improvement/EvolutionaryPilot.js +16 -4
  29. package/dist/cjs/agentic/improvement/GoalArchitect.d.ts +6 -2
  30. package/dist/cjs/agentic/improvement/GoalArchitect.js +72 -34
  31. package/dist/cjs/agentic/improvement/GovernanceManager.d.ts +20 -6
  32. package/dist/cjs/agentic/improvement/GovernanceManager.js +134 -155
  33. package/dist/cjs/agentic/improvement/HiveLink.d.ts +7 -3
  34. package/dist/cjs/agentic/improvement/HiveLink.js +135 -113
  35. package/dist/cjs/agentic/improvement/KnowledgeDistiller.js +43 -35
  36. package/dist/cjs/agentic/improvement/QuotaManager.d.ts +41 -0
  37. package/dist/cjs/agentic/improvement/QuotaManager.js +185 -0
  38. package/dist/cjs/agentic/improvement/RecursiveReasoner.js +50 -25
  39. package/dist/cjs/agentic/improvement/ReflectionEngine.d.ts +4 -1
  40. package/dist/cjs/agentic/improvement/ReflectionEngine.js +3 -1
  41. package/dist/cjs/agentic/improvement/RitualOrchestrator.js +27 -16
  42. package/dist/cjs/agentic/improvement/RuleEngine.d.ts +1 -1
  43. package/dist/cjs/agentic/improvement/RuleEngine.js +10 -4
  44. package/dist/cjs/agentic/improvement/SelfEvolution.js +22 -17
  45. package/dist/cjs/agentic/improvement/SelfTestRegistry.d.ts +5 -0
  46. package/dist/cjs/agentic/improvement/SelfTestRegistry.js +129 -109
  47. package/dist/cjs/agentic/improvement/SkillSynthesizer.d.ts +1 -0
  48. package/dist/cjs/agentic/improvement/SkillSynthesizer.js +22 -13
  49. package/dist/cjs/agentic/improvement/StrategicPlanner.d.ts +1 -0
  50. package/dist/cjs/agentic/improvement/StrategicPlanner.js +26 -19
  51. package/dist/cjs/agentic/improvement/governance/AuditContext.d.ts +17 -0
  52. package/dist/cjs/agentic/improvement/governance/AuditContext.js +2 -0
  53. package/dist/cjs/agentic/improvement/governance/BudgetAuditor.d.ts +4 -0
  54. package/dist/cjs/agentic/improvement/governance/BudgetAuditor.js +50 -0
  55. package/dist/cjs/agentic/improvement/governance/EmergenceAuditor.d.ts +4 -0
  56. package/dist/cjs/agentic/improvement/governance/EmergenceAuditor.js +37 -0
  57. package/dist/cjs/agentic/improvement/governance/MaintenanceOracle.d.ts +4 -0
  58. package/dist/cjs/agentic/improvement/governance/MaintenanceOracle.js +67 -0
  59. package/dist/cjs/agentic/improvement/governance/PerformanceAuditor.d.ts +4 -0
  60. package/dist/cjs/agentic/improvement/governance/PerformanceAuditor.js +43 -0
  61. package/dist/cjs/agentic/improvement/governance/PersonaAuditor.d.ts +6 -0
  62. package/dist/cjs/agentic/improvement/governance/PersonaAuditor.js +74 -0
  63. package/dist/cjs/agentic/improvement/governance/RemediationEngine.d.ts +5 -0
  64. package/dist/cjs/agentic/improvement/governance/RemediationEngine.js +43 -0
  65. package/dist/cjs/agentic/improvement/governance/SkillAuditor.d.ts +5 -0
  66. package/dist/cjs/agentic/improvement/governance/SkillAuditor.js +52 -0
  67. package/dist/cjs/agentic/telemetry/CognitiveSynthesizer.d.ts +5 -0
  68. package/dist/cjs/agentic/telemetry/CognitiveSynthesizer.js +54 -12
  69. package/dist/cjs/agentic/telemetry/EventHarvester.d.ts +1 -1
  70. package/dist/cjs/agentic/telemetry/EventHarvester.js +10 -3
  71. package/dist/cjs/agentic/telemetry/ResearchAlchemist.d.ts +7 -2
  72. package/dist/cjs/agentic/telemetry/ResearchAlchemist.js +49 -8
  73. package/dist/cjs/agentic/telemetry/TelemetryOrchestrator.d.ts +4 -1
  74. package/dist/cjs/agentic/telemetry/TelemetryOrchestrator.js +38 -11
  75. package/dist/cjs/cli/commands/inspect.js +40 -1
  76. package/dist/cjs/cli/commands/watch.js +31 -25
  77. package/dist/cjs/cli/index.js +0 -0
  78. package/dist/cjs/dialect/sqlite/sqlite-introspector.js +15 -5
  79. package/dist/cjs/helpers/agent-schema.js +15 -14
  80. package/dist/cjs/migration/data_migrator.js +4 -4
  81. package/dist/cjs/migration/schema_differ.js +37 -15
  82. package/dist/cjs/types/index.d.ts +12 -0
  83. package/dist/cjs/util/safe-sql-helpers.js +7 -10
  84. package/dist/esm/agentic/ActionJournal.d.ts +5 -2
  85. package/dist/esm/agentic/ActionJournal.js +13 -5
  86. package/dist/esm/agentic/CapabilityManager.d.ts +7 -0
  87. package/dist/esm/agentic/CapabilityManager.js +84 -7
  88. package/dist/esm/agentic/CognitiveRepository.js +3 -6
  89. package/dist/esm/agentic/Cortex.d.ts +4 -0
  90. package/dist/esm/agentic/Cortex.js +38 -17
  91. package/dist/esm/agentic/EpisodicMemory.d.ts +5 -1
  92. package/dist/esm/agentic/EpisodicMemory.js +11 -4
  93. package/dist/esm/agentic/PersonaManager.js +37 -31
  94. package/dist/esm/agentic/PolicyEnforcer.d.ts +6 -1
  95. package/dist/esm/agentic/PolicyEnforcer.js +74 -17
  96. package/dist/esm/agentic/ResourceMonitor.d.ts +9 -0
  97. package/dist/esm/agentic/ResourceMonitor.js +36 -2
  98. package/dist/esm/agentic/SessionManager.js +24 -17
  99. package/dist/esm/agentic/VectorIndexer.d.ts +1 -0
  100. package/dist/esm/agentic/VectorIndexer.js +26 -17
  101. package/dist/esm/agentic/improvement/AblationEngine.d.ts +4 -6
  102. package/dist/esm/agentic/improvement/AblationEngine.js +57 -37
  103. package/dist/esm/agentic/improvement/ActionRefiner.js +30 -14
  104. package/dist/esm/agentic/improvement/ConflictResolver.d.ts +3 -1
  105. package/dist/esm/agentic/improvement/ConflictResolver.js +59 -47
  106. package/dist/esm/agentic/improvement/CortexJanitor.js +11 -0
  107. package/dist/esm/agentic/improvement/CuriosityEngine.d.ts +1 -1
  108. package/dist/esm/agentic/improvement/CuriosityEngine.js +48 -21
  109. package/dist/esm/agentic/improvement/EvolutionRitual.js +26 -14
  110. package/dist/esm/agentic/improvement/EvolutionaryPilot.js +16 -4
  111. package/dist/esm/agentic/improvement/GoalArchitect.d.ts +6 -2
  112. package/dist/esm/agentic/improvement/GoalArchitect.js +72 -34
  113. package/dist/esm/agentic/improvement/GovernanceManager.d.ts +20 -6
  114. package/dist/esm/agentic/improvement/GovernanceManager.js +134 -155
  115. package/dist/esm/agentic/improvement/HiveLink.d.ts +7 -3
  116. package/dist/esm/agentic/improvement/HiveLink.js +135 -113
  117. package/dist/esm/agentic/improvement/KnowledgeDistiller.js +43 -35
  118. package/dist/esm/agentic/improvement/QuotaManager.d.ts +41 -0
  119. package/dist/esm/agentic/improvement/QuotaManager.js +182 -0
  120. package/dist/esm/agentic/improvement/RecursiveReasoner.js +50 -25
  121. package/dist/esm/agentic/improvement/ReflectionEngine.d.ts +4 -1
  122. package/dist/esm/agentic/improvement/ReflectionEngine.js +3 -1
  123. package/dist/esm/agentic/improvement/RitualOrchestrator.js +27 -16
  124. package/dist/esm/agentic/improvement/RuleEngine.d.ts +1 -1
  125. package/dist/esm/agentic/improvement/RuleEngine.js +10 -4
  126. package/dist/esm/agentic/improvement/SelfEvolution.js +22 -17
  127. package/dist/esm/agentic/improvement/SelfTestRegistry.d.ts +5 -0
  128. package/dist/esm/agentic/improvement/SelfTestRegistry.js +129 -109
  129. package/dist/esm/agentic/improvement/SkillSynthesizer.d.ts +1 -0
  130. package/dist/esm/agentic/improvement/SkillSynthesizer.js +22 -13
  131. package/dist/esm/agentic/improvement/StrategicPlanner.d.ts +1 -0
  132. package/dist/esm/agentic/improvement/StrategicPlanner.js +26 -19
  133. package/dist/esm/agentic/improvement/governance/AuditContext.d.ts +17 -0
  134. package/dist/esm/agentic/improvement/governance/AuditContext.js +2 -0
  135. package/dist/esm/agentic/improvement/governance/BudgetAuditor.d.ts +4 -0
  136. package/dist/esm/agentic/improvement/governance/BudgetAuditor.js +47 -0
  137. package/dist/esm/agentic/improvement/governance/EmergenceAuditor.d.ts +4 -0
  138. package/dist/esm/agentic/improvement/governance/EmergenceAuditor.js +34 -0
  139. package/dist/esm/agentic/improvement/governance/MaintenanceOracle.d.ts +4 -0
  140. package/dist/esm/agentic/improvement/governance/MaintenanceOracle.js +64 -0
  141. package/dist/esm/agentic/improvement/governance/PerformanceAuditor.d.ts +4 -0
  142. package/dist/esm/agentic/improvement/governance/PerformanceAuditor.js +40 -0
  143. package/dist/esm/agentic/improvement/governance/PersonaAuditor.d.ts +6 -0
  144. package/dist/esm/agentic/improvement/governance/PersonaAuditor.js +71 -0
  145. package/dist/esm/agentic/improvement/governance/RemediationEngine.d.ts +5 -0
  146. package/dist/esm/agentic/improvement/governance/RemediationEngine.js +40 -0
  147. package/dist/esm/agentic/improvement/governance/SkillAuditor.d.ts +5 -0
  148. package/dist/esm/agentic/improvement/governance/SkillAuditor.js +49 -0
  149. package/dist/esm/agentic/telemetry/CognitiveSynthesizer.d.ts +5 -0
  150. package/dist/esm/agentic/telemetry/CognitiveSynthesizer.js +54 -12
  151. package/dist/esm/agentic/telemetry/EventHarvester.d.ts +1 -1
  152. package/dist/esm/agentic/telemetry/EventHarvester.js +10 -3
  153. package/dist/esm/agentic/telemetry/ResearchAlchemist.d.ts +7 -2
  154. package/dist/esm/agentic/telemetry/ResearchAlchemist.js +49 -8
  155. package/dist/esm/agentic/telemetry/TelemetryOrchestrator.d.ts +4 -1
  156. package/dist/esm/agentic/telemetry/TelemetryOrchestrator.js +38 -11
  157. package/dist/esm/cli/commands/inspect.js +40 -1
  158. package/dist/esm/cli/commands/watch.js +31 -25
  159. package/dist/esm/dialect/sqlite/sqlite-introspector.js +15 -5
  160. package/dist/esm/helpers/agent-schema.js +15 -14
  161. package/dist/esm/migration/data_migrator.js +4 -4
  162. package/dist/esm/migration/schema_differ.js +37 -15
  163. package/dist/esm/types/index.d.ts +12 -0
  164. package/dist/esm/util/safe-sql-helpers.js +7 -10
  165. package/package.json +44 -40
@@ -8,6 +8,7 @@ export class PolicyEnforcer {
8
8
  config;
9
9
  policiesTable;
10
10
  metricsTable;
11
+ metricCache = new Map();
11
12
  constructor(db, config = {}) {
12
13
  this.db = db;
13
14
  this.config = config;
@@ -22,11 +23,15 @@ export class PolicyEnforcer {
22
23
  */
23
24
  async definePolicy(name, type, definition, isEnabled = true) {
24
25
  return await this.db.transaction().execute(async (trx) => {
25
- const existing = await trx
26
+ let query = trx
26
27
  .selectFrom(this.policiesTable)
27
28
  .select('id')
28
- .where('name', '=', name)
29
- .executeTakeFirst();
29
+ .where('name', '=', name);
30
+ // Audit Phase 16: Exclusive lock for provisioning (Skip for SQLite)
31
+ if (this.db.getExecutor().adapter?.constructor.name !== 'SqliteAdapter') {
32
+ query = query.forUpdate();
33
+ }
34
+ const existing = await query.executeTakeFirst();
30
35
  if (existing) {
31
36
  const updated = await trx
32
37
  .updateTable(this.policiesTable)
@@ -60,7 +65,19 @@ export class PolicyEnforcer {
60
65
  * Comprehensive policy evaluation against a context value.
61
66
  * Supports thresholds, regex patterns, and cumulative budgets.
62
67
  */
63
- async checkPolicy(name, value) {
68
+ /**
69
+ * Comprehensive policy evaluation against a context value.
70
+ * Supports thresholds, regex patterns, and cumulative budgets.
71
+ */
72
+ async checkPolicy(name, value, visited = new Set()) {
73
+ // Audit Pass 6: Re-entrancy / Circular Dependency Detection
74
+ if (visited.has(name)) {
75
+ return {
76
+ allowed: false,
77
+ reason: `Circular policy dependency detected: ${Array.from(visited).join(' -> ')} -> ${name}`,
78
+ };
79
+ }
80
+ visited.add(name);
64
81
  const policy = await this.typedDb
65
82
  .selectFrom(this.policiesTable)
66
83
  .selectAll()
@@ -87,18 +104,33 @@ export class PolicyEnforcer {
87
104
  }
88
105
  // 2. Pattern Check (String/Regex)
89
106
  if (typeof value === 'string' && def.pattern) {
90
- const regex = new RegExp(def.pattern, 'i');
91
- if (def.mustMatch && !regex.test(value)) {
92
- return {
93
- allowed: false,
94
- reason: `Value does not match required pattern for policy '${name}'`,
95
- };
107
+ // PRODUCTION HARDENING: ReDoS Prevention
108
+ // Sanitize regex: check for dangerous nested quantifiers and length
109
+ if (def.pattern.length > 500) {
110
+ return { allowed: false, reason: `Policy '${name}' regex pattern too long (potential ReDoS risk)` };
96
111
  }
97
- if (!def.mustMatch && regex.test(value)) {
98
- return {
99
- allowed: false,
100
- reason: `Value contains forbidden pattern for policy '${name}'`,
101
- };
112
+ const dangerousPatterns = /(\*|\+)\1|\(\.\*\)\*/;
113
+ if (dangerousPatterns.test(def.pattern)) {
114
+ return { allowed: false, reason: `Policy '${name}' contains potentially dangerous ReDoS pattern` };
115
+ }
116
+ const flags = def.flags || 'i';
117
+ try {
118
+ const regex = new RegExp(def.pattern, flags);
119
+ if (def.mustMatch && !regex.test(value)) {
120
+ return {
121
+ allowed: false,
122
+ reason: `Value does not match required pattern for policy '${name}'`,
123
+ };
124
+ }
125
+ if (!def.mustMatch && regex.test(value)) {
126
+ return {
127
+ allowed: false,
128
+ reason: `Value contains forbidden pattern for policy '${name}'`,
129
+ };
130
+ }
131
+ }
132
+ catch (e) {
133
+ return { allowed: false, reason: `Invalid regex in policy '${name}': ${String(e)}` };
102
134
  }
103
135
  }
104
136
  // 3. Budget Check (Cumulative)
@@ -113,6 +145,16 @@ export class PolicyEnforcer {
113
145
  };
114
146
  }
115
147
  }
148
+ // 4. Composite Policy Check: Recursive evaluation of dependencies
149
+ // Audit Pass 6: Moved from evaluateContext to checkPolicy for deeper nesting support
150
+ if (def.dependsOn && Array.isArray(def.dependsOn)) {
151
+ for (const depName of def.dependsOn) {
152
+ const result = await this.checkPolicy(depName, value, new Set(visited));
153
+ if (!result.allowed) {
154
+ return { allowed: false, reason: `Composite block: ${name} -> ${result.reason}` };
155
+ }
156
+ }
157
+ }
116
158
  return { allowed: true };
117
159
  }
118
160
  /**
@@ -152,8 +194,21 @@ export class PolicyEnforcer {
152
194
  return list.map((p) => this.parsePolicy(p));
153
195
  }
154
196
  async getCumulativeMetric(metricName, period) {
155
- let cutoff = new Date(0); // beginning of time
197
+ const cacheKey = `${metricName}:${period}`;
198
+ const cached = this.metricCache.get(cacheKey);
156
199
  const now = new Date();
200
+ const ttl = this.config.policyCacheTTL || 60000;
201
+ if (cached && now.getTime() - cached.timestamp < ttl) {
202
+ return cached.value;
203
+ }
204
+ // Map Hardening: Simple LRU-like eviction to prevent memory leaks
205
+ if (this.metricCache.size > 1000) {
206
+ const firstKey = this.metricCache.keys().next().value;
207
+ if (firstKey !== undefined) {
208
+ this.metricCache.delete(firstKey);
209
+ }
210
+ }
211
+ let cutoff = new Date(0); // beginning of time
157
212
  if (period === 'daily') {
158
213
  cutoff = new Date(now.getFullYear(), now.getMonth(), now.getDate());
159
214
  }
@@ -166,7 +221,9 @@ export class PolicyEnforcer {
166
221
  .where('metric_name', '=', metricName)
167
222
  .where('created_at', '>=', cutoff)
168
223
  .executeTakeFirst();
169
- return Number(result?.total || 0);
224
+ const total = Number(result?.total || 0);
225
+ this.metricCache.set(cacheKey, { value: total, timestamp: now.getTime() });
226
+ return total;
170
227
  }
171
228
  parsePolicy(p) {
172
229
  return {
@@ -28,6 +28,15 @@ export declare class ResourceMonitor {
28
28
  * Record token usage
29
29
  */
30
30
  recordUsage(sessionId: string | number, modelName: string, inputTokens: number, outputTokens: number, cost?: number, agentId?: string, metadata?: Record<string, any>): Promise<ResourceUsage>;
31
+ /**
32
+ * Pre-run quota validation.
33
+ * Blocks operations if persona or swarm limits are breached.
34
+ * Includes cost projection to prevent mid-run budget failure.
35
+ */
36
+ validateQuota(agentId: string, swarmId?: string, estimatedTokens?: number): Promise<{
37
+ allowed: boolean;
38
+ reason?: string;
39
+ }>;
31
40
  /**
32
41
  * Get total cost for a session
33
42
  */
@@ -1,5 +1,4 @@
1
1
  /// <reference types="./ResourceMonitor.d.ts" />
2
- import { sql } from '../raw-builder/sql.js';
3
2
  /**
4
3
  * ResourceMonitor tracks token usage and costs across sessions.
5
4
  */
@@ -36,6 +35,39 @@ export class ResourceMonitor {
36
35
  .executeTakeFirstOrThrow();
37
36
  return this.parseUsage(usage);
38
37
  }
38
+ /**
39
+ * Pre-run quota validation.
40
+ * Blocks operations if persona or swarm limits are breached.
41
+ * Includes cost projection to prevent mid-run budget failure.
42
+ */
43
+ async validateQuota(agentId, swarmId, estimatedTokens = 2000) {
44
+ // 1. Project cost using Persistent Oracle from QuotaManager
45
+ let projection = 0;
46
+ const quotas = this.config.cortex?.quotas;
47
+ if (quotas) {
48
+ // Dynamic Lookup via Oracle sync
49
+ const rate = await quotas.getExchangeRate('USD'); // Oracle baseline
50
+ projection = estimatedTokens * (rate * 0.00001); // Weighted projection
51
+ }
52
+ else {
53
+ projection = estimatedTokens * 0.00002; // Safe fallback
54
+ }
55
+ // 2. Persona Quota Check
56
+ const personaCheck = await this.config.cortex?.quotas.checkQuota('persona', agentId);
57
+ if (personaCheck && !personaCheck.allowed)
58
+ return personaCheck;
59
+ // 3. Swarm Quota Check
60
+ if (swarmId) {
61
+ const swarmCheck = await this.config.cortex?.quotas.checkQuota('swarm', swarmId);
62
+ if (swarmCheck && !swarmCheck.allowed)
63
+ return swarmCheck;
64
+ }
65
+ // 4. Global Quota Check
66
+ const globalCheck = await this.config.cortex?.quotas.checkQuota('global');
67
+ if (globalCheck && !globalCheck.allowed)
68
+ return globalCheck;
69
+ return { allowed: true };
70
+ }
39
71
  /**
40
72
  * Get total cost for a session
41
73
  */
@@ -65,7 +97,9 @@ export class ResourceMonitor {
65
97
  .selectFrom(this.resourcesTable)
66
98
  .select([
67
99
  'model_name',
68
- (eb) => eb.fn.sum(sql `input_tokens + output_tokens`).as('totalTokens'),
100
+ (eb) => eb.fn
101
+ .sum(eb('input_tokens', '+', 'output_tokens'))
102
+ .as('totalTokens'),
69
103
  (eb) => eb.fn.sum('cost').as('totalCost'),
70
104
  ])
71
105
  .groupBy('model_name')
@@ -137,6 +137,7 @@ export class SessionManager {
137
137
  .selectAll()
138
138
  .where('session_id', '=', sessionId)
139
139
  .where('description', '=', description)
140
+ .forUpdate() // Audit Phase 13: Atomic goal lock
140
141
  .executeTakeFirst();
141
142
  if (existing) {
142
143
  const updated = await trx
@@ -203,23 +204,29 @@ export class SessionManager {
203
204
  * Mark a message as a semantic anchor to prevent it from being pruned
204
205
  */
205
206
  async markMessageAsAnchor(messageId) {
206
- const message = await this.typedDb
207
- .selectFrom(this.messagesTable)
208
- .selectAll()
209
- .where('id', '=', messageId)
210
- .executeTakeFirstOrThrow();
211
- const metadata = typeof message.metadata === 'string'
212
- ? JSON.parse(message.metadata)
213
- : message.metadata || {};
214
- const updatedMetadata = { ...metadata, anchor: true };
215
- const updated = await this.typedDb
216
- .updateTable(this.messagesTable)
217
- .set({
218
- metadata: JSON.stringify(updatedMetadata),
219
- })
220
- .where('id', '=', messageId)
221
- .returningAll()
222
- .executeTakeFirstOrThrow();
207
+ // PRODUCTION HARDENING: Atomic Metadata Patching
208
+ // We avoid the Read-Modify-Write race condition by letting the DB handle the merge
209
+ // or by using a strict transaction if the DB doesn't support JSON patching natively.
210
+ const updated = await this.db.transaction().execute(async (trx) => {
211
+ const message = await trx
212
+ .selectFrom(this.messagesTable)
213
+ .select('metadata')
214
+ .where('id', '=', messageId)
215
+ .forUpdate() // Lock the row for the duration of the transaction
216
+ .executeTakeFirstOrThrow();
217
+ const metadata = typeof message.metadata === 'string'
218
+ ? JSON.parse(message.metadata)
219
+ : message.metadata || {};
220
+ const updatedMetadata = { ...metadata, anchor: true };
221
+ return await trx
222
+ .updateTable(this.messagesTable)
223
+ .set({
224
+ metadata: JSON.stringify(updatedMetadata),
225
+ })
226
+ .where('id', '=', messageId)
227
+ .returningAll()
228
+ .executeTakeFirstOrThrow();
229
+ });
223
230
  return this.parseMessage(updated);
224
231
  }
225
232
  parseSession(session) {
@@ -27,6 +27,7 @@ export declare class VectorIndexer {
27
27
  addMemory(content: string, embedding: number[], sessionId?: string | number, metadata?: Record<string, any>): Promise<AgentMemory>;
28
28
  /**
29
29
  * Batch add memories
30
+ * Refactored Phase 12: Chunked execution to prevent OOM and long-running locks.
30
31
  */
31
32
  addMemories(items: {
32
33
  content: string;
@@ -34,21 +34,28 @@ export class VectorIndexer {
34
34
  }
35
35
  /**
36
36
  * Batch add memories
37
+ * Refactored Phase 12: Chunked execution to prevent OOM and long-running locks.
37
38
  */
38
39
  async addMemories(items) {
39
- const values = items.map((item) => ({
40
- content: item.content,
41
- embedding: JSON.stringify(item.embedding),
42
- session_id: item.sessionId || null,
43
- metadata: item.metadata ? JSON.stringify(item.metadata) : null,
44
- created_at: new Date(),
45
- }));
46
- const memories = await this.typedDb
47
- .insertInto(this.memoriesTable)
48
- .values(values)
49
- .returningAll()
50
- .execute();
51
- return memories.map((m) => this.parseMemory(m));
40
+ const BATCH_SIZE = 50;
41
+ const results = [];
42
+ for (let i = 0; i < items.length; i += BATCH_SIZE) {
43
+ const chunk = items.slice(i, i + BATCH_SIZE);
44
+ const values = chunk.map((item) => ({
45
+ content: item.content,
46
+ embedding: JSON.stringify(item.embedding),
47
+ session_id: item.sessionId || null,
48
+ metadata: item.metadata ? JSON.stringify(item.metadata) : null,
49
+ created_at: new Date(),
50
+ }));
51
+ const memories = await this.typedDb
52
+ .insertInto(this.memoriesTable)
53
+ .values(values)
54
+ .returningAll()
55
+ .execute();
56
+ results.push(...memories.map((m) => this.parseMemory(m)));
57
+ }
58
+ return results;
52
59
  }
53
60
  /**
54
61
  * Search for similar memories using Hybrid Search (Vector + Keyword)
@@ -84,13 +91,15 @@ export class VectorIndexer {
84
91
  }
85
92
  if (vectorResults.length === 0) {
86
93
  // Manual Fallback (Cosine Similarity in-memory)
87
- let query = this.typedDb.selectFrom(this.memoriesTable).selectAll();
94
+ // Audit Phase 12: Hard limit on candidate set to protect memory
95
+ let query = this.typedDb
96
+ .selectFrom(this.memoriesTable)
97
+ .selectAll()
98
+ .orderBy('created_at', 'desc')
99
+ .limit(1000);
88
100
  if (sessionId) {
89
101
  query = query.where('session_id', '=', sessionId);
90
102
  }
91
- if (!sessionId) {
92
- query = query.orderBy('created_at', 'desc').limit(1000);
93
- }
94
103
  const allMemories = await query.execute();
95
104
  const scored = allMemories.map((mem) => {
96
105
  const vec = typeof mem.embedding === 'string'
@@ -16,24 +16,22 @@ export declare class AblationEngine {
16
16
  private get typedDb();
17
17
  /**
18
18
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
19
- * Checks for linked dependencies before deletion.
20
19
  */
21
20
  pruneZombies(thresholdDays?: number): Promise<number>;
22
21
  /**
23
- * Monitor Performance: Check if recent success rates satisfy the safety baseline.
24
- * If performance has dropped > 20% since ablation tests started, trigger auto-recovery.
22
+ * Monitor Performance and perform Intelligent Rollbacks.
23
+ * Prioritizes recovery of items with highest historical hit counts.
25
24
  */
26
25
  monitorAblationPerformance(): Promise<{
27
26
  status: 'stable' | 'degraded';
28
27
  recoveredCount: number;
29
28
  }>;
30
29
  /**
31
- * Conduct an "Ablation Test": Temporarily disable a knowledge item
32
- * to see if it impacts reasoning.
30
+ * Conduct an "Ablation Test": Temporarily disable a knowledge item.
33
31
  */
34
32
  testAblation(id: string | number): Promise<boolean>;
35
33
  /**
36
34
  * Restore an ablated knowledge item to its original state.
37
35
  */
38
- recoverAblatedItem(id: string | number): Promise<boolean>;
36
+ recoverAblatedItem(id: string | number, trx?: any): Promise<boolean>;
39
37
  }
@@ -23,13 +23,13 @@ export class AblationEngine {
23
23
  }
24
24
  /**
25
25
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
26
- * Checks for linked dependencies before deletion.
27
26
  */
28
27
  async pruneZombies(thresholdDays = 30) {
29
28
  const cutoff = new Date(Date.now() - thresholdDays * 24 * 3600000);
30
29
  let totalPruned = 0;
31
30
  return await this.db.transaction().execute(async (trx) => {
32
- // 1. Prune Knowledge (with dependency check)
31
+ // 1. Prune Knowledge (with dependency check and pagination)
32
+ // Audit Phase 9: Paginated selection to prevent OOM
33
33
  const knowledgeToPrune = await trx
34
34
  .selectFrom(this.knowledgeTable)
35
35
  .selectAll()
@@ -39,16 +39,16 @@ export class AblationEngine {
39
39
  eb('metadata', 'is', null),
40
40
  ]))
41
41
  .where('updated_at', '<', cutoff)
42
- // Exclude items that are linked
43
42
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('source_id'))
44
43
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('target_id'))
44
+ .limit(500) // Audit Phase 9: Batch limit
45
+ .forUpdate() // Audit Phase 9: Lock candidates
45
46
  .execute();
46
47
  if (knowledgeToPrune.length > 0) {
47
48
  const candidates = knowledgeToPrune.map((k) => this.cortex.knowledge['parseKnowledge'](k));
48
49
  const idsToDelete = [];
49
50
  for (const item of candidates) {
50
51
  const fitness = this.cortex.knowledge.calculateFitness(item);
51
- // Prune if fitness is below threshold (e.g., 0.3)
52
52
  if (fitness < 0.3) {
53
53
  idsToDelete.push(item.id);
54
54
  }
@@ -61,14 +61,17 @@ export class AblationEngine {
61
61
  totalPruned += Number(result.numDeletedRows || 0);
62
62
  }
63
63
  }
64
- // 2. Prune Memories
64
+ // 2. Prune Memories (Paginated)
65
65
  const memoriesResult = await trx
66
66
  .deleteFrom(this.memoriesTable)
67
+ .where('id', 'in', (eb) => eb.selectFrom(this.memoriesTable)
68
+ .select('id')
67
69
  .where('created_at', '<', cutoff)
68
- .where((eb) => eb.or([
69
- eb('metadata', 'not like', '%"anchor":true%'),
70
- eb('metadata', 'is', null),
70
+ .where((eb2) => eb2.or([
71
+ eb2('metadata', 'not like', '%"anchor":true%'),
72
+ eb2('metadata', 'is', null),
71
73
  ]))
74
+ .limit(1000))
72
75
  .executeTakeFirst();
73
76
  totalPruned += Number(memoriesResult.numDeletedRows || 0);
74
77
  if (totalPruned > 0) {
@@ -78,34 +81,44 @@ export class AblationEngine {
78
81
  });
79
82
  }
80
83
  /**
81
- * Monitor Performance: Check if recent success rates satisfy the safety baseline.
82
- * If performance has dropped > 20% since ablation tests started, trigger auto-recovery.
84
+ * Monitor Performance and perform Intelligent Rollbacks.
85
+ * Prioritizes recovery of items with highest historical hit counts.
83
86
  */
84
87
  async monitorAblationPerformance() {
85
- console.log(`[AblationEngine] Running performance monitoring for active ablation tests...`);
86
- const baseline = await this.cortex.metrics.getAverageMetric('success_rate');
87
- const stats = await this.cortex.metrics.getMetricStats('success_rate');
88
- // If current average is significantly lower than overall average
89
- if (stats.count > 10 && stats.avg < baseline * 0.8) {
90
- console.warn(`[AblationEngine] PERFORMANCE DEGRADATION DETECTED (Avg: ${stats.avg}, Baseline: ${baseline}). Triggering mass recovery.`);
91
- const ablatedItems = await this.typedDb
92
- .selectFrom(this.knowledgeTable)
93
- .select('id')
94
- .where('metadata', 'like', '%"ablation_test":true%')
95
- .execute();
96
- let recoveredCount = 0;
97
- for (const item of ablatedItems) {
98
- if (await this.recoverAblatedItem(item.id)) {
99
- recoveredCount++;
88
+ return await this.db.transaction().execute(async (trx) => {
89
+ const baseline = await this.cortex.metrics.getAverageMetric('success_rate');
90
+ const stats = await this.cortex.metrics.getMetricStats('success_rate');
91
+ // If current average is significantly lower than overall average
92
+ if (stats.count > 10 && stats.avg < baseline * 0.8) {
93
+ console.warn(`[AblationEngine] PERFORMANCE DEGRADATION DETECTED (Avg: ${stats.avg}, Baseline: ${baseline}). Triggering targeted recovery.`);
94
+ // Fetch ablated items, ordered by hit_count descending (prioritize high-value restore)
95
+ const ablatedItems = await trx
96
+ .selectFrom(this.knowledgeTable)
97
+ .select(['id', 'metadata'])
98
+ .where('metadata', 'like', '%"ablation_test":true%')
99
+ .execute();
100
+ // Sort by hit_count in memory for precise weighted recovery
101
+ const sortedItems = ablatedItems.sort((a, b) => {
102
+ const metaA = typeof a.metadata === 'string' ? JSON.parse(a.metadata) : a.metadata || {};
103
+ const metaB = typeof b.metadata === 'string' ? JSON.parse(b.metadata) : b.metadata || {};
104
+ return (metaB.hit_count || 0) - (metaA.hit_count || 0);
105
+ });
106
+ let recoveredCount = 0;
107
+ for (const item of sortedItems) {
108
+ if (await this.recoverAblatedItem(item.id, trx)) {
109
+ recoveredCount++;
110
+ }
111
+ // Only recover until performance stabilizes or we've recovered a reasonable chunk (e.g. 5)
112
+ if (recoveredCount >= 5)
113
+ break;
100
114
  }
115
+ return { status: 'degraded', recoveredCount };
101
116
  }
102
- return { status: 'degraded', recoveredCount };
103
- }
104
- return { status: 'stable', recoveredCount: 0 };
117
+ return { status: 'stable', recoveredCount: 0 };
118
+ });
105
119
  }
106
120
  /**
107
- * Conduct an "Ablation Test": Temporarily disable a knowledge item
108
- * to see if it impacts reasoning.
121
+ * Conduct an "Ablation Test": Temporarily disable a knowledge item.
109
122
  */
110
123
  async testAblation(id) {
111
124
  console.log(`[AblationEngine] Conducting ablation test on item ${id}`);
@@ -114,18 +127,18 @@ export class AblationEngine {
114
127
  .selectFrom(this.knowledgeTable)
115
128
  .selectAll()
116
129
  .where('id', '=', id)
130
+ .forUpdate() // Audit Phase 9: Atomic lock for test initiation
117
131
  .executeTakeFirst());
118
132
  if (!item)
119
133
  return false;
120
134
  const metadata = typeof item.metadata === 'string'
121
135
  ? JSON.parse(item.metadata)
122
136
  : item.metadata || {};
123
- // 1. Record the experiment in reflections
124
137
  await this.cortex.reflections.reflect(item.source_session_id || 'system', 'success', `Ablation experiment initiated for item ${id}`, [
125
138
  `Temporary confidence reduction to evaluate reasoning impact.`,
126
139
  `Original confidence: ${item.confidence}`,
140
+ `Historical hits: ${metadata.hit_count || 0}`
127
141
  ]);
128
- // 2. Perform the ablation
129
142
  await trx
130
143
  .updateTable(this.knowledgeTable)
131
144
  .set({
@@ -145,12 +158,13 @@ export class AblationEngine {
145
158
  /**
146
159
  * Restore an ablated knowledge item to its original state.
147
160
  */
148
- async recoverAblatedItem(id) {
149
- return await this.db.transaction().execute(async (trx) => {
150
- const item = (await trx
161
+ async recoverAblatedItem(id, trx) {
162
+ const recoveryStep = async (t) => {
163
+ const item = (await t
151
164
  .selectFrom(this.knowledgeTable)
152
165
  .selectAll()
153
166
  .where('id', '=', id)
167
+ .forUpdate() // Audit Phase 9: Atomic lock for restoration
154
168
  .executeTakeFirst());
155
169
  if (!item)
156
170
  return false;
@@ -163,7 +177,7 @@ export class AblationEngine {
163
177
  delete metadata.ablation_test;
164
178
  delete metadata.original_confidence;
165
179
  delete metadata.ablated_at;
166
- await trx
180
+ await t
167
181
  .updateTable(this.knowledgeTable)
168
182
  .set({
169
183
  confidence: originalConfidence,
@@ -174,6 +188,12 @@ export class AblationEngine {
174
188
  .execute();
175
189
  console.log(`[AblationEngine] Item ${id} recovered. Confidence restored to ${originalConfidence}.`);
176
190
  return true;
177
- });
191
+ };
192
+ if (trx) {
193
+ return await recoveryStep(trx);
194
+ }
195
+ else {
196
+ return await this.db.transaction().execute(recoveryStep);
197
+ }
178
198
  }
179
199
  }
@@ -19,7 +19,9 @@ export class ActionRefiner {
19
19
  */
20
20
  async refineActions() {
21
21
  const recommendations = [];
22
- // 1. Find tools with high failure rates
22
+ // 1. Find tools with high failure rates (Last 24h Window)
23
+ // Audit Phase 14: Sliding window to prevent global table scans
24
+ const windowStart = new Date(Date.now() - 24 * 60 * 60 * 1000);
23
25
  const failureStats = (await this.db
24
26
  .selectFrom(this.actionsTable)
25
27
  .select('tool_name')
@@ -27,23 +29,27 @@ export class ActionRefiner {
27
29
  .select((eb) => eb.fn
28
30
  .sum(eb.case().when('status', '=', 'failure').then(1).else(0).end())
29
31
  .as('failures'))
32
+ .where('created_at', '>', windowStart)
30
33
  .groupBy('tool_name')
31
34
  .execute());
35
+ const failureRateThreshold = this.config.refiner?.failureRateThreshold || 0.3;
36
+ const minActionBatch = this.config.refiner?.minActionBatch || 3;
32
37
  for (const stat of failureStats) {
33
38
  const failures = Number(stat.failures || 0);
34
39
  const total = Number(stat.total || 1);
35
40
  const rate = failures / total;
36
- if (rate > 0.3 && total > 3) {
41
+ if (rate > failureRateThreshold && total > minActionBatch) {
37
42
  recommendations.push(`Tool '${stat.tool_name}' has a ${Math.round(rate * 100)}% failure rate. Suggesting automatic reflection rule.`);
38
43
  // Automatically propose a rule to reflect on this tool's usage
39
44
  await this.proposeReflectionRule(stat.tool_name);
40
45
  }
41
46
  }
42
- // 2. Discover missing capabilities based on error patterns
47
+ // 2. Discover missing capabilities based on error patterns (Last 24h)
43
48
  const missingCapabilities = (await this.db
44
49
  .selectFrom(this.actionsTable)
45
50
  .select('tool_name')
46
51
  .where('status', '=', 'failure')
52
+ .where('created_at', '>', windowStart)
47
53
  .where((eb) => eb.or([
48
54
  eb('error', 'like', '%permission denied%'),
49
55
  eb('error', 'like', '%unknown tool%'),
@@ -62,17 +68,27 @@ export class ActionRefiner {
62
68
  * Propose a rule to reflect on a specific tool usage
63
69
  */
64
70
  async proposeReflectionRule(toolName) {
65
- const existing = await this.cortex.rules.getActiveRules('agent_actions', 'insert');
66
- const hasRule = existing.some((r) => r.metadata?.targetTool === toolName);
67
- if (!hasRule) {
68
- console.log(`[ActionRefiner] Proposing reflection rule for tool: ${toolName}`);
69
- await this.cortex.rules.defineRule('agent_actions', 'insert', 'audit', {
70
- metadata: {
71
- targetTool: toolName,
72
- reason: 'High failure rate detected by ActionRefiner',
73
- },
74
- });
75
- }
71
+ // Audit Phase 19: Atomic rule proposal via transaction + existence check
72
+ await this.db.transaction().execute(async (trx) => {
73
+ const rulesTable = this.cortex.config.rulesTable || 'agent_rules';
74
+ const existing = await trx
75
+ .selectFrom(rulesTable)
76
+ .select('id')
77
+ .where('tableName', '=', 'agent_actions')
78
+ .where('operation', '=', 'insert')
79
+ .where('metadata', 'like', `%\"targetTool\":\"${toolName}\"%`)
80
+ .forUpdate() // Lock to prevent concurrent proposals
81
+ .executeTakeFirst();
82
+ if (!existing) {
83
+ console.log(`[ActionRefiner] Proposing reflection rule for tool: ${toolName}`);
84
+ await this.cortex.rules.defineRule('agent_actions', 'insert', 'audit', {
85
+ metadata: {
86
+ targetTool: toolName,
87
+ reason: 'High failure rate detected by ActionRefiner',
88
+ },
89
+ }, trx); // Pass transaction object
90
+ }
91
+ });
76
92
  }
77
93
  /**
78
94
  * Propose an update to capabilities
@@ -12,7 +12,9 @@ export declare class ConflictResolver {
12
12
  /**
13
13
  * Audit rules for direct conflicts and semantic overlaps.
14
14
  */
15
- auditRuleConflicts(): Promise<string[]>;
15
+ auditRuleConflicts(options?: {
16
+ batchSize?: number;
17
+ }): Promise<string[]>;
16
18
  /**
17
19
  * Resolve a detected conflict by disabling the older rule.
18
20
  * Real implementation: Find all active rules for the conflict, and disable all but the newest one.