lex-mind-growth 0.1.5 → 0.1.7
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 +17 -0
- data/lib/legion/extensions/mind_growth/helpers/constants.rb +14 -0
- data/lib/legion/extensions/mind_growth/runners/governance.rb +122 -0
- data/lib/legion/extensions/mind_growth/runners/retrospective.rb +147 -0
- data/lib/legion/extensions/mind_growth/runners/risk_assessor.rb +106 -0
- data/lib/legion/extensions/mind_growth/version.rb +1 -1
- data/lib/legion/extensions/mind_growth.rb +3 -0
- data/spec/legion/extensions/mind_growth/runners/governance_spec.rb +439 -0
- data/spec/legion/extensions/mind_growth/runners/retrospective_spec.rb +466 -0
- data/spec/legion/extensions/mind_growth/runners/risk_assessor_spec.rb +395 -0
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2182f87f0f59f727c61f209083c225b1b31d9cbb5589af437618350433e8b692
|
|
4
|
+
data.tar.gz: 1ee0428c83686efdb168054b16d68af66443dfa60bd5f0bd8e2725f4d7d87ab4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e7320c15ecd31d531bd961b03f20baa8c30a77946f98e58c25557ebcd1027b42b7c9af7c9ce8ae781089e25966a76d183209922ce8b2e7a780c141853cf6d96
|
|
7
|
+
data.tar.gz: b7abcbc0ea3109d64a4cc1cda9508ea0ee8ab777271e205abc1ae4903d1f2bf349b78053aa071fe5835790a790f4974be95800cf57ad2bfa8ab96182b358d312
|
|
@@ -30,6 +30,23 @@ module Legion
|
|
|
30
30
|
# Orchestrator delegation
|
|
31
31
|
def run_growth_cycle(**) = Runners::Orchestrator.run_growth_cycle(**)
|
|
32
32
|
def growth_status(**) = Runners::Orchestrator.growth_status(**)
|
|
33
|
+
|
|
34
|
+
# Retrospective delegation
|
|
35
|
+
def session_report(**) = Runners::Retrospective.session_report(**)
|
|
36
|
+
def trend_analysis(**) = Runners::Retrospective.trend_analysis(**)
|
|
37
|
+
def learning_extraction(**) = Runners::Retrospective.learning_extraction(**)
|
|
38
|
+
|
|
39
|
+
# Governance delegation
|
|
40
|
+
def submit_proposal(**) = Runners::Governance.submit_proposal(**)
|
|
41
|
+
def vote_on_proposal(**) = Runners::Governance.vote_on_proposal(**)
|
|
42
|
+
def tally_votes(**) = Runners::Governance.tally_votes(**)
|
|
43
|
+
def approve_proposal(**) = Runners::Governance.approve_proposal(**)
|
|
44
|
+
def reject_proposal(**) = Runners::Governance.reject_proposal(**)
|
|
45
|
+
def governance_stats(**) = Runners::Governance.governance_stats(**)
|
|
46
|
+
|
|
47
|
+
# RiskAssessor delegation
|
|
48
|
+
def assess_risk(**) = Runners::RiskAssessor.assess_risk(**)
|
|
49
|
+
def risk_summary(**) = Runners::RiskAssessor.risk_summary(**)
|
|
33
50
|
end
|
|
34
51
|
end
|
|
35
52
|
end
|
|
@@ -48,6 +48,20 @@ module Legion
|
|
|
48
48
|
|
|
49
49
|
# Reference cognitive models
|
|
50
50
|
COGNITIVE_MODELS = %i[global_workspace free_energy dual_process somatic_marker working_memory].freeze
|
|
51
|
+
|
|
52
|
+
# Governance
|
|
53
|
+
QUORUM = 3
|
|
54
|
+
REJECTION_COOLDOWN_HOURS = 24
|
|
55
|
+
GOVERNANCE_STATUSES = %i[pending approved rejected expired].freeze
|
|
56
|
+
|
|
57
|
+
# Risk assessment
|
|
58
|
+
RISK_TIERS = %i[low medium high critical].freeze
|
|
59
|
+
RISK_RECOMMENDATIONS = {
|
|
60
|
+
low: :auto_approve,
|
|
61
|
+
medium: :governance,
|
|
62
|
+
high: :human_required,
|
|
63
|
+
critical: :blocked
|
|
64
|
+
}.freeze
|
|
51
65
|
end
|
|
52
66
|
end
|
|
53
67
|
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module Governance
|
|
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
|
+
VOTE_VALUES = %i[approve reject].freeze
|
|
14
|
+
|
|
15
|
+
def submit_proposal(proposal_id:, **)
|
|
16
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
17
|
+
return { success: false, error: :not_found } unless proposal
|
|
18
|
+
|
|
19
|
+
return { success: false, error: :invalid_status, current_status: proposal.status } unless %i[proposed evaluating].include?(proposal.status)
|
|
20
|
+
|
|
21
|
+
proposal.transition!(:evaluating)
|
|
22
|
+
{ success: true, proposal_id: proposal_id, status: :evaluating }
|
|
23
|
+
rescue ArgumentError => e
|
|
24
|
+
{ success: false, error: e.message }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def vote_on_proposal(proposal_id:, vote:, agent_id: 'default', rationale: nil, **)
|
|
28
|
+
vote_sym = vote.to_sym
|
|
29
|
+
return { success: false, error: :invalid_vote } unless VOTE_VALUES.include?(vote_sym)
|
|
30
|
+
|
|
31
|
+
votes_mutex.synchronize do
|
|
32
|
+
votes_store[proposal_id] ||= []
|
|
33
|
+
votes_store[proposal_id] << { vote: vote_sym, agent_id: agent_id.to_s, rationale: rationale,
|
|
34
|
+
cast_at: Time.now.utc }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
{ success: true, proposal_id: proposal_id, vote: vote_sym, agent_id: agent_id.to_s }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def tally_votes(proposal_id:, **)
|
|
41
|
+
ballots = votes_mutex.synchronize { (votes_store[proposal_id] || []).dup }
|
|
42
|
+
|
|
43
|
+
approve_count = ballots.count { |b| b[:vote] == :approve }
|
|
44
|
+
reject_count = ballots.count { |b| b[:vote] == :reject }
|
|
45
|
+
total = ballots.size
|
|
46
|
+
|
|
47
|
+
verdict = if total < Helpers::Constants::QUORUM
|
|
48
|
+
:pending
|
|
49
|
+
elsif approve_count > reject_count
|
|
50
|
+
:approved
|
|
51
|
+
else
|
|
52
|
+
:rejected
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
{ success: true, proposal_id: proposal_id, approve_count: approve_count,
|
|
56
|
+
reject_count: reject_count, total: total, verdict: verdict }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def approve_proposal(proposal_id:, _reason: nil, **)
|
|
60
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
61
|
+
return { success: false, error: :not_found } unless proposal
|
|
62
|
+
|
|
63
|
+
proposal.transition!(:approved)
|
|
64
|
+
{ success: true, proposal_id: proposal_id, status: :approved }
|
|
65
|
+
rescue ArgumentError => e
|
|
66
|
+
{ success: false, error: e.message }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def reject_proposal(proposal_id:, reason: nil, **)
|
|
70
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
71
|
+
return { success: false, error: :not_found } unless proposal
|
|
72
|
+
|
|
73
|
+
proposal.transition!(:rejected)
|
|
74
|
+
{ success: true, proposal_id: proposal_id, status: :rejected, reason: reason }
|
|
75
|
+
rescue ArgumentError => e
|
|
76
|
+
{ success: false, error: e.message }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def governance_stats(**)
|
|
80
|
+
all_votes = votes_mutex.synchronize { votes_store.dup }
|
|
81
|
+
|
|
82
|
+
total_votes = all_votes.values.sum(&:size)
|
|
83
|
+
proposals_with_votes = all_votes.size
|
|
84
|
+
|
|
85
|
+
vote_summary = all_votes.transform_values do |ballots|
|
|
86
|
+
{
|
|
87
|
+
approve: ballots.count { |b| b[:vote] == :approve },
|
|
88
|
+
reject: ballots.count { |b| b[:vote] == :reject },
|
|
89
|
+
total: ballots.size
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
proposal_stats = Runners::Proposer.proposal_stats
|
|
94
|
+
by_status = proposal_stats[:stats][:by_status]
|
|
95
|
+
|
|
96
|
+
governance_breakdown = Helpers::Constants::GOVERNANCE_STATUSES.to_h do |s|
|
|
97
|
+
[s, by_status[s] || 0]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
{
|
|
101
|
+
success: true,
|
|
102
|
+
total_votes: total_votes,
|
|
103
|
+
proposals_with_votes: proposals_with_votes,
|
|
104
|
+
vote_summary: vote_summary,
|
|
105
|
+
governance_breakdown: governance_breakdown
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def votes_store
|
|
112
|
+
@votes_store ||= {}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def votes_mutex
|
|
116
|
+
@votes_mutex ||= Mutex.new
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module Retrospective
|
|
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
|
+
# Generates a summary of growth activity: proposals by status, recent builds, failures
|
|
14
|
+
def session_report(**)
|
|
15
|
+
proposals = Runners::Proposer.proposal_stats
|
|
16
|
+
recent = Runners::Proposer.list_proposals(limit: 10)
|
|
17
|
+
|
|
18
|
+
built = recent[:proposals].select { |p| %i[passing wired active].include?(p[:status]) }
|
|
19
|
+
failed = recent[:proposals].select { |p| %i[build_failed rejected pruned].include?(p[:status]) }
|
|
20
|
+
in_progress = recent[:proposals].select { |p| %i[proposed evaluating approved building testing].include?(p[:status]) }
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
success: true,
|
|
24
|
+
summary: {
|
|
25
|
+
total_proposals: proposals[:stats][:total],
|
|
26
|
+
by_status: proposals[:stats][:by_status],
|
|
27
|
+
recent_built: built.map { |p| { id: p[:id], name: p[:name], status: p[:status] } },
|
|
28
|
+
recent_failed: failed.map { |p| { id: p[:id], name: p[:name], status: p[:status] } },
|
|
29
|
+
in_progress: in_progress.map { |p| { id: p[:id], name: p[:name], status: p[:status] } }
|
|
30
|
+
},
|
|
31
|
+
generated_at: Time.now.utc
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Tracks extension count, quality, coverage over time
|
|
36
|
+
# Returns snapshot metrics suitable for time-series storage
|
|
37
|
+
def trend_analysis(extensions: [], **)
|
|
38
|
+
profile = Runners::Analyzer.cognitive_profile(existing_extensions: extensions.empty? ? nil : extensions)
|
|
39
|
+
ranked = extensions.empty? ? [] : Helpers::FitnessEvaluator.rank(extensions)
|
|
40
|
+
|
|
41
|
+
avg_fitness = ranked.empty? ? 0.0 : (ranked.sum { |e| e[:fitness] } / ranked.size).round(3)
|
|
42
|
+
prune_count = ranked.count { |e| e[:fitness] < Helpers::Constants::PRUNE_THRESHOLD }
|
|
43
|
+
healthy_count = ranked.count { |e| e[:fitness] >= Helpers::Constants::IMPROVEMENT_THRESHOLD }
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
success: true,
|
|
47
|
+
snapshot: {
|
|
48
|
+
extension_count: ranked.size,
|
|
49
|
+
overall_coverage: profile[:overall_coverage],
|
|
50
|
+
model_coverage: profile[:model_coverage]&.map { |m| { model: m[:model], coverage: m[:coverage] } },
|
|
51
|
+
avg_fitness: avg_fitness,
|
|
52
|
+
healthy_extensions: healthy_count,
|
|
53
|
+
prune_candidates: prune_count,
|
|
54
|
+
improvement_candidates: ranked.size - healthy_count - prune_count
|
|
55
|
+
},
|
|
56
|
+
generated_at: Time.now.utc
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Identifies patterns from build failures to improve future LLM prompts
|
|
61
|
+
def learning_extraction(**)
|
|
62
|
+
all_proposals = Runners::Proposer.list_proposals(limit: 100)
|
|
63
|
+
proposals = all_proposals[:proposals]
|
|
64
|
+
|
|
65
|
+
failed = proposals.select { |p| p[:status] == :build_failed }
|
|
66
|
+
rejected = proposals.select { |p| p[:status] == :rejected }
|
|
67
|
+
succeeded = proposals.select { |p| %i[passing wired active].include?(p[:status]) }
|
|
68
|
+
|
|
69
|
+
# Category success rates
|
|
70
|
+
category_stats = compute_category_stats(proposals)
|
|
71
|
+
|
|
72
|
+
# Extract patterns from failures
|
|
73
|
+
failure_patterns = extract_failure_patterns(failed)
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
success: true,
|
|
77
|
+
learnings: {
|
|
78
|
+
total_analyzed: proposals.size,
|
|
79
|
+
success_rate: proposals.empty? ? 0.0 : (succeeded.size.to_f / proposals.size).round(3),
|
|
80
|
+
rejection_rate: proposals.empty? ? 0.0 : (rejected.size.to_f / proposals.size).round(3),
|
|
81
|
+
build_failure_rate: proposals.empty? ? 0.0 : (failed.size.to_f / proposals.size).round(3),
|
|
82
|
+
category_stats: category_stats,
|
|
83
|
+
failure_patterns: failure_patterns,
|
|
84
|
+
recommendations: generate_recommendations(category_stats, failure_patterns)
|
|
85
|
+
},
|
|
86
|
+
generated_at: Time.now.utc
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def compute_category_stats(proposals)
|
|
93
|
+
by_category = proposals.group_by { |p| p[:category] }
|
|
94
|
+
by_category.transform_values do |cat_proposals|
|
|
95
|
+
succeeded = cat_proposals.count { |p| %i[passing wired active].include?(p[:status]) }
|
|
96
|
+
{
|
|
97
|
+
total: cat_proposals.size,
|
|
98
|
+
succeeded: succeeded,
|
|
99
|
+
success_rate: cat_proposals.empty? ? 0.0 : (succeeded.to_f / cat_proposals.size).round(3)
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def extract_failure_patterns(failed_proposals)
|
|
105
|
+
return [] if failed_proposals.empty?
|
|
106
|
+
|
|
107
|
+
# Group failures by category to identify problematic areas
|
|
108
|
+
by_category = failed_proposals.group_by { |p| p[:category] }
|
|
109
|
+
patterns = by_category.map do |category, proposals|
|
|
110
|
+
{ category: category, failure_count: proposals.size,
|
|
111
|
+
names: proposals.map { |p| p[:name] } }
|
|
112
|
+
end
|
|
113
|
+
patterns.sort_by { |p| -p[:failure_count] }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def generate_recommendations(category_stats, failure_patterns)
|
|
117
|
+
recs = []
|
|
118
|
+
|
|
119
|
+
# Recommend avoiding categories with high failure rates
|
|
120
|
+
category_stats.each do |category, stats|
|
|
121
|
+
if stats[:total] >= 3 && stats[:success_rate] < 0.3
|
|
122
|
+
recs << { type: :avoid_category, category: category,
|
|
123
|
+
reason: "low success rate (#{(stats[:success_rate] * 100).round}%)" }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Recommend focus on categories with high success rates
|
|
127
|
+
if stats[:total] >= 3 && stats[:success_rate] > 0.8
|
|
128
|
+
recs << { type: :focus_category, category: category,
|
|
129
|
+
reason: "high success rate (#{(stats[:success_rate] * 100).round}%)" }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Flag recurring failure patterns
|
|
134
|
+
failure_patterns.each do |pattern|
|
|
135
|
+
if pattern[:failure_count] >= 3
|
|
136
|
+
recs << { type: :investigate_failures, category: pattern[:category],
|
|
137
|
+
reason: "#{pattern[:failure_count]} build failures" }
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
recs
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module MindGrowth
|
|
6
|
+
module Runners
|
|
7
|
+
module RiskAssessor
|
|
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
|
+
HIGH_BLAST_CATEGORIES = %i[safety coordination].freeze
|
|
14
|
+
MEDIUM_BLAST_CATEGORIES = %i[cognition].freeze
|
|
15
|
+
HOT_PATH_CATEGORIES = %i[perception memory].freeze
|
|
16
|
+
|
|
17
|
+
def assess_risk(proposal_id:, **)
|
|
18
|
+
proposal = Runners::Proposer.get_proposal_object(proposal_id)
|
|
19
|
+
return { success: false, error: :not_found } unless proposal
|
|
20
|
+
|
|
21
|
+
dimensions = evaluate_dimensions(proposal)
|
|
22
|
+
tier = calculate_tier(dimensions)
|
|
23
|
+
recommendation = Helpers::Constants::RISK_RECOMMENDATIONS[tier]
|
|
24
|
+
|
|
25
|
+
{ success: true, proposal_id: proposal_id, risk_tier: tier,
|
|
26
|
+
dimensions: dimensions, recommendation: recommendation }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def risk_summary(proposals: nil, **)
|
|
30
|
+
ids = if proposals
|
|
31
|
+
Array(proposals).map { |p| p.is_a?(Hash) ? p[:id] : p.to_s }
|
|
32
|
+
else
|
|
33
|
+
Runners::Proposer.list_proposals(limit: 100)[:proposals].map { |p| p[:id] }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
results = ids.filter_map do |id|
|
|
37
|
+
result = assess_risk(proposal_id: id)
|
|
38
|
+
next unless result[:success]
|
|
39
|
+
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
grouped = Helpers::Constants::RISK_TIERS.to_h { |tier| [tier, []] }
|
|
44
|
+
results.each { |r| grouped[r[:risk_tier]] << r }
|
|
45
|
+
|
|
46
|
+
{ success: true, total: results.size, by_tier: grouped }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def evaluate_dimensions(proposal)
|
|
52
|
+
helper_count = Array(proposal.helpers).size
|
|
53
|
+
category = proposal.category.to_sym
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
complexity: complexity_level(helper_count, Array(proposal.runner_methods).size),
|
|
57
|
+
blast_radius: blast_radius_level(category),
|
|
58
|
+
reversibility: :high,
|
|
59
|
+
performance_impact: performance_impact_level(category)
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def complexity_level(helper_count, runner_count)
|
|
64
|
+
total = helper_count + runner_count
|
|
65
|
+
if total >= 7
|
|
66
|
+
:high
|
|
67
|
+
elsif total >= 4
|
|
68
|
+
:medium
|
|
69
|
+
else
|
|
70
|
+
:low
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def blast_radius_level(category)
|
|
75
|
+
if HIGH_BLAST_CATEGORIES.include?(category)
|
|
76
|
+
:high
|
|
77
|
+
elsif MEDIUM_BLAST_CATEGORIES.include?(category)
|
|
78
|
+
:medium
|
|
79
|
+
else
|
|
80
|
+
:low
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def performance_impact_level(category)
|
|
85
|
+
HOT_PATH_CATEGORIES.include?(category) ? :medium : :low
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def calculate_tier(dimensions)
|
|
89
|
+
# Reversibility is a positive attribute (high = easily reversed) — exclude from risk calc
|
|
90
|
+
risk_values = dimensions.except(:reversibility).values
|
|
91
|
+
|
|
92
|
+
if risk_values.include?(:critical)
|
|
93
|
+
:critical
|
|
94
|
+
elsif risk_values.include?(:high)
|
|
95
|
+
:high
|
|
96
|
+
elsif risk_values.include?(:medium)
|
|
97
|
+
:medium
|
|
98
|
+
else
|
|
99
|
+
:low
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -17,6 +17,9 @@ require 'legion/extensions/mind_growth/runners/validator'
|
|
|
17
17
|
require 'legion/extensions/mind_growth/runners/orchestrator'
|
|
18
18
|
require 'legion/extensions/mind_growth/runners/wirer'
|
|
19
19
|
require 'legion/extensions/mind_growth/runners/integration_tester'
|
|
20
|
+
require 'legion/extensions/mind_growth/runners/retrospective'
|
|
21
|
+
require 'legion/extensions/mind_growth/runners/governance'
|
|
22
|
+
require 'legion/extensions/mind_growth/runners/risk_assessor'
|
|
20
23
|
require 'legion/extensions/mind_growth/client'
|
|
21
24
|
|
|
22
25
|
module Legion
|