@timmeck/brain-core 2.25.1 → 2.27.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 (62) hide show
  1. package/dist/causal/engine.d.ts +47 -0
  2. package/dist/causal/engine.js +142 -0
  3. package/dist/causal/engine.js.map +1 -1
  4. package/dist/codegen/code-generator.d.ts +17 -0
  5. package/dist/codegen/code-generator.js +61 -0
  6. package/dist/codegen/code-generator.js.map +1 -1
  7. package/dist/codegen/index.d.ts +1 -0
  8. package/dist/codegen/index.js.map +1 -1
  9. package/dist/curiosity/curiosity-engine.d.ts +29 -0
  10. package/dist/curiosity/curiosity-engine.js +147 -0
  11. package/dist/curiosity/curiosity-engine.js.map +1 -1
  12. package/dist/curiosity/index.d.ts +1 -1
  13. package/dist/debate/debate-engine.d.ts +27 -0
  14. package/dist/debate/debate-engine.js +169 -0
  15. package/dist/debate/debate-engine.js.map +1 -1
  16. package/dist/debate/index.d.ts +1 -1
  17. package/dist/dream/dream-engine.d.ts +16 -1
  18. package/dist/dream/dream-engine.js +190 -0
  19. package/dist/dream/dream-engine.js.map +1 -1
  20. package/dist/dream/index.d.ts +1 -1
  21. package/dist/dream/types.d.ts +18 -0
  22. package/dist/emergence/emergence-engine.d.ts +19 -0
  23. package/dist/emergence/emergence-engine.js +118 -0
  24. package/dist/emergence/emergence-engine.js.map +1 -1
  25. package/dist/hypothesis/engine.d.ts +38 -0
  26. package/dist/hypothesis/engine.js +167 -0
  27. package/dist/hypothesis/engine.js.map +1 -1
  28. package/dist/index.d.ts +20 -5
  29. package/dist/index.js +9 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/metacognition/auto-experiment-engine.d.ts +72 -0
  32. package/dist/metacognition/auto-experiment-engine.js +272 -0
  33. package/dist/metacognition/auto-experiment-engine.js.map +1 -0
  34. package/dist/metacognition/index.d.ts +12 -0
  35. package/dist/metacognition/index.js +7 -0
  36. package/dist/metacognition/index.js.map +1 -0
  37. package/dist/metacognition/meta-cognition-layer.d.ts +112 -0
  38. package/dist/metacognition/meta-cognition-layer.js +402 -0
  39. package/dist/metacognition/meta-cognition-layer.js.map +1 -0
  40. package/dist/metacognition/parameter-registry.d.ts +71 -0
  41. package/dist/metacognition/parameter-registry.js +162 -0
  42. package/dist/metacognition/parameter-registry.js.map +1 -0
  43. package/dist/metacognition/self-test-engine.d.ts +52 -0
  44. package/dist/metacognition/self-test-engine.js +210 -0
  45. package/dist/metacognition/self-test-engine.js.map +1 -0
  46. package/dist/metacognition/simulation-engine.d.ts +71 -0
  47. package/dist/metacognition/simulation-engine.js +267 -0
  48. package/dist/metacognition/simulation-engine.js.map +1 -0
  49. package/dist/metacognition/teach-engine.d.ts +63 -0
  50. package/dist/metacognition/teach-engine.js +185 -0
  51. package/dist/metacognition/teach-engine.js.map +1 -0
  52. package/dist/research/data-scout.d.ts +68 -0
  53. package/dist/research/data-scout.js +254 -0
  54. package/dist/research/data-scout.js.map +1 -0
  55. package/dist/research/research-orchestrator.d.ts +32 -1
  56. package/dist/research/research-orchestrator.js +344 -4
  57. package/dist/research/research-orchestrator.js.map +1 -1
  58. package/dist/transfer/index.d.ts +1 -1
  59. package/dist/transfer/transfer-engine.d.ts +38 -0
  60. package/dist/transfer/transfer-engine.js +138 -0
  61. package/dist/transfer/transfer-engine.js.map +1 -1
  62. package/package.json +1 -1
