agentic-qe 3.7.21 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/.claude/helpers/brain-checkpoint.cjs +4 -1
  2. package/.claude/helpers/statusline-v3.cjs +3 -1
  3. package/.claude/skills/skills-manifest.json +1 -1
  4. package/CHANGELOG.md +45 -0
  5. package/README.md +2 -14
  6. package/assets/helpers/statusline-v3.cjs +3 -1
  7. package/dist/cli/brain-commands.js +6 -10
  8. package/dist/cli/bundle.js +7441 -4327
  9. package/dist/cli/commands/audit.d.ts +43 -0
  10. package/dist/cli/commands/audit.js +125 -0
  11. package/dist/cli/commands/hooks.js +29 -6
  12. package/dist/cli/commands/init.js +1 -73
  13. package/dist/cli/commands/learning.js +270 -13
  14. package/dist/cli/commands/ruvector-commands.d.ts +15 -0
  15. package/dist/cli/commands/ruvector-commands.js +271 -0
  16. package/dist/cli/handlers/init-handler.d.ts +0 -1
  17. package/dist/cli/handlers/init-handler.js +0 -6
  18. package/dist/cli/index.js +4 -2
  19. package/dist/context/sources/defect-source.js +2 -2
  20. package/dist/context/sources/memory-source.js +2 -2
  21. package/dist/context/sources/requirements-source.js +2 -2
  22. package/dist/coordination/behavior-tree/decorators.d.ts +108 -0
  23. package/dist/coordination/behavior-tree/decorators.js +251 -0
  24. package/dist/coordination/behavior-tree/index.d.ts +12 -0
  25. package/dist/coordination/behavior-tree/index.js +15 -0
  26. package/dist/coordination/behavior-tree/nodes.d.ts +165 -0
  27. package/dist/coordination/behavior-tree/nodes.js +338 -0
  28. package/dist/coordination/behavior-tree/qe-trees.d.ts +105 -0
  29. package/dist/coordination/behavior-tree/qe-trees.js +181 -0
  30. package/dist/coordination/coherence-action-gate.d.ts +284 -0
  31. package/dist/coordination/coherence-action-gate.js +512 -0
  32. package/dist/coordination/index.d.ts +4 -0
  33. package/dist/coordination/index.js +8 -0
  34. package/dist/coordination/reasoning-qec.d.ts +315 -0
  35. package/dist/coordination/reasoning-qec.js +585 -0
  36. package/dist/coordination/task-executor.d.ts +16 -0
  37. package/dist/coordination/task-executor.js +99 -0
  38. package/dist/coordination/workflow-orchestrator.d.ts +29 -0
  39. package/dist/coordination/workflow-orchestrator.js +42 -0
  40. package/dist/domains/visual-accessibility/cnn-visual-regression.d.ts +135 -0
  41. package/dist/domains/visual-accessibility/cnn-visual-regression.js +327 -0
  42. package/dist/domains/visual-accessibility/index.d.ts +1 -0
  43. package/dist/domains/visual-accessibility/index.js +4 -0
  44. package/dist/governance/coherence-validator.d.ts +112 -0
  45. package/dist/governance/coherence-validator.js +180 -0
  46. package/dist/governance/index.d.ts +1 -0
  47. package/dist/governance/index.js +2 -0
  48. package/dist/governance/witness-chain.d.ts +311 -0
  49. package/dist/governance/witness-chain.js +509 -0
  50. package/dist/init/index.d.ts +0 -2
  51. package/dist/init/index.js +0 -1
  52. package/dist/init/init-wizard-steps.d.ts +10 -0
  53. package/dist/init/init-wizard-steps.js +87 -1
  54. package/dist/init/init-wizard.d.ts +1 -9
  55. package/dist/init/init-wizard.js +3 -69
  56. package/dist/init/orchestrator.js +0 -1
  57. package/dist/init/phases/01-detection.js +0 -27
  58. package/dist/init/phases/07-hooks.js +6 -4
  59. package/dist/init/phases/phase-interface.d.ts +0 -1
  60. package/dist/init/settings-merge.js +1 -1
  61. package/dist/integrations/browser/qe-dashboard/clustering.d.ts +48 -0
  62. package/dist/integrations/browser/qe-dashboard/clustering.js +183 -0
  63. package/dist/integrations/browser/qe-dashboard/index.d.ts +12 -0
  64. package/dist/integrations/browser/qe-dashboard/index.js +15 -0
  65. package/dist/integrations/browser/qe-dashboard/pattern-explorer.d.ts +165 -0
  66. package/dist/integrations/browser/qe-dashboard/pattern-explorer.js +260 -0
  67. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.d.ts +144 -0
  68. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +277 -0
  69. package/dist/integrations/ruvector/cognitive-container-codec.d.ts +51 -0
  70. package/dist/integrations/ruvector/cognitive-container-codec.js +180 -0
  71. package/dist/integrations/ruvector/cognitive-container.d.ts +125 -0
  72. package/dist/integrations/ruvector/cognitive-container.js +306 -0
  73. package/dist/integrations/ruvector/coherence-gate.d.ts +309 -0
  74. package/dist/integrations/ruvector/coherence-gate.js +631 -0
  75. package/dist/integrations/ruvector/compressed-hnsw-integration.d.ts +176 -0
  76. package/dist/integrations/ruvector/compressed-hnsw-integration.js +301 -0
  77. package/dist/integrations/ruvector/dither-adapter.d.ts +122 -0
  78. package/dist/integrations/ruvector/dither-adapter.js +295 -0
  79. package/dist/integrations/ruvector/domain-transfer.d.ts +129 -0
  80. package/dist/integrations/ruvector/domain-transfer.js +220 -0
  81. package/dist/integrations/ruvector/feature-flags.d.ts +214 -2
  82. package/dist/integrations/ruvector/feature-flags.js +167 -2
  83. package/dist/integrations/ruvector/filter-adapter.d.ts +71 -0
  84. package/dist/integrations/ruvector/filter-adapter.js +285 -0
  85. package/dist/integrations/ruvector/gnn-wrapper.d.ts +20 -0
  86. package/dist/integrations/ruvector/gnn-wrapper.js +40 -0
  87. package/dist/integrations/ruvector/hnsw-health-monitor.d.ts +237 -0
  88. package/dist/integrations/ruvector/hnsw-health-monitor.js +394 -0
  89. package/dist/integrations/ruvector/index.d.ts +8 -2
  90. package/dist/integrations/ruvector/index.js +18 -2
  91. package/dist/integrations/ruvector/interfaces.d.ts +40 -0
  92. package/dist/integrations/ruvector/sona-persistence.d.ts +54 -0
  93. package/dist/integrations/ruvector/sona-persistence.js +162 -0
  94. package/dist/integrations/ruvector/sona-three-loop.d.ts +392 -0
  95. package/dist/integrations/ruvector/sona-three-loop.js +814 -0
  96. package/dist/integrations/ruvector/sona-wrapper.d.ts +97 -0
  97. package/dist/integrations/ruvector/sona-wrapper.js +147 -3
  98. package/dist/integrations/ruvector/spectral-math.d.ts +101 -0
  99. package/dist/integrations/ruvector/spectral-math.js +254 -0
  100. package/dist/integrations/ruvector/temporal-compression.d.ts +163 -0
  101. package/dist/integrations/ruvector/temporal-compression.js +318 -0
  102. package/dist/integrations/ruvector/thompson-sampler.d.ts +61 -0
  103. package/dist/integrations/ruvector/thompson-sampler.js +118 -0
  104. package/dist/integrations/ruvector/transfer-coherence-stub.d.ts +80 -0
  105. package/dist/integrations/ruvector/transfer-coherence-stub.js +63 -0
  106. package/dist/integrations/ruvector/transfer-verification.d.ts +119 -0
  107. package/dist/integrations/ruvector/transfer-verification.js +115 -0
  108. package/dist/kernel/hnsw-adapter.d.ts +52 -1
  109. package/dist/kernel/hnsw-adapter.js +139 -4
  110. package/dist/kernel/hnsw-index-provider.d.ts +5 -0
  111. package/dist/kernel/native-hnsw-backend.d.ts +110 -0
  112. package/dist/kernel/native-hnsw-backend.js +408 -0
  113. package/dist/kernel/unified-memory.js +5 -6
  114. package/dist/learning/aqe-learning-engine.d.ts +2 -0
  115. package/dist/learning/aqe-learning-engine.js +65 -0
  116. package/dist/learning/experience-capture-middleware.js +20 -0
  117. package/dist/learning/experience-capture.d.ts +10 -0
  118. package/dist/learning/experience-capture.js +34 -0
  119. package/dist/learning/index.d.ts +2 -2
  120. package/dist/learning/index.js +4 -4
  121. package/dist/learning/metrics-tracker.d.ts +11 -0
  122. package/dist/learning/metrics-tracker.js +29 -13
  123. package/dist/learning/pattern-lifecycle.d.ts +30 -1
  124. package/dist/learning/pattern-lifecycle.js +92 -20
  125. package/dist/learning/pattern-store.d.ts +8 -0
  126. package/dist/learning/pattern-store.js +8 -2
  127. package/dist/learning/qe-unified-memory.js +1 -28
  128. package/dist/learning/regret-tracker.d.ts +201 -0
  129. package/dist/learning/regret-tracker.js +361 -0
  130. package/dist/mcp/bundle.js +5915 -474
  131. package/dist/routing/index.d.ts +4 -2
  132. package/dist/routing/index.js +3 -1
  133. package/dist/routing/neural-tiny-dancer-router.d.ts +268 -0
  134. package/dist/routing/neural-tiny-dancer-router.js +514 -0
  135. package/dist/routing/queen-integration.js +5 -5
  136. package/dist/routing/routing-config.d.ts +6 -0
  137. package/dist/routing/routing-config.js +1 -0
  138. package/dist/routing/simple-neural-router.d.ts +76 -0
  139. package/dist/routing/simple-neural-router.js +202 -0
  140. package/dist/routing/tiny-dancer-router.d.ts +20 -1
  141. package/dist/routing/tiny-dancer-router.js +21 -2
  142. package/dist/test-scheduling/dag-attention-scheduler.d.ts +81 -0
  143. package/dist/test-scheduling/dag-attention-scheduler.js +358 -0
  144. package/dist/test-scheduling/dag-attention-types.d.ts +81 -0
  145. package/dist/test-scheduling/dag-attention-types.js +10 -0
  146. package/dist/test-scheduling/index.d.ts +1 -0
  147. package/dist/test-scheduling/index.js +4 -0
  148. package/dist/test-scheduling/pipeline.d.ts +8 -0
  149. package/dist/test-scheduling/pipeline.js +28 -0
  150. package/package.json +6 -2
  151. package/dist/cli/commands/migrate.d.ts +0 -9
  152. package/dist/cli/commands/migrate.js +0 -566
  153. package/dist/init/init-wizard-migration.d.ts +0 -52
  154. package/dist/init/init-wizard-migration.js +0 -345
  155. package/dist/init/migration/config-migrator.d.ts +0 -31
  156. package/dist/init/migration/config-migrator.js +0 -149
  157. package/dist/init/migration/data-migrator.d.ts +0 -72
  158. package/dist/init/migration/data-migrator.js +0 -232
  159. package/dist/init/migration/detector.d.ts +0 -44
  160. package/dist/init/migration/detector.js +0 -105
  161. package/dist/init/migration/index.d.ts +0 -8
  162. package/dist/init/migration/index.js +0 -8
  163. package/dist/learning/v2-to-v3-migration.d.ts +0 -86
  164. package/dist/learning/v2-to-v3-migration.js +0 -529
