@timmeck/brain-core 2.36.67 → 2.36.69

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 (37) hide show
  1. package/dist/chat/chat-engine.d.ts +6 -0
  2. package/dist/chat/chat-engine.js +52 -0
  3. package/dist/chat/chat-engine.js.map +1 -1
  4. package/dist/chat/index.d.ts +2 -0
  5. package/dist/chat/index.js +1 -0
  6. package/dist/chat/index.js.map +1 -1
  7. package/dist/chat/multi-brain-router.d.ts +25 -0
  8. package/dist/chat/multi-brain-router.js +88 -0
  9. package/dist/chat/multi-brain-router.js.map +1 -0
  10. package/dist/debate/debate-engine.d.ts +2 -0
  11. package/dist/debate/debate-engine.js +5 -7
  12. package/dist/debate/debate-engine.js.map +1 -1
  13. package/dist/index.d.ts +6 -4
  14. package/dist/index.js +4 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/research/adaptive-scheduler.d.ts +53 -0
  17. package/dist/research/adaptive-scheduler.js +122 -0
  18. package/dist/research/adaptive-scheduler.js.map +1 -0
  19. package/dist/research/knowledge-distiller.d.ts +4 -0
  20. package/dist/research/knowledge-distiller.js +17 -0
  21. package/dist/research/knowledge-distiller.js.map +1 -1
  22. package/dist/research/research-orchestrator.d.ts +42 -0
  23. package/dist/research/research-orchestrator.js +301 -29
  24. package/dist/research/research-orchestrator.js.map +1 -1
  25. package/dist/strategy/index.d.ts +4 -0
  26. package/dist/strategy/index.js +2 -0
  27. package/dist/strategy/index.js.map +1 -1
  28. package/dist/strategy/strategy-exporter.d.ts +26 -0
  29. package/dist/strategy/strategy-exporter.js +47 -0
  30. package/dist/strategy/strategy-exporter.js.map +1 -0
  31. package/dist/strategy/strategy-forge.d.ts +2 -0
  32. package/dist/strategy/strategy-forge.js +4 -0
  33. package/dist/strategy/strategy-forge.js.map +1 -1
  34. package/dist/strategy/strategy-importer.d.ts +15 -0
  35. package/dist/strategy/strategy-importer.js +69 -0
  36. package/dist/strategy/strategy-importer.js.map +1 -0
  37. package/package.json +1 -1
