agentic-qe 3.8.10 → 3.8.12

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 (119) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/CHANGELOG.md +40 -0
  3. package/dist/cli/bundle.js +1345 -1003
  4. package/dist/cli/command-registry.js +5 -1
  5. package/dist/cli/commands/pipeline.d.ts +16 -0
  6. package/dist/cli/commands/pipeline.js +314 -0
  7. package/dist/cli/commands/ruvector-commands.js +17 -0
  8. package/dist/cli/commands/token-usage.js +24 -1
  9. package/dist/cli/handlers/heartbeat-handler.d.ts +26 -0
  10. package/dist/cli/handlers/heartbeat-handler.js +382 -0
  11. package/dist/cli/handlers/index.d.ts +2 -0
  12. package/dist/cli/handlers/index.js +2 -0
  13. package/dist/cli/handlers/routing-handler.d.ts +22 -0
  14. package/dist/cli/handlers/routing-handler.js +227 -0
  15. package/dist/cli/index.js +2 -0
  16. package/dist/coordination/deterministic-actions.d.ts +36 -0
  17. package/dist/coordination/deterministic-actions.js +257 -0
  18. package/dist/coordination/workflow-orchestrator.d.ts +18 -1
  19. package/dist/coordination/workflow-orchestrator.js +113 -3
  20. package/dist/coordination/workflow-types.d.ts +19 -1
  21. package/dist/coordination/workflow-types.js +3 -0
  22. package/dist/coordination/yaml-pipeline-loader.d.ts +1 -0
  23. package/dist/coordination/yaml-pipeline-loader.js +34 -0
  24. package/dist/domains/code-intelligence/coordinator-gnn.d.ts +21 -0
  25. package/dist/domains/code-intelligence/coordinator-gnn.js +102 -0
  26. package/dist/domains/contract-testing/coordinator.js +13 -0
  27. package/dist/domains/coverage-analysis/coordinator.js +5 -0
  28. package/dist/domains/defect-intelligence/coordinator.d.ts +1 -0
  29. package/dist/domains/defect-intelligence/coordinator.js +43 -0
  30. package/dist/domains/quality-assessment/coordinator.js +26 -0
  31. package/dist/domains/test-generation/coordinator.js +14 -0
  32. package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.d.ts +11 -0
  33. package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.js +44 -1
  34. package/dist/integrations/rl-suite/algorithms/eprop.d.ts +79 -0
  35. package/dist/integrations/rl-suite/algorithms/eprop.js +284 -0
  36. package/dist/integrations/rl-suite/algorithms/index.d.ts +2 -1
  37. package/dist/integrations/rl-suite/algorithms/index.js +2 -1
  38. package/dist/integrations/rl-suite/index.d.ts +2 -2
  39. package/dist/integrations/rl-suite/index.js +2 -2
  40. package/dist/integrations/rl-suite/interfaces.d.ts +3 -3
  41. package/dist/integrations/rl-suite/interfaces.js +1 -1
  42. package/dist/integrations/rl-suite/orchestrator.d.ts +2 -2
  43. package/dist/integrations/rl-suite/orchestrator.js +3 -2
  44. package/dist/integrations/rl-suite/reward-signals.d.ts +1 -1
  45. package/dist/integrations/rl-suite/reward-signals.js +1 -1
  46. package/dist/integrations/ruvector/coherence-gate-cohomology.d.ts +41 -0
  47. package/dist/integrations/ruvector/coherence-gate-cohomology.js +47 -0
  48. package/dist/integrations/ruvector/coherence-gate-core.d.ts +200 -0
  49. package/dist/integrations/ruvector/coherence-gate-core.js +294 -0
  50. package/dist/integrations/ruvector/coherence-gate-energy.d.ts +136 -0
  51. package/dist/integrations/ruvector/coherence-gate-energy.js +373 -0
  52. package/dist/integrations/ruvector/coherence-gate-vector.d.ts +38 -0
  53. package/dist/integrations/ruvector/coherence-gate-vector.js +76 -0
  54. package/dist/integrations/ruvector/coherence-gate.d.ts +10 -311
  55. package/dist/integrations/ruvector/coherence-gate.js +10 -652
  56. package/dist/integrations/ruvector/cold-tier-trainer.d.ts +103 -0
  57. package/dist/integrations/ruvector/cold-tier-trainer.js +377 -0
  58. package/dist/integrations/ruvector/cusum-detector.d.ts +70 -0
  59. package/dist/integrations/ruvector/cusum-detector.js +142 -0
  60. package/dist/integrations/ruvector/delta-tracker.d.ts +122 -0
  61. package/dist/integrations/ruvector/delta-tracker.js +311 -0
  62. package/dist/integrations/ruvector/domain-transfer.d.ts +79 -1
  63. package/dist/integrations/ruvector/domain-transfer.js +158 -2
  64. package/dist/integrations/ruvector/eprop-learner.d.ts +135 -0
  65. package/dist/integrations/ruvector/eprop-learner.js +351 -0
  66. package/dist/integrations/ruvector/feature-flags.d.ts +177 -0
  67. package/dist/integrations/ruvector/feature-flags.js +145 -0
  68. package/dist/integrations/ruvector/graphmae-encoder.d.ts +88 -0
  69. package/dist/integrations/ruvector/graphmae-encoder.js +360 -0
  70. package/dist/integrations/ruvector/hdc-fingerprint.d.ts +127 -0
  71. package/dist/integrations/ruvector/hdc-fingerprint.js +222 -0
  72. package/dist/integrations/ruvector/hopfield-memory.d.ts +97 -0
  73. package/dist/integrations/ruvector/hopfield-memory.js +238 -0
  74. package/dist/integrations/ruvector/index.d.ts +13 -2
  75. package/dist/integrations/ruvector/index.js +46 -2
  76. package/dist/integrations/ruvector/mincut-wrapper.d.ts +7 -0
  77. package/dist/integrations/ruvector/mincut-wrapper.js +54 -2
  78. package/dist/integrations/ruvector/reservoir-replay.d.ts +172 -0
  79. package/dist/integrations/ruvector/reservoir-replay.js +335 -0
  80. package/dist/integrations/ruvector/solver-adapter.d.ts +93 -0
  81. package/dist/integrations/ruvector/solver-adapter.js +299 -0
  82. package/dist/integrations/ruvector/sona-persistence.d.ts +33 -0
  83. package/dist/integrations/ruvector/sona-persistence.js +47 -0
  84. package/dist/integrations/ruvector/spectral-sparsifier.d.ts +154 -0
  85. package/dist/integrations/ruvector/spectral-sparsifier.js +389 -0
  86. package/dist/integrations/ruvector/temporal-causality.d.ts +63 -0
  87. package/dist/integrations/ruvector/temporal-causality.js +317 -0
  88. package/dist/learning/pattern-promotion.d.ts +63 -0
  89. package/dist/learning/pattern-promotion.js +235 -1
  90. package/dist/learning/pattern-store.d.ts +2 -0
  91. package/dist/learning/pattern-store.js +187 -1
  92. package/dist/learning/sqlite-persistence.d.ts +2 -0
  93. package/dist/learning/sqlite-persistence.js +4 -0
  94. package/dist/mcp/bundle.js +477 -380
  95. package/dist/mcp/handlers/heartbeat-handlers.d.ts +67 -0
  96. package/dist/mcp/handlers/heartbeat-handlers.js +180 -0
  97. package/dist/mcp/handlers/index.d.ts +2 -1
  98. package/dist/mcp/handlers/index.js +5 -1
  99. package/dist/mcp/handlers/task-handlers.d.ts +28 -0
  100. package/dist/mcp/handlers/task-handlers.js +39 -0
  101. package/dist/mcp/protocol-server.js +45 -1
  102. package/dist/mcp/server.js +41 -1
  103. package/dist/optimization/index.d.ts +2 -0
  104. package/dist/optimization/index.js +1 -0
  105. package/dist/optimization/session-cache.d.ts +80 -0
  106. package/dist/optimization/session-cache.js +227 -0
  107. package/dist/optimization/token-optimizer-service.d.ts +10 -0
  108. package/dist/optimization/token-optimizer-service.js +51 -0
  109. package/dist/routing/economic-routing.d.ts +126 -0
  110. package/dist/routing/economic-routing.js +290 -0
  111. package/dist/routing/index.d.ts +2 -0
  112. package/dist/routing/index.js +2 -0
  113. package/dist/routing/routing-feedback.d.ts +29 -0
  114. package/dist/routing/routing-feedback.js +75 -0
  115. package/dist/shared/utils/index.d.ts +1 -0
  116. package/dist/shared/utils/index.js +1 -0
  117. package/dist/shared/utils/xorshift128.d.ts +24 -0
  118. package/dist/shared/utils/xorshift128.js +50 -0
  119. package/package.json +1 -1
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { LoggerFactory } from '../../logging/index.js';
8
8
  import { QEGNNIndexFactory, initGNN, } from '../../integrations/ruvector/wrappers';