@@ -0,0 +1,514 @@
1
+ /**
2
+ * Neural TinyDancer Router - ADR-082
3
+ * Neural Model Routing via FastGRNN-style Network
4
+ *
5
+ * Replaces rule-based complexity thresholds with a lightweight neural network
6
+ * for routing decisions. Implements shadow mode for safe rollout, circuit
7
+ * breaker for reliability, and online learning from outcome feedback.
8
+ *
9
+ * Design:
10
+ * - Input features: [complexityScore, tokenEstimate, domainIndex, historicalSuccessRate]
11
+ * - Hidden layer: 32 units with ReLU activation
12
+ * - Output: softmax probability distribution over [Tier1/haiku, Tier2/sonnet, Tier3/opus]
13
+ * - Shadow mode: first 1000 decisions run both routers, tracks disagreement
14
+ * - Circuit breaker: falls back to rule-based if error rate exceeds threshold
15
+ *
16
+ * @module routing/neural-tiny-dancer-router
17
+ */
18
+ import { performance } from 'perf_hooks';
19
+ import { TinyDancerRouter, } from './tiny-dancer-router.js';
20
+ // Re-export SimpleNeuralRouter from its own module for backward compatibility
21
+ export { SimpleNeuralRouter } from './simple-neural-router.js';
22
+ import { SimpleNeuralRouter } from './simple-neural-router.js';
23
+ // ============================================================================
24
+ // Constants
25
+ // ============================================================================
26
+ /** Decisions required before shadow mode can end */
27
+ const SHADOW_MODE_DECISIONS = 1000;
28
+ /** Maximum disagreement rate to exit shadow mode */
29
+ const SHADOW_MODE_MAX_DISAGREEMENT = 0.10;
30
+ /** Default circuit breaker error threshold */
31
+ const DEFAULT_CIRCUIT_BREAKER_THRESHOLD = 0.20;
32
+ /** Window size for circuit breaker error rate calculation */
33
+ const CIRCUIT_BREAKER_WINDOW = 50;
34
+ /** Default learning rate for weight updates */
35
+ const DEFAULT_LEARNING_RATE = 0.01;
36
+ /** Map tier index to ClaudeModel */
37
+ const TIER_INDEX_TO_MODEL = ['haiku', 'sonnet', 'opus'];
38
+ /** Map ClaudeModel to tier index */
39
+ const MODEL_TO_TIER_INDEX = {
40
+ haiku: 0,
41
+ sonnet: 1,
42
+ opus: 2,
43
+ };
44
+ /** Map QEDomain to a normalized domain index (0-1) */
45
+ const DOMAIN_INDEX_MAP = {
46
+ 'test-generation': 0.1,
47
+ 'test-execution': 0.15,
48
+ 'coverage-analysis': 0.2,
49
+ 'quality-assessment': 0.3,
50
+ 'requirements-validation': 0.35,
51
+ 'code-intelligence': 0.4,
52
+ 'contract-testing': 0.45,
53
+ 'visual-accessibility': 0.5,
54
+ 'learning-optimization': 0.55,
55
+ 'defect-intelligence': 0.7,
56
+ 'chaos-resilience': 0.8,
57
+ 'security-compliance': 0.9,
58
+ };
59
+ // ============================================================================
60
+ // Neural TinyDancer Router
61
+ // ============================================================================
62
+ /**
63
+ * Neural-enhanced TinyDancer Router
64
+ *
65
+ * Wraps the rule-based TinyDancerRouter with a lightweight neural network
66
+ * that learns optimal routing decisions from outcomes. Operates in shadow
67
+ * mode initially, then transitions to neural-primary when proven reliable.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const router = new NeuralTinyDancerRouter({ learningRate: 0.01 });
72
+ * const result = await router.route(task);
73
+ * // Later, record outcome for learning
74
+ * router.recordNeuralOutcome(task, result, true, 0.95);
75
+ * ```
76
+ */
77
+ export class NeuralTinyDancerRouter {
78
+ /** Rule-based fallback router (always available) */
79
+ ruleRouter;
80
+ /** Neural network for routing decisions */
81
+ neuralNet;
82
+ /** Configuration */
83
+ circuitBreakerThreshold;
84
+ shadowModeDecisionLimit;
85
+ shadowModeMaxDisagreement;
86
+ /** Shadow mode state */
87
+ shadowModeActive;
88
+ shadowDecisions = [];
89
+ shadowDisagreements = 0;
90
+ /** Circuit breaker state */
91
+ circuitBreakerTripped = false;
92
+ recentOutcomes = [];
93
+ /** Tracking */
94
+ totalNeuralDecisions = 0;
95
+ totalWeightUpdates = 0;
96
+ neuralPrimary = false;
97
+ /** Calibration scores for empirical confidence bounds */
98
+ calibrationScores = [];
99
+ maxCalibrationScores = 500;
100
+ /** Historical success rates by domain for feature extraction */
101
+ domainSuccessRates = new Map();
102
+ /** Config passthrough */
103
+ config;
104
+ /** Whether native ruvector module is available */
105
+ nativeRouterAvailable = false;
106
+ constructor(config = {}) {
107
+ this.config = config;
108
+ this.ruleRouter = new TinyDancerRouter(config);
109
+ this.neuralNet = new SimpleNeuralRouter(config.learningRate ?? DEFAULT_LEARNING_RATE);
110
+ this.circuitBreakerThreshold = config.circuitBreakerThreshold ?? DEFAULT_CIRCUIT_BREAKER_THRESHOLD;
111
+ this.shadowModeDecisionLimit = config.shadowModeDecisions ?? SHADOW_MODE_DECISIONS;
112
+ this.shadowModeMaxDisagreement = config.shadowModeMaxDisagreement ?? SHADOW_MODE_MAX_DISAGREEMENT;
113
+ // Determine initial shadow mode state
114
+ if (config.forceShadowMode !== undefined) {
115
+ this.shadowModeActive = config.forceShadowMode;
116
+ this.neuralPrimary = !config.forceShadowMode;
117
+ }
118
+ else {
119
+ this.shadowModeActive = true;
120
+ this.neuralPrimary = false;
121
+ }
122
+ // Attempt native ruvector import (non-blocking)
123
+ this.tryLoadNativeRouter();
124
+ }
125
+ /**
126
+ * Check for native router availability.
127
+ *
128
+ * The `@ruvector/tiny-dancer` NAPI package exists but the ARM64 binary
129
+ * is missing from the published package (packaging bug upstream).
130
+ * The TypeScript `SimpleNeuralRouter` IS the production implementation —
131
+ * its 4→32→3 network is too small to benefit from native acceleration.
132
+ */
133
+ tryLoadNativeRouter() {
134
+ this.nativeRouterAvailable = false;
135
+ }
136
+ /**
137
+ * Route a task to the optimal Claude model.
138
+ *
139
+ * Behavior depends on current mode:
140
+ * - Shadow mode: uses rule-based result, logs neural decision alongside
141
+ * - Neural primary: uses neural decision with rule-based as validation
142
+ * - Circuit breaker tripped: uses rule-based only
143
+ *
144
+ * @param task - The task to route
145
+ * @returns Routing result with model recommendation and confidence
146
+ */
147
+ async route(task) {
148
+ const startTime = performance.now();
149
+ // Always get the rule-based result (fallback guarantee)
150
+ const ruleResult = await this.ruleRouter.route(task);
151
+ // If circuit breaker is tripped, use rule-based only
152
+ if (this.circuitBreakerTripped) {
153
+ return ruleResult;
154
+ }
155
+ // Get neural network decision
156
+ const features = this.extractFeatures(task, ruleResult.classification);
157
+ let neuralProbs;
158
+ try {
159
+ neuralProbs = this.neuralNet.forward(features);
160
+ }
161
+ catch {
162
+ // Neural network error - fall back to rule-based
163
+ this.tripCircuitBreaker();
164
+ return ruleResult;
165
+ }
166
+ const neuralTierIndex = this.argmax(neuralProbs);
167
+ const neuralModel = TIER_INDEX_TO_MODEL[neuralTierIndex];
168
+ const neuralConfidence = neuralProbs[neuralTierIndex];
169
+ this.totalNeuralDecisions++;
170
+ // Shadow mode: log both decisions, use rule-based result
171
+ if (this.shadowModeActive) {
172
+ const agreed = ruleResult.model === neuralModel;
173
+ if (!agreed) {
174
+ this.shadowDisagreements++;
175
+ }
176
+ this.shadowDecisions.push({
177
+ taskDescription: task.description.slice(0, 100),
178
+ ruleDecision: ruleResult.model,
179
+ neuralDecision: neuralModel,
180
+ agreed,
181
+ neuralConfidence,
182
+ timestamp: new Date(),
183
+ });
184
+ // Check if we should exit shadow mode
185
+ this.evaluateShadowModeExit();
186
+ // In shadow mode, always return the rule-based result
187
+ return ruleResult;
188
+ }
189
+ // Neural-primary mode: use neural decision
190
+ const latencyMs = performance.now() - startTime;
191
+ // Build empirical confidence bounds from historical calibration scores
192
+ const empiricalBounds = this.computeEmpiricalConfidenceBounds(neuralProbs);
193
+ // Determine if we should override neural with rule-based
194
+ // (when neural confidence is very low or calibration score is too high)
195
+ if (neuralConfidence < 0.3 || empiricalBounds.calibrationScore > 0.8) {
196
+ return ruleResult;
197
+ }
198
+ // Build neural route result
199
+ const result = {
200
+ model: neuralModel,
201
+ confidence: neuralConfidence,
202
+ uncertainty: 1 - neuralConfidence,
203
+ triggerMultiModel: ruleResult.triggerMultiModel,
204
+ triggerHumanReview: ruleResult.triggerHumanReview,
205
+ complexity: ruleResult.complexity,
206
+ classification: ruleResult.classification,
207
+ latencyMs,
208
+ reasoning: this.buildNeuralReasoning(neuralModel, neuralConfidence, neuralProbs, ruleResult, empiricalBounds),
209
+ };
210
+ return result;
211
+ }
212
+ /**
213
+ * Extract feature vector from a task for neural network input.
214
+ *
215
+ * Features:
216
+ * [0] complexityScore: normalized classification score (0-1)
217
+ * [1] tokenEstimate: estimated token count, normalized (0-1)
218
+ * [2] domainIndex: domain-based complexity signal (0-1)
219
+ * [3] historicalSuccessRate: domain success rate (0-1)
220
+ */
221
+ extractFeatures(task, classification) {
222
+ // Feature 1: Normalized complexity score (0-100 -> 0-1)
223
+ const complexityScore = Math.min(1, classification.score / 100);
224
+ // Feature 2: Token estimate (based on description length + context)
225
+ const descLen = task.description.length;
226
+ const contextLen = task.context?.code?.length ?? 0;
227
+ const rawTokenEstimate = (descLen + contextLen) / 4; // rough char-to-token ratio
228
+ const tokenEstimate = Math.min(1, rawTokenEstimate / 10000); // normalize to 0-1
229
+ // Feature 3: Domain index
230
+ const domain = task.domain ?? '';
231
+ const domainIndex = DOMAIN_INDEX_MAP[domain] ?? 0.25;
232
+ // Feature 4: Historical success rate for this domain
233
+ const domainStats = this.domainSuccessRates.get(domain);
234
+ const successRate = domainStats
235
+ ? domainStats.success / Math.max(1, domainStats.total)
236
+ : 0.7; // default assumption
237
+ return [complexityScore, tokenEstimate, domainIndex, successRate];
238
+ }
239
+ /**
240
+ * Record the outcome of a routing decision for neural learning.
241
+ *
242
+ * Updates both the rule-based router (for stats) and the neural network
243
+ * weights (via policy gradient).
244
+ */
245
+ recordNeuralOutcome(task, routeResult, success, qualityScore = success ? 1.0 : 0.0, actualModelUsed = routeResult.model, durationMs = 0) {
246
+ // Forward to rule-based router for stats
247
+ this.ruleRouter.recordOutcome(task, routeResult, success, qualityScore, actualModelUsed, durationMs);
248
+ // Update domain success rates
249
+ const domain = task.domain ?? 'unknown';
250
+ const stats = this.domainSuccessRates.get(domain) ?? { success: 0, total: 0 };
251
+ stats.total++;
252
+ if (success)
253
+ stats.success++;
254
+ this.domainSuccessRates.set(domain, stats);
255
+ // Track recent outcomes for circuit breaker
256
+ this.recentOutcomes.push(success);
257
+ if (this.recentOutcomes.length > CIRCUIT_BREAKER_WINDOW) {
258
+ this.recentOutcomes.shift();
259
+ }
260
+ // Check circuit breaker
261
+ this.checkCircuitBreaker();
262
+ // Update neural network weights
263
+ const features = this.extractFeatures(task, routeResult.classification);
264
+ const tierIndex = MODEL_TO_TIER_INDEX[actualModelUsed];
265
+ const reward = (qualityScore - 0.5) * 2; // Scale to -1..1
266
+ try {
267
+ this.neuralNet.updateWeights(features, tierIndex, reward);
268
+ this.totalWeightUpdates++;
269
+ }
270
+ catch {
271
+ // Weight update failure is non-fatal
272
+ }
273
+ // Update calibration scores for empirical confidence bounds
274
+ const probs = this.neuralNet.forward(features);
275
+ const predictedTier = this.argmax(probs);
276
+ const calibrationScore = 1 - probs[tierIndex];
277
+ this.calibrationScores.push(calibrationScore);
278
+ if (this.calibrationScores.length > this.maxCalibrationScores) {
279
+ this.calibrationScores.shift();
280
+ }
281
+ }
282
+ /**
283
+ * Compute empirical confidence bounds from historical calibration scores.
284
+ *
285
+ * Note: This is NOT proper conformal prediction (which requires exchangeability
286
+ * guarantees and per-class nonconformity scoring). These are quantile-based
287
+ * intervals from historical routing outcomes.
288
+ */
289
+ computeEmpiricalConfidenceBounds(probs) {
290
+ const coverageLevel = 0.90;
291
+ const maxProb = Math.max(...probs);
292
+ const calibrationScore = 1 - maxProb;
293
+ if (this.calibrationScores.length < 10) {
294
+ // Insufficient calibration data - return wide bounds
295
+ return {
296
+ lower: 0,
297
+ upper: 1,
298
+ coverageLevel,
299
+ calibrationScore,
300
+ };
301
+ }
302
+ // Compute quantile of calibration scores
303
+ const sorted = [...this.calibrationScores].sort((a, b) => a - b);
304
+ const quantileIndex = Math.ceil(coverageLevel * sorted.length) - 1;
305
+ const threshold = sorted[Math.min(quantileIndex, sorted.length - 1)];
306
+ return {
307
+ lower: Math.max(0, maxProb - threshold),
308
+ upper: Math.min(1, maxProb + threshold),
309
+ coverageLevel,
310
+ calibrationScore,
311
+ };
312
+ }
313
+ /**
314
+ * Backward-compatible alias for computeEmpiricalConfidenceBounds.
315
+ * @deprecated Use computeEmpiricalConfidenceBounds instead.
316
+ */
317
+ computeConformalBounds(probs) {
318
+ return this.computeEmpiricalConfidenceBounds(probs);
319
+ }
320
+ /**
321
+ * Check whether shadow mode should end.
322
+ * Exits when enough decisions made AND disagreement rate is acceptable.
323
+ */
324
+ evaluateShadowModeExit() {
325
+ if (!this.shadowModeActive)
326
+ return;
327
+ if (this.config.forceShadowMode === true)
328
+ return; // Forced on
329
+ const totalShadow = this.shadowDecisions.length;
330
+ if (totalShadow < this.shadowModeDecisionLimit)
331
+ return;
332
+ const disagreementRate = this.shadowDisagreements / totalShadow;
333
+ if (disagreementRate <= this.shadowModeMaxDisagreement) {
334
+ this.shadowModeActive = false;
335
+ this.neuralPrimary = true;
336
+ }
337
+ }
338
+ /**
339
+ * Check circuit breaker and trip if error rate exceeds threshold.
340
+ */
341
+ checkCircuitBreaker() {
342
+ if (this.recentOutcomes.length < 10)
343
+ return;
344
+ const failures = this.recentOutcomes.filter(s => !s).length;
345
+ const errorRate = failures / this.recentOutcomes.length;
346
+ if (errorRate > this.circuitBreakerThreshold) {
347
+ this.tripCircuitBreaker();
348
+ }
349
+ else if (this.circuitBreakerTripped && errorRate < this.circuitBreakerThreshold * 0.5) {
350
+ // Auto-reset circuit breaker when error rate drops significantly
351
+ this.circuitBreakerTripped = false;
352
+ }
353
+ }
354
+ /**
355
+ * Trip the circuit breaker, falling back to rule-based routing.
356
+ */
357
+ tripCircuitBreaker() {
358
+ this.circuitBreakerTripped = true;
359
+ this.neuralPrimary = false;
360
+ }
361
+ /**
362
+ * Build reasoning string for neural routing decision
363
+ */
364
+ buildNeuralReasoning(model, confidence, probs, ruleResult, bounds) {
365
+ const parts = [];
366
+ parts.push(`[Neural] Routing to ${model.toUpperCase()}`);
367
+ parts.push(`with ${(confidence * 100).toFixed(0)}% neural confidence.`);
368
+ parts.push(`Tier probabilities: haiku=${(probs[0] * 100).toFixed(0)}%,`);
369
+ parts.push(`sonnet=${(probs[1] * 100).toFixed(0)}%,`);
370
+ parts.push(`opus=${(probs[2] * 100).toFixed(0)}%.`);
371
+ if (model !== ruleResult.model) {
372
+ parts.push(`Rule-based would choose ${ruleResult.model.toUpperCase()}.`);
373
+ }
374
+ parts.push(`Empirical bounds: [${bounds.lower.toFixed(2)}, ${bounds.upper.toFixed(2)}]`);
375
+ parts.push(`at ${(bounds.coverageLevel * 100).toFixed(0)}% coverage.`);
376
+ return parts.join(' ');
377
+ }
378
+ /**
379
+ * Get the index of the maximum value in an array.
380
+ */
381
+ argmax(arr) {
382
+ let maxIdx = 0;
383
+ let maxVal = arr[0];
384
+ for (let i = 1; i < arr.length; i++) {
385
+ if (arr[i] > maxVal) {
386
+ maxVal = arr[i];
387
+ maxIdx = i;
388
+ }
389
+ }
390
+ return maxIdx;
391
+ }
392
+ // ============================================================================
393
+ // Public Accessors
394
+ // ============================================================================
395
+ /**
396
+ * Get neural router statistics
397
+ */
398
+ getNeuralStats() {
399
+ const totalShadow = this.shadowDecisions.length;
400
+ const disagreementRate = totalShadow > 0
401
+ ? this.shadowDisagreements / totalShadow
402
+ : 0;
403
+ const failures = this.recentOutcomes.filter(s => !s).length;
404
+ const recentErrorRate = this.recentOutcomes.length > 0
405
+ ? failures / this.recentOutcomes.length
406
+ : 0;
407
+ return {
408
+ shadowModeActive: this.shadowModeActive,
409
+ shadowDecisions: totalShadow,
410
+ disagreementRate,
411
+ circuitBreakerTripped: this.circuitBreakerTripped,
412
+ recentErrorRate,
413
+ totalNeuralDecisions: this.totalNeuralDecisions,
414
+ totalWeightUpdates: this.totalWeightUpdates,
415
+ neuralPrimary: this.neuralPrimary,
416
+ };
417
+ }
418
+ /**
419
+ * Get shadow mode decision logs
420
+ */
421
+ getShadowDecisionLogs() {
422
+ return this.shadowDecisions;
423
+ }
424
+ /**
425
+ * Get the underlying rule-based router (for direct access if needed)
426
+ */
427
+ getRuleRouter() {
428
+ return this.ruleRouter;
429
+ }
430
+ /**
431
+ * Get the underlying neural network (for serialization/deserialization)
432
+ */
433
+ getNeuralNet() {
434
+ return this.neuralNet;
435
+ }
436
+ /**
437
+ * Check if native ruvector router is available
438
+ */
439
+ isNativeRouterAvailable() {
440
+ return this.nativeRouterAvailable;
441
+ }
442
+ /**
443
+ * Check if shadow mode is active
444
+ */
445
+ isShadowModeActive() {
446
+ return this.shadowModeActive;
447
+ }
448
+ /**
449
+ * Check if neural routing is primary
450
+ */
451
+ isNeuralPrimary() {
452
+ return this.neuralPrimary;
453
+ }
454
+ /**
455
+ * Check if circuit breaker is tripped
456
+ */
457
+ isCircuitBreakerTripped() {
458
+ return this.circuitBreakerTripped;
459
+ }
460
+ /**
461
+ * Manually reset the circuit breaker
462
+ */
463
+ resetCircuitBreaker() {
464
+ this.circuitBreakerTripped = false;
465
+ this.recentOutcomes = [];
466
+ }
467
+ /**
468
+ * Get the rule-based router's stats (delegates)
469
+ */
470
+ getStats() {
471
+ return this.ruleRouter.getStats();
472
+ }
473
+ /**
474
+ * Get the rule-based router's config (delegates)
475
+ */
476
+ getConfig() {
477
+ return this.ruleRouter.getConfig();
478
+ }
479
+ /**
480
+ * Reset all state (both rule-based and neural)
481
+ */
482
+ reset() {
483
+ this.ruleRouter.reset();
484
+ this.shadowDecisions = [];
485
+ this.shadowDisagreements = 0;
486
+ this.circuitBreakerTripped = false;
487
+ this.recentOutcomes = [];
488
+ this.totalNeuralDecisions = 0;
489
+ this.totalWeightUpdates = 0;
490
+ this.calibrationScores = [];
491
+ this.domainSuccessRates.clear();
492
+ if (this.config.forceShadowMode !== undefined) {
493
+ this.shadowModeActive = this.config.forceShadowMode;
494
+ this.neuralPrimary = !this.config.forceShadowMode;
495
+ }
496
+ else {
497
+ this.shadowModeActive = true;
498
+ this.neuralPrimary = false;
499
+ }
500
+ }
501
+ }
502
+ // ============================================================================
503
+ // Factory Function
504
+ // ============================================================================
505
+ /**
506
+ * Create a new Neural TinyDancer router instance
507
+ *
508
+ * @param config - Neural router configuration
509
+ * @returns Configured Neural TinyDancer router
510
+ */
511
+ export function createNeuralTinyDancerRouter(config) {
512
+ return new NeuralTinyDancerRouter(config);
513
+ }
514
+ //# sourceMappingURL=neural-tiny-dancer-router.js.map
@@ -7,7 +7,7 @@
7
7
  * to agent pool tiers and handles fallback scenarios.