@@ -89,6 +89,7 @@ export class ResearchOrchestrator {
89
89
  runtimeInfluenceTracker = null;
90
90
  loopDetector = null;
91
91
  governanceLayer = null;
92
+ adaptiveScheduler = null;
92
93
  lastAutoMissionTime = 0;
93
94
  lastGoalMissionTime = 0;
94
95
  roadmapBootstrapped = false;
@@ -113,6 +114,13 @@ export class ResearchOrchestrator {
113
114
  lastSuggestionsCycle = -1;
114
115
  /** Recent debate topic keys to prevent repeating the same debate. */
115
116
  recentDebateTopics = [];
117
+ // ── Desire Feedback Tracking ──────────────────────────────
118
+ /** Tracks outcomes per desire key: successes, failures, last result. */
119
+ desireOutcomes = new Map();
120
+ /** Category-level success rates for adaptive confidence. */
121
+ desireCategoryRates = new Map();
122
+ /** Desire keys currently being actuated by other brains (received via cross-brain). */
123
+ crossBrainActiveDesires = new Map();
116
124
  constructor(db, config, causalGraph) {
117
125
  this.db = db;
118
126
  this.brainName = config.brainName;
@@ -139,6 +147,14 @@ export class ResearchOrchestrator {
139
147
  setOnSuggestion(callback) {
140
148
  this.onSuggestionCallback = callback;
141
149
  }
150
+ /** Set the AdaptiveScheduler for dynamic cycle intervals. */
151
+ setAdaptiveScheduler(scheduler) {
152
+ this.adaptiveScheduler = scheduler;
153
+ }
154
+ /** Get the AdaptiveScheduler instance. */
155
+ getAdaptiveScheduler() {
156
+ return this.adaptiveScheduler;
157
+ }
142
158
  /** Set the DataMiner instance for DB-driven engine feeding. */
143
159
  setDataMiner(miner) {
144
160
  this.dataMiner = miner;
@@ -326,20 +342,31 @@ export class ResearchOrchestrator {
326
342
  start(intervalMs = 300_000) {
327
343
  if (this.feedbackTimer)
328
344
  return;
329
- this.feedbackTimer = setInterval(() => {
345
+ this.startIntervalMs = intervalMs;
346
+ this.scheduleNextCycle(intervalMs);
347
+ this.log.info(`[orchestrator] Research orchestrator started (feedback every ${intervalMs}ms)`);
348
+ }
349
+ /** Schedule the next feedback cycle (supports adaptive intervals). */
350
+ scheduleNextCycle(intervalMs) {
351
+ if (this.feedbackTimer)
352
+ clearTimeout(this.feedbackTimer);
353
+ this.feedbackTimer = setTimeout(async () => {
330
354
  try {
331
- void this.runFeedbackCycle();
355
+ await this.runFeedbackCycle();
332
356
  }
333
357
  catch (err) {
334
358
  this.log.error('[orchestrator] Feedback cycle error', { error: err.message });
335
359
  }
360
+ // Re-schedule with adaptive or base interval
361
+ const nextInterval = this.adaptiveScheduler?.getNextInterval() ?? this.startIntervalMs;
362
+ this.scheduleNextCycle(nextInterval);
336
363
  }, intervalMs);
337
- this.log.info(`[orchestrator] Research orchestrator started (feedback every ${intervalMs}ms)`);
338
364
  }
365
+ startIntervalMs = 300_000;
339
366
  /** Stop the feedback loop. */
340
367
  stop() {
341
368
  if (this.feedbackTimer) {
342
- clearInterval(this.feedbackTimer);
369
+ clearTimeout(this.feedbackTimer);
343
370
  this.feedbackTimer = null;
344
371
  }
345
372
  this.dreamEngine?.stop();
@@ -365,6 +392,44 @@ export class ResearchOrchestrator {
365
392
  onCrossBrainEvent(sourceBrain, eventType, data = {}) {
366
393
  this.crossDomain.recordEvent(sourceBrain, eventType, data);
367
394
  this.anomalyDetective.recordMetric(`cross:${sourceBrain}:${eventType}`, 1);
395
+ // Handle cross-brain desire coordination signals
396
+ if (eventType === 'desire_active' && data.desireKey) {
397
+ this.onCrossBrainDesireSignal(sourceBrain, data.desireKey, data.priority ?? 0);
398
+ }
399
+ // Handle cross-brain debate perspective requests
400
+ if (eventType === 'debate_perspective_request' && data.question && this.debateEngine) {
401
+ try {
402
+ const perspective = this.debateEngine.generatePerspective(data.question);
403
+ // Send perspective back via signal
404
+ if (this.signalRouter) {
405
+ this.signalRouter.emit({
406
+ targetBrain: sourceBrain,
407
+ signalType: 'debate_perspective_response',
408
+ payload: {
409
+ debateId: data.debateId,
410
+ perspective: { brainName: perspective.brainName, position: perspective.position, confidence: perspective.confidence, relevance: perspective.relevance, arguments: perspective.arguments },
411
+ },
412
+ confidence: perspective.confidence,
413
+ }).catch(() => { });
414
+ }
415
+ }
416
+ catch { /* debate engine not ready */ }
417
+ }
418
+ // Handle incoming debate perspective response — add to our debate
419
+ if (eventType === 'debate_perspective_response' && data.debateId && data.perspective && this.debateEngine) {
420
+ try {
421
+ const p = data.perspective;
422
+ this.debateEngine.addPerspective(data.debateId, {
423
+ brainName: p.brainName ?? sourceBrain,
424
+ position: p.position ?? '',
425
+ confidence: p.confidence ?? 0,
426
+ relevance: p.relevance ?? 0,
427
+ arguments: p.arguments ?? [],
428
+ });
429
+ this.log.info(`[orchestrator] Added cross-brain perspective from ${sourceBrain} to debate #${data.debateId}`);
430
+ }
431
+ catch { /* debate may not exist */ }
432
+ }
368
433
  }
369
434
  /**
370
435
  * Hook into AutonomousResearchScheduler cycle completion.
@@ -1245,6 +1310,11 @@ export class ResearchOrchestrator {
1245
1310
  const kSummary = this.knowledgeDistiller.getSummary();
1246
1311
  this.hypothesisEngine.observe({ source: this.brainName, type: 'internal:distillation_throughput', value: kSummary.principles + kSummary.antiPatterns + kSummary.strategies, timestamp: now, metadata: { principles: kSummary.principles, avgConfidence: kSummary.avgConfidence } });
1247
1312
  }
1313
+ else if (topic.includes('dream') || topic.includes('consolidat')) {
1314
+ const dStatus = this.dreamEngine?.getStatus();
1315
+ const totals = dStatus?.totals;
1316
+ this.hypothesisEngine.observe({ source: this.brainName, type: 'internal:dream_consolidation_count', value: (totals?.memoriesConsolidated ?? 0), timestamp: now });
1317
+ }
1248
1318
  }
1249
1319
  catch { /* internal observation non-critical */ }
1250
1320
  }
@@ -1389,25 +1459,57 @@ export class ResearchOrchestrator {
1389
1459
  this.log.error(`[orchestrator] Emergence step error: ${err.message}`);
1390
1460
  }
1391
1461
  }
1392
- // 20. Internal Debate: periodically debate key findings to synthesize cross-engine wisdom
1462
+ // 20. Internal + Cross-Brain Debate: debate key findings, solicit cross-brain perspectives
1393
1463
  if (this.debateEngine && this.cycleCount % this.reflectEvery === 0) {
1394
- ts?.emit('reflecting', 'reflecting', 'Initiating internal debate on recent findings...');
1464
+ ts?.emit('reflecting', 'reflecting', 'Initiating debate on recent findings...');
1395
1465
  try {
1396
- // Pick a debate topic from recent attention or agenda
1397
1466
  const topic = this.pickDebateTopic();
1398
1467
  if (topic) {
1399
1468
  const debate = this.debateEngine.startDebate(topic);
1469
+ // Solicit cross-brain perspectives via SignalRouter
1470
+ if (this.signalRouter) {
1471
+ const peers = ['brain', 'trading-brain', 'marketing-brain'].filter(b => b !== this.brainName);
1472
+ for (const peer of peers) {
1473
+ try {
1474
+ this.signalRouter.emit({
1475
+ targetBrain: peer,
1476
+ signalType: 'debate_perspective_request',
1477
+ payload: { debateId: debate.id, question: topic },
1478
+ confidence: 0.7,
1479
+ }).catch(() => { });
1480
+ }
1481
+ catch { /* peer offline */ }
1482
+ }
1483
+ }
1400
1484
  const synthesis = this.debateEngine.synthesize(debate.id);
1401
- if (synthesis && synthesis.conflicts.length > 0) {
1402
- this.journal.write({
1403
- type: 'discovery',
1404
- title: `Debate: ${topic.substring(0, 80)}`,
1405
- content: `Internal debate with ${synthesis.participantCount} perspective(s). ${synthesis.conflicts.length} conflict(s). Resolution: ${synthesis.resolution}`,
1406
- tags: [this.brainName, 'debate', 'synthesis'],
1407
- references: [],
1408
- significance: synthesis.conflicts.length > 2 ? 'notable' : 'routine',
1409
- data: { debate: { question: topic, synthesis } },
1410
- });
1485
+ if (synthesis) {
1486
+ // Journal the debate
1487
+ if (synthesis.conflicts.length > 0) {
1488
+ this.journal.write({
1489
+ type: 'discovery',
1490
+ title: `Debate: ${topic.substring(0, 80)}`,
1491
+ content: `Debate with ${synthesis.participantCount} perspective(s). ${synthesis.conflicts.length} conflict(s). Resolution: ${synthesis.resolution}`,
1492
+ tags: [this.brainName, 'debate', 'synthesis'],
1493
+ references: [],
1494
+ significance: synthesis.conflicts.length > 2 ? 'notable' : 'routine',
1495
+ data: { debate: { question: topic, synthesis } },
1496
+ });
1497
+ }
1498
+ // Convert recommendations to ActionBridge proposals
1499
+ if (this.actionBridge && synthesis.recommendations.length > 0) {
1500
+ for (const rec of synthesis.recommendations.slice(0, 2)) {
1501
+ this.actionBridge.propose({
1502
+ source: 'research',
1503
+ type: 'create_goal',
1504
+ title: `Debate recommendation: ${rec.substring(0, 70)}`,
1505
+ description: `From debate "${topic.substring(0, 80)}": ${rec}`,
1506
+ confidence: synthesis.confidence,
1507
+ payload: { debateId: debate.id, recommendation: rec },
1508
+ });
1509
+ }
1510
+ }
1511
+ // Auto-close the debate after synthesis
1512
+ this.debateEngine.closeDebate(debate.id);
1411
1513
  }
1412
1514
  ts?.emit('reflecting', 'reflecting', `Debate on "${topic.substring(0, 40)}...": ${synthesis?.conflicts.length ?? 0} conflicts, confidence=${((synthesis?.confidence ?? 0) * 100).toFixed(0)}%`, synthesis && synthesis.conflicts.length > 0 ? 'notable' : 'routine');
1413
1515
  }
@@ -1561,14 +1663,16 @@ export class ResearchOrchestrator {
1561
1663
  this.log.warn(`[orchestrator] Step 24 error: ${err.message}`);
1562
1664
  }
1563
1665
  }
1564
- // Step 25: Advocatus Diaboli — challenge a random confirmed principle (every 10 cycles)
1666
+ // Step 25: Advocatus Diaboli — challenge weakest principle + adjust confidence (every 10 cycles)
1565
1667
  if (this.debateEngine && this.cycleCount % 10 === 0) {
1566
1668
  try {
1567
1669
  ts?.emit('orchestrator', 'reflecting', 'Step 25: Challenging a principle...', 'routine');
1568
1670
  const principles = this.knowledgeDistiller.getPrinciples(undefined, 20);
1569
1671
  if (principles.length > 0) {
1570
- const randomPrinciple = principles[Math.floor(Math.random() * principles.length)];
1571
- const challenge = this.debateEngine.challenge(randomPrinciple.statement);
1672
+ // Target weakest principles first (lowest confidence), not random
1673
+ const sorted = [...principles].sort((a, b) => a.confidence - b.confidence);
1674
+ const targetPrinciple = sorted[0];
1675
+ const challenge = this.debateEngine.challenge(targetPrinciple.statement);
1572
1676
  this.journal.write({
1573
1677
  type: 'reflection',
1574
1678
  title: `Principle challenged: resilience=${(challenge.resilienceScore * 100).toFixed(0)}% → ${challenge.outcome}`,
@@ -1578,6 +1682,24 @@ export class ResearchOrchestrator {
1578
1682
  significance: challenge.outcome === 'disproved' ? 'notable' : 'routine',
1579
1683
  data: { challenge },
1580
1684
  });
1685
+ // Actually adjust principle confidence based on challenge outcome
1686
+ if (challenge.principleId !== null) {
1687
+ const principleIdStr = String(challenge.principleId);
1688
+ if (challenge.outcome === 'disproved') {
1689
+ // Disproved → remove principle entirely
1690
+ this.knowledgeDistiller.removePrinciple(principleIdStr);
1691
+ this.log.info(`[orchestrator] Step 25: Principle "${targetPrinciple.statement.substring(0, 50)}" REMOVED (disproved)`);
1692
+ }
1693
+ else if (challenge.outcome === 'weakened') {
1694
+ // Weakened → reduce confidence by 30%
1695
+ this.knowledgeDistiller.adjustPrincipleConfidence(principleIdStr, 0.7);
1696
+ this.log.info(`[orchestrator] Step 25: Principle confidence reduced by 30% (weakened)`);
1697
+ }
1698
+ else if (challenge.outcome === 'survived') {
1699
+ // Survived → slight boost (+10%)
1700
+ this.knowledgeDistiller.adjustPrincipleConfidence(principleIdStr, 1.1);
1701
+ }
1702
+ }
1581
1703
  }
1582
1704
  if (this.metaCognitionLayer)
1583
1705
  this.metaCognitionLayer.recordStep('advocatus_diaboli', this.cycleCount, { insights: 1 });
@@ -2768,12 +2890,42 @@ export class ResearchOrchestrator {
2768
2890
  }
2769
2891
  }
2770
2892
  // Step 64: DesireActuator — convert top desire to action (every 15 cycles)
2893
+ // Fix 1: Feedback-loop — deprioritize failed desires, boost successful ones
2894
+ // Fix 2: Cross-brain coordination — skip desires already active in other brains
2895
+ // Fix 3: Adaptive confidence — use category success rate instead of static priority/10
2771
2896
  if (this.actionBridge && this.cycleCount - this.lastDesireActuationCycle >= 15) {
2772
2897
  try {
2773
2898
  const desires = this.getDesires();
2774
- const topDesire = desires.find(d => d.priority >= 5);
2899
+ // Apply feedback adjustments to priorities
2900
+ const adjusted = desires.map(d => {
2901
+ const outcome = this.desireOutcomes.get(d.key);
2902
+ let adjustedPriority = d.priority;
2903
+ if (outcome) {
2904
+ // Deprioritize desires that keep failing (−2 per failure, +1 per success, floor 0)
2905
+ adjustedPriority = Math.max(0, d.priority + outcome.successes - outcome.failures * 2);
2906
+ // If failed 3+ times consecutively, hard suppress below threshold
2907
+ if (outcome.failures >= 3 && outcome.lastResult === 'failure') {
2908
+ adjustedPriority = Math.min(adjustedPriority, 2);
2909
+ this.log.info(`[orchestrator] Step 64: Desire "${d.key}" suppressed (${outcome.failures} consecutive failures)`);
2910
+ }
2911
+ }
2912
+ return { ...d, adjustedPriority };
2913
+ });
2914
+ // Re-sort by adjusted priority
2915
+ adjusted.sort((a, b) => b.adjustedPriority - a.adjustedPriority);
2916
+ // Find top desire that passes threshold AND isn't already active in another brain
2917
+ const topDesire = adjusted.find(d => {
2918
+ if (d.adjustedPriority < 5)
2919
+ return false;
2920
+ const crossActive = this.crossBrainActiveDesires.get(d.key);
2921
+ if (crossActive && this.cycleCount - crossActive.cycle < 30) {
2922
+ this.log.info(`[orchestrator] Step 64: Skipping "${d.key}" — active in ${crossActive.brain}`);
2923
+ return false;
2924
+ }
2925
+ return true;
2926
+ });
2775
2927
  if (topDesire) {
2776
- ts?.emit('desire', 'analyzing', `Step 64: Actuating desire "${topDesire.key}" (P${topDesire.priority})...`, 'notable');
2928
+ ts?.emit('desire', 'analyzing', `Step 64: Actuating desire "${topDesire.key}" (P${topDesire.adjustedPriority})...`, 'notable');
2777
2929
  // Map desire key → action type
2778
2930
  let actionType = 'create_goal';
2779
2931
  if (topDesire.key.startsWith('contradiction_')) {
@@ -2782,25 +2934,50 @@ export class ResearchOrchestrator {
2782
2934
  else if (topDesire.key.startsWith('no_predictions') || topDesire.key.startsWith('low_accuracy')) {
2783
2935
  actionType = 'adjust_parameter';
2784
2936
  }
2937
+ // Adaptive confidence: use category success rate if available
2938
+ const category = this.desireKeyToCategory(topDesire.key);
2939
+ const categoryRate = this.desireCategoryRates.get(category);
2940
+ let confidence;
2941
+ if (categoryRate && categoryRate.total >= 3) {
2942
+ // Blend: 60% category success rate + 40% priority-based
2943
+ const rateComponent = categoryRate.successes / categoryRate.total;
2944
+ const priorityComponent = Math.min(topDesire.adjustedPriority / 10, 0.9);
2945
+ confidence = Math.min(rateComponent * 0.6 + priorityComponent * 0.4, 0.9);
2946
+ }
2947
+ else {
2948
+ confidence = Math.min(topDesire.adjustedPriority / 10, 0.9);
2949
+ }
2785
2950
  const actionId = this.actionBridge.propose({
2786
2951
  source: 'desire',
2787
2952
  type: actionType,
2788
2953
  title: `Desire: ${topDesire.suggestion.substring(0, 80)}`,
2789
2954
  description: topDesire.suggestion,
2790
- confidence: Math.min(topDesire.priority / 10, 0.9),
2791
- payload: { desireKey: topDesire.key, priority: topDesire.priority, alternatives: topDesire.alternatives },
2955
+ confidence,
2956
+ payload: { desireKey: topDesire.key, priority: topDesire.adjustedPriority, category, alternatives: topDesire.alternatives },
2792
2957
  });
2793
2958
  if (actionId > 0) {
2794
- this.log.info(`[orchestrator] Step 64: Desire "${topDesire.key}" → Action #${actionId} (${actionType})`);
2959
+ this.log.info(`[orchestrator] Step 64: Desire "${topDesire.key}" → Action #${actionId} (${actionType}, conf=${confidence.toFixed(2)})`);
2795
2960
  this.journal.write({
2796
2961
  title: `Desire Actuation: ${topDesire.key}`,
2797
- content: `Converted desire (P${topDesire.priority}) to ${actionType} action #${actionId}: ${topDesire.suggestion}`,
2962
+ content: `Converted desire (P${topDesire.adjustedPriority}, conf=${confidence.toFixed(2)}) to ${actionType} action #${actionId}: ${topDesire.suggestion}`,
2798
2963
  type: 'insight',
2799
2964
  significance: 'notable',
2800
2965
  tags: [this.brainName, 'desire', 'actuation'],
2801
2966
  references: [],
2802
- data: { desireKey: topDesire.key, actionId, actionType },
2967
+ data: { desireKey: topDesire.key, actionId, actionType, adjustedPriority: topDesire.adjustedPriority, confidence },
2803
2968
  });
2969
+ // Broadcast to other brains that we're working on this desire
2970
+ if (this.signalRouter) {
2971
+ const peers = ['brain', 'trading-brain', 'marketing-brain'].filter(b => b !== this.brainName);
2972
+ for (const peer of peers) {
2973
+ this.signalRouter.emit({
2974
+ targetBrain: peer,
2975
+ signalType: 'desire_active',
2976
+ payload: { desireKey: topDesire.key, priority: topDesire.adjustedPriority },
2977
+ confidence,
2978
+ }).catch(() => { });
2979
+ }
2980
+ }
2804
2981
  }
2805
2982
  this.lastDesireActuationCycle = this.cycleCount;
2806
2983
  }
@@ -2810,6 +2987,7 @@ export class ResearchOrchestrator {
2810
2987
  }
2811
2988
  }
2812
2989
  // Step 65: Action-Outcome Review (every 20 cycles)
2990
+ // Enhanced: Feed desire outcomes back into desireOutcomes + desireCategoryRates
2813
2991
  if (this.actionBridge && this.cycleCount % 20 === 0) {
2814
2992
  try {
2815
2993
  const history = this.actionBridge.getHistory(10);
@@ -2817,7 +2995,7 @@ export class ResearchOrchestrator {
2817
2995
  const recentFailed = history.filter(a => a.status === 'failed' || (a.outcome && !a.outcome.success));
2818
2996
  if (recentCompleted.length > 0 || recentFailed.length > 0) {
2819
2997
  ts?.emit('orchestrator', 'reflecting', `Step 65: Reviewing ${recentCompleted.length} successes, ${recentFailed.length} failures`, 'routine');
2820
- // Success → journal lesson learned
2998
+ // Success → journal lesson learned + desire feedback
2821
2999
  for (const action of recentCompleted.slice(0, 3)) {
2822
3000
  const lesson = action.outcome?.learnedLesson ?? `Action "${action.title}" succeeded`;
2823
3001
  this.journal.write({
@@ -2829,8 +3007,19 @@ export class ResearchOrchestrator {
2829
3007
  references: [],
2830
3008
  data: { actionId: action.id, type: action.type, source: action.source },
2831
3009
  });
3010
+ // Feed success back into desire tracking
3011
+ if (action.source === 'desire') {
3012
+ const desireKey = action.payload.desireKey;
3013
+ const category = action.payload.category;
3014
+ if (desireKey) {
3015
+ this.recordDesireOutcome(desireKey, 'success');
3016
+ }
3017
+ if (category) {
3018
+ this.recordDesireCategoryOutcome(category, true);
3019
+ }
3020
+ }
2832
3021
  }
2833
- // Failure → journal + hypothesis rejection
3022
+ // Failure → journal + desire feedback
2834
3023
  for (const action of recentFailed.slice(0, 3)) {
2835
3024
  this.journal.write({
2836
3025
  title: `Action Failed: ${action.title}`,
@@ -2841,6 +3030,17 @@ export class ResearchOrchestrator {
2841
3030
  references: [],
2842
3031
  data: { actionId: action.id, type: action.type, source: action.source },
2843
3032
  });
3033
+ // Feed failure back into desire tracking
3034
+ if (action.source === 'desire') {
3035
+ const desireKey = action.payload.desireKey;
3036
+ const category = action.payload.category;
3037
+ if (desireKey) {
3038
+ this.recordDesireOutcome(desireKey, 'failure');
3039
+ }
3040
+ if (category) {
3041
+ this.recordDesireCategoryOutcome(category, false);
3042
+ }
3043
+ }
2844
3044
  }
2845
3045
  if (this.metaCognitionLayer) {
2846
3046
  this.metaCognitionLayer.recordStep('action_outcome_review', this.cycleCount, {
@@ -2934,6 +3134,15 @@ export class ResearchOrchestrator {
2934
3134
  }
2935
3135
  catch { /* checkpoint save should never break the cycle */ }
2936
3136
  }
3137
+ // Adaptive Scheduling: record cycle outcome for interval optimization
3138
+ if (this.adaptiveScheduler) {
3139
+ this.adaptiveScheduler.recordOutcome({
3140
+ insightsFound: insights.length,
3141
+ rulesLearned: 0, // rules come from external learning engines
3142
+ anomaliesDetected: anomalies.length,
3143
+ durationMs: duration,
3144
+ });
3145
+ }
2937
3146
  // Step-profiling summary: log slow steps if any
2938
3147
  if (stepTimings.length > 0) {
2939
3148
  this.log.warn(`[orchestrator] Cycle #${this.cycleCount} slow steps: ${stepTimings.map(s => `${s.step}(${s.ms}ms)`).join(', ')}`);
@@ -3337,6 +3546,69 @@ export class ResearchOrchestrator {
3337
3546
  }
3338
3547
  return result;
3339
3548
  }
3549
+ // ── Desire Feedback Helpers ──────────────────────────────
3550
+ /** Record a desire outcome (success or failure) for feedback-loop. */
3551
+ recordDesireOutcome(desireKey, result) {
3552
+ const existing = this.desireOutcomes.get(desireKey) ?? { successes: 0, failures: 0, lastResult: result, lastCycle: 0 };
3553
+ if (result === 'success') {
3554
+ existing.successes++;
3555
+ }
3556
+ else {
3557
+ existing.failures++;
3558
+ }
3559
+ existing.lastResult = result;
3560
+ existing.lastCycle = this.cycleCount;
3561
+ this.desireOutcomes.set(desireKey, existing);
3562
+ this.log.info(`[orchestrator] Desire feedback: "${desireKey}" → ${result} (${existing.successes}S/${existing.failures}F)`);
3563
+ }
3564
+ /** Record category-level outcome for adaptive confidence. */
3565
+ recordDesireCategoryOutcome(category, success) {
3566
+ const existing = this.desireCategoryRates.get(category) ?? { successes: 0, total: 0 };
3567
+ existing.total++;
3568
+ if (success)
3569
+ existing.successes++;
3570
+ this.desireCategoryRates.set(category, existing);
3571
+ }
3572
+ /** Map a desire key to a broad category for confidence tracking. */
3573
+ desireKeyToCategory(key) {
3574
+ if (key.startsWith('no_predictions') || key.startsWith('low_accuracy'))
3575
+ return 'prediction';
3576
+ if (key.startsWith('contradiction_'))
3577
+ return 'contradiction';
3578
+ if (key.startsWith('curiosity_gap_'))
3579
+ return 'curiosity';
3580
+ if (key.startsWith('no_knowledge'))
3581
+ return 'knowledge';
3582
+ if (key.startsWith('pending_transfers') || key.startsWith('want_cross_brain'))
3583
+ return 'cross_brain';
3584
+ if (key.startsWith('deep_dive_'))
3585
+ return 'deep_dive';
3586
+ return 'general';
3587
+ }
3588
+ /** Handle incoming cross-brain desire signal. */
3589
+ onCrossBrainDesireSignal(brain, desireKey, priority) {
3590
+ this.crossBrainActiveDesires.set(desireKey, { brain, priority, cycle: this.cycleCount });
3591
+ this.log.info(`[orchestrator] Cross-brain desire received: "${desireKey}" from ${brain} (P${priority})`);
3592
+ // Clean up stale entries (older than 60 cycles)
3593
+ for (const [key, entry] of this.crossBrainActiveDesires) {
3594
+ if (this.cycleCount - entry.cycle > 60) {
3595
+ this.crossBrainActiveDesires.delete(key);
3596
+ }
3597
+ }
3598
+ }
3599
+ /** Get desire feedback stats for monitoring. */
3600
+ getDesireFeedbackStats() {
3601
+ const outcomes = [...this.desireOutcomes.entries()].map(([key, v]) => ({
3602
+ key, successes: v.successes, failures: v.failures, lastResult: v.lastResult,
3603
+ }));
3604
+ const categoryRates = [...this.desireCategoryRates.entries()].map(([category, v]) => ({
3605
+ category, successRate: v.total > 0 ? v.successes / v.total : 0, total: v.total,
3606
+ }));
3607
+ const crossBrainActive = [...this.crossBrainActiveDesires.entries()].map(([key, v]) => ({
3608
+ key, brain: v.brain, priority: v.priority,
3609
+ }));
3610
+ return { outcomes, categoryRates, crossBrainActive };
3611
+ }
3340
3612
  /** Get structured self-improvement desires with priority and alternatives. */
3341
3613
  getDesires() {
3342
3614
  const raw = [];