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