9
+ import { isGraphMAEEnabled, isColdTierGNNEnabled, createGraphMAEEncoder, createColdTierTrainer, InMemoryGraph, } from '../../integrations/ruvector/index.js';
9
10
  /**
10
11
  * Initialize GNN for code graph embeddings
11
12
  */
@@ -55,6 +56,73 @@ export async function indexCodeEmbeddings(gnnIndex, fileReader, paths) {
55
56
  logger.error('Failed to index code embeddings:', error instanceof Error ? error : undefined);
56
57
  }
57
58
  }
59
+ // R4: GraphMAE singleton encoder (lazy-initialized)
60
+ let graphMAEEncoder = null;
61
+ /**
62
+ * R4: Generate graph-aware embeddings for a set of files using GraphMAE.
63
+ * Builds a dependency graph from import relationships and uses masked
64
+ * autoencoders to produce structure-aware embeddings.
65
+ * Falls back to feature-hash embeddings when GraphMAE is disabled.
66
+ */
67
+ export async function generateGraphMAEEmbeddings(fileReader, paths) {
68
+ const embeddings = new Map();
69
+ if (!isGraphMAEEnabled() || paths.length < 2) {
70
+ // Fallback: use feature-hash for each file independently
71
+ for (const p of paths) {
72
+ const result = await fileReader.readFile(p);
73
+ if (result.success && result.value) {
74
+ embeddings.set(p, await generateCodeEmbedding(p, result.value));
75
+ }
76
+ }
77
+ return embeddings;
78
+ }
79
+ try {
80
+ // Build QEGraph: nodes are files, edges are import dependencies
81
+ const nodes = new Map();
82
+ const edges = new Map();
83
+ const contentCache = new Map();
84
+ for (const p of paths) {
85
+ const result = await fileReader.readFile(p);
86
+ if (result.success && result.value) {
87
+ contentCache.set(p, result.value);
88
+ const featureVec = await generateCodeEmbedding(p, result.value);
89
+ nodes.set(p, new Float32Array(featureVec.slice(0, 32)));
90
+ // Extract import targets as edges
91
+ const imports = result.value.match(/from\s+['"]([^'"]+)['"]/g) ?? [];
92
+ const targets = imports
93
+ .map(m => m.replace(/from\s+['"]/, '').replace(/['"]$/, ''))
94
+ .filter(t => paths.some(pp => pp.includes(t.replace(/^\.\//, ''))));
95
+ edges.set(p, targets.length > 0 ? targets : []);
96
+ }
97
+ }
98
+ if (nodes.size < 2) {
99
+ // Not enough nodes for meaningful graph learning
100
+ for (const [p, content] of contentCache) {
101
+ embeddings.set(p, await generateCodeEmbedding(p, content));
102
+ }
103
+ return embeddings;
104
+ }
105
+ const graph = { nodes, edges };
106
+ if (!graphMAEEncoder) {
107
+ graphMAEEncoder = createGraphMAEEncoder({ embeddingDim: 128, numHeads: 4 });
108
+ }
109
+ const graphEmbeddings = graphMAEEncoder.embed(graph);
110
+ for (const [nodeId, emb] of graphEmbeddings) {
111
+ embeddings.set(nodeId, Array.from(emb));
112
+ }
113
+ logger.info(`[R4] GraphMAE generated ${graphEmbeddings.size} graph-aware embeddings`);
114
+ }
115
+ catch (error) {
116
+ logger.error('[R4] GraphMAE embedding failed, using feature-hash fallback:', error instanceof Error ? error : undefined);
117
+ for (const p of paths) {
118
+ const result = await fileReader.readFile(p);
119
+ if (result.success && result.value) {
120
+ embeddings.set(p, await generateCodeEmbedding(p, result.value));
121
+ }
122
+ }
123
+ }
124
+ return embeddings;
125
+ }
58
126
  /**
59
127
  * Generate code embedding using semantic features
60
128
  */
@@ -171,6 +239,40 @@ export function mergeSearchResults(semanticResults, gnnResults) {
171
239
  .sort((a, b) => b.score - a.score)
172
240
  .slice(0, 20);
173
241
  }
242
+ // R6: ColdTier trainer singleton (lazy-initialized)
243
+ let coldTierTrainer = null;
244
+ /**
245
+ * R6: Train GNN embeddings with memory-bounded cold-tier training.
246
+ * Uses LRU hotset caching when the graph exceeds hotsetSize, falling
247
+ * back to full in-memory training for small graphs.
248
+ */
249
+ export function trainWithColdTier(nodeFeatures, adjacency, options = {}) {
250
+ if (!isColdTierGNNEnabled()) {
251
+ return { embeddings: new Map(), loss: 0, usedColdTier: false };
252
+ }
253
+ try {
254
+ if (!coldTierTrainer) {
255
+ coldTierTrainer = createColdTierTrainer({
256
+ hotsetSize: options.hotsetSize ?? 10000,
257
+ epochs: options.epochs ?? 10,
258
+ hiddenDim: options.hiddenDim ?? 64,
259
+ });
260
+ }
261
+ const graph = new InMemoryGraph(nodeFeatures, adjacency);
262
+ const result = coldTierTrainer.train(graph);
263
+ logger.info(`[R6] ColdTier training: ${graph.nodeCount} nodes, ` +
264
+ `loss=${result.loss.toFixed(4)}, mode=${result.usedInMemoryMode ? 'in-memory' : 'cold-tier'}`);
265
+ return {
266
+ embeddings: result.embeddings,
267
+ loss: result.loss,
268
+ usedColdTier: !result.usedInMemoryMode,
269
+ };
270
+ }
271
+ catch (error) {
272
+ logger.error('[R6] ColdTier training failed:', error instanceof Error ? error : undefined);
273
+ return { embeddings: new Map(), loss: 0, usedColdTier: false };
274
+ }
275
+ }
174
276
  /**
175
277
  * Simple hash function for strings
176
278
  */
@@ -16,6 +16,8 @@ import { ContractValidatorService } from './services/contract-validator.js';
16
16
  import { ApiCompatibilityService } from './services/api-compatibility.js';
17
17
  import { SARSAAlgorithm } from '../../integrations/rl-suite/algorithms/sarsa.js';
18
18
  import { createPersistentSONAEngine } from '../../integrations/ruvector/sona-persistence.js';
19
+ // Three-loop feature flag for instantAdapt protocol
20
+ import { isSONAThreeLoopEnabled } from '../../integrations/ruvector/feature-flags.js';
19
21
  import { createDomainFinding, } from '../../coordination/consensus/domain-findings.js';
20
22
  // CQ-002: Base domain coordinator
21
23
  import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
@@ -960,6 +962,17 @@ export class ContractTestingCoordinator extends BaseDomainCoordinator {
960
962
  contract.endpoints.filter((e) => e.responseSchema).length / 100,
961
963
  ],
962
964
  };
965
+ // Three-loop protocol: instantAdapt must precede recordOutcome
966
+ if (isSONAThreeLoopEnabled() && this.qesona.isThreeLoopEnabled()) {
967
+ this.qesona.instantAdapt([
968
+ contract.endpoints.length / 100,
969
+ contract.consumers.length / 50,
970
+ contract.schemas.length / 50,
971
+ quality,
972
+ validationSuccess ? 1 : 0,
973
+ contract.version.major / 10,
974
+ ]);
975
+ }
963
976
  const action = {
964
977
  type: validationSuccess ? 'validate' : 'reject',
965
978
  value: quality,
@@ -69,6 +69,11 @@ export class CoverageAnalysisCoordinator extends BaseDomainCoordinator {
69
69
  async onInitialize() {
70
70
  // Services are stateless, no domain-specific initialization needed
71
71
  // ADR-059: Ghost coverage analyzer is lazy-initialized on first use
72
+ // NOTE: EWC++ three-loop integration not available in this coordinator.
73
+ // Coverage-analysis uses Q-Learning (not SONA), so the three-loop engine
74
+ // is not accessible here. To enable EWC++ for coverage patterns, this
75
+ // coordinator would need a PersistentSONAEngine instance wired the same
76
+ // way as quality-assessment and test-generation coordinators.
72
77
  }
73
78
  async onDispose() {
74
79
  // No domain-specific cleanup needed
@@ -54,6 +54,7 @@ export declare class DefectIntelligenceCoordinator extends BaseDomainCoordinator
54
54
  private readonly predictor;
55
55
  private readonly patternLearner;
56
56
  private readonly rootCauseAnalyzer;
57
+ private readonly testExecutionHistory;
57
58
  constructor(eventBus: EventBus, memory: MemoryBackend, agentCoordinator: AgentCoordinator, config?: Partial<CoordinatorConfig>);
58
59
  protected onInitialize(): Promise<void>;
59
60
  protected onDispose(): Promise<void>;
@@ -17,6 +17,9 @@ import { PatternLearnerService, } from './services/pattern-learner';
17
17
  import { RootCauseAnalyzerService, } from './services/root-cause-analyzer';
18
18
  // CQ-002: Base domain coordinator
19
19
  import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
20
+ // R12: Granger Causality for temporal failure prediction (ADR-087)
21
+ import { getRuVectorFeatureFlags } from '../../integrations/ruvector/feature-flags.js';
22
+ import { GrangerAnalyzer } from '../../integrations/ruvector/temporal-causality.js';
20
23
  const DEFAULT_CONFIG = {
21
24
  maxConcurrentWorkflows: 5,
22
25
  defaultTimeout: 60000,
@@ -49,6 +52,8 @@ export class DefectIntelligenceCoordinator extends BaseDomainCoordinator {
49
52
  predictor;
50
53
  patternLearner;
51
54
  rootCauseAnalyzer;
55
+ // R12: Accumulated test execution history for Granger causality (ADR-087)
56
+ testExecutionHistory = new Map();
52
57
  constructor(eventBus, memory, agentCoordinator, config = {}) {
53
58
  const fullConfig = { ...DEFAULT_CONFIG, ...config };
54
59
  super(eventBus, 'defect-intelligence', fullConfig, {
@@ -160,6 +165,44 @@ export class DefectIntelligenceCoordinator extends BaseDomainCoordinator {
160
165
  if (this.config.enablePatternLearning) {
161
166
  await this.autoAnalyzeHighRisk(enhancedResult);
162
167
  }
168
+ // R12: Accumulate test history and run Granger causality (ADR-087)
169
+ if (getRuVectorFeatureFlags().useGrangerCausality) {
170
+ try {
171
+ const now = Date.now();
172
+ // Accumulate prediction outcomes into per-test history
173
+ for (const p of enhancedResult.predictions) {
174
+ const history = this.testExecutionHistory.get(p.file) ?? { timestamps: [], outcomes: [] };
175
+ history.timestamps.push(now);
176
+ history.outcomes.push(p.probability > 0.5 ? 0 : 1);
177
+ // Cap history at 500 points per test
178
+ if (history.timestamps.length > 500) {
179
+ history.timestamps.splice(0, history.timestamps.length - 500);
180
+ history.outcomes.splice(0, history.outcomes.length - 500);
181
+ }
182
+ this.testExecutionHistory.set(p.file, history);
183
+ }
184
+ // Run Granger analysis when we have enough accumulated history
185
+ const eligibleSeries = Array.from(this.testExecutionHistory.entries())
186
+ .filter(([, h]) => h.timestamps.length >= 30)
187
+ .map(([testId, h]) => ({ testId, timestamps: h.timestamps, outcomes: h.outcomes }));
188
+ if (eligibleSeries.length >= 3) {
189
+ const analyzer = new GrangerAnalyzer({ maxLag: 5, alpha: 0.05 });
190
+ const causalLinks = analyzer.analyzeCausality(eligibleSeries);
191
+ if (causalLinks.length > 0) {
192
+ logger.info('Granger causality found causal links in defect predictions', {
193
+ linkCount: causalLinks.length,
194
+ historyDepth: eligibleSeries[0].timestamps.length,
195
+ topLink: `${causalLinks[0].sourceTestId} → ${causalLinks[0].targetTestId} (lag=${causalLinks[0].lag}, p=${causalLinks[0].pValue.toFixed(4)})`,
196
+ });
197
+ }
198
+ }
199
+ }
200
+ catch (grangerErr) {
201
+ logger.warn('Granger causality analysis failed (non-fatal)', {
202
+ error: grangerErr instanceof Error ? grangerErr.message : 'unknown',
203
+ });
204
+ }
205
+ }
163
206
  // Stop the agent
164
207
  await this.agentCoordinator.stop(agentResult.value);
165
208
  return ok(enhancedResult);
@@ -28,6 +28,8 @@ import * as ClaimVerifierHelpers from './coordinator-claim-verifier.js';
28
28
  import * as GateEvalHelpers from './coordinator-gate-evaluation.js';
29
29
  // ADR-070: Witness Chain audit trail
30
30
  import { getWitnessChain } from '../../audit/witness-chain.js';
31
+ // Three-loop feature flag for instantAdapt protocol
32
+ import { isSONAThreeLoopEnabled } from '../../integrations/ruvector/feature-flags.js';
31
33
  // CQ-002: Base domain coordinator
32
34
  import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
33
35
  const DEFAULT_CONFIG = {
@@ -227,6 +229,20 @@ export class QualityAssessmentCoordinator extends BaseDomainCoordinator {
227
229
  }
228
230
  // Success path
229
231
  this.completeWorkflow(workflowId);
232
+ // Three-loop protocol: instantAdapt must precede recordOutcome
233
+ if (isSONAThreeLoopEnabled() && this.qesona?.isThreeLoopEnabled()) {
234
+ const m = effectiveRequest.metrics;
235
+ this.qesona.instantAdapt([
236
+ m.coverage / 100,
237
+ m.testsPassing / 100,
238
+ m.criticalBugs / 10,
239
+ m.codeSmells / 100,
240
+ m.securityVulnerabilities / 10,
241
+ m.technicalDebt / 100,
242
+ m.duplications / 100,
243
+ finalResult.overallScore / 100,
244
+ ]);
245
+ }
230
246
  // Store quality pattern in SONA if enabled
231
247
  if (this.config.enableSONAPatternLearning && this.qesona) {
232
248
  await this.storeQualityPattern(effectiveRequest, finalResult);
@@ -322,6 +338,16 @@ export class QualityAssessmentCoordinator extends BaseDomainCoordinator {
322
338
  result.value = enhanced;
323
339
  }
324
340
  }
341
+ // Three-loop protocol: instantAdapt must precede recordOutcome
342
+ if (isSONAThreeLoopEnabled() && this.qesona?.isThreeLoopEnabled()) {
343
+ const score = result.value.score;
344
+ this.qesona.instantAdapt([
345
+ score.overall / 100,
346
+ result.value.metrics.length / 20,
347
+ result.value.trends.length / 10,
348
+ result.value.recommendations.length / 10,
349
+ ]);
350
+ }
325
351
  // Store quality pattern in SONA
326
352
  if (this.config.enableSONAPatternLearning && this.qesona) {
327
353
  await this.storeQualityAnalysisPattern(request, result.value);
@@ -24,6 +24,8 @@ import { createDomainFinding, } from '../../coordination/consensus/domain-findin
24
24
  import { createPersistentSONAEngine, } from '../../integrations/ruvector/sona-persistence.js';
25
25
  import { createQEFlashAttention, } from '../../integrations/ruvector/wrappers.js';
26
26
  import { DecisionTransformerAlgorithm, } from '../../integrations/rl-suite/algorithms/decision-transformer.js';
27
+ // Three-loop feature flag for instantAdapt protocol
28
+ import { isSONAThreeLoopEnabled } from '../../integrations/ruvector/feature-flags.js';
27
29
  // Coherence Gate Integration (ADR-052)
28
30
  import { createTestGenerationCoherenceGate, } from './services/coherence-gate-service.js';
29
31
  const DEFAULT_CONFIG = {
@@ -307,6 +309,18 @@ export class TestGenerationCoordinator extends BaseDomainCoordinator {
307
309
  await this.publishTestGenerated(test, request.framework ?? 'vitest');
308
310
  }
309
311
  }
312
+ // Three-loop protocol: instantAdapt must precede recordOutcome
313
+ if (isSONAThreeLoopEnabled() && this.qesona?.isThreeLoopEnabled()) {
314
+ const tests = result.value;
315
+ this.qesona.instantAdapt([
316
+ tests.tests.length / 20,
317
+ tests.coverageEstimate / 100,
318
+ tests.patternsUsed.length / 10,
319
+ request.sourceFiles.length / 20,
320
+ (request.coverageTarget ?? 80) / 100,
321
+ tests.tests.filter(t => t.type === 'unit').length / 20,
322
+ ]);
323
+ }
310
324
  // Learn from successful generation using QESONA
311
325
  if (this.config.enableQESONA && this.qesona) {
312
326
  await this.storeTestGenerationPattern(result.value, request);
@@ -117,6 +117,7 @@ export declare class ExperienceReplay {
117
117
  private experienceIdToHnswId;
118
118
  private nextHnswId;
119
119
  private recentExperiences;
120
+ private reservoirBuffer;
120
121
  private stats;
121
122
  constructor(config?: Partial<ExperienceReplayConfig>);
122
123
  /**
@@ -197,6 +198,16 @@ export declare class ExperienceReplay {
197
198
  hnswIndexSize: number;
198
199
  recentBufferSize: number;
199
200
  };
201
+ /**
202
+ * Get reservoir buffer stats (R10, ADR-087).
203
+ * Returns null if the reservoir is not enabled.
204
+ */
205
+ getReservoirStats(): {
206
+ size: number;
207
+ totalAdmitted: number;
208
+ totalRejected: number;
209
+ tierCounts: Record<string, number>;
210
+ } | null;
200
211
  /**
201
212
  * Dispose and cleanup
202
213
  */
@@ -19,6 +19,8 @@ import { CircularBuffer } from '../../../shared/utils/circular-buffer.js';
19
19
  import { HNSWEmbeddingIndex } from '../../embeddings/index/HNSWIndex.js';
20
20
  import { safeJsonParse } from '../../../shared/safe-json.js';
21
21
  import { ExperienceConsolidator } from '../../../learning/experience-consolidation.js';
22
+ import { getRuVectorFeatureFlags } from '../../ruvector/feature-flags.js';
23
+ import { ReservoirReplayBuffer } from '../../ruvector/reservoir-replay.js';
22
24
  const DEFAULT_CONFIG = {
23
25
  minQualityThreshold: 0.6,
24
26
  maxExperiencesPerDomain: 500,
@@ -64,6 +66,8 @@ export class ExperienceReplay {
64
66
  nextHnswId = 0;
65
67
  // Recent experiences buffer
66
68
  recentExperiences;
69
+ // Reservoir replay buffer (R10, ADR-087) — coherence-gated admission
70
+ reservoirBuffer = null;
67
71
  // Statistics
68
72
  stats = {
69
73
  experiencesStored: 0,
@@ -99,6 +103,11 @@ export class ExperienceReplay {
99
103
  this.prepareStatements();
100
104
  // Load embeddings into memory index
101
105
  await this.loadEmbeddingIndex();
106
+ // Initialize reservoir buffer if feature flag is enabled (R10, ADR-087)
107
+ if (getRuVectorFeatureFlags().useReservoirReplay) {
108
+ this.reservoirBuffer = new ReservoirReplayBuffer({ capacity: 10_000 });
109
+ console.log('[ExperienceReplay] Reservoir replay buffer enabled');
110
+ }
102
111
  this.initialized = true;
103
112
  console.log('[ExperienceReplay] Initialized');
104
113
  }
@@ -333,6 +342,10 @@ export class ExperienceReplay {
333
342
  }
334
343
  // Add to recent buffer
335
344
  this.recentExperiences.push(experience);
345
+ // Admit to reservoir buffer with coherence gating (R10, ADR-087)
346
+ if (this.reservoirBuffer) {
347
+ this.reservoirBuffer.admit(experience.id, experience, experience.qualityScore);
348
+ }
336
349
  this.stats.experiencesStored++;
337
350
  // Auto-consolidate if enabled (replaces destructive auto-prune)
338
351
  if (this.config.autoPrune) {
@@ -349,8 +362,23 @@ export class ExperienceReplay {
349
362
  */
350
363
  async getGuidance(task, domain) {
351
364
  this.ensureInitialized();
352
- // Find similar experiences
365
+ // Find similar experiences via HNSW
353
366
  const similar = await this.findSimilarExperiences(task, domain);
367
+ // Blend in high-coherence experiences from reservoir buffer (R10, ADR-087)
368
+ if (this.reservoirBuffer && this.reservoirBuffer.size() > 0) {
369
+ const reservoirSamples = this.reservoirBuffer.sample(Math.max(2, Math.floor(this.config.topK / 2)), 0.6);
370
+ for (const entry of reservoirSamples) {
371
+ const exp = entry.data;
372
+ // Skip if already in HNSW results
373
+ if (similar.some(s => s.experience.id === exp.id))
374
+ continue;
375
+ // Skip if domain filter doesn't match
376
+ if (domain && exp.domain !== domain)
377
+ continue;
378
+ // Add with a coherence-based similarity score
379
+ similar.push({ experience: exp, similarity: entry.coherenceScore * 0.8 });
380
+ }
381
+ }
354
382
  if (similar.length === 0) {
355
383
  return null;
356
384
  }
@@ -564,6 +592,21 @@ export class ExperienceReplay {
564
592
  recentBufferSize: this.recentExperiences.length,
565
593
  };
566
594
  }
595
+ /**
596
+ * Get reservoir buffer stats (R10, ADR-087).
597
+ * Returns null if the reservoir is not enabled.
598
+ */
599
+ getReservoirStats() {
600
+ if (!this.reservoirBuffer)
601
+ return null;
602
+ const stats = this.reservoirBuffer.getStats();
603
+ return {
604
+ size: stats.size,
605
+ totalAdmitted: stats.totalAdmitted,
606
+ totalRejected: stats.totalRejected,
607
+ tierCounts: stats.tierCounts,
608
+ };
609
+ }
567
610
  /**
568
611
  * Dispose and cleanup
569
612
  */
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Agentic QE v3 - E-prop Online Learning Algorithm (ADR-087 Milestone 4)
3
+ *
4
+ * RL algorithm #10: Eligibility propagation for online learning.
5
+ * Uses 12 bytes/synapse with no backprop required.
6
+ *
7
+ * Application: Online adaptive test strategies — learns in real time
8
+ * from test execution feedback without storing replay buffers.
9
+ */
10
+ import { BaseRLAlgorithm } from '../base-algorithm';
11
+ import type { RLState, RLPrediction, RLTrainingStats, RLExperience, RLAlgorithmInfo, RewardSignal } from '../interfaces';
12
+ interface EpropAlgorithmConfig {
13
+ /** Number of state features */
14
+ stateSize: number;
15
+ /** Hidden layer size for the E-prop network */
16
+ hiddenSize: number;
17
+ /** Number of discrete actions */
18
+ actionSize: number;
19
+ /** E-prop learning rate */
20
+ epropLearningRate: number;
21
+ /** Eligibility trace decay */
22
+ eligibilityDecay: number;
23
+ /** Use feedback alignment */
24
+ feedbackAlignment: boolean;
25
+ }
26
+ /**
27
+ * E-prop online learning algorithm for adaptive test strategies.
28
+ *
29
+ * Unlike batch RL algorithms, E-prop learns from each experience
30
+ * immediately using eligibility traces — no replay buffer needed.
31
+ *
32
+ * Key advantages:
33
+ * - Online: updates weights after every step
34
+ * - Memory-efficient: 12 bytes/synapse (vs kilobytes for replay-based)
35
+ * - Biologically plausible: no weight transport (feedback alignment)
36
+ * - Fast: no backward pass through the full network
37
+ */
38
+ export declare class EpropAlgorithm extends BaseRLAlgorithm {
39
+ private network;
40
+ private epropConfig;
41
+ private actions;
42
+ constructor(config?: Partial<EpropAlgorithmConfig>, rewardSignals?: RewardSignal[]);
43
+ /**
44
+ * Predict best action for a given state.
45
+ * Runs the E-prop network forward pass and selects the action
46
+ * with highest output activation.
47
+ */
48
+ predict(state: RLState): Promise<RLPrediction>;
49
+ /**
50
+ * Train with a single experience — the core online learning step.
51
+ *
52
+ * Unlike batch algorithms, E-prop processes each experience immediately:
53
+ * 1. Forward pass (already done during predict)
54
+ * 2. Online update: dw = eta * eligibility * reward
55
+ */
56
+ train(experience: RLExperience): Promise<RLTrainingStats>;
57
+ /**
58
+ * Core training logic for batch experiences.
59
+ * E-prop processes each experience online (sequentially).
60
+ */
61
+ protected trainCore(experiences: RLExperience[]): Promise<RLTrainingStats>;
62
+ /**
63
+ * Get algorithm-specific info.
64
+ */
65
+ protected getAlgorithmInfo(): RLAlgorithmInfo;
66
+ protected exportCustomData(): Promise<Record<string, unknown>>;
67
+ protected importCustomData(data: Record<string, unknown>): Promise<void>;
68
+ protected resetAlgorithm(): Promise<void>;
69
+ private prepareState;
70
+ private argmax;
71
+ private calculateConfidence;
72
+ private generateReasoning;
73
+ }
74
+ /**
75
+ * Create a new E-prop RL algorithm instance.
76
+ */
77
+ export declare function createEpropAlgorithm(config?: Partial<EpropAlgorithmConfig>, rewardSignals?: RewardSignal[]): EpropAlgorithm;
78
+ export {};
79
+ //# sourceMappingURL=eprop.d.ts.map