lex-mind-growth 0.1.7 → 0.1.8
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.
- checksums.yaml +4 -4
- data/lib/legion/extensions/mind_growth/client.rb +21 -0
- data/lib/legion/extensions/mind_growth/helpers/composition_map.rb +76 -0
- data/lib/legion/extensions/mind_growth/helpers/constants.rb +4 -0
- data/lib/legion/extensions/mind_growth/runners/composer.rb +118 -0
- data/lib/legion/extensions/mind_growth/runners/dream_ideation.rb +120 -0
- data/lib/legion/extensions/mind_growth/runners/monitor.rb +103 -0
- data/lib/legion/extensions/mind_growth/version.rb +1 -1
- data/lib/legion/extensions/mind_growth.rb +4 -0
- data/spec/legion/extensions/mind_growth/helpers/composition_map_spec.rb +248 -0
- data/spec/legion/extensions/mind_growth/runners/composer_spec.rb +223 -0
- data/spec/legion/extensions/mind_growth/runners/dream_ideation_spec.rb +207 -0
- data/spec/legion/extensions/mind_growth/runners/monitor_spec.rb +336 -0
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 87d35372e2ef409b603807723d816df60439d40bc8f4289d48799d31b731d232
|
|
4
|
+
data.tar.gz: fd49c0c8bb06f49374cbbb3afb497f45ee58193e71ff66b1ef1c622b94bbeaa6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d3c07088c0173a6e5669af58bf3fbd315f2ef9098fa9e3f3f65228815159e6a061860c05aba14b75a0f0dcd9f01aea50f5a89ec9455a5796484037c6e1571328
|
|
7
|
+
data.tar.gz: 98b9b07557efbb5a3546a4018300ab984a0bfecc24ae93ab2534c35c90b991877d5564863460a75137525b262c996b7536ca14c6bbd20f77671225a8501ba402
|
|
@@ -47,6 +47,27 @@ module Legion
|
|
|
47
47
|
# RiskAssessor delegation
|
|
48
48
|
def assess_risk(**) = Runners::RiskAssessor.assess_risk(**)
|
|
49
49
|
def risk_summary(**) = Runners::RiskAssessor.risk_summary(**)
|
|
50
|
+
|
|
51
|
+
# Monitor delegation
|
|
52
|
+
def health_check(**) = Runners::Monitor.health_check(**)
|
|
53
|
+
def usage_stats(**) = Runners::Monitor.usage_stats(**)
|
|
54
|
+
def impact_score(**) = Runners::Monitor.impact_score(**)
|
|
55
|
+
def decay_check(**) = Runners::Monitor.decay_check(**)
|
|
56
|
+
def auto_prune(**) = Runners::Monitor.auto_prune(**)
|
|
57
|
+
def health_summary(**) = Runners::Monitor.health_summary(**)
|
|
58
|
+
|
|
59
|
+
# Composer delegation
|
|
60
|
+
def add_composition(**) = Runners::Composer.add_composition(**)
|
|
61
|
+
def remove_composition(**) = Runners::Composer.remove_composition(**)
|
|
62
|
+
def evaluate_output(**) = Runners::Composer.evaluate_output(**)
|
|
63
|
+
def composition_stats(**) = Runners::Composer.composition_stats(**)
|
|
64
|
+
def suggest_compositions(**) = Runners::Composer.suggest_compositions(**)
|
|
65
|
+
def list_compositions(**) = Runners::Composer.list_compositions(**)
|
|
66
|
+
|
|
67
|
+
# DreamIdeation delegation
|
|
68
|
+
def generate_dream_proposals(**) = Runners::DreamIdeation.generate_dream_proposals(**)
|
|
69
|
+
def dream_agenda_items(**) = Runners::DreamIdeation.dream_agenda_items(**)
|
|
70
|
+
def enrich_from_dream_context(**) = Runners::DreamIdeation.enrich_from_dream_context(**)
|
|
50
71
|
end
|
|
51
72
|
end
|
|
52
73
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Helpers
|
|
7
|
+
module CompositionMap
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
@rules = {}
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
|
|
13
|
+
def add_rule(source_extension:, output_key:, target_extension:, target_method:, transform: nil, **)
|
|
14
|
+
rule_id = SecureRandom.uuid
|
|
15
|
+
rule = {
|
|
16
|
+
id: rule_id,
|
|
17
|
+
source_extension: source_extension.to_s,
|
|
18
|
+
output_key: output_key.to_sym,
|
|
19
|
+
target_extension: target_extension.to_s,
|
|
20
|
+
target_method: target_method.to_sym,
|
|
21
|
+
transform: transform
|
|
22
|
+
}
|
|
23
|
+
@mutex.synchronize { @rules[rule_id] = rule }
|
|
24
|
+
{ success: true, rule_id: rule_id }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def remove_rule(rule_id:, **)
|
|
28
|
+
removed = @mutex.synchronize { @rules.delete(rule_id) }
|
|
29
|
+
{ success: !removed.nil?, rule_id: rule_id }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def rules_for(source_extension:, **)
|
|
33
|
+
src = source_extension.to_s
|
|
34
|
+
@mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def all_rules
|
|
38
|
+
@mutex.synchronize { @rules.values.dup }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def match_output(source_extension:, output:, **)
|
|
42
|
+
src = source_extension.to_s
|
|
43
|
+
out_h = output.is_a?(Hash) ? output : {}
|
|
44
|
+
rules = @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
|
|
45
|
+
|
|
46
|
+
rules.filter_map do |rule|
|
|
47
|
+
key = rule[:output_key]
|
|
48
|
+
next unless out_h.key?(key)
|
|
49
|
+
|
|
50
|
+
{ rule: rule, matched_value: out_h[key] }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def clear!
|
|
55
|
+
@mutex.synchronize { @rules.clear }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def stats
|
|
59
|
+
all = @mutex.synchronize { @rules.values.dup }
|
|
60
|
+
|
|
61
|
+
by_source = Hash.new(0)
|
|
62
|
+
by_target = Hash.new(0)
|
|
63
|
+
all.each do |r|
|
|
64
|
+
by_source[r[:source_extension]] += 1
|
|
65
|
+
by_target[r[:target_extension]] += 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
{ total_rules: all.size,
|
|
69
|
+
by_source: by_source.transform_values { |v| v },
|
|
70
|
+
by_target: by_target.transform_values { |v| v } }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -54,6 +54,10 @@ module Legion
|
|
|
54
54
|
REJECTION_COOLDOWN_HOURS = 24
|
|
55
55
|
GOVERNANCE_STATUSES = %i[pending approved rejected expired].freeze
|
|
56
56
|
|
|
57
|
+
# Health monitoring
|
|
58
|
+
HEALTH_LEVELS = { excellent: 0.8, good: 0.6, fair: 0.4, degraded: 0.2, critical: 0.0 }.freeze
|
|
59
|
+
DECAY_INVOCATION_THRESHOLD = 5
|
|
60
|
+
|
|
57
61
|
# Risk assessment
|
|
58
62
|
RISK_TIERS = %i[low medium high critical].freeze
|
|
59
63
|
RISK_RECOMMENDATIONS = {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module Composer
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
extend self
|
|
12
|
+
|
|
13
|
+
# Category adjacency used for heuristic suggestions
|
|
14
|
+
CATEGORY_FLOW = [
|
|
15
|
+
%i[perception cognition],
|
|
16
|
+
%i[cognition memory],
|
|
17
|
+
%i[cognition introspection],
|
|
18
|
+
%i[memory cognition],
|
|
19
|
+
%i[introspection safety],
|
|
20
|
+
%i[motivation cognition],
|
|
21
|
+
%i[cognition communication],
|
|
22
|
+
%i[communication coordination]
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
def add_composition(source_extension:, output_key:, target_extension:, target_method:,
|
|
26
|
+
transform: nil, **)
|
|
27
|
+
Helpers::CompositionMap.add_rule(
|
|
28
|
+
source_extension: source_extension,
|
|
29
|
+
output_key: output_key,
|
|
30
|
+
target_extension: target_extension,
|
|
31
|
+
target_method: target_method,
|
|
32
|
+
transform: transform
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def remove_composition(rule_id:, **)
|
|
37
|
+
result = Helpers::CompositionMap.remove_rule(rule_id: rule_id)
|
|
38
|
+
{ success: result[:success] }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def evaluate_output(source_extension:, output:, **)
|
|
42
|
+
matches = Helpers::CompositionMap.match_output(
|
|
43
|
+
source_extension: source_extension,
|
|
44
|
+
output: output
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
dispatches = matches.map do |match|
|
|
48
|
+
rule = match[:rule]
|
|
49
|
+
value = match[:matched_value]
|
|
50
|
+
input = rule[:transform] ? rule[:transform].call(value) : value
|
|
51
|
+
|
|
52
|
+
{ target_extension: rule[:target_extension],
|
|
53
|
+
target_method: rule[:target_method],
|
|
54
|
+
input: input }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
{ success: true, dispatches: dispatches, count: dispatches.size }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def composition_stats(**)
|
|
61
|
+
{ success: true, **Helpers::CompositionMap.stats }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def suggest_compositions(extensions:, **)
|
|
65
|
+
exts = Array(extensions)
|
|
66
|
+
|
|
67
|
+
return suggest_with_llm(exts) if defined?(Legion::LLM) && Legion::LLM.respond_to?(:started?) && Legion::LLM.started?
|
|
68
|
+
|
|
69
|
+
suggestions = heuristic_suggestions(exts)
|
|
70
|
+
{ success: true, suggestions: suggestions, count: suggestions.size }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def list_compositions(**)
|
|
74
|
+
rules = Helpers::CompositionMap.all_rules
|
|
75
|
+
{ success: true, rules: rules, count: rules.size }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def heuristic_suggestions(extensions)
|
|
81
|
+
ext_by_category = {}
|
|
82
|
+
extensions.each do |ext|
|
|
83
|
+
cat = (ext[:category] || :cognition).to_sym
|
|
84
|
+
(ext_by_category[cat] ||= []) << ext
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
suggestions = []
|
|
88
|
+
CATEGORY_FLOW.each do |src_cat, tgt_cat|
|
|
89
|
+
src_exts = ext_by_category[src_cat] || []
|
|
90
|
+
tgt_exts = ext_by_category[tgt_cat] || []
|
|
91
|
+
|
|
92
|
+
src_exts.each do |src|
|
|
93
|
+
tgt_exts.each do |tgt|
|
|
94
|
+
suggestions << {
|
|
95
|
+
source_extension: src[:name] || src[:extension_name],
|
|
96
|
+
output_key: :result,
|
|
97
|
+
target_extension: tgt[:name] || tgt[:extension_name],
|
|
98
|
+
target_method: :process,
|
|
99
|
+
rationale: "#{src_cat} -> #{tgt_cat} flow"
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
suggestions
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def suggest_with_llm(extensions)
|
|
109
|
+
suggestions = heuristic_suggestions(extensions)
|
|
110
|
+
{ success: true, suggestions: suggestions, count: suggestions.size }
|
|
111
|
+
rescue StandardError
|
|
112
|
+
{ success: true, suggestions: [], count: 0 }
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module DreamIdeation
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
extend self
|
|
12
|
+
|
|
13
|
+
DREAM_NOVELTY_BONUS = 0.15
|
|
14
|
+
|
|
15
|
+
# Agenda item weight by how underrepresented the category is
|
|
16
|
+
MAX_AGENDA_WEIGHT = 1.0
|
|
17
|
+
MIN_AGENDA_WEIGHT = 0.1
|
|
18
|
+
|
|
19
|
+
def generate_dream_proposals(existing_extensions: nil, max_proposals: 2, **)
|
|
20
|
+
gap_result = Runners::Proposer.analyze_gaps(existing_extensions: existing_extensions)
|
|
21
|
+
return { success: false, error: :gap_analysis_failed } unless gap_result[:success]
|
|
22
|
+
|
|
23
|
+
recommendations = gap_result[:recommendations] || []
|
|
24
|
+
proposals = []
|
|
25
|
+
|
|
26
|
+
recommendations.first(max_proposals).each do |rec|
|
|
27
|
+
name = rec.is_a?(Hash) ? rec[:name] : rec.to_s
|
|
28
|
+
result = Runners::Proposer.propose_concept(
|
|
29
|
+
name: "lex-dream-#{name.to_s.downcase.gsub(/[^a-z0-9]/, '-')}",
|
|
30
|
+
description: "Dream-originated proposal for #{name} cognitive capability",
|
|
31
|
+
enrich: false
|
|
32
|
+
)
|
|
33
|
+
next unless result[:success]
|
|
34
|
+
|
|
35
|
+
proposal_id = result[:proposal][:id]
|
|
36
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
37
|
+
proposal&.instance_variable_set(:@origin, :dream)
|
|
38
|
+
|
|
39
|
+
proposals << result[:proposal]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
{ success: true, proposals: proposals, count: proposals.size,
|
|
43
|
+
gaps_analyzed: recommendations.size }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def dream_agenda_items(existing_extensions: nil, **)
|
|
47
|
+
gap_result = Runners::Proposer.analyze_gaps(existing_extensions: existing_extensions)
|
|
48
|
+
return { success: false, error: :gap_analysis_failed } unless gap_result[:success]
|
|
49
|
+
|
|
50
|
+
target = Helpers::Constants::TARGET_DISTRIBUTION
|
|
51
|
+
models = gap_result[:models] || []
|
|
52
|
+
|
|
53
|
+
coverage_by_cat = build_coverage_by_category(models)
|
|
54
|
+
|
|
55
|
+
items = target.filter_map do |category, target_pct|
|
|
56
|
+
actual_pct = coverage_by_cat[category] || 0.0
|
|
57
|
+
gap = (target_pct - actual_pct).clamp(0.0, 1.0)
|
|
58
|
+
next if gap <= 0.0
|
|
59
|
+
|
|
60
|
+
weight = ((gap / target_pct) * MAX_AGENDA_WEIGHT).clamp(MIN_AGENDA_WEIGHT, MAX_AGENDA_WEIGHT).round(3)
|
|
61
|
+
|
|
62
|
+
{ type: :architectural_gap,
|
|
63
|
+
content: { gap_name: category, model: :target_distribution, coverage: actual_pct },
|
|
64
|
+
weight: weight }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
{ success: true, items: items, count: items.size }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def enrich_from_dream_context(proposal_id:, dream_context: {}, **)
|
|
71
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
72
|
+
return { success: false, error: :not_found } unless proposal
|
|
73
|
+
|
|
74
|
+
if dream_context && !dream_context.empty?
|
|
75
|
+
existing = proposal.rationale.to_s
|
|
76
|
+
additions = dream_context.map { |k, v| "#{k}: #{v}" }.join('; ')
|
|
77
|
+
new_rationale = existing.empty? ? additions : "#{existing}. Dream context: #{additions}"
|
|
78
|
+
proposal.instance_variable_set(:@rationale, new_rationale)
|
|
79
|
+
{ success: true, proposal_id: proposal_id, enriched: true }
|
|
80
|
+
else
|
|
81
|
+
{ success: true, proposal_id: proposal_id, enriched: false }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def build_coverage_by_category(models)
|
|
88
|
+
coverage = {}
|
|
89
|
+
models.each do |model|
|
|
90
|
+
cat = infer_category_from_model(model[:model])
|
|
91
|
+
next unless cat
|
|
92
|
+
|
|
93
|
+
existing = coverage[cat] || 1.0
|
|
94
|
+
coverage[cat] = [existing, model_coverage_fraction(model)].min
|
|
95
|
+
end
|
|
96
|
+
coverage
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def model_coverage_fraction(model)
|
|
100
|
+
total = model[:total_required] || 1
|
|
101
|
+
missing = (model[:missing] || []).size
|
|
102
|
+
covered = total - missing
|
|
103
|
+
total.positive? ? (covered.to_f / total).round(3) : 0.0
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def infer_category_from_model(model_name)
|
|
107
|
+
mapping = {
|
|
108
|
+
global_workspace: :cognition,
|
|
109
|
+
free_energy: :introspection,
|
|
110
|
+
dual_process: :cognition,
|
|
111
|
+
somatic_marker: :motivation,
|
|
112
|
+
working_memory: :memory
|
|
113
|
+
}
|
|
114
|
+
mapping[model_name&.to_sym]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module Monitor
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
extend self
|
|
12
|
+
|
|
13
|
+
HEALTH_LEVELS = {
|
|
14
|
+
excellent: 0.8,
|
|
15
|
+
good: 0.6,
|
|
16
|
+
fair: 0.4,
|
|
17
|
+
degraded: 0.2,
|
|
18
|
+
critical: 0.0
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
def health_check(extension:, **)
|
|
22
|
+
name = extension[:name] || extension[:extension_name]
|
|
23
|
+
fitness = Helpers::FitnessEvaluator.fitness(extension)
|
|
24
|
+
level = classify_health(fitness)
|
|
25
|
+
alert = %i[degraded critical].include?(level)
|
|
26
|
+
|
|
27
|
+
{ success: true, extension_name: name, fitness: fitness,
|
|
28
|
+
health_level: level, alert: alert }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def usage_stats(extensions:, **)
|
|
32
|
+
stats = Array(extensions).map do |ext|
|
|
33
|
+
{ extension_name: ext[:name] || ext[:extension_name],
|
|
34
|
+
invocation_count: ext[:invocation_count] || 0,
|
|
35
|
+
error_rate: ext[:error_rate] || 0.0,
|
|
36
|
+
avg_latency_ms: ext[:avg_latency_ms] || 0 }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
{ success: true, stats: stats, count: stats.size }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def impact_score(extension:, extensions: nil, **)
|
|
43
|
+
name = extension[:name] || extension[:extension_name]
|
|
44
|
+
impact = extension[:impact_score] || 0.5
|
|
45
|
+
|
|
46
|
+
percentile = if extensions && !Array(extensions).empty?
|
|
47
|
+
all_impacts = Array(extensions).map { |e| e[:impact_score] || 0.5 }.sort
|
|
48
|
+
rank = all_impacts.count { |i| i <= impact }
|
|
49
|
+
(rank.to_f / all_impacts.size * 100).round(1)
|
|
50
|
+
else
|
|
51
|
+
50.0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
{ success: true, extension_name: name, impact: impact, rank_percentile: percentile }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def decay_check(extensions:, **)
|
|
58
|
+
threshold = Helpers::Constants::DECAY_INVOCATION_THRESHOLD
|
|
59
|
+
decayed = Array(extensions).select do |ext|
|
|
60
|
+
count = ext[:invocation_count] || 0
|
|
61
|
+
fitness = Helpers::FitnessEvaluator.fitness(ext)
|
|
62
|
+
count < threshold || fitness < Helpers::Constants::PRUNE_THRESHOLD
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
{ success: true, decayed: decayed, count: decayed.size }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def auto_prune(extensions:, **)
|
|
69
|
+
pruned = Helpers::FitnessEvaluator.prune_candidates(Array(extensions))
|
|
70
|
+
{ success: true, pruned: pruned, count: pruned.size }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def health_summary(extensions:, **)
|
|
74
|
+
exts = Array(extensions)
|
|
75
|
+
|
|
76
|
+
by_health_level = HEALTH_LEVELS.keys.to_h { |level| [level, 0] }
|
|
77
|
+
alerts = []
|
|
78
|
+
prune_candidates = Helpers::FitnessEvaluator.prune_candidates(exts)
|
|
79
|
+
|
|
80
|
+
exts.each do |ext|
|
|
81
|
+
fitness = Helpers::FitnessEvaluator.fitness(ext)
|
|
82
|
+
level = classify_health(fitness)
|
|
83
|
+
by_health_level[level] += 1
|
|
84
|
+
alerts << ext if %i[degraded critical].include?(level)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
{ success: true, total: exts.size, by_health_level: by_health_level,
|
|
88
|
+
alerts: alerts, prune_candidates: prune_candidates }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def classify_health(fitness)
|
|
94
|
+
HEALTH_LEVELS.each do |level, threshold|
|
|
95
|
+
return level if fitness >= threshold
|
|
96
|
+
end
|
|
97
|
+
:critical
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -20,6 +20,10 @@ require 'legion/extensions/mind_growth/runners/integration_tester'
|
|
|
20
20
|
require 'legion/extensions/mind_growth/runners/retrospective'
|
|
21
21
|
require 'legion/extensions/mind_growth/runners/governance'
|
|
22
22
|
require 'legion/extensions/mind_growth/runners/risk_assessor'
|
|
23
|
+
require 'legion/extensions/mind_growth/helpers/composition_map'
|
|
24
|
+
require 'legion/extensions/mind_growth/runners/monitor'
|
|
25
|
+
require 'legion/extensions/mind_growth/runners/composer'
|
|
26
|
+
require 'legion/extensions/mind_growth/runners/dream_ideation'
|
|
23
27
|
require 'legion/extensions/mind_growth/client'
|
|
24
28
|
|
|
25
29
|
module Legion
|