lex-agentic-affect 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-affect.gemspec +30 -0
- data/lib/legion/extensions/agentic/affect/appraisal/client.rb +20 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal.rb +112 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine.rb +129 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/affect/appraisal/runners/appraisal.rb +105 -0
- data/lib/legion/extensions/agentic/affect/appraisal/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/appraisal.rb +19 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/client.rb +19 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/constants.rb +37 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine.rb +151 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective.rb +92 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy.rb +93 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy.rb +20 -0
- data/lib/legion/extensions/agentic/affect/contagion/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/constants.rb +34 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/contagion_engine.rb +184 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/meme.rb +97 -0
- data/lib/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion.rb +125 -0
- data/lib/legion/extensions/agentic/affect/contagion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/contagion.rb +19 -0
- data/lib/legion/extensions/agentic/affect/defusion/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/constants.rb +64 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/defusion_engine.rb +167 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/thought.rb +92 -0
- data/lib/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion.rb +127 -0
- data/lib/legion/extensions/agentic/affect/defusion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/defusion.rb +19 -0
- data/lib/legion/extensions/agentic/affect/emotion/actors/momentum_decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/emotion/client.rb +36 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/baseline.rb +52 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/momentum.rb +52 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/valence.rb +92 -0
- data/lib/legion/extensions/agentic/affect/emotion/runners/gut.rb +102 -0
- data/lib/legion/extensions/agentic/affect/emotion/runners/valence.rb +120 -0
- data/lib/legion/extensions/agentic/affect/emotion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/emotion.rb +20 -0
- data/lib/legion/extensions/agentic/affect/empathy/client.rb +21 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/constants.rb +54 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/mental_model.rb +185 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/model_store.rb +88 -0
- data/lib/legion/extensions/agentic/affect/empathy/runners/empathy.rb +173 -0
- data/lib/legion/extensions/agentic/affect/empathy/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/empathy.rb +20 -0
- data/lib/legion/extensions/agentic/affect/fatigue/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/constants.rb +54 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/energy_model.rb +181 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store.rb +146 -0
- data/lib/legion/extensions/agentic/affect/fatigue/runners/fatigue.rb +89 -0
- data/lib/legion/extensions/agentic/affect/fatigue/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/fatigue.rb +19 -0
- data/lib/legion/extensions/agentic/affect/flow/client.rb +25 -0
- data/lib/legion/extensions/agentic/affect/flow/helpers/constants.rb +84 -0
- data/lib/legion/extensions/agentic/affect/flow/helpers/flow_detector.rb +166 -0
- data/lib/legion/extensions/agentic/affect/flow/runners/flow.rb +129 -0
- data/lib/legion/extensions/agentic/affect/flow/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/flow.rb +18 -0
- data/lib/legion/extensions/agentic/affect/interoception/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/interoception/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb +152 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/constants.rb +68 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/somatic_marker.rb +75 -0
- data/lib/legion/extensions/agentic/affect/interoception/runners/interoception.rb +101 -0
- data/lib/legion/extensions/agentic/affect/interoception/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/interoception.rb +20 -0
- data/lib/legion/extensions/agentic/affect/mood/client.rb +21 -0
- data/lib/legion/extensions/agentic/affect/mood/helpers/constants.rb +78 -0
- data/lib/legion/extensions/agentic/affect/mood/helpers/mood_state.rb +154 -0
- data/lib/legion/extensions/agentic/affect/mood/runners/mood.rb +122 -0
- data/lib/legion/extensions/agentic/affect/mood/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/mood.rb +18 -0
- data/lib/legion/extensions/agentic/affect/motivation/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/constants.rb +48 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/drive_state.rb +98 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/motivation_store.rb +106 -0
- data/lib/legion/extensions/agentic/affect/motivation/runners/motivation.rb +165 -0
- data/lib/legion/extensions/agentic/affect/motivation/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/motivation.rb +19 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate.rb +45 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/constants.rb +82 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event.rb +98 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer.rb +88 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine.rb +153 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal.rb +164 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/reappraisal.rb +20 -0
- data/lib/legion/extensions/agentic/affect/regulation/client.rb +25 -0
- data/lib/legion/extensions/agentic/affect/regulation/helpers/constants.rb +71 -0
- data/lib/legion/extensions/agentic/affect/regulation/helpers/regulation_model.rb +175 -0
- data/lib/legion/extensions/agentic/affect/regulation/runners/emotional_regulation.rb +127 -0
- data/lib/legion/extensions/agentic/affect/regulation/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/regulation.rb +18 -0
- data/lib/legion/extensions/agentic/affect/resilience/client.rb +27 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker.rb +130 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/constants.rb +79 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/resilience_model.rb +165 -0
- data/lib/legion/extensions/agentic/affect/resilience/runners/resilience.rb +150 -0
- data/lib/legion/extensions/agentic/affect/resilience/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/resilience.rb +19 -0
- data/lib/legion/extensions/agentic/affect/resonance/client.rb +24 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/category.rb +75 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/constants.rb +47 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/resonance_engine.rb +115 -0
- data/lib/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance.rb +94 -0
- data/lib/legion/extensions/agentic/affect/resonance/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/resonance.rb +19 -0
- data/lib/legion/extensions/agentic/affect/reward/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/constants.rb +67 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/reward_signal.rb +178 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/reward_store.rb +142 -0
- data/lib/legion/extensions/agentic/affect/reward/runners/reward.rb +92 -0
- data/lib/legion/extensions/agentic/affect/reward/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/reward.rb +19 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/client.rb +29 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/body_state.rb +69 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb +160 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker.rb +74 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker.rb +132 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker.rb +20 -0
- data/lib/legion/extensions/agentic/affect/version.rb +11 -0
- data/lib/legion/extensions/agentic/affect.rb +34 -0
- data/spec/legion/extensions/agentic/affect/appraisal/client_spec.rb +52 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine_spec.rb +161 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_spec.rb +175 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/constants_spec.rb +49 -0
- data/spec/legion/extensions/agentic/affect/appraisal/runners/appraisal_spec.rb +116 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/client_spec.rb +62 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine_spec.rb +316 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective_spec.rb +132 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy_spec.rb +200 -0
- data/spec/legion/extensions/agentic/affect/contagion/client_spec.rb +63 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/constants_spec.rb +86 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/contagion_engine_spec.rb +241 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/meme_spec.rb +160 -0
- data/spec/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion_spec.rb +211 -0
- data/spec/legion/extensions/agentic/affect/defusion/client_spec.rb +80 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/constants_spec.rb +84 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/defusion_engine_spec.rb +250 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/thought_spec.rb +178 -0
- data/spec/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion_spec.rb +185 -0
- data/spec/legion/extensions/agentic/affect/emotion/actors/momentum_decay_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/emotion/client_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/baseline_spec.rb +48 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/momentum_spec.rb +45 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/valence_spec.rb +91 -0
- data/spec/legion/extensions/agentic/affect/emotion/runners/gut_spec.rb +73 -0
- data/spec/legion/extensions/agentic/affect/emotion/runners/valence_spec.rb +67 -0
- data/spec/legion/extensions/agentic/affect/empathy/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/constants_spec.rb +23 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/mental_model_spec.rb +150 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/model_store_spec.rb +94 -0
- data/spec/legion/extensions/agentic/affect/empathy/runners/empathy_spec.rb +127 -0
- data/spec/legion/extensions/agentic/affect/fatigue/client_spec.rb +66 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/constants_spec.rb +130 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/energy_model_spec.rb +281 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store_spec.rb +157 -0
- data/spec/legion/extensions/agentic/affect/fatigue/runners/fatigue_spec.rb +127 -0
- data/spec/legion/extensions/agentic/affect/flow/client_spec.rb +58 -0
- data/spec/legion/extensions/agentic/affect/flow/helpers/constants_spec.rb +112 -0
- data/spec/legion/extensions/agentic/affect/flow/helpers/flow_detector_spec.rb +268 -0
- data/spec/legion/extensions/agentic/affect/flow/runners/flow_spec.rb +222 -0
- data/spec/legion/extensions/agentic/affect/interoception/client_spec.rb +52 -0
- data/spec/legion/extensions/agentic/affect/interoception/helpers/body_budget_spec.rb +178 -0
- data/spec/legion/extensions/agentic/affect/interoception/helpers/somatic_marker_spec.rb +120 -0
- data/spec/legion/extensions/agentic/affect/interoception/runners/interoception_spec.rb +108 -0
- data/spec/legion/extensions/agentic/affect/mood/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/affect/mood/helpers/constants_spec.rb +29 -0
- data/spec/legion/extensions/agentic/affect/mood/helpers/mood_state_spec.rb +94 -0
- data/spec/legion/extensions/agentic/affect/mood/runners/mood_spec.rb +71 -0
- data/spec/legion/extensions/agentic/affect/motivation/client_spec.rb +35 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/constants_spec.rb +111 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/drive_state_spec.rb +183 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/motivation_store_spec.rb +185 -0
- data/spec/legion/extensions/agentic/affect/motivation/runners/motivation_spec.rb +248 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/client_spec.rb +64 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/constants_spec.rb +102 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event_spec.rb +177 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer_spec.rb +161 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine_spec.rb +211 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal_spec.rb +312 -0
- data/spec/legion/extensions/agentic/affect/regulation/client_spec.rb +61 -0
- data/spec/legion/extensions/agentic/affect/regulation/helpers/constants_spec.rb +108 -0
- data/spec/legion/extensions/agentic/affect/regulation/helpers/regulation_model_spec.rb +200 -0
- data/spec/legion/extensions/agentic/affect/regulation/runners/emotional_regulation_spec.rb +190 -0
- data/spec/legion/extensions/agentic/affect/resilience/client_spec.rb +36 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker_spec.rb +164 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/constants_spec.rb +78 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/resilience_model_spec.rb +133 -0
- data/spec/legion/extensions/agentic/affect/resilience/runners/resilience_spec.rb +150 -0
- data/spec/legion/extensions/agentic/affect/resonance/client_spec.rb +66 -0
- data/spec/legion/extensions/agentic/affect/resonance/cognitive_resonance_spec.rb +27 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/category_spec.rb +146 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/constants_spec.rb +104 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/resonance_engine_spec.rb +189 -0
- data/spec/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance_spec.rb +197 -0
- data/spec/legion/extensions/agentic/affect/reward/client_spec.rb +42 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/constants_spec.rb +91 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/reward_signal_spec.rb +296 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/reward_store_spec.rb +167 -0
- data/spec/legion/extensions/agentic/affect/reward/runners/reward_spec.rb +149 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/client_spec.rb +83 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/body_state_spec.rb +155 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store_spec.rb +233 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker_spec.rb +172 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker_spec.rb +181 -0
- data/spec/spec_helper.rb +46 -0
- metadata +302 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Motivation::Runners::Motivation do
|
|
6
|
+
let(:client) { Legion::Extensions::Agentic::Affect::Motivation::Client.new }
|
|
7
|
+
|
|
8
|
+
let(:normal_tick) do
|
|
9
|
+
{
|
|
10
|
+
consent: { tier: :collaborate },
|
|
11
|
+
prediction_engine: { accuracy: 0.8 },
|
|
12
|
+
trust: { overall_level: 0.7 },
|
|
13
|
+
memory_retrieval: { novel_traces: 3 },
|
|
14
|
+
scheduler: { pending_tasks: 5 },
|
|
15
|
+
extinction: { level: 0 }
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
let(:adverse_tick) do
|
|
20
|
+
{
|
|
21
|
+
consent: { tier: :supervised },
|
|
22
|
+
prediction_engine: { accuracy: 0.2 },
|
|
23
|
+
trust: { overall_level: 0.1 },
|
|
24
|
+
memory_retrieval: { novel_traces: 0 },
|
|
25
|
+
scheduler: { pending_tasks: 0 },
|
|
26
|
+
extinction: { level: 3 }
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#update_motivation' do
|
|
31
|
+
it 'returns a hash with expected keys' do
|
|
32
|
+
result = client.update_motivation(tick_results: normal_tick)
|
|
33
|
+
expect(result).to include(:mode, :overall_level, :intrinsic_average,
|
|
34
|
+
:extrinsic_average, :amotivated, :burnout)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'returns a valid mode symbol' do
|
|
38
|
+
result = client.update_motivation(tick_results: normal_tick)
|
|
39
|
+
expect(Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::MOTIVATION_MODES).to include(result[:mode])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'handles empty tick results' do
|
|
43
|
+
result = client.update_motivation(tick_results: {})
|
|
44
|
+
expect(result[:overall_level]).to be_a(Float)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'handles missing tick keys gracefully' do
|
|
48
|
+
result = client.update_motivation(tick_results: { trust: {} })
|
|
49
|
+
expect(result).to include(:mode)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'returns amotivated as false initially' do
|
|
53
|
+
result = client.update_motivation(tick_results: {})
|
|
54
|
+
expect(result[:amotivated]).to be false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'decays drives on each tick' do
|
|
58
|
+
initial = client.motivation_store.drive_state.overall_level
|
|
59
|
+
client.update_motivation(tick_results: {})
|
|
60
|
+
after = client.motivation_store.drive_state.overall_level
|
|
61
|
+
expect(after).to be < initial
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#signal_drive' do
|
|
66
|
+
it 'updates a valid drive' do
|
|
67
|
+
result = client.signal_drive(drive: :autonomy, signal: 0.9)
|
|
68
|
+
expect(result[:success]).to be true
|
|
69
|
+
expect(result[:drive]).to eq(:autonomy)
|
|
70
|
+
expect(result[:level]).to be_a(Float)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'accepts string drive names' do
|
|
74
|
+
result = client.signal_drive(drive: 'competence', signal: 0.7)
|
|
75
|
+
expect(result[:success]).to be true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'rejects unknown drive' do
|
|
79
|
+
result = client.signal_drive(drive: :nonexistent, signal: 0.5)
|
|
80
|
+
expect(result[:success]).to be false
|
|
81
|
+
expect(result[:error]).to include('unknown drive')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'reflects updated level in drive_status' do
|
|
85
|
+
client.signal_drive(drive: :novelty, signal: 1.0)
|
|
86
|
+
status = client.drive_status
|
|
87
|
+
expect(status[:drives][:novelty][:level]).to be > 0.5
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe '#commit_to_goal' do
|
|
92
|
+
it 'commits a goal with valid drives' do
|
|
93
|
+
result = client.commit_to_goal(goal_id: 'goal_a', drives: %i[autonomy competence])
|
|
94
|
+
expect(result[:success]).to be true
|
|
95
|
+
expect(result[:goal_id]).to eq('goal_a')
|
|
96
|
+
expect(result[:energy]).to be_a(Float)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'returns failure for entirely invalid drives' do
|
|
100
|
+
result = client.commit_to_goal(goal_id: 'bad', drives: [:nonexistent])
|
|
101
|
+
expect(result[:success]).to be false
|
|
102
|
+
expect(result[:error]).to be_a(String)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#release_goal' do
|
|
107
|
+
it 'releases a committed goal' do
|
|
108
|
+
client.commit_to_goal(goal_id: 'temp_goal', drives: [:autonomy])
|
|
109
|
+
result = client.release_goal(goal_id: 'temp_goal')
|
|
110
|
+
expect(result[:success]).to be true
|
|
111
|
+
expect(client.motivation_store.goal_motivations).not_to have_key('temp_goal')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'succeeds for unknown goal id' do
|
|
115
|
+
result = client.release_goal(goal_id: 'no_such_goal')
|
|
116
|
+
expect(result[:success]).to be true
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe '#motivation_for' do
|
|
121
|
+
it 'returns 0.0 energy for uncommitted goal' do
|
|
122
|
+
result = client.motivation_for(goal_id: 'unknown_goal')
|
|
123
|
+
expect(result[:energy]).to eq(0.0)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'returns positive energy for committed goal' do
|
|
127
|
+
client.commit_to_goal(goal_id: 'tracked', drives: %i[autonomy competence])
|
|
128
|
+
result = client.motivation_for(goal_id: 'tracked')
|
|
129
|
+
expect(result[:energy]).to be >= 0.0
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'includes goal_id in result' do
|
|
133
|
+
result = client.motivation_for(goal_id: 'some_goal')
|
|
134
|
+
expect(result[:goal_id]).to eq('some_goal')
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe '#most_motivated_goal' do
|
|
139
|
+
it 'returns nil goal_id when no goals committed' do
|
|
140
|
+
result = client.most_motivated_goal
|
|
141
|
+
expect(result[:goal_id]).to be_nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'returns the most energized goal' do
|
|
145
|
+
client.commit_to_goal(goal_id: 'low', drives: [:obligation])
|
|
146
|
+
client.commit_to_goal(goal_id: 'high', drives: %i[autonomy competence relatedness novelty])
|
|
147
|
+
%i[autonomy competence relatedness novelty].each do |d|
|
|
148
|
+
5.times { client.signal_drive(drive: d, signal: 1.0) }
|
|
149
|
+
end
|
|
150
|
+
result = client.most_motivated_goal
|
|
151
|
+
expect(result[:goal_id]).to eq('high')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'includes energy and drives in result' do
|
|
155
|
+
client.commit_to_goal(goal_id: 'g1', drives: [:autonomy])
|
|
156
|
+
result = client.most_motivated_goal
|
|
157
|
+
expect(result).to include(:goal_id, :energy, :drives)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe '#drive_status' do
|
|
162
|
+
it 'returns drives hash' do
|
|
163
|
+
status = client.drive_status
|
|
164
|
+
expect(status).to have_key(:drives)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'returns mode' do
|
|
168
|
+
status = client.drive_status
|
|
169
|
+
expect(status).to have_key(:mode)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'returns overall level' do
|
|
173
|
+
status = client.drive_status
|
|
174
|
+
expect(status).to have_key(:overall)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'includes level and satisfied for each drive type' do
|
|
178
|
+
status = client.drive_status
|
|
179
|
+
Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |type|
|
|
180
|
+
expect(status[:drives][type]).to include(:level, :satisfied)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe '#motivation_stats' do
|
|
186
|
+
it 'returns overall_level' do
|
|
187
|
+
expect(client.motivation_stats).to have_key(:overall_level)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'returns current_mode' do
|
|
191
|
+
expect(client.motivation_stats).to have_key(:current_mode)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'returns intrinsic_average' do
|
|
195
|
+
expect(client.motivation_stats).to have_key(:intrinsic_average)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'returns extrinsic_average' do
|
|
199
|
+
expect(client.motivation_stats).to have_key(:extrinsic_average)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'returns amotivated flag' do
|
|
203
|
+
expect(client.motivation_stats).to have_key(:amotivated)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it 'returns goal_count' do
|
|
207
|
+
expect(client.motivation_stats).to have_key(:goal_count)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
describe 'drive signal extraction from tick results' do
|
|
212
|
+
it 'extracts autonomy from consent tier :autonomous' do
|
|
213
|
+
client.update_motivation(tick_results: { consent: { tier: :autonomous } })
|
|
214
|
+
expect(client.motivation_store.drive_state.drive_level(:autonomy)).to be > 0.5
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'extracts competence from prediction accuracy' do
|
|
218
|
+
client.update_motivation(tick_results: { prediction_engine: { accuracy: 0.95 } })
|
|
219
|
+
expect(client.motivation_store.drive_state.drive_level(:competence)).to be > 0.5
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it 'extracts relatedness from trust level' do
|
|
223
|
+
client.update_motivation(tick_results: { trust: { overall_level: 0.9 } })
|
|
224
|
+
expect(client.motivation_store.drive_state.drive_level(:relatedness)).to be > 0.5
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'extracts novelty from novel traces count' do
|
|
228
|
+
client.update_motivation(tick_results: { memory_retrieval: { novel_traces: 8 } })
|
|
229
|
+
expect(client.motivation_store.drive_state.drive_level(:novelty)).to be >= 0.0
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it 'extracts obligation from pending tasks' do
|
|
233
|
+
client.update_motivation(tick_results: { scheduler: { pending_tasks: 10 } })
|
|
234
|
+
expect(client.motivation_store.drive_state.drive_level(:obligation)).to be > 0.0
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'extracts survival from extinction level' do
|
|
238
|
+
client.update_motivation(tick_results: { extinction: { level: 4 } })
|
|
239
|
+
expect(client.motivation_store.drive_state.drive_level(:survival)).to be > 0.5
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'lowers autonomy from constrained consent tier' do
|
|
243
|
+
initial = client.motivation_store.drive_state.drive_level(:autonomy)
|
|
244
|
+
client.update_motivation(tick_results: { consent: { tier: :supervised } })
|
|
245
|
+
expect(client.motivation_store.drive_state.drive_level(:autonomy)).to be < initial
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Actors
|
|
6
|
+
class Every # rubocop:disable Lint/EmptyClass
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
$LOADED_FEATURES << 'legion/extensions/actors/every'
|
|
13
|
+
|
|
14
|
+
require_relative '../../../../../../../lib/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate'
|
|
15
|
+
|
|
16
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Reappraisal::Actor::AutoRegulate do
|
|
17
|
+
subject(:actor) { described_class.new }
|
|
18
|
+
|
|
19
|
+
describe '#runner_class' do
|
|
20
|
+
it { expect(actor.runner_class).to eq Legion::Extensions::Agentic::Affect::Reappraisal::Runners::CognitiveReappraisal }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#runner_function' do
|
|
24
|
+
it { expect(actor.runner_function).to eq 'regulate_pending_events' }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#time' do
|
|
28
|
+
it { expect(actor.time).to eq 300 }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#run_now?' do
|
|
32
|
+
it { expect(actor.run_now?).to be false }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#use_runner?' do
|
|
36
|
+
it { expect(actor.use_runner?).to be false }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '#check_subtask?' do
|
|
40
|
+
it { expect(actor.check_subtask?).to be false }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#generate_task?' do
|
|
44
|
+
it { expect(actor.generate_task?).to be false }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/affect/reappraisal/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Reappraisal::Client do
|
|
6
|
+
it 'responds to all runner methods' do
|
|
7
|
+
client = described_class.new
|
|
8
|
+
expect(client).to respond_to(:register_event)
|
|
9
|
+
expect(client).to respond_to(:reappraise_event)
|
|
10
|
+
expect(client).to respond_to(:auto_reappraise_event)
|
|
11
|
+
expect(client).to respond_to(:negative_events)
|
|
12
|
+
expect(client).to respond_to(:intense_events)
|
|
13
|
+
expect(client).to respond_to(:most_regulated_events)
|
|
14
|
+
expect(client).to respond_to(:reappraisal_status)
|
|
15
|
+
expect(client).to respond_to(:reappraisal_report)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'accepts an injected engine' do
|
|
19
|
+
engine = Legion::Extensions::Agentic::Affect::Reappraisal::Helpers::ReappraisalEngine.new
|
|
20
|
+
client = described_class.new(engine: engine)
|
|
21
|
+
result = client.register_event(
|
|
22
|
+
content: 'injected test',
|
|
23
|
+
valence: -0.5,
|
|
24
|
+
intensity: 0.4,
|
|
25
|
+
appraisal: 'difficult',
|
|
26
|
+
engine: engine
|
|
27
|
+
)
|
|
28
|
+
expect(result[:success]).to be true
|
|
29
|
+
expect(engine.events.size).to eq(1)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'creates its own engine when none injected' do
|
|
33
|
+
client = described_class.new
|
|
34
|
+
result = client.register_event(
|
|
35
|
+
content: 'standalone test',
|
|
36
|
+
valence: 0.3,
|
|
37
|
+
intensity: 0.2,
|
|
38
|
+
appraisal: 'fine'
|
|
39
|
+
)
|
|
40
|
+
expect(result[:success]).to be true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'executes a full register -> reappraise -> report cycle' do
|
|
44
|
+
client = described_class.new
|
|
45
|
+
reg = client.register_event(
|
|
46
|
+
content: 'system alert',
|
|
47
|
+
valence: -0.6,
|
|
48
|
+
intensity: 0.6,
|
|
49
|
+
appraisal: 'unrecoverable failure'
|
|
50
|
+
)
|
|
51
|
+
expect(reg[:success]).to be true
|
|
52
|
+
|
|
53
|
+
reap = client.reappraise_event(
|
|
54
|
+
event_id: reg[:event_id],
|
|
55
|
+
strategy: :temporal_distancing,
|
|
56
|
+
new_appraisal: 'this will be a minor footnote in six months'
|
|
57
|
+
)
|
|
58
|
+
expect(reap[:success]).to be true
|
|
59
|
+
|
|
60
|
+
report = client.reappraisal_report
|
|
61
|
+
expect(report[:report][:total_events]).to eq(1)
|
|
62
|
+
expect(report[:report][:total_reappraisals]).to eq(1)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Reappraisal::Helpers::Constants do
|
|
4
|
+
describe 'STRATEGIES' do
|
|
5
|
+
it 'includes all six strategies' do
|
|
6
|
+
expect(described_class::STRATEGIES).to include(
|
|
7
|
+
:reinterpretation, :distancing, :benefit_finding,
|
|
8
|
+
:normalizing, :perspective_taking, :temporal_distancing
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'is frozen' do
|
|
13
|
+
expect(described_class::STRATEGIES).to be_frozen
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'STRATEGY_EFFECTIVENESS' do
|
|
18
|
+
it 'has an entry for every strategy' do
|
|
19
|
+
described_class::STRATEGIES.each do |s|
|
|
20
|
+
expect(described_class::STRATEGY_EFFECTIVENESS).to have_key(s)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'rates reinterpretation highest' do
|
|
25
|
+
expect(described_class::STRATEGY_EFFECTIVENESS[:reinterpretation]).to be >
|
|
26
|
+
described_class::STRATEGY_EFFECTIVENESS[:temporal_distancing]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'all effectiveness values are between 0 and 1' do
|
|
30
|
+
described_class::STRATEGY_EFFECTIVENESS.each_value do |v|
|
|
31
|
+
expect(v).to be_between(0.0, 1.0)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '.valid_strategy?' do
|
|
37
|
+
it 'returns true for valid strategies' do
|
|
38
|
+
expect(described_class.valid_strategy?(:reinterpretation)).to be true
|
|
39
|
+
expect(described_class.valid_strategy?(:distancing)).to be true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'returns false for unknown strategy' do
|
|
43
|
+
expect(described_class.valid_strategy?(:nonexistent)).to be false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '.label_for' do
|
|
48
|
+
it 'returns :positive for valence 0.8' do
|
|
49
|
+
expect(described_class.label_for(0.8, described_class::VALENCE_LABELS)).to eq(:positive)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'returns :negative for valence -0.8' do
|
|
53
|
+
expect(described_class.label_for(-0.8, described_class::VALENCE_LABELS)).to eq(:negative)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'returns :neutral for valence 0.0' do
|
|
57
|
+
expect(described_class.label_for(0.0, described_class::VALENCE_LABELS)).to eq(:neutral)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'returns :overwhelming for intensity 0.9' do
|
|
61
|
+
expect(described_class.label_for(0.9, described_class::INTENSITY_LABELS)).to eq(:overwhelming)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'returns :faint for intensity 0.1' do
|
|
65
|
+
expect(described_class.label_for(0.1, described_class::INTENSITY_LABELS)).to eq(:faint)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'returns :excellent for regulation 0.9' do
|
|
69
|
+
expect(described_class.label_for(0.9, described_class::REGULATION_LABELS)).to eq(:excellent)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe '.clamp' do
|
|
74
|
+
it 'clamps to -1..1 by default' do
|
|
75
|
+
expect(described_class.clamp(2.0)).to eq(1.0)
|
|
76
|
+
expect(described_class.clamp(-2.0)).to eq(-1.0)
|
|
77
|
+
expect(described_class.clamp(0.5)).to eq(0.5)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe '.clamp_intensity' do
|
|
82
|
+
it 'clamps to 0..1' do
|
|
83
|
+
expect(described_class.clamp_intensity(1.5)).to eq(1.0)
|
|
84
|
+
expect(described_class.clamp_intensity(-0.1)).to eq(0.0)
|
|
85
|
+
expect(described_class.clamp_intensity(0.7)).to eq(0.7)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe 'thresholds' do
|
|
90
|
+
it 'defines NEGATIVE_VALENCE_THRESHOLD' do
|
|
91
|
+
expect(described_class::NEGATIVE_VALENCE_THRESHOLD).to eq(-0.3)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'defines HIGH_INTENSITY_THRESHOLD' do
|
|
95
|
+
expect(described_class::HIGH_INTENSITY_THRESHOLD).to eq(0.7)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'defines REAPPRAISAL_DIFFICULTY_MULTIPLIER' do
|
|
99
|
+
expect(described_class::REAPPRAISAL_DIFFICULTY_MULTIPLIER).to eq(0.5)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Reappraisal::Helpers::EmotionalEvent do
|
|
4
|
+
subject(:event) do
|
|
5
|
+
described_class.new(
|
|
6
|
+
content: 'test event',
|
|
7
|
+
valence: -0.6,
|
|
8
|
+
intensity: 0.5,
|
|
9
|
+
appraisal: 'threatening situation'
|
|
10
|
+
)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#initialize' do
|
|
14
|
+
it 'assigns a UUID id' do
|
|
15
|
+
expect(event.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'stores content' do
|
|
19
|
+
expect(event.content).to eq('test event')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'stores initial_valence clamped to -1..1' do
|
|
23
|
+
e = described_class.new(content: 'x', valence: -2.0, intensity: 0.5, appraisal: 'a')
|
|
24
|
+
expect(e.initial_valence).to eq(-1.0)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'stores initial_intensity clamped to 0..1' do
|
|
28
|
+
e = described_class.new(content: 'x', valence: 0.0, intensity: 1.5, appraisal: 'a')
|
|
29
|
+
expect(e.initial_intensity).to eq(1.0)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'sets current_valence equal to initial_valence' do
|
|
33
|
+
expect(event.current_valence).to eq(event.initial_valence)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'sets current_intensity equal to initial_intensity' do
|
|
37
|
+
expect(event.current_intensity).to eq(event.initial_intensity)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'starts with reappraisal_count 0' do
|
|
41
|
+
expect(event.reappraisal_count).to eq(0)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'sets created_at to a Time' do
|
|
45
|
+
expect(event.created_at).to be_a(Time)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe '#reappraise!' do
|
|
50
|
+
it 'increases valence toward positive' do
|
|
51
|
+
before = event.current_valence
|
|
52
|
+
event.reappraise!(strategy: :reinterpretation, new_appraisal: 'challenge')
|
|
53
|
+
expect(event.current_valence).to be > before
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'reduces intensity' do
|
|
57
|
+
before = event.current_intensity
|
|
58
|
+
event.reappraise!(strategy: :reinterpretation, new_appraisal: 'challenge')
|
|
59
|
+
expect(event.current_intensity).to be < before
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'increments reappraisal_count' do
|
|
63
|
+
expect { event.reappraise!(strategy: :distancing, new_appraisal: 'distant') }
|
|
64
|
+
.to change(event, :reappraisal_count).by(1)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'updates appraisal text' do
|
|
68
|
+
event.reappraise!(strategy: :benefit_finding, new_appraisal: 'growth opportunity')
|
|
69
|
+
expect(event.appraisal).to eq('growth opportunity')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'returns amount of change as a Float' do
|
|
73
|
+
change = event.reappraise!(strategy: :reinterpretation, new_appraisal: 'new view')
|
|
74
|
+
expect(change).to be_a(Float)
|
|
75
|
+
expect(change).to be >= 0.0
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'returns 0.0 for invalid strategy' do
|
|
79
|
+
change = event.reappraise!(strategy: :nonexistent, new_appraisal: 'irrelevant')
|
|
80
|
+
expect(change).to eq(0.0)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'applies difficulty multiplier for high-intensity events' do
|
|
84
|
+
high = described_class.new(content: 'x', valence: -0.8, intensity: 0.9, appraisal: 'bad')
|
|
85
|
+
low = described_class.new(content: 'x', valence: -0.8, intensity: 0.3, appraisal: 'bad')
|
|
86
|
+
|
|
87
|
+
high_change = high.reappraise!(strategy: :reinterpretation, new_appraisal: 'reframed')
|
|
88
|
+
low_change = low.reappraise!(strategy: :reinterpretation, new_appraisal: 'reframed')
|
|
89
|
+
|
|
90
|
+
expect(high_change).to be < low_change
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'does not allow valence to exceed 1.0' do
|
|
94
|
+
e = described_class.new(content: 'x', valence: 0.95, intensity: 0.1, appraisal: 'ok')
|
|
95
|
+
10.times { e.reappraise!(strategy: :reinterpretation, new_appraisal: 'great') }
|
|
96
|
+
expect(e.current_valence).to be <= 1.0
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'does not allow intensity to go below 0.0' do
|
|
100
|
+
e = described_class.new(content: 'x', valence: -0.5, intensity: 0.05, appraisal: 'bad')
|
|
101
|
+
10.times { e.reappraise!(strategy: :reinterpretation, new_appraisal: 'better') }
|
|
102
|
+
expect(e.current_intensity).to be >= 0.0
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#negative?' do
|
|
107
|
+
it 'returns true when current_valence is below threshold' do
|
|
108
|
+
expect(event.negative?).to be true
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'returns false for positive valence' do
|
|
112
|
+
e = described_class.new(content: 'x', valence: 0.5, intensity: 0.3, appraisal: 'good')
|
|
113
|
+
expect(e.negative?).to be false
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe '#intense?' do
|
|
118
|
+
it 'returns false for moderate intensity' do
|
|
119
|
+
expect(event.intense?).to be false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'returns true for high intensity' do
|
|
123
|
+
e = described_class.new(content: 'x', valence: -0.5, intensity: 0.8, appraisal: 'bad')
|
|
124
|
+
expect(e.intense?).to be true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe '#regulation_amount' do
|
|
129
|
+
it 'returns 0.0 for unmodified event' do
|
|
130
|
+
expect(event.regulation_amount).to eq(0.0)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'returns positive value after reappraisal' do
|
|
134
|
+
event.reappraise!(strategy: :reinterpretation, new_appraisal: 'changed')
|
|
135
|
+
expect(event.regulation_amount).to be > 0.0
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'returns value between 0 and 1' do
|
|
139
|
+
event.reappraise!(strategy: :reinterpretation, new_appraisal: 'changed')
|
|
140
|
+
expect(event.regulation_amount).to be_between(0.0, 1.0)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe '#valence_label' do
|
|
145
|
+
it 'returns :negative for valence -0.6' do
|
|
146
|
+
expect(event.valence_label).to eq(:negative)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'returns :positive after positive reappraisals' do
|
|
150
|
+
e = described_class.new(content: 'x', valence: 0.7, intensity: 0.3, appraisal: 'good')
|
|
151
|
+
expect(e.valence_label).to eq(:positive)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe '#intensity_label' do
|
|
156
|
+
it 'returns :moderate for intensity 0.5' do
|
|
157
|
+
expect(event.intensity_label).to eq(:moderate)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe '#to_h' do
|
|
162
|
+
it 'returns a hash with all expected keys' do
|
|
163
|
+
h = event.to_h
|
|
164
|
+
expect(h).to include(:id, :content, :initial_valence, :current_valence,
|
|
165
|
+
:initial_intensity, :current_intensity, :appraisal,
|
|
166
|
+
:reappraisal_count, :negative, :intense,
|
|
167
|
+
:regulation_amount, :valence_label, :intensity_label, :created_at)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it 'reflects updated state after reappraisal' do
|
|
171
|
+
event.reappraise!(strategy: :benefit_finding, new_appraisal: 'growth')
|
|
172
|
+
h = event.to_h
|
|
173
|
+
expect(h[:reappraisal_count]).to eq(1)
|
|
174
|
+
expect(h[:appraisal]).to eq('growth')
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|