8
8
  */
9
9
  import { performance } from 'perf_hooks';
10
- import { TinyDancerRouter } from './tiny-dancer-router.js';
10
+ import { createSmartTinyDancerRouter } from './tiny-dancer-router.js';
11
11
  import { DEFAULT_ROUTING_CONFIG, loadRoutingConfigFromEnv, mapComplexityToTier, getNextFallbackTier, tierToModel, estimateTaskCost, validateRoutingConfig, } from './routing-config.js';
12
12
  // ============================================================================
13
13
  // Queen Router Adapter Implementation
@@ -44,8 +44,8 @@ export class QueenRouterAdapter {
44
44
  outcomes = [];
45
45
  maxOutcomes = 1000;
46
46
  constructor(config = {}) {
47
- // Initialize TinyDancer router
48
- this.tinyDancer = new TinyDancerRouter(config.tinyDancer);
47
+ // Initialize TinyDancer router (uses neural if useNeuralRouting flag is on)
48
+ this.tinyDancer = createSmartTinyDancerRouter(config.tinyDancer);
49
49
  // Deep merge partial routing config with defaults, then apply env overrides
50
50
  const mergedConfig = this.mergeRoutingConfig(config.routing);
51
51
  this.routingConfig = loadRoutingConfigFromEnv(mergedConfig);
@@ -141,7 +141,7 @@ export class QueenRouterAdapter {
141
141
  this.outcomes.shift();
142
142
  }
143
143
  // Also record outcome in TinyDancer for its learning
144
- this.tinyDancer.recordOutcome(task, decision.tinyDancerResult, success, qualityScore, tierToModel(usedTier), durationMs);
144
+ this.tinyDancer.recordOutcome?.(task, decision.tinyDancerResult, success, qualityScore, tierToModel(usedTier), durationMs);
145
145
  if (this.routingConfig.verbose) {
146
146
  console.log(`[QueenRouter] Recorded outcome: tier=${usedTier}, ` +
147
147
  `success=${success}, quality=${(qualityScore * 100).toFixed(0)}%, ` +
@@ -232,7 +232,7 @@ export class QueenRouterAdapter {
232
232
  this.dailyCost = 0;
233
233
  this.lastCostReset = new Date();
234
234
  this.outcomes = [];
235
- this.tinyDancer.reset();
235
+ this.tinyDancer.reset?.();
236
236
  }
237
237
  // ============================================================================
238
238
  // Private Methods
@@ -87,6 +87,12 @@ export interface RoutingConfig {
87
87
  enableEMACalibration: boolean;
88
88
  /** Enable automatic tier escalation/de-escalation on consecutive outcomes (default: true) */
89
89
  enableAutoEscalation: boolean;
90
+ /** Enable neural model routing via NeuralTinyDancerRouter (ADR-082, Task 2.1).
91
+ * When true, createSmartTinyDancerRouter returns a NeuralTinyDancerRouter
92
+ * that runs alongside (shadow mode) or replaces rule-based routing.
93
+ * Actual activation is controlled by the useNeuralRouting feature flag.
94
+ * @default false */
95
+ enableNeuralRouting: boolean;
90
96
  }
91
97
  /**
92
98
  * Default confidence thresholds
@@ -84,6 +84,7 @@ export const DEFAULT_ROUTING_CONFIG = {
84
84
  verbose: false,
85
85
  enableEMACalibration: true,
86
86
  enableAutoEscalation: true,
87
+ enableNeuralRouting: false,
87
88
  };
88
89
  // ============================================================================
89
90
  // Environment Variable Overrides
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Simple Neural Router - Extracted from neural-tiny-dancer-router.ts
3
+ *
4
+ * Lightweight feedforward neural network for routing decisions.
5
+ * Uses Xavier initialization and simple policy gradient updates.
6
+ *
7
+ * Architecture:
8
+ * Input(4) -> Dense(32, ReLU) -> Dense(3, Softmax) -> [p_haiku, p_sonnet, p_opus]
9
+ *
10
+ * @module routing/simple-neural-router
11
+ */
12
+ /** Number of input features for the neural network */
13
+ export declare const INPUT_SIZE = 4;
14
+ /** Number of hidden units */
15
+ export declare const HIDDEN_SIZE = 32;
16
+ /** Number of output classes (tier1=haiku, tier2=sonnet, tier3=opus) */
17
+ export declare const OUTPUT_SIZE = 3;
18
+ /** Default learning rate for weight updates */
19
+ export declare const DEFAULT_LEARNING_RATE = 0.01;
20
+ /**
21
+ * Lightweight feedforward neural network for routing decisions.
22
+ * Uses Xavier initialization and simple policy gradient updates.
23
+ *
24
+ * Architecture:
25
+ * Input(4) -> Dense(32, ReLU) -> Dense(3, Softmax) -> [p_haiku, p_sonnet, p_opus]
26
+ */
27
+ export declare class SimpleNeuralRouter {
28
+ private weightsInputHidden;
29
+ private weightsHiddenOutput;
30
+ private biasHidden;
31
+ private biasOutput;
32
+ private learningRate;
33
+ constructor(learningRate?: number);
34
+ /**
35
+ * Xavier/Glorot initialization for weight matrices
36
+ */
37
+ private xavierInit;
38
+ /**
39
+ * Forward pass through the network
40
+ *
41
+ * @param features - Input feature vector [complexityScore, tokenEstimate, domainIndex, successRate]
42
+ * @returns Probability distribution over tiers [p_haiku, p_sonnet, p_opus]
43
+ */
44
+ forward(features: number[]): number[];
45
+ /**
46
+ * Numerically stable softmax
47
+ */
48
+ private softmax;
49
+ /**
50
+ * Update weights using simple policy gradient (REINFORCE)
51
+ *
52
+ * @param features - Input features used for the decision
53
+ * @param chosenTierIndex - Index of the tier that was chosen (0=haiku, 1=sonnet, 2=opus)
54
+ * @param reward - Reward signal (-1 to 1, where 1 = perfect, -1 = total failure)
55
+ */
56
+ updateWeights(features: number[], chosenTierIndex: number, reward: number): void;
57
+ /**
58
+ * Serialize weights for persistence
59
+ */
60
+ serialize(): {
61
+ weightsInputHidden: number[];
62
+ weightsHiddenOutput: number[];
63
+ biasHidden: number[];
64
+ biasOutput: number[];
65
+ };
66
+ /**
67
+ * Deserialize weights from persistence
68
+ */
69
+ deserialize(data: {
70
+ weightsInputHidden: number[];
71
+ weightsHiddenOutput: number[];
72
+ biasHidden: number[];
73
+ biasOutput: number[];
74
+ }): void;
75
+ }
76
+ //# sourceMappingURL=simple-neural-router.d.ts.map