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,645 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+
5
+ module SuperInstance
6
+ module Equipment
7
+ module ConsensusEngine
8
+ # TripartiteDeliberation - Pathos/Logos/Ethos 3-agent deliberation
9
+ #
10
+ # Implements the classical rhetorical framework for argumentation
11
+ # through three fundamental modes of persuasion.
12
+ #
13
+ # The tripartite framework originates from Aristotle's Rhetoric and provides
14
+ # a comprehensive approach to argumentation:
15
+ #
16
+ # - **Pathos**: Appeals to emotion, intent, and human experience
17
+ # - **Logos**: Appeals to logic, reason, and rational argument
18
+ # - **Ethos**: Appeals to ethics, credibility, and moral character
19
+ #
20
+ # @example
21
+ # deliberation = SuperInstance::Equipment::ConsensusEngine::TripartiteDeliberation.new
22
+ #
23
+ # pathos_analysis = deliberation.analyze(
24
+ # :pathos,
25
+ # 'Should we reduce work hours?',
26
+ # 'A company is considering a 4-day work week'
27
+ # )
28
+ class TripartiteDeliberation
29
+ # Creates a new TripartiteDeliberation instance
30
+ def initialize
31
+ @perspective_configs = {
32
+ pathos: { threshold: 0.6, style: :collaborative },
33
+ logos: { threshold: 0.7, style: :inquisitive },
34
+ ethos: { threshold: 0.75, style: :adversarial }
35
+ }
36
+ end
37
+
38
+ # Analyzes a proposition from a specific perspective
39
+ # @param perspective [Symbol] The perspective to analyze from
40
+ # @param proposition [String] The proposition to analyze
41
+ # @param context [String] The context for deliberation
42
+ # @param previous_opinions [Array<Hash>] Opinions from previous rounds
43
+ # @return [Hash] The perspective's analysis
44
+ def analyze(perspective, proposition, context, previous_opinions = [])
45
+ case perspective
46
+ when :pathos
47
+ analyze_from_pathos(proposition, context, previous_opinions)
48
+ when :logos
49
+ analyze_from_logos(proposition, context, previous_opinions)
50
+ when :ethos
51
+ analyze_from_ethos(proposition, context, previous_opinions)
52
+ else
53
+ raise ArgumentError, "Unknown perspective: #{perspective}"
54
+ end
55
+ end
56
+
57
+ # Sets the configuration for a perspective
58
+ # @param perspective [Symbol] The perspective to configure
59
+ # @param config [Hash] Configuration options { threshold: Float, style: Symbol }
60
+ def set_perspective_config(perspective, config)
61
+ current = @perspective_configs[perspective]
62
+ return unless current
63
+
64
+ @perspective_configs[perspective] = {
65
+ threshold: config[:threshold] || current[:threshold],
66
+ style: config[:style] || current[:style]
67
+ }
68
+ end
69
+
70
+ # Gets the configuration for a perspective
71
+ # @param perspective [Symbol] The perspective to get config for
72
+ # @return [Hash] Configuration { threshold: Float, style: Symbol }
73
+ def get_perspective_config(perspective)
74
+ config = @perspective_configs[perspective]
75
+ raise ArgumentError, "Unknown perspective: #{perspective}" unless config
76
+ config.dup
77
+ end
78
+
79
+ private
80
+
81
+ # Analyzes from the Pathos perspective (emotion/intent)
82
+ def analyze_from_pathos(proposition, context, previous_opinions)
83
+ # Extract emotional dimensions
84
+ characteristics = extract_pathos_characteristics(proposition, context)
85
+
86
+ # Consider previous emotional arguments
87
+ previous_pathos = previous_opinions.find { |op| op[:perspective] == :pathos }
88
+
89
+ # Generate emotional analysis
90
+ verdict = generate_pathos_verdict(proposition, characteristics, previous_pathos)
91
+ confidence = calculate_pathos_confidence(characteristics, previous_opinions)
92
+ arguments = generate_pathos_arguments(characteristics)
93
+ concerns = identify_pathos_concerns(characteristics)
94
+
95
+ {
96
+ perspective: :pathos,
97
+ verdict: verdict,
98
+ confidence: confidence,
99
+ arguments: arguments,
100
+ concerns: concerns,
101
+ emotional_tone: characteristics[:primary_emotion],
102
+ suggestions: generate_pathos_suggestions(characteristics)
103
+ }
104
+ end
105
+
106
+ # Analyzes from the Logos perspective (logic/reason)
107
+ def analyze_from_logos(proposition, context, previous_opinions)
108
+ # Extract logical structure
109
+ characteristics = extract_logos_characteristics(proposition, context)
110
+
111
+ # Consider previous logical arguments
112
+ previous_logos = previous_opinions.find { |op| op[:perspective] == :logos }
113
+
114
+ # Generate logical analysis
115
+ verdict = generate_logos_verdict(proposition, characteristics, previous_logos)
116
+ confidence = calculate_logos_confidence(characteristics, previous_opinions)
117
+ arguments = generate_logos_arguments(characteristics)
118
+ concerns = identify_logos_concerns(characteristics)
119
+ logical_validity = assess_logical_validity(characteristics)
120
+
121
+ {
122
+ perspective: :logos,
123
+ verdict: verdict,
124
+ confidence: confidence,
125
+ arguments: arguments,
126
+ concerns: concerns,
127
+ logical_validity: logical_validity,
128
+ suggestions: generate_logos_suggestions(characteristics)
129
+ }
130
+ end
131
+
132
+ # Analyzes from the Ethos perspective (ethics/truth)
133
+ def analyze_from_ethos(proposition, context, previous_opinions)
134
+ # Extract ethical dimensions
135
+ characteristics = extract_ethos_characteristics(proposition, context)
136
+
137
+ # Consider previous ethical arguments
138
+ previous_ethos = previous_opinions.find { |op| op[:perspective] == :ethos }
139
+
140
+ # Generate ethical analysis
141
+ verdict = generate_ethos_verdict(proposition, characteristics, previous_ethos)
142
+ confidence = calculate_ethos_confidence(characteristics, previous_opinions)
143
+ arguments = generate_ethos_arguments(characteristics)
144
+ concerns = identify_ethos_concerns(characteristics)
145
+ ethical_alignment = assess_ethical_alignment(characteristics)
146
+
147
+ {
148
+ perspective: :ethos,
149
+ verdict: verdict,
150
+ confidence: confidence,
151
+ arguments: arguments,
152
+ concerns: concerns,
153
+ ethical_alignment: ethical_alignment,
154
+ suggestions: generate_ethos_suggestions(characteristics)
155
+ }
156
+ end
157
+
158
+ # Extracts pathos characteristics from proposition and context
159
+ def extract_pathos_characteristics(proposition, context)
160
+ combined = "#{proposition} #{context}".downcase
161
+
162
+ # Detect primary emotion
163
+ emotions = %w[hope fear joy anger sadness surprise trust anticipation]
164
+ detected_emotions = emotions.select { |e| combined.include?(e) }
165
+ primary_emotion = detected_emotions[0] || 'neutral'
166
+
167
+ # Calculate emotional intensity based on emotional words
168
+ emotional_words = %w[urgent critical important essential vital crucial]
169
+ intensity = emotional_words.sum do |word|
170
+ combined.include?(word) ? 0.15 : 0
171
+ end
172
+ intensity = [intensity + 0.3, 1.0].min
173
+
174
+ # Identify stakeholders
175
+ stakeholders = identify_stakeholders(combined)
176
+
177
+ # Identify emotional risks
178
+ emotional_risks = identify_emotional_risks(combined)
179
+
180
+ {
181
+ primary_emotion: primary_emotion,
182
+ intensity: intensity,
183
+ stakeholders: stakeholders,
184
+ emotional_risks: emotional_risks
185
+ }
186
+ end
187
+
188
+ # Extracts logos characteristics from proposition and context
189
+ def extract_logos_characteristics(proposition, context)
190
+ combined = "#{proposition} #{context}".downcase
191
+
192
+ # Determine logical structure
193
+ logical_structure = :inductive
194
+ if combined.include?('therefore') || combined.include?('thus') || combined.include?('must')
195
+ logical_structure = :deductive
196
+ elsif combined.include?('likely') || combined.include?('probably') || combined.include?('suggests')
197
+ logical_structure = :abductive
198
+ elsif combined.include?('like') || combined.include?('similar') || combined.include?('comparable')
199
+ logical_structure = :analogical
200
+ end
201
+
202
+ # Extract premises
203
+ premises = extract_premises(combined)
204
+
205
+ # Identify assumptions
206
+ assumptions = identify_assumptions(combined)
207
+
208
+ # Identify logical risks
209
+ logical_risks = identify_logical_risks(combined)
210
+
211
+ {
212
+ logical_structure: logical_structure,
213
+ premises: premises,
214
+ assumptions: assumptions,
215
+ logical_risks: logical_risks
216
+ }
217
+ end
218
+
219
+ # Extracts ethos characteristics from proposition and context
220
+ def extract_ethos_characteristics(proposition, context)
221
+ combined = "#{proposition} #{context}".downcase
222
+
223
+ # Determine ethical framework
224
+ ethical_framework = :utilitarian
225
+ if combined.include?('rights') || combined.include?('duty') || combined.include?('obligation')
226
+ ethical_framework = :deontological
227
+ elsif combined.include?('virtue') || combined.include?('character') || combined.include?('integrity')
228
+ ethical_framework = :virtue_ethics
229
+ elsif combined.include?('care') || combined.include?('relationship') || combined.include?('empathy')
230
+ ethical_framework = :care_ethics
231
+ end
232
+
233
+ # Identify principles
234
+ principles = identify_principles(combined)
235
+
236
+ # Identify values at stake
237
+ values_at_stake = identify_values_at_stake(combined)
238
+
239
+ # Identify ethical risks
240
+ ethical_risks = identify_ethical_risks(combined)
241
+
242
+ {
243
+ ethical_framework: ethical_framework,
244
+ principles: principles,
245
+ values_at_stake: values_at_stake,
246
+ ethical_risks: ethical_risks
247
+ }
248
+ end
249
+
250
+ # Helper methods for pathos analysis
251
+ def identify_stakeholders(text)
252
+ stakeholders = []
253
+ if text.include?('employee') || text.include?('worker') || text.include?('staff')
254
+ stakeholders << 'employees'
255
+ end
256
+ if text.include?('customer') || text.include?('client') || text.include?('user')
257
+ stakeholders << 'customers'
258
+ end
259
+ if text.include?('community') || text.include?('society') || text.include?('public')
260
+ stakeholders << 'community'
261
+ end
262
+ if text.include?('environment') || text.include?('nature') || text.include?('ecosystem')
263
+ stakeholders << 'environment'
264
+ end
265
+ stakeholders.any? ? stakeholders : ['affected parties']
266
+ end
267
+
268
+ def identify_emotional_risks(text)
269
+ risks = []
270
+ if text.include?('change') || text.include?('transform')
271
+ risks << 'Resistance to change'
272
+ end
273
+ if text.include?('reduce') || text.include?('cut') || text.include?('decrease')
274
+ risks << 'Anxiety about loss'
275
+ end
276
+ if text.include?('increase') || text.include?('expand') || text.include?('grow')
277
+ risks << 'Fear of overwhelm'
278
+ end
279
+ risks.any? ? risks : ['Unknown emotional impact']
280
+ end
281
+
282
+ def generate_pathos_verdict(proposition, characteristics, previous_pathos)
283
+ emotional_appeal = characteristics[:intensity] > 0.6 ? 'strong' : 'moderate'
284
+ stakeholder_count = characteristics[:stakeholders].length
285
+
286
+ if previous_pathos
287
+ return "After reconsideration, the emotional impact on #{characteristics[:stakeholders].join(', ')} remains a key factor. The proposition has #{emotional_appeal} emotional appeal with #{characteristics[:primary_emotion]} as the primary emotion. Proceeding with caution is advised."
288
+ end
289
+
290
+ "From an emotional standpoint, this proposition affects #{stakeholder_count} stakeholder groups: #{characteristics[:stakeholders].join(', ')}. The primary emotion of #{characteristics[:primary_emotion]} with #{emotional_appeal} intensity suggests #{characteristics[:intensity] > 0.5 ? 'proceeding with empathetic consideration' : 'the emotional impact may be manageable'}."
291
+ end
292
+
293
+ def calculate_pathos_confidence(characteristics, previous_opinions)
294
+ confidence = 0.5
295
+
296
+ # Higher confidence with more identified stakeholders
297
+ confidence += [0.2, characteristics[:stakeholders].length * 0.05].min
298
+
299
+ # Higher confidence with clear emotional signal
300
+ if characteristics[:primary_emotion] != 'neutral'
301
+ confidence += 0.1
302
+ end
303
+
304
+ # Consider previous logos agreement
305
+ previous_logos = previous_opinions.find { |op| op[:perspective] == :logos }
306
+ if previous_logos && previous_logos[:confidence] > 0.6
307
+ confidence += 0.05
308
+ end
309
+
310
+ [confidence, 1.0].min
311
+ end
312
+
313
+ def generate_pathos_arguments(characteristics)
314
+ args = []
315
+
316
+ args << "Addresses emotional needs of #{characteristics[:stakeholders].join(' and ')}"
317
+
318
+ if characteristics[:intensity] > 0.6
319
+ args << "Strong emotional engagement through #{characteristics[:primary_emotion]}"
320
+ end
321
+
322
+ if characteristics[:emotional_risks].any?
323
+ args << "Requires managing: #{characteristics[:emotional_risks].join(', ')}"
324
+ end
325
+
326
+ args
327
+ end
328
+
329
+ def identify_pathos_concerns(characteristics)
330
+ concerns = []
331
+
332
+ if characteristics[:intensity] > 0.7
333
+ concerns << 'High emotional intensity may cloud rational judgment'
334
+ end
335
+
336
+ if characteristics[:stakeholders].length > 3
337
+ concerns << 'Multiple stakeholder groups may have conflicting emotional needs'
338
+ end
339
+
340
+ if characteristics[:emotional_risks].any? { |r| r.include?('Resistance') || r.include?('Anxiety') }
341
+ concerns << 'Potential for emotional resistance that needs addressing'
342
+ end
343
+
344
+ concerns.any? ? concerns : ['Emotional impact appears manageable']
345
+ end
346
+
347
+ def generate_pathos_suggestions(characteristics)
348
+ suggestions = []
349
+
350
+ suggestions << "Consider communication strategy for #{characteristics[:stakeholders].join(' and ')}"
351
+
352
+ if characteristics[:primary_emotion] != 'neutral'
353
+ suggestions << "Address the #{characteristics[:primary_emotion]} emotion directly in implementation"
354
+ end
355
+
356
+ suggestions
357
+ end
358
+
359
+ # Helper methods for logos analysis
360
+ def extract_premises(text)
361
+ premises = []
362
+
363
+ if text.include?('because') || text.include?('since')
364
+ premises << 'Causal reasoning detected in argument'
365
+ end
366
+ if text.include?('data') || text.include?('evidence') || text.include?('research')
367
+ premises << 'Empirical evidence cited'
368
+ end
369
+ if text.include?('experience') || text.include?('history') || text.include?('track record')
370
+ premises << 'Historical precedent referenced'
371
+ end
372
+
373
+ premises.any? ? premises : ['Implicit premises require examination']
374
+ end
375
+
376
+ def identify_assumptions(text)
377
+ assumptions = []
378
+
379
+ if text.include?('will') || text.include?('going to')
380
+ assumptions << 'Future prediction assumed certain'
381
+ end
382
+ if text.include?('always') || text.include?('never')
383
+ assumptions << 'Absolute statements may oversimplify'
384
+ end
385
+ if text.include?('everyone') || text.include?('nobody')
386
+ assumptions << 'Universal claims need verification'
387
+ end
388
+
389
+ assumptions.any? ? assumptions : ['Standard assumptions apply']
390
+ end
391
+
392
+ def identify_logical_risks(text)
393
+ risks = []
394
+
395
+ if text.include?('all') && text.include?('must')
396
+ risks << 'Potential hasty generalization'
397
+ end
398
+ if text.include?('either') && text.include?('or')
399
+ risks << 'Possible false dichotomy'
400
+ end
401
+ if text.include?('because') && text.include?('popular')
402
+ risks << 'Potential appeal to popularity'
403
+ end
404
+
405
+ risks.any? ? risks : ['Logical structure appears sound']
406
+ end
407
+
408
+ def generate_logos_verdict(proposition, characteristics, previous_logos)
409
+ structure_desc = {
410
+ deductive: 'following a deductive structure from general principles',
411
+ inductive: 'building from specific observations to general conclusions',
412
+ abductive: 'inferring the most likely explanation',
413
+ analogical: 'drawing parallels from comparable situations'
414
+ }
415
+
416
+ if previous_logos
417
+ return "Upon re-examination, the #{characteristics[:logical_structure]} reasoning remains valid with #{characteristics[:premises].length} supporting premises. The logical risks (#{characteristics[:logical_risks].join(', ')}) should be monitored."
418
+ end
419
+
420
+ "The proposition presents #{structure_desc[characteristics[:logical_structure]]}. #{characteristics[:premises].length} premises have been identified. The argument's logical foundation is #{characteristics[:assumptions].length > 1 ? 'subject to several assumptions that warrant scrutiny' : 'relatively straightforward'}."
421
+ end
422
+
423
+ def calculate_logos_confidence(characteristics, previous_opinions)
424
+ confidence = 0.5
425
+
426
+ # More premises increase confidence
427
+ confidence += [0.2, characteristics[:premises].length * 0.05].min
428
+
429
+ # Fewer assumptions is better
430
+ confidence -= [0.15, characteristics[:assumptions].length * 0.03].min
431
+
432
+ # Fewer logical risks is better
433
+ confidence -= [0.1, characteristics[:logical_risks].length * 0.02].min
434
+
435
+ # Consider previous ethos agreement
436
+ previous_ethos = previous_opinions.find { |op| op[:perspective] == :ethos }
437
+ if previous_ethos && previous_ethos[:confidence] > 0.6
438
+ confidence += 0.05
439
+ end
440
+
441
+ [[confidence, 1.0].min, 0.0].max
442
+ end
443
+
444
+ def generate_logos_arguments(characteristics)
445
+ args = []
446
+
447
+ args << "Reasoning follows #{characteristics[:logical_structure]} structure"
448
+
449
+ characteristics[:premises].each do |premise|
450
+ args << "Premise: #{premise}"
451
+ end
452
+
453
+ if characteristics[:assumptions].any?
454
+ args << "Assumptions to verify: #{characteristics[:assumptions].join(', ')}"
455
+ end
456
+
457
+ args
458
+ end
459
+
460
+ def identify_logos_concerns(characteristics)
461
+ concerns = []
462
+
463
+ if characteristics[:assumptions].length > 2
464
+ concerns << 'Multiple unverified assumptions in the argument'
465
+ end
466
+
467
+ characteristics[:logical_risks].each do |risk|
468
+ concerns << risk unless risk.include?('appears sound')
469
+ end
470
+
471
+ if characteristics[:premises].any? { |p| p.include?('Implicit') }
472
+ concerns << 'Implicit premises need explicit articulation'
473
+ end
474
+
475
+ concerns.any? ? concerns : ['Logical structure is sound']
476
+ end
477
+
478
+ def assess_logical_validity(characteristics)
479
+ validity = 0.7
480
+
481
+ validity -= [0.2, characteristics[:logical_risks].length * 0.05].min
482
+ validity -= [0.1, characteristics[:assumptions].length * 0.02].min
483
+
484
+ [[validity, 0.3].max, 1.0].min
485
+ end
486
+
487
+ def generate_logos_suggestions(characteristics)
488
+ suggestions = []
489
+
490
+ characteristics[:assumptions].slice(0, 2).each do |assumption|
491
+ suggestions << "Verify assumption: #{assumption}"
492
+ end
493
+
494
+ if characteristics[:premises].any? { |p| p.include?('Implicit') }
495
+ suggestions << 'Make implicit premises explicit for clarity'
496
+ end
497
+
498
+ suggestions
499
+ end
500
+
501
+ # Helper methods for ethos analysis
502
+ def identify_principles(text)
503
+ principles = []
504
+
505
+ if text.include?('fair') || text.include?('equitable') || text.include?('just')
506
+ principles << 'Fairness and justice'
507
+ end
508
+ if text.include?('honest') || text.include?('transparent') || text.include?('truthful')
509
+ principles << 'Honesty and transparency'
510
+ end
511
+ if text.include?('respect') || text.include?('dignity') || text.include?('worth')
512
+ principles << 'Respect for dignity'
513
+ end
514
+ if text.include?('responsibility') || text.include?('accountable') || text.include?('liable')
515
+ principles << 'Accountability and responsibility'
516
+ end
517
+
518
+ principles.any? ? principles : ['General ethical principles apply']
519
+ end
520
+
521
+ def identify_values_at_stake(text)
522
+ values = []
523
+
524
+ if text.include?('privacy') || text.include?('confidential') || text.include?('secret')
525
+ values << 'Privacy rights'
526
+ end
527
+ if text.include?('safety') || text.include?('security') || text.include?('protection')
528
+ values << 'Safety and security'
529
+ end
530
+ if text.include?('freedom') || text.include?('autonomy') || text.include?('choice')
531
+ values << 'Autonomy and freedom'
532
+ end
533
+ if text.include?('equality') || text.include?('equal') || text.include?('discriminat')
534
+ values << 'Equality and non-discrimination'
535
+ end
536
+
537
+ values.any? ? values : ['Standard ethical values']
538
+ end
539
+
540
+ def identify_ethical_risks(text)
541
+ risks = []
542
+
543
+ if text.include?('profit') && !text.include?('people')
544
+ risks << 'Potential prioritization of profit over people'
545
+ end
546
+ if text.include?('secret') || text.include?('hidden') || text.include?('undisclosed')
547
+ risks << 'Transparency concerns'
548
+ end
549
+ if text.include?('minority') || text.include?('vulnerable') || text.include?('disadvantaged')
550
+ risks << 'Impact on vulnerable populations needs assessment'
551
+ end
552
+
553
+ risks.any? ? risks : ['No significant ethical risks identified']
554
+ end
555
+
556
+ def generate_ethos_verdict(proposition, characteristics, previous_ethos)
557
+ if previous_ethos
558
+ significant_risks = characteristics[:ethical_risks].none? { |r| r.include?('No significant') }
559
+ return "Upon ethical re-evaluation using #{characteristics[:ethical_framework]} framework, the proposition's alignment with #{characteristics[:principles].join(', ')} #{significant_risks ? 'requires attention to identified risks' : 'remains acceptable'}."
560
+ end
561
+
562
+ "From an ethical perspective informed by #{characteristics[:ethical_framework]} principles, this proposition #{characteristics[:values_at_stake].length > 2 ? 'implicates multiple values' : 'has limited ethical implications'}. The key principles at stake are #{characteristics[:principles].slice(0, 2).join(' and ')}."
563
+ end
564
+
565
+ def calculate_ethos_confidence(characteristics, previous_opinions)
566
+ confidence = 0.6
567
+
568
+ # More principles = clearer ethical framework
569
+ confidence += [0.1, characteristics[:principles].length * 0.02].min
570
+
571
+ # Fewer risks = higher confidence
572
+ if characteristics[:ethical_risks].any? { |r| r.include?('No significant') }
573
+ confidence += 0.1
574
+ else
575
+ confidence -= [0.15, characteristics[:ethical_risks].length * 0.03].min
576
+ end
577
+
578
+ # Consider previous pathos alignment
579
+ previous_pathos = previous_opinions.find { |op| op[:perspective] == :pathos }
580
+ if previous_pathos && previous_pathos[:confidence] > 0.6
581
+ confidence += 0.05
582
+ end
583
+
584
+ [[confidence, 1.0].min, 0.0].max
585
+ end
586
+
587
+ def generate_ethos_arguments(characteristics)
588
+ args = []
589
+
590
+ args << "Ethical framework: #{characteristics[:ethical_framework]}"
591
+
592
+ characteristics[:principles].slice(0, 2).each do |principle|
593
+ args << "Principle invoked: #{principle}"
594
+ end
595
+
596
+ if characteristics[:values_at_stake].any?
597
+ args << "Values at stake: #{characteristics[:values_at_stake].join(', ')}"
598
+ end
599
+
600
+ args
601
+ end
602
+
603
+ def identify_ethos_concerns(characteristics)
604
+ concerns = []
605
+
606
+ characteristics[:ethical_risks].each do |risk|
607
+ concerns << risk unless risk.include?('No significant')
608
+ end
609
+
610
+ if characteristics[:values_at_stake].length > 3
611
+ concerns << 'Multiple values may create ethical tensions'
612
+ end
613
+
614
+ concerns.any? ? concerns : ['Ethical considerations appear manageable']
615
+ end
616
+
617
+ def assess_ethical_alignment(characteristics)
618
+ alignment = 0.7
619
+
620
+ # Reduce for identified risks
621
+ significant_risks = characteristics[:ethical_risks].count { |r| !r.include?('No significant') }
622
+ alignment -= [0.2, significant_risks * 0.05].min
623
+
624
+ [[alignment, 0.3].max, 1.0].min
625
+ end
626
+
627
+ def generate_ethos_suggestions(characteristics)
628
+ suggestions = []
629
+
630
+ if characteristics[:ethical_risks].any? { |r| !r.include?('No significant') }
631
+ suggestions << 'Address identified ethical risks before implementation'
632
+ end
633
+
634
+ if characteristics[:values_at_stake].length > 2
635
+ suggestions << 'Consider ethical trade-offs between competing values'
636
+ end
637
+
638
+ suggestions << "Apply #{characteristics[:ethical_framework]} framework consistently"
639
+
640
+ suggestions
641
+ end
642
+ end
643
+ end
644
+ end
645
+ end