superinstance-equipment-consensus-engine 1.0.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.
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module SuperInstance
6
+ module Equipment
7
+ module ConsensusEngine
8
+ # Types module containing shared type constants and enums
9
+
10
+ # Types of tripartite perspectives
11
+ module PerspectiveType
12
+ PATHOS = :pathos
13
+ LOGOS = :logos
14
+ ETHOS = :ethos
15
+
16
+ ALL = Set[:pathos, :logos, :ethos].freeze
17
+
18
+ def self.valid?(value)
19
+ ALL.include?(value)
20
+ end
21
+ end
22
+
23
+ # Alias for TripartitePerspective
24
+ TripartitePerspective = PerspectiveType
25
+
26
+ # Types of domains that affect perspective weighting
27
+ module DomainType
28
+ FACTUAL = :factual
29
+ EMOTIONAL = :emotional
30
+ SENSITIVE = :sensitive
31
+ CREATIVE = :creative
32
+ BALANCED = :balanced
33
+ TECHNICAL = :technical
34
+ SOCIAL = :social
35
+ BUSINESS = :business
36
+ PERSONAL = :personal
37
+ MARITIME = :maritime
38
+
39
+ ALL = Set[
40
+ :factual, :emotional, :sensitive, :creative, :balanced,
41
+ :technical, :social, :business, :personal, :maritime
42
+ ].freeze
43
+
44
+ def self.valid?(value)
45
+ ALL.include?(value)
46
+ end
47
+ end
48
+
49
+ # Types of conflicts that can occur between perspectives
50
+ module ConflictType
51
+ FUNDAMENTAL_DISAGREEMENT = :fundamental_disagreement
52
+ UNCERTAINTY = :uncertainty
53
+ PARTIAL_DISAGREEMENT = :partial_disagreement
54
+ WEIGHT_IMBALANCE = :weight_imbalance
55
+ CROSS_PERSPECTIVE_TENSION = :cross_perspective_tension
56
+ CONTEXT_INCONSISTENCY = :context_inconsistency
57
+
58
+ ALL = Set[
59
+ :fundamental_disagreement, :uncertainty, :partial_disagreement,
60
+ :weight_imbalance, :cross_perspective_tension, :context_inconsistency
61
+ ].freeze
62
+ end
63
+
64
+ # Severity levels for conflicts
65
+ module ConflictSeverity
66
+ LOW = :low
67
+ MEDIUM = :medium
68
+ HIGH = :high
69
+ CRITICAL = :critical
70
+
71
+ ALL = Set[:low, :medium, :high, :critical].freeze
72
+ end
73
+
74
+ # Strategies for resolving conflicts
75
+ module ResolutionStrategy
76
+ WEIGHTED_VOTING = :weighted_voting
77
+ DELIBERATION_EXTENSION = :deliberation_extension
78
+ REFRAMING = :reframing
79
+ ESCALATION = :escalation
80
+ COMPROMISE = :compromise
81
+ CONDITIONAL_APPROVAL = :conditional_approval
82
+ SUSPENSION = :suspension
83
+ PERSPECTIVE_DOMINANCE = :perspective_dominance
84
+
85
+ ALL = Set[
86
+ :weighted_voting, :deliberation_extension, :reframing,
87
+ :escalation, :compromise, :conditional_approval,
88
+ :suspension, :perspective_dominance
89
+ ].freeze
90
+ end
91
+
92
+ # Deliberation mode affects how perspectives interact
93
+ module DeliberationMode
94
+ COLLABORATIVE = :collaborative
95
+ ADVERSARIAL = :adversarial
96
+ INQUISITIVE = :inquisitive
97
+ SYNTHESIZING = :synthesizing
98
+
99
+ ALL = Set[:collaborative, :adversarial, :inquisitive, :synthesizing].freeze
100
+ end
101
+
102
+ # Audit entry action types
103
+ module AuditAction
104
+ DELIBERATION_START = :deliberation_start
105
+ ROUND_COMPLETE = :round_complete
106
+ CONFLICT_DETECTED = :conflict_detected
107
+ CONFLICT_RESOLVED = :conflict_resolved
108
+ CONSENSUS_REACHED = :consensus_reached
109
+ TIMEOUT = :timeout
110
+ ERROR = :error
111
+ DELIBERATION_COMPLETE = :deliberation_complete
112
+
113
+ ALL = Set[
114
+ :deliberation_start, :round_complete, :conflict_detected,
115
+ :conflict_resolved, :consensus_reached, :timeout,
116
+ :error, :deliberation_complete
117
+ ].freeze
118
+ end
119
+
120
+ # Logial structure types for logos perspective
121
+ module LogicalStructure
122
+ DEDUCTIVE = :deductive
123
+ INDUCTIVE = :inductive
124
+ ABDUCTIVE = :abductive
125
+ ANALOGICAL = :analogical
126
+
127
+ ALL = Set[:deductive, :inductive, :abductive, :analogical].freeze
128
+ end
129
+
130
+ # Ethical framework types for ethos perspective
131
+ module EthicalFramework
132
+ UTILITARIAN = :utilitarian
133
+ DEONTOLOGICAL = :deontological
134
+ VIRTUE_ETHICS = :virtue_ethics
135
+ CARE_ETHICS = :care_ethics
136
+
137
+ ALL = Set[:utilitarian, :deontological, :virtue_ethics, :care_ethics].freeze
138
+ end
139
+
140
+ # Cross-examination evaluation types
141
+ module CrossExaminationEvaluation
142
+ SATISFACTORY = :satisfactory
143
+ UNSATISFACTORY = :unsatisfactory
144
+ NEEDS_CLARIFICATION = :needs_clarification
145
+
146
+ ALL = Set[:satisfactory, :unsatisfactory, :needs_clarification].freeze
147
+ end
148
+
149
+ # Keyword sets for verdict analysis
150
+ module VerdictIndicators
151
+ POSITIVE = Set[
152
+ 'yes', 'agree', 'support', 'affirm', 'positive', 'true', 'proceed'
153
+ ].freeze
154
+
155
+ NEGATIVE = Set[
156
+ 'no', 'disagree', 'oppose', 'reject', 'negative', 'false', 'decline'
157
+ ].freeze
158
+ end
159
+
160
+ # Keyword sets for domain detection
161
+ module DomainKeywords
162
+ FACTUAL = {
163
+ 'data' => 2, 'research' => 2, 'study' => 1, 'analysis' => 1,
164
+ 'evidence' => 2, 'scientific' => 2, 'measurement' => 1,
165
+ 'statistic' => 2, 'empirical' => 2, 'hypothesis' => 1,
166
+ 'experiment' => 1, 'result' => 1, 'fact' => 1
167
+ }.freeze
168
+
169
+ EMOTIONAL = {
170
+ 'feel' => 2, 'emotion' => 2, 'relationship' => 1, 'care' => 1,
171
+ 'love' => 2, 'passion' => 2, 'heart' => 2, 'empathy' => 2,
172
+ 'connection' => 1, 'support' => 1, 'understand' => 1,
173
+ 'personal' => 1, 'family' => 1, 'friend' => 1
174
+ }.freeze
175
+
176
+ SENSITIVE = {
177
+ 'ethics' => 2, 'moral' => 2, 'right' => 1, 'wrong' => 1,
178
+ 'justice' => 2, 'fair' => 1, 'equality' => 2, 'rights' => 2,
179
+ 'dignity' => 2, 'vulnerable' => 2, 'discrimination' => 2,
180
+ 'privacy' => 1, 'consent' => 2, 'harm' => 2
181
+ }.freeze
182
+
183
+ CREATIVE = {
184
+ 'creative' => 2, 'innovative' => 2, 'design' => 1, 'art' => 2,
185
+ 'imagine' => 1, 'explore' => 1, 'novel' => 1, 'original' => 2,
186
+ 'express' => 1, 'aesthetic' => 2, 'beauty' => 1, 'inspire' => 1,
187
+ 'vision' => 1, 'transform' => 1
188
+ }.freeze
189
+
190
+ TECHNICAL = {
191
+ 'technical' => 2, 'engineering' => 2, 'system' => 1,
192
+ 'implement' => 1, 'architecture' => 2, 'code' => 1,
193
+ 'algorithm' => 2, 'optimize' => 1, 'performance' => 1,
194
+ 'infrastructure' => 2, 'specification' => 1, 'integration' => 1,
195
+ 'deploy' => 1, 'scalability' => 1
196
+ }.freeze
197
+
198
+ SOCIAL = {
199
+ 'community' => 2, 'society' => 2, 'public' => 1, 'social' => 2,
200
+ 'people' => 1, 'collective' => 2, 'together' => 1, 'group' => 1,
201
+ 'shared' => 1, 'common' => 1, 'collaborative' => 1,
202
+ 'participate' => 1, 'democratic' => 2, 'citizens' => 2
203
+ }.freeze
204
+
205
+ BUSINESS = {
206
+ 'business' => 2, 'profit' => 2, 'market' => 1, 'revenue' => 2,
207
+ 'customer' => 1, 'strategy' => 1, 'competitive' => 1,
208
+ 'investment' => 1, 'roi' => 2, 'stakeholder' => 1, 'growth' => 1,
209
+ 'enterprise' => 1, 'commercial' => 2, 'industry' => 1
210
+ }.freeze
211
+
212
+ PERSONAL = {
213
+ 'personal' => 2, 'individual' => 1, 'self' => 2, 'my' => 1,
214
+ 'myself' => 2, 'life' => 1, 'choice' => 1, 'decision' => 1,
215
+ 'goal' => 1, 'future' => 1, 'happiness' => 2, 'fulfillment' => 2,
216
+ 'wellbeing' => 1, 'career' => 1
217
+ }.freeze
218
+
219
+ MARITIME = {
220
+ 'vessel' => 2, 'crew' => 2, 'safety' => 2, 'captain' => 2,
221
+ 'fleet' => 1, 'navigation' => 2, 'weather' => 1, 'sea' => 1,
222
+ 'port' => 1, 'harbor' => 1, 'maritime' => 2, 'fishing' => 1,
223
+ 'catch' => 1, 'tide' => 1, 'anchor' => 1, 'deck' => 1,
224
+ 'haul' => 1, 'sortie' => 2, 'bearing' => 1, 'course' => 1
225
+ }.freeze
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SuperInstance
4
+ module Equipment
5
+ module ConsensusEngine
6
+ VERSION = '1.0.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,438 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+
5
+ module SuperInstance
6
+ module Equipment
7
+ module ConsensusEngine
8
+ # WeightCalculator - Domain-specific weight calculation for perspectives
9
+ #
10
+ # Calculates appropriate weights for Pathos, Logos, and Ethos perspectives
11
+ # based on the domain of the deliberation.
12
+ #
13
+ # @example
14
+ # calculator = SuperInstance::Equipment::ConsensusEngine::WeightCalculator.new
15
+ #
16
+ # # Get weights for a factual domain
17
+ # factual_profile = calculator.get_profile(:factual)
18
+ # puts factual_profile[:logos_weight] # 0.60
19
+ #
20
+ # # Calculate adjusted weights based on content
21
+ # adjusted = calculator.calculate_adjusted_weights(
22
+ # :sensitive,
23
+ # 'This decision affects vulnerable populations...'
24
+ # )
25
+ class WeightCalculator
26
+ # Domain characteristics for analysis
27
+ DOMAIN_CHARACTERISTICS = {
28
+ factual: {
29
+ emotional_importance: 0.2,
30
+ logical_importance: 0.8,
31
+ ethical_importance: 0.4,
32
+ uncertainty_level: 0.3,
33
+ stakeholder_complexity: 0.3
34
+ },
35
+ emotional: {
36
+ emotional_importance: 0.8,
37
+ logical_importance: 0.3,
38
+ ethical_importance: 0.5,
39
+ uncertainty_level: 0.5,
40
+ stakeholder_complexity: 0.7
41
+ },
42
+ sensitive: {
43
+ emotional_importance: 0.6,
44
+ logical_importance: 0.4,
45
+ ethical_importance: 0.9,
46
+ uncertainty_level: 0.4,
47
+ stakeholder_complexity: 0.8
48
+ },
49
+ creative: {
50
+ emotional_importance: 0.7,
51
+ logical_importance: 0.5,
52
+ ethical_importance: 0.4,
53
+ uncertainty_level: 0.6,
54
+ stakeholder_complexity: 0.4
55
+ },
56
+ balanced: {
57
+ emotional_importance: 0.5,
58
+ logical_importance: 0.5,
59
+ ethical_importance: 0.5,
60
+ uncertainty_level: 0.5,
61
+ stakeholder_complexity: 0.5
62
+ },
63
+ technical: {
64
+ emotional_importance: 0.1,
65
+ logical_importance: 0.9,
66
+ ethical_importance: 0.3,
67
+ uncertainty_level: 0.2,
68
+ stakeholder_complexity: 0.2
69
+ },
70
+ social: {
71
+ emotional_importance: 0.7,
72
+ logical_importance: 0.4,
73
+ ethical_importance: 0.6,
74
+ uncertainty_level: 0.5,
75
+ stakeholder_complexity: 0.9
76
+ },
77
+ business: {
78
+ emotional_importance: 0.4,
79
+ logical_importance: 0.7,
80
+ ethical_importance: 0.5,
81
+ uncertainty_level: 0.4,
82
+ stakeholder_complexity: 0.6
83
+ },
84
+ maritime: {
85
+ emotional_importance: 0.3,
86
+ logical_importance: 0.8,
87
+ ethical_importance: 0.6,
88
+ uncertainty_level: 0.5,
89
+ stakeholder_complexity: 0.4
90
+ },
91
+ personal: {
92
+ emotional_importance: 0.8,
93
+ logical_importance: 0.4,
94
+ ethical_importance: 0.4,
95
+ uncertainty_level: 0.6,
96
+ stakeholder_complexity: 0.3
97
+ }
98
+ }.freeze
99
+
100
+ # Creates a new WeightCalculator instance
101
+ # @param custom_weights [Hash] Optional custom weight overrides to apply to all profiles
102
+ def initialize(custom_weights = {})
103
+ @profiles = build_default_profiles
104
+ @custom_overrides = custom_weights
105
+ end
106
+
107
+ # Gets the weight profile for a specific domain
108
+ # @param domain [Symbol] The domain to get weights for
109
+ # @return [Hash] The weight profile for the domain
110
+ def get_profile(domain)
111
+ base_profile = @profiles[domain]
112
+ raise ArgumentError, "Unknown domain: #{domain}" unless base_profile
113
+
114
+ # Apply custom overrides
115
+ base_profile.merge(@custom_overrides).merge(domain: domain)
116
+ end
117
+
118
+ # Sets a custom weight profile for a domain
119
+ # @param domain [Symbol] The domain to set
120
+ # @param weights [Hash] The weights to apply
121
+ def set_profile(domain, weights)
122
+ current = @profiles[domain]
123
+ raise ArgumentError, "Unknown domain: #{domain}" unless current
124
+
125
+ # Normalize weights to sum to 1
126
+ raw_pathos = weights[:pathos_weight] || current[:pathos_weight]
127
+ raw_logos = weights[:logos_weight] || current[:logos_weight]
128
+ raw_ethos = weights[:ethos_weight] || current[:ethos_weight]
129
+ total = raw_pathos + raw_logos + raw_ethos
130
+
131
+ @profiles[domain] = {
132
+ pathos_weight: raw_pathos / total,
133
+ logos_weight: raw_logos / total,
134
+ ethos_weight: raw_ethos / total,
135
+ domain: domain,
136
+ description: weights[:description] || current[:description],
137
+ adjustment_rules: current[:adjustment_rules]
138
+ }
139
+ end
140
+
141
+ # Calculates adjusted weights based on content analysis
142
+ # @param domain [Symbol] The base domain
143
+ # @param content [String] The content to analyze
144
+ # @param base_weights [Hash, nil] Optional base weights to start from
145
+ # @return [Hash] Adjusted weight profile
146
+ def calculate_adjusted_weights(domain, content, base_weights = nil)
147
+ base_profile = base_weights || get_profile(domain)
148
+ rules = base_profile[:adjustment_rules] || []
149
+
150
+ # Sort rules by priority
151
+ sorted_rules = rules.sort_by { |r| -r[:priority] }
152
+
153
+ pathos_weight = base_profile[:pathos_weight]
154
+ logos_weight = base_profile[:logos_weight]
155
+ ethos_weight = base_profile[:ethos_weight]
156
+
157
+ # Apply matching rules
158
+ sorted_rules.each do |rule|
159
+ if matches_condition(content, rule[:condition])
160
+ case rule[:perspective]
161
+ when :pathos
162
+ pathos_weight += rule[:adjustment]
163
+ when :logos
164
+ logos_weight += rule[:adjustment]
165
+ when :ethos
166
+ ethos_weight += rule[:adjustment]
167
+ end
168
+ end
169
+ end
170
+
171
+ # Normalize to sum to 1
172
+ total = pathos_weight + logos_weight + ethos_weight
173
+
174
+ {
175
+ pathos_weight: pathos_weight / total,
176
+ logos_weight: logos_weight / total,
177
+ ethos_weight: ethos_weight / total,
178
+ domain: domain,
179
+ description: "Adjusted profile for #{domain} domain based on content analysis",
180
+ adjustment_rules: rules
181
+ }
182
+ end
183
+
184
+ # Detects the most appropriate domain from content
185
+ # @param content [String] The content to analyze
186
+ # @return [Symbol] The detected domain
187
+ def detect_domain(content)
188
+ lower_content = content.downcase
189
+ scores = []
190
+
191
+ # Check for each domain type
192
+ scores << { domain: :factual, score: score_domain(lower_content, DomainKeywords::FACTUAL) }
193
+ scores << { domain: :emotional, score: score_domain(lower_content, DomainKeywords::EMOTIONAL) }
194
+ scores << { domain: :sensitive, score: score_domain(lower_content, DomainKeywords::SENSITIVE) }
195
+ scores << { domain: :creative, score: score_domain(lower_content, DomainKeywords::CREATIVE) }
196
+ scores << { domain: :technical, score: score_domain(lower_content, DomainKeywords::TECHNICAL) }
197
+ scores << { domain: :social, score: score_domain(lower_content, DomainKeywords::SOCIAL) }
198
+ scores << { domain: :business, score: score_domain(lower_content, DomainKeywords::BUSINESS) }
199
+ scores << { domain: :personal, score: score_domain(lower_content, DomainKeywords::PERSONAL) }
200
+ scores << { domain: :maritime, score: score_domain(lower_content, DomainKeywords::MARITIME) }
201
+
202
+ # Find highest score
203
+ scores.sort! { |a, b| b[:score] <=> a[:score] }
204
+
205
+ # If no strong signal, return balanced
206
+ return :balanced if scores[0][:score] < 3
207
+
208
+ scores[0][:domain]
209
+ end
210
+
211
+ # Gets domain characteristics
212
+ # @param domain [Symbol] The domain to get characteristics for
213
+ # @return [Hash] The domain characteristics
214
+ def get_domain_characteristics(domain)
215
+ DOMAIN_CHARACTERISTICS[domain].dup
216
+ end
217
+
218
+ # Lists all available domains
219
+ # @return [Array<Symbol>] Array of available domains
220
+ def list_domains
221
+ %i[factual emotional sensitive creative balanced technical social business personal maritime]
222
+ end
223
+
224
+ # Creates a custom weight profile by blending multiple domains
225
+ # @param domains [Array<Hash>] Domains to blend with weights [{ domain: :factual, weight: 0.5 }]
226
+ # @return [Hash] Blended weight profile
227
+ def blend_domains(domains)
228
+ if domains.empty?
229
+ return get_profile(:balanced)
230
+ end
231
+
232
+ # Normalize input weights
233
+ total_input_weight = domains.sum { |d| d[:weight] }
234
+ normalized_domains = domains.map do |d|
235
+ { domain: d[:domain], weight: d[:weight] / total_input_weight }
236
+ end
237
+
238
+ # Blend the weights
239
+ pathos_weight = 0.0
240
+ logos_weight = 0.0
241
+ ethos_weight = 0.0
242
+ all_rules = []
243
+
244
+ normalized_domains.each do |item|
245
+ profile = get_profile(item[:domain])
246
+ pathos_weight += profile[:pathos_weight] * item[:weight]
247
+ logos_weight += profile[:logos_weight] * item[:weight]
248
+ ethos_weight += profile[:ethos_weight] * item[:weight]
249
+ all_rules.concat(profile[:adjustment_rules] || [])
250
+ end
251
+
252
+ # Normalize to sum to 1
253
+ total = pathos_weight + logos_weight + ethos_weight
254
+
255
+ {
256
+ pathos_weight: pathos_weight / total,
257
+ logos_weight: logos_weight / total,
258
+ ethos_weight: ethos_weight / total,
259
+ domain: :balanced,
260
+ description: "Blended profile from: #{domains.map { |d| d[:domain] }.join(', ')}",
261
+ adjustment_rules: all_rules
262
+ }
263
+ end
264
+
265
+ # Validates a weight profile
266
+ # @param profile [Hash] Profile to validate
267
+ # @return [Hash] Validation result { valid: Boolean, errors: Array<String> }
268
+ def validate_profile(profile)
269
+ errors = []
270
+
271
+ if profile[:pathos_weight]
272
+ if profile[:pathos_weight] < 0 || profile[:pathos_weight] > 1
273
+ errors << 'pathos_weight must be between 0 and 1'
274
+ end
275
+ end
276
+
277
+ if profile[:logos_weight]
278
+ if profile[:logos_weight] < 0 || profile[:logos_weight] > 1
279
+ errors << 'logos_weight must be between 0 and 1'
280
+ end
281
+ end
282
+
283
+ if profile[:ethos_weight]
284
+ if profile[:ethos_weight] < 0 || profile[:ethos_weight] > 1
285
+ errors << 'ethos_weight must be between 0 and 1'
286
+ end
287
+ end
288
+
289
+ if profile[:pathos_weight] && profile[:logos_weight] && profile[:ethos_weight]
290
+ sum = profile[:pathos_weight] + profile[:logos_weight] + profile[:ethos_weight]
291
+ if (sum - 1.0).abs > 0.001
292
+ errors << "Weights must sum to 1, got #{sum.round(3)}"
293
+ end
294
+ end
295
+
296
+ { valid: errors.empty?, errors: errors }
297
+ end
298
+
299
+ private
300
+
301
+ def build_default_profiles
302
+ {
303
+ factual: {
304
+ pathos_weight: 0.15,
305
+ logos_weight: 0.60,
306
+ ethos_weight: 0.25,
307
+ domain: :factual,
308
+ description: 'Scientific and data-driven decisions prioritize logic over emotion',
309
+ adjustment_rules: [
310
+ { name: 'data_present', condition: 'Content contains statistical data or research findings', perspective: :logos, adjustment: 0.1, priority: 10 },
311
+ { name: 'human_subjects', condition: 'Research involves human subjects', perspective: :ethos, adjustment: 0.1, priority: 8 }
312
+ ]
313
+ },
314
+ emotional: {
315
+ pathos_weight: 0.50,
316
+ logos_weight: 0.20,
317
+ ethos_weight: 0.30,
318
+ domain: :emotional,
319
+ description: 'Human-centered decisions value emotional resonance highly',
320
+ adjustment_rules: [
321
+ { name: 'personal_story', condition: 'Content includes personal narratives or testimonials', perspective: :pathos, adjustment: 0.15, priority: 10 },
322
+ { name: 'group_dynamics', condition: 'Decision affects group relationships', perspective: :pathos, adjustment: 0.1, priority: 8 }
323
+ ]
324
+ },
325
+ sensitive: {
326
+ pathos_weight: 0.30,
327
+ logos_weight: 0.25,
328
+ ethos_weight: 0.45,
329
+ domain: :sensitive,
330
+ description: 'Ethically complex decisions prioritize moral considerations',
331
+ adjustment_rules: [
332
+ { name: 'vulnerable_populations', condition: 'Decision affects vulnerable populations', perspective: :ethos, adjustment: 0.15, priority: 10 },
333
+ { name: 'rights_implications', condition: 'Decision has rights implications', perspective: :ethos, adjustment: 0.1, priority: 9 }
334
+ ]
335
+ },
336
+ creative: {
337
+ pathos_weight: 0.40,
338
+ logos_weight: 0.30,
339
+ ethos_weight: 0.30,
340
+ domain: :creative,
341
+ description: 'Creative decisions balance all perspectives with slight emotional edge',
342
+ adjustment_rules: [
343
+ { name: 'innovation_focus', condition: 'Decision involves innovation or new approaches', perspective: :logos, adjustment: 0.05, priority: 7 },
344
+ { name: 'artistic_expression', condition: 'Decision involves artistic or creative expression', perspective: :pathos, adjustment: 0.1, priority: 8 }
345
+ ]
346
+ },
347
+ balanced: {
348
+ pathos_weight: 0.333,
349
+ logos_weight: 0.334,
350
+ ethos_weight: 0.333,
351
+ domain: :balanced,
352
+ description: 'Equal weighting for general-purpose deliberations',
353
+ adjustment_rules: []
354
+ },
355
+ technical: {
356
+ pathos_weight: 0.10,
357
+ logos_weight: 0.70,
358
+ ethos_weight: 0.20,
359
+ domain: :technical,
360
+ description: 'Engineering decisions strongly prioritize logical reasoning',
361
+ adjustment_rules: [
362
+ { name: 'safety_critical', condition: 'Decision involves safety-critical systems', perspective: :logos, adjustment: 0.05, priority: 10 },
363
+ { name: 'user_impact', condition: 'Technical change affects end users', perspective: :pathos, adjustment: 0.1, priority: 7 }
364
+ ]
365
+ },
366
+ social: {
367
+ pathos_weight: 0.40,
368
+ logos_weight: 0.25,
369
+ ethos_weight: 0.35,
370
+ domain: :social,
371
+ description: 'Community decisions value emotional and ethical dimensions',
372
+ adjustment_rules: [
373
+ { name: 'community_impact', condition: 'Decision affects community cohesion', perspective: :ethos, adjustment: 0.1, priority: 9 },
374
+ { name: 'public_opinion', condition: 'Decision will be subject to public scrutiny', perspective: :pathos, adjustment: 0.05, priority: 8 }
375
+ ]
376
+ },
377
+ business: {
378
+ pathos_weight: 0.25,
379
+ logos_weight: 0.45,
380
+ ethos_weight: 0.30,
381
+ domain: :business,
382
+ description: 'Business decisions balance logic with stakeholder impact',
383
+ adjustment_rules: [
384
+ { name: 'profit_pressure', condition: 'Financial metrics are primary consideration', perspective: :logos, adjustment: 0.1, priority: 8 },
385
+ { name: 'reputation_risk', condition: 'Decision affects company reputation', perspective: :ethos, adjustment: 0.1, priority: 9 }
386
+ ]
387
+ },
388
+ maritime: {
389
+ pathos_weight: 0.20,
390
+ logos_weight: 0.55,
391
+ ethos_weight: 0.25,
392
+ domain: :maritime,
393
+ description: 'Maritime operations prioritize safety, logistics, and crew welfare',
394
+ adjustment_rules: [
395
+ { name: 'safety_critical', condition: 'Decision involves crew safety or vessel integrity', perspective: :ethos, adjustment: 0.15, priority: 10 },
396
+ { name: 'weather_hazard', condition: 'Weather or sea conditions are a factor', perspective: :logos, adjustment: 0.1, priority: 9 },
397
+ { name: 'crew_welfare', condition: 'Decision affects crew rest, health, or morale', perspective: :pathos, adjustment: 0.1, priority: 8 },
398
+ { name: 'regulatory_compliance', condition: 'Decision involves catch limits, seasons, or regulations', perspective: :ethos, adjustment: 0.1, priority: 9 }
399
+ ]
400
+ },
401
+ personal: {
402
+ pathos_weight: 0.45,
403
+ logos_weight: 0.30,
404
+ ethos_weight: 0.25,
405
+ domain: :personal,
406
+ description: 'Personal decisions emphasize individual emotional needs',
407
+ adjustment_rules: [
408
+ { name: 'life_changing', condition: 'Decision has significant life impact', perspective: :pathos, adjustment: 0.1, priority: 10 },
409
+ { name: 'relationships', condition: 'Decision affects personal relationships', perspective: :ethos, adjustment: 0.1, priority: 9 }
410
+ ]
411
+ }
412
+ }
413
+ end
414
+
415
+ # Scores content against keyword weights
416
+ def score_domain(content, keywords)
417
+ score = 0.0
418
+ keywords.each do |keyword, weight|
419
+ score += weight if content.include?(keyword)
420
+ end
421
+ score
422
+ end
423
+
424
+ # Checks if content matches a condition
425
+ def matches_condition(content, condition)
426
+ lower_content = content.downcase
427
+ lower_condition = condition.downcase
428
+
429
+ # Simple keyword matching
430
+ keywords = lower_condition.scan(/\b[a-z]+\b/)
431
+ matching_keywords = keywords.select { |kw| lower_content.include?(kw) }
432
+
433
+ matching_keywords.length >= (keywords.length * 0.3).ceil
434
+ end
435
+ end
436
+ end
437
+ end
438
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'equipment/consensus_engine/version'
4
+
5
+ require_relative 'equipment/consensus_engine/types'
6
+ require_relative 'equipment/consensus_engine/weight_calculator'
7
+ require_relative 'equipment/consensus_engine/tripartite_deliberation'
8
+ require_relative 'equipment/consensus_engine/conflict_resolution'
9
+ require_relative 'equipment/consensus_engine/consensus_engine'
10
+
11
+ module SuperInstance
12
+ module Equipment
13
+ module ConsensusEngine
14
+ # Main entry point for the ConsensusEngine gem
15
+ end
16
+ end
17
+ end