@@ -39,6 +39,13 @@ export class ResearchOrchestrator {
39
39
  curiosityEngine = null;
40
40
  emergenceEngine = null;
41
41
  debateEngine = null;
42
+ parameterRegistry = null;
43
+ metaCognitionLayer = null;
44
+ autoExperimentEngine = null;
45
+ selfTestEngine = null;
46
+ teachEngine = null;
47
+ dataScout = null;
48
+ simulationEngine = null;
42
49
  brainName;
43
50
  feedbackTimer = null;
44
51
  cycleCount = 0;
@@ -50,6 +57,8 @@ export class ResearchOrchestrator {
50
57
  suggestionHistory = new Map();
51
58
  /** Max repeats before trying an alternative. */
52
59
  stalledThreshold = 3;
60
+ /** Hash of last written suggestions to prevent duplicate file writes. */
61
+ lastSuggestionsHash = '';
53
62
  constructor(db, config, causalGraph) {
54
63
  this.brainName = config.brainName;
55
64
  this.distillEvery = config.distillEvery ?? 5;
@@ -121,6 +130,26 @@ export class ResearchOrchestrator {
121
130
  setDebateEngine(engine) {
122
131
  this.debateEngine = engine;
123
132
  }
133
+ /** Set the ParameterRegistry — central tunable parameter store. */
134
+ setParameterRegistry(registry) {
135
+ this.parameterRegistry = registry;
136
+ }
137
+ /** Set the MetaCognitionLayer — engine evaluation and frequency adjustment. */
138
+ setMetaCognitionLayer(layer) {
139
+ this.metaCognitionLayer = layer;
140
+ }
141
+ /** Set the AutoExperimentEngine — autonomous parameter tuning. */
142
+ setAutoExperimentEngine(engine) {
143
+ this.autoExperimentEngine = engine;
144
+ }
145
+ /** Set the SelfTestEngine — tests understanding depth of principles. */
146
+ setSelfTestEngine(engine) { this.selfTestEngine = engine; }
147
+ /** Set the TeachEngine — generates onboarding packages for new brains. */
148
+ setTeachEngine(engine) { this.teachEngine = engine; }
149
+ /** Set the DataScout — actively scouts external data sources. */
150
+ setDataScout(scout) { this.dataScout = scout; }
151
+ /** Set the SimulationEngine — runs what-if scenarios. */
152
+ setSimulationEngine(engine) { this.simulationEngine = engine; }
124
153
  /** Set the PredictionEngine — wires journal into it. */
125
154
  setPredictionEngine(engine) {
126
155
  this.predictionEngine = engine;
@@ -466,14 +495,39 @@ export class ResearchOrchestrator {
466
495
  this.predictionEngine.recordMetric('auto_response_count', responderStatus.total_responses, 'metric');
467
496
  ts?.emit('orchestrator', 'perceiving', `Self-metrics recorded: ${anomalies.length} anomalies, ${insights.length} insights, ${cycleDuration}ms`);
468
497
  }
469
- // 12. Auto-Experiments: propose experiments on own parameters when none exist
470
- if (this.cycleCount > 3) {
498
+ // 12. Auto-Experiments: use AutoExperimentEngine if available, otherwise hardcoded fallback
499
+ if (this.autoExperimentEngine && this.cycleCount > 3 && this.cycleCount % 5 === 0) {
500
+ ts?.emit('auto_experiment', 'experimenting', 'Processing auto-experiments...');
501
+ try {
502
+ // Feed measurements
503
+ this.autoExperimentEngine.feedMeasurement('insight_count', insights.length);
504
+ this.autoExperimentEngine.feedMeasurement('anomaly_count', anomalies.length);
505
+ // Process completed
506
+ const completed = this.autoExperimentEngine.processCompleted(this.cycleCount);
507
+ for (const c of completed) {
508
+ ts?.emit('auto_experiment', 'discovering', `Auto-experiment #${c.autoExpId}: ${c.action}`, c.action === 'adopted' ? 'notable' : 'routine');
509
+ }
510
+ // Propose new
511
+ const candidates = this.autoExperimentEngine.discoverCandidates(this.cycleCount);
512
+ if (candidates.length > 0) {
513
+ const best = candidates[0];
514
+ const started = this.autoExperimentEngine.startExperiment(best);
515
+ if (started) {
516
+ ts?.emit('auto_experiment', 'experimenting', `Started: ${best.engine}.${best.name} ${best.currentValue.toFixed(3)} → ${best.proposedValue.toFixed(3)}`, 'notable');
517
+ }
518
+ }
519
+ }
520
+ catch (err) {
521
+ this.log.error(`[orchestrator] AutoExperiment error: ${err.message}`);
522
+ }
523
+ }
524
+ else if (this.cycleCount > 3) {
525
+ // Fallback: hardcoded experiments when no AutoExperimentEngine
471
526
  const running = this.experimentEngine.list('running_control', 5).length
472
527
  + this.experimentEngine.list('running_treatment', 5).length;
473
528
  if (running === 0 && this.cycleCount % 5 === 0) {
474
529
  this.proposeAutoExperiment(ts);
475
530
  }
476
- // Feed measurements into running experiments
477
531
  this.feedExperimentMeasurements(anomalies.length, insights.length);
478
532
  }
479
533
  // 13. Periodic Dream Consolidation: don't wait for idle, consolidate every 20 cycles
@@ -742,9 +796,282 @@ export class ResearchOrchestrator {
742
796
  this.log.error(`[orchestrator] Debate step error: ${err.message}`);
743
797
  }
744
798
  }
799
+ // 21. MetaCognition: evaluate engine performance and adjust frequencies
800
+ if (this.metaCognitionLayer && this.cycleCount % this.reflectEvery === 0) {
801
+ ts?.emit('metacognition', 'analyzing', 'Evaluating engine performance...');
802
+ try {
803
+ const cards = this.metaCognitionLayer.evaluate();
804
+ if (cards.length > 0) {
805
+ const topGrade = cards.sort((a, b) => b.combined_score - a.combined_score)[0];
806
+ const worstGrade = cards.sort((a, b) => a.combined_score - b.combined_score)[0];
807
+ ts?.emit('metacognition', 'discovering', `${cards.length} engines evaluated. Best: ${topGrade.engine} (${topGrade.grade}), Worst: ${worstGrade.engine} (${worstGrade.grade})`, cards.some(c => c.grade === 'F') ? 'notable' : 'routine');
808
+ const adjustments = this.metaCognitionLayer.adjustFrequencies(cards);
809
+ if (adjustments.length > 0) {
810
+ ts?.emit('metacognition', 'discovering', `Frequency adjusted: ${adjustments.map(a => `${a.engine} ${a.old_frequency}→${a.new_frequency}`).join(', ')}`, 'notable');
811
+ }
812
+ }
813
+ }
814
+ catch (err) {
815
+ this.log.error(`[orchestrator] MetaCognition error: ${err.message}`);
816
+ }
817
+ }
818
+ // 22. Parameter Registry: refresh orchestrator params from registry
819
+ if (this.parameterRegistry) {
820
+ const distill = this.parameterRegistry.get('orchestrator', 'distillEvery');
821
+ if (distill !== undefined && distill !== this.distillEvery) {
822
+ this.log.info(`[orchestrator] distillEvery refreshed: ${this.distillEvery} → ${distill}`);
823
+ this.distillEvery = distill;
824
+ }
825
+ const agenda = this.parameterRegistry.get('orchestrator', 'agendaEvery');
826
+ if (agenda !== undefined && agenda !== this.agendaEvery) {
827
+ this.log.info(`[orchestrator] agendaEvery refreshed: ${this.agendaEvery} → ${agenda}`);
828
+ this.agendaEvery = agenda;
829
+ }
830
+ const reflect = this.parameterRegistry.get('orchestrator', 'reflectEvery');
831
+ if (reflect !== undefined && reflect !== this.reflectEvery) {
832
+ this.log.info(`[orchestrator] reflectEvery refreshed: ${this.reflectEvery} → ${reflect}`);
833
+ this.reflectEvery = reflect;
834
+ }
835
+ }
836
+ // Step 23: Blind Spot Detection (every 5 cycles)
837
+ if (this.curiosityEngine && this.cycleCount % 5 === 0) {
838
+ try {
839
+ ts?.emit('orchestrator', 'analyzing', 'Step 23: Detecting blind spots...', 'routine');
840
+ const blindSpots = this.curiosityEngine.detectBlindSpots();
841
+ for (const bs of blindSpots) {
842
+ this.journal.write({
843
+ type: 'discovery',
844
+ title: `Blind spot: "${bs.topic}" (severity=${(bs.severity * 100).toFixed(0)}%)`,
845
+ content: `Knowledge blind spot detected. Hypotheses: ${bs.hypothesisCount}, Predictions: ${bs.predictionCount}, Journal: ${bs.journalCount}, Experiments: ${bs.experimentCount}`,
846
+ tags: ['blind-spot', bs.topic],
847
+ references: [],
848
+ significance: bs.severity > 0.85 ? 'notable' : 'routine',
849
+ data: { blindSpot: bs },
850
+ });
851
+ this.researchAgenda.ask(`Investigate blind spot: ${bs.topic} — severity ${(bs.severity * 100).toFixed(0)}%, needs more research`, 'knowledge_gap');
852
+ }
853
+ if (this.metaCognitionLayer)
854
+ this.metaCognitionLayer.recordStep('blind_spot_detector', this.cycleCount, { insights: blindSpots.length });
855
+ }
856
+ catch (err) {
857
+ this.log.warn(`[orchestrator] Step 23 error: ${err.message}`);
858
+ }
859
+ }
860
+ // Step 24: Creative Hypotheses (every 10 cycles)
861
+ if (this.cycleCount % 10 === 0) {
862
+ try {
863
+ ts?.emit('orchestrator', 'hypothesizing', 'Step 24: Generating creative hypotheses...', 'routine');
864
+ const creative = this.hypothesisEngine.generateCreative(3);
865
+ for (const h of creative) {
866
+ this.journal.write({
867
+ type: 'insight',
868
+ title: `Creative hypothesis: ${h.statement.substring(0, 80)}`,
869
+ content: `Source: ${h.source}, Type: ${h.type}`,
870
+ tags: ['creative-hypothesis', h.source],
871
+ references: [],
872
+ significance: 'routine',
873
+ data: { hypothesis: h },
874
+ });
875
+ }
876
+ if (this.metaCognitionLayer)
877
+ this.metaCognitionLayer.recordStep('creative_hypotheses', this.cycleCount, { insights: creative.length });
878
+ }
879
+ catch (err) {
880
+ this.log.warn(`[orchestrator] Step 24 error: ${err.message}`);
881
+ }
882
+ }
883
+ // Step 25: Advocatus Diaboli — challenge a random confirmed principle (every 10 cycles)
884
+ if (this.debateEngine && this.cycleCount % 10 === 0) {
885
+ try {
886
+ ts?.emit('orchestrator', 'reflecting', 'Step 25: Challenging a principle...', 'routine');
887
+ const principles = this.knowledgeDistiller.getPrinciples(undefined, 20);
888
+ if (principles.length > 0) {
889
+ const randomPrinciple = principles[Math.floor(Math.random() * principles.length)];
890
+ const challenge = this.debateEngine.challenge(randomPrinciple.statement);
891
+ this.journal.write({
892
+ type: 'reflection',
893
+ title: `Principle challenged: resilience=${(challenge.resilienceScore * 100).toFixed(0)}% → ${challenge.outcome}`,
894
+ content: `"${challenge.principleStatement.substring(0, 100)}" — Supporting: ${challenge.supportingEvidence.length}, Contradicting: ${challenge.contradictingEvidence.length}`,
895
+ tags: ['challenge', challenge.outcome],
896
+ references: [],
897
+ significance: challenge.outcome === 'disproved' ? 'notable' : 'routine',
898
+ data: { challenge },
899
+ });
900
+ }
901
+ if (this.metaCognitionLayer)
902
+ this.metaCognitionLayer.recordStep('advocatus_diaboli', this.cycleCount, { insights: 1 });
903
+ }
904
+ catch (err) {
905
+ this.log.warn(`[orchestrator] Step 25 error: ${err.message}`);
906
+ }
907
+ }
908
+ // Step 26: Dream Retrospective — analyze pruning regret (every 20 cycles)
909
+ if (this.dreamEngine && this.cycleCount % 20 === 0) {
910
+ try {
911
+ ts?.emit('orchestrator', 'reflecting', 'Step 26: Analyzing dream retrospective...', 'routine');
912
+ const retrospectives = this.dreamEngine.analyzeRetrospective(5);
913
+ for (const r of retrospectives) {
914
+ if (r.regretScore > 0.3) {
915
+ this.journal.write({
916
+ type: 'reflection',
917
+ title: `Dream regret: ${(r.regretScore * 100).toFixed(0)}% of pruned items reappeared`,
918
+ content: r.lesson,
919
+ tags: ['dream', 'retrospective'],
920
+ references: [],
921
+ significance: r.regretScore > 0.5 ? 'notable' : 'routine',
922
+ data: { retrospective: r },
923
+ });
924
+ }
925
+ }
926
+ if (this.metaCognitionLayer)
927
+ this.metaCognitionLayer.recordStep('dream_retrospective', this.cycleCount, { insights: retrospectives.length });
928
+ }
929
+ catch (err) {
930
+ this.log.warn(`[orchestrator] Step 26 error: ${err.message}`);
931
+ }
932
+ }
933
+ // Step 27: Cross-Brain Dialogue — formulate and answer questions across domains (every 10 cycles)
934
+ if (this.transferEngine && this.cycleCount % 10 === 0) {
935
+ try {
936
+ ts?.emit('orchestrator', 'correlating', 'Step 27: Cross-brain dialogue...', 'routine');
937
+ let topic = 'general knowledge';
938
+ if (this.attentionEngine) {
939
+ const topTopics = this.attentionEngine.getTopTopics(5);
940
+ if (topTopics.length > 0)
941
+ topic = topTopics[0].topic;
942
+ }
943
+ const question = this.transferEngine.formulateQuestion(topic);
944
+ const answer = this.transferEngine.answerQuestion(question);
945
+ this.transferEngine.recordDialogue(this.brainName, 'self', question, answer, `cycle:${this.cycleCount}`);
946
+ if (this.metaCognitionLayer)
947
+ this.metaCognitionLayer.recordStep('cross_brain_dialogue', this.cycleCount, { insights: 1 });
948
+ }
949
+ catch (err) {
950
+ this.log.warn(`[orchestrator] Step 27 error: ${err.message}`);
951
+ }
952
+ }
953
+ // Step 28: Self-Test — test understanding depth of principles (every 10 cycles)
954
+ if (this.selfTestEngine && this.cycleCount % 10 === 0) {
955
+ try {
956
+ ts?.emit('orchestrator', 'analyzing', 'Step 28: Self-testing principles...', 'routine');
957
+ const results = this.selfTestEngine.testAll();
958
+ const shallow = results.filter(r => r.understandingDepth < 0.3);
959
+ for (const s of shallow) {
960
+ this.researchAgenda.ask(`Deepen understanding: "${s.principleStatement.substring(0, 60)}" — shallow depth (${(s.understandingDepth * 100).toFixed(0)}%), need more predictions/experiments`, 'knowledge_gap');
961
+ }
962
+ if (this.metaCognitionLayer)
963
+ this.metaCognitionLayer.recordStep('self_test', this.cycleCount, { insights: results.length, journal_entries: shallow.length });
964
+ }
965
+ catch (err) {
966
+ this.log.warn(`[orchestrator] Step 28 error: ${err.message}`);
967
+ }
968
+ }
969
+ // Step 29: DataScout — scout external data sources (every 20 cycles)
970
+ if (this.dataScout && this.cycleCount % 20 === 0) {
971
+ try {
972
+ ts?.emit('orchestrator', 'exploring', 'Step 29: Scouting external data...', 'routine');
973
+ const discoveries = await this.dataScout.scout();
974
+ for (const d of discoveries.slice(0, 3)) {
975
+ this.journal.write({
976
+ type: 'discovery',
977
+ title: `Scout: ${d.title}`,
978
+ content: `Source: ${d.source}, Relevance: ${(d.relevanceScore * 100).toFixed(0)}%. ${d.description.substring(0, 200)}`,
979
+ tags: ['scout', d.source],
980
+ references: [],
981
+ significance: d.relevanceScore > 0.7 ? 'notable' : 'routine',
982
+ data: { discovery: d },
983
+ });
984
+ }
985
+ if (this.metaCognitionLayer)
986
+ this.metaCognitionLayer.recordStep('data_scout', this.cycleCount, { insights: discoveries.length });
987
+ }
988
+ catch (err) {
989
+ this.log.warn(`[orchestrator] Step 29 error: ${err.message}`);
990
+ }
991
+ }
992
+ // Step 30: Emergence Explanation — explain unexplained emergence events (every 5 cycles)
993
+ if (this.emergenceEngine && this.cycleCount % 5 === 0) {
994
+ try {
995
+ ts?.emit('orchestrator', 'analyzing', 'Step 30: Explaining recent emergence events...', 'routine');
996
+ const events = this.emergenceEngine.getEvents(5);
997
+ let explained = 0;
998
+ for (const e of events) {
999
+ if (!e.id)
1000
+ continue;
1001
+ const existing = this.emergenceEngine.getExplanation(e.id);
1002
+ if (!existing) {
1003
+ this.emergenceEngine.explain(e.id);
1004
+ explained++;
1005
+ }
1006
+ }
1007
+ if (this.metaCognitionLayer)
1008
+ this.metaCognitionLayer.recordStep('emergence_explain', this.cycleCount, { insights: explained });
1009
+ }
1010
+ catch (err) {
1011
+ this.log.warn(`[orchestrator] Step 30 error: ${err.message}`);
1012
+ }
1013
+ }
1014
+ // Step 31: Meta-Trends — record system-wide trend data every cycle
1015
+ if (this.metaCognitionLayer) {
1016
+ try {
1017
+ const totalPrinciples = this.knowledgeDistiller.getPrinciples(undefined, 1000).length;
1018
+ const hypothesisSummary = this.hypothesisEngine.getSummary();
1019
+ const totalHypotheses = hypothesisSummary.total ?? 0;
1020
+ const predictionAccuracy = 0; // Will be filled if prediction engine available
1021
+ let closedGaps = 0;
1022
+ if (this.curiosityEngine) {
1023
+ const status = this.curiosityEngine.getStatus();
1024
+ closedGaps = status.totalGaps - status.activeGaps;
1025
+ }
1026
+ const emergenceCount = this.emergenceEngine ? this.emergenceEngine.getStatus().totalEvents : 0;
1027
+ this.metaCognitionLayer.recordTrend(this.cycleCount, {
1028
+ newPrinciples: totalPrinciples,
1029
+ newHypotheses: totalHypotheses,
1030
+ predictionAccuracy,
1031
+ closedGaps,
1032
+ totalPrinciples,
1033
+ totalHypotheses,
1034
+ emergenceCount,
1035
+ });
1036
+ }
1037
+ catch (err) {
1038
+ this.log.warn(`[orchestrator] Step 31 error: ${err.message}`);
1039
+ }
1040
+ }
1041
+ // Step 32: Simulation — run what-if scenarios (every 20 cycles)
1042
+ if (this.simulationEngine && this.cycleCount % 20 === 0) {
1043
+ try {
1044
+ ts?.emit('orchestrator', 'hypothesizing', 'Step 32: Running what-if simulations...', 'routine');
1045
+ const scenarios = ['error_rate doubles', 'learning_rate halves', 'prediction_accuracy increases by 20%'];
1046
+ const scenario = scenarios[this.cycleCount % scenarios.length];
1047
+ const sim = this.simulationEngine.simulate(scenario);
1048
+ this.journal.write({
1049
+ type: 'insight',
1050
+ title: `Simulation: "${scenario}"`,
1051
+ content: `Predicted ${sim.predictedOutcomes.length} outcomes. ${sim.predictedOutcomes.map(o => `${o.metric}: ${o.direction} (${(o.confidence * 100).toFixed(0)}%)`).join(', ')}`,
1052
+ tags: ['simulation', 'what-if'],
1053
+ references: [],
1054
+ significance: 'routine',
1055
+ data: { simulation: sim },
1056
+ });
1057
+ if (this.metaCognitionLayer)
1058
+ this.metaCognitionLayer.recordStep('simulation', this.cycleCount, { predictions: sim.predictedOutcomes.length });
1059
+ }
1060
+ catch (err) {
1061
+ this.log.warn(`[orchestrator] Step 32 error: ${err.message}`);
1062
+ }
1063
+ }
745
1064
  const duration = Date.now() - start;
746
1065
  ts?.emit('orchestrator', 'reflecting', `Feedback Cycle #${this.cycleCount} complete (${duration}ms)`);
747
1066
  this.log.info(`[orchestrator] ─── Feedback Cycle #${this.cycleCount} complete (${duration}ms) ───`);
1067
+ // Record cycle metrics into MetaCognition for engine-level tracking
1068
+ if (this.metaCognitionLayer) {
1069
+ this.metaCognitionLayer.recordStep('orchestrator', this.cycleCount, {
1070
+ insights: insights.length,
1071
+ anomalies: anomalies.length,
1072
+ duration_ms: duration,
1073
+ });
1074
+ }
748
1075
  }
749
1076
  /** Analyze Brain's own state and generate concrete improvement suggestions.
750
1077
  * Tracks suggestion history — if a suggestion repeats 3+ times without resolution,
@@ -1240,9 +1567,15 @@ export class ResearchOrchestrator {
1240
1567
  this.experimentEngine.recordMeasurement(exp.id, value);
1241
1568
  }
1242
1569
  }
1243
- /** Append improvement suggestions to ~/.brain/improvement-requests.md */
1570
+ /** Append improvement suggestions to ~/.brain/improvement-requests.md.
1571
+ * Skips writing if suggestions are identical to the last write (dedup). */
1244
1572
  writeSuggestionsToFile(suggestions) {
1245
1573
  try {
1574
+ // Dedup: hash current suggestions and skip if identical to last write
1575
+ const contentHash = suggestions.join('\n').trim();
1576
+ if (contentHash === this.lastSuggestionsHash)
1577
+ return;
1578
+ this.lastSuggestionsHash = contentHash;
1246
1579
  const brainDir = path.join(os.homedir(), '.brain');
1247
1580
  const filePath = path.join(brainDir, 'improvement-requests.md');
1248
1581
  const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
@@ -1284,6 +1617,13 @@ export class ResearchOrchestrator {
1284
1617
  attention: this.attentionEngine?.getStatus() ?? null,
1285
1618
  transfer: this.transferEngine?.getStatus() ?? null,
1286
1619
  narrative: this.narrativeEngine?.getStatus() ?? null,
1620
+ metacognition: this.metaCognitionLayer?.getStatus() ?? null,
1621
+ autoExperiment: this.autoExperimentEngine?.getStatus(this.cycleCount) ?? null,
1622
+ parameterRegistry: this.parameterRegistry?.getStatus() ?? null,
1623
+ selfTest: this.selfTestEngine?.getStatus() ?? null,
1624
+ teach: this.teachEngine?.getStatus() ?? null,
1625
+ dataScout: this.dataScout?.getStatus() ?? null,
1626
+ simulation: this.simulationEngine?.getStatus() ?? null,
1287
1627
  };
1288
1628
  }
1289
1629
  }