lex-cognitive-weathering 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: db91ee5a95c7738bea4c0f2f8c81a941e27277376864e4981340b12bee855604
4
+ data.tar.gz: 3872c8f28774524bcdda173da925369949b08337b17a729efb9758cf1f2ff8e7
5
+ SHA512:
6
+ metadata.gz: d01d7ab9af6ad5db0f289c88b57f5d34fa862c032442d202b581eb0915590da52515191501a95d8afdf95ed1a84e508882475c61cd538af518197129f59c6cf7
7
+ data.tar.gz: b259fc75e57095227014081979a61f5d748ff2d3567af1a627f8ee5653cc2a99625df072a4627405a55dd6d0ca3b659d877e64886bf5f758febe4542abfaa39c
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'rspec', '~> 3.13'
9
+ gem 'rspec_junit_formatter'
10
+ gem 'rubocop', '~> 1.75', require: false
11
+ gem 'rubocop-rspec', require: false
12
+ gem 'simplecov'
13
+ end
14
+
15
+ gem 'legion-gaia', path: '../../legion-gaia'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Esity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # lex-cognitive-weathering
2
+
3
+ A LegionIO cognitive architecture extension that models long-term cumulative cognitive wear. Based on allostatic load theory: sustained demands erode integrity, but manageable challenges also build tempering — a resilience multiplier that allows tempered agents to exceed their baseline capacity.
4
+
5
+ ## What It Does
6
+
7
+ Tracks cognitive **integrity** (0.0–1.0) and **tempering level** (0.0–1.0) through stressor events and recovery.
8
+
9
+ Each stressor has:
10
+ - A type (`:cognitive_overload`, `:emotional_strain`, `:decision_fatigue`, `:conflict_exposure`, `:uncertainty`, `:time_pressure`, `:monotony`, `:complexity`)
11
+ - Intensity (0.0–1.0) and duration (seconds)
12
+ - `cumulative_impact` = `intensity * (duration / 3600.0)`
13
+
14
+ Stressors with intensity <= 0.4 are **manageable** — they wear down integrity *and* build tempering. Overwhelming stressors (intensity >= 0.8) erode without building resilience.
15
+
16
+ **Effective capacity** = `integrity * (1 + tempering * 0.2)` — a tempered agent can exceed 1.0 base capacity (up to 1.2).
17
+
18
+ ## Usage
19
+
20
+ ```ruby
21
+ require 'lex-cognitive-weathering'
22
+
23
+ client = Legion::Extensions::CognitiveWeathering::Client.new
24
+
25
+ # Apply an overwhelming stressor (erodes integrity, no tempering)
26
+ client.apply_stressor(
27
+ description: 'Sprint deadline pressure',
28
+ stressor_type: :time_pressure,
29
+ intensity: 0.8,
30
+ duration: 7200,
31
+ domain: 'engineering'
32
+ )
33
+ # => { integrity: 0.9984, tempering_level: 0.0, effective_capacity: 0.9984, fragile: false, ... }
34
+
35
+ # Apply a manageable stressor (erodes slightly, builds tempering)
36
+ client.apply_stressor(
37
+ description: 'Steady background complexity',
38
+ stressor_type: :complexity,
39
+ intensity: 0.3,
40
+ duration: 3600
41
+ )
42
+ # => { integrity: 0.9980, tempering_level: 0.0009, effective_capacity: 0.9982, ... }
43
+
44
+ # Check current state
45
+ client.integrity_status
46
+ # => { integrity: 0.9980, integrity_label: "pristine", tempering_level: 0.0009, weathering_label: "eroded", ... }
47
+
48
+ # Recover from wear (small increment)
49
+ client.recover(amount: 1.0)
50
+ # => { integrity: 0.9990, ... }
51
+
52
+ # Full rest (5x recovery rate)
53
+ client.rest(amount: 1.0)
54
+ # => { integrity: 0.9995, ... }
55
+
56
+ # Full weathering report
57
+ client.weathering_report
58
+ # => { integrity: 0.9995, integrity_label: "pristine", tempering_level: 0.0009, weathering_label: "eroded",
59
+ # effective_capacity: 0.9997, total_wear: 0.0021, total_recovery: 0.0015,
60
+ # stressor_count: 2, fragile: false, breaking: false, recent_stressors: [...] }
61
+ ```
62
+
63
+ ## Development
64
+
65
+ ```bash
66
+ bundle install
67
+ bundle exec rspec
68
+ bundle exec rubocop
69
+ ```
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/legion/extensions/cognitive_weathering/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'lex-cognitive-weathering'
7
+ spec.version = Legion::Extensions::CognitiveWeathering::VERSION
8
+ spec.authors = ['Esity']
9
+ spec.email = ['matthewdiverson@gmail.com']
10
+
11
+ spec.summary = 'LEX Cognitive Weathering'
12
+ spec.description = 'Models long-term cognitive wear from sustained workloads based on allostatic load theory'
13
+ spec.homepage = 'https://github.com/LegionIO/lex-cognitive-weathering'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 3.4'
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-weathering'
19
+ spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-weathering'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-weathering'
21
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-weathering/issues'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ Dir.glob('{lib,spec}/**/*') + %w[lex-cognitive-weathering.gemspec Gemfile LICENSE README.md]
26
+ end
27
+ spec.require_paths = ['lib']
28
+ spec.add_development_dependency 'legion-gaia'
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/cognitive_weathering/helpers/constants'
4
+ require 'legion/extensions/cognitive_weathering/helpers/stressor'
5
+ require 'legion/extensions/cognitive_weathering/helpers/weathering_engine'
6
+ require 'legion/extensions/cognitive_weathering/runners/cognitive_weathering'
7
+
8
+ module Legion
9
+ module Extensions
10
+ module CognitiveWeathering
11
+ class Client
12
+ include Runners::CognitiveWeathering
13
+
14
+ def initialize(**)
15
+ @weathering_engine = Helpers::WeatheringEngine.new
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveWeathering
6
+ module Helpers
7
+ module Constants
8
+ MAX_STRESSORS = 200
9
+ MAX_EVENTS = 500
10
+
11
+ DEFAULT_INTEGRITY = 1.0
12
+ WEAR_RATE = 0.02
13
+ RECOVERY_RATE = 0.01
14
+ TEMPERING_RATE = 0.03
15
+
16
+ TEMPERING_THRESHOLD = 0.4
17
+ CRITICAL_INTEGRITY = 0.3
18
+ BREAKDOWN_INTEGRITY = 0.1
19
+
20
+ STRESSOR_TYPES = %i[
21
+ cognitive_overload
22
+ emotional_strain
23
+ decision_fatigue
24
+ conflict_exposure
25
+ uncertainty
26
+ time_pressure
27
+ monotony
28
+ complexity
29
+ ].freeze
30
+
31
+ INTEGRITY_LABELS = [
32
+ { range: (0.8..1.0), label: 'pristine' },
33
+ { range: (0.6...0.8), label: 'strong' },
34
+ { range: (0.4...0.6), label: 'worn' },
35
+ { range: (0.2...0.4), label: 'fragile' },
36
+ { range: (0.0...0.2), label: 'breaking' }
37
+ ].freeze
38
+
39
+ WEATHERING_LABELS = [
40
+ { range: (0.7..1.0), label: 'tempered' },
41
+ { range: (0.5...0.7), label: 'resilient' },
42
+ { range: (0.3...0.5), label: 'stable' },
43
+ { range: (0.1...0.3), label: 'weathered' },
44
+ { range: (0.0...0.1), label: 'eroded' }
45
+ ].freeze
46
+
47
+ module_function
48
+
49
+ def integrity_label(integrity)
50
+ entry = INTEGRITY_LABELS.find { |e| e[:range].cover?(integrity) }
51
+ entry ? entry[:label] : 'breaking'
52
+ end
53
+
54
+ def weathering_label(tempering_level)
55
+ entry = WEATHERING_LABELS.find { |e| e[:range].cover?(tempering_level) }
56
+ entry ? entry[:label] : 'eroded'
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module CognitiveWeathering
8
+ module Helpers
9
+ class Stressor
10
+ include Constants
11
+
12
+ attr_reader :id, :description, :stressor_type, :intensity, :duration, :domain, :recorded_at
13
+
14
+ def initialize(description:, stressor_type:, intensity:, duration:, domain: nil)
15
+ @id = SecureRandom.uuid
16
+ @description = description
17
+ @stressor_type = validate_type(stressor_type)
18
+ @intensity = intensity.clamp(0.0, 1.0)
19
+ @duration = [duration.to_f, 0.0].max
20
+ @domain = domain
21
+ @recorded_at = Time.now.utc
22
+ end
23
+
24
+ def cumulative_impact
25
+ (intensity * (duration / 3600.0)).clamp(0.0, 1.0).round(10)
26
+ end
27
+
28
+ def manageable?
29
+ intensity <= Constants::TEMPERING_THRESHOLD
30
+ end
31
+
32
+ def overwhelming?
33
+ intensity >= 0.8
34
+ end
35
+
36
+ def to_h
37
+ {
38
+ id: id,
39
+ description: description,
40
+ stressor_type: stressor_type,
41
+ intensity: intensity,
42
+ duration: duration,
43
+ domain: domain,
44
+ cumulative_impact: cumulative_impact,
45
+ manageable: manageable?,
46
+ overwhelming: overwhelming?,
47
+ recorded_at: recorded_at.iso8601
48
+ }
49
+ end
50
+
51
+ private
52
+
53
+ def validate_type(type)
54
+ sym = type.to_sym
55
+ Constants::STRESSOR_TYPES.include?(sym) ? sym : :cognitive_overload
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveWeathering
6
+ module Helpers
7
+ class WeatheringEngine
8
+ include Constants
9
+
10
+ attr_reader :integrity, :tempering_level, :total_wear, :total_recovery
11
+
12
+ def initialize
13
+ @stressors = []
14
+ @events = []
15
+ @integrity = Constants::DEFAULT_INTEGRITY
16
+ @tempering_level = 0.0
17
+ @total_wear = 0.0
18
+ @total_recovery = 0.0
19
+ end
20
+
21
+ def apply_stressor(stressor)
22
+ prune_stressors
23
+ @stressors << stressor
24
+
25
+ record_event(:stressor_applied, stressor.to_h)
26
+ wear!(stressor.cumulative_impact)
27
+ temper!(stressor.cumulative_impact * Constants::TEMPERING_RATE) if stressor.manageable?
28
+
29
+ to_h
30
+ end
31
+
32
+ def recover!(amount)
33
+ amount = amount.clamp(0.0, 1.0)
34
+ delta = [amount * Constants::RECOVERY_RATE, 1.0 - @integrity].min
35
+ @integrity = (@integrity + delta).clamp(0.0, 1.0).round(10)
36
+ @total_recovery = (@total_recovery + delta).round(10)
37
+ record_event(:recovery, { amount: amount, delta: delta, integrity: @integrity })
38
+ to_h
39
+ end
40
+
41
+ def rest!(amount = 1.0)
42
+ amount = amount.clamp(0.0, 1.0)
43
+ delta = [amount * (Constants::RECOVERY_RATE * 5.0), 1.0 - @integrity].min
44
+ @integrity = (@integrity + delta).clamp(0.0, 1.0).round(10)
45
+ @total_recovery = (@total_recovery + delta).round(10)
46
+ record_event(:rest, { amount: amount, delta: delta, integrity: @integrity })
47
+ to_h
48
+ end
49
+
50
+ def effective_capacity
51
+ (@integrity * (1.0 + (@tempering_level * 0.2))).clamp(0.0, 1.2).round(10)
52
+ end
53
+
54
+ def fragile?
55
+ @integrity <= Constants::CRITICAL_INTEGRITY
56
+ end
57
+
58
+ def breaking?
59
+ @integrity <= Constants::BREAKDOWN_INTEGRITY
60
+ end
61
+
62
+ def stressor_count
63
+ @stressors.size
64
+ end
65
+
66
+ def weathering_report
67
+ {
68
+ integrity: @integrity.round(10),
69
+ integrity_label: Constants.integrity_label(@integrity),
70
+ tempering_level: @tempering_level.round(10),
71
+ weathering_label: Constants.weathering_label(@tempering_level),
72
+ effective_capacity: effective_capacity,
73
+ total_wear: @total_wear.round(10),
74
+ total_recovery: @total_recovery.round(10),
75
+ stressor_count: @stressors.size,
76
+ fragile: fragile?,
77
+ breaking: breaking?,
78
+ recent_stressors: @stressors.last(5).map(&:to_h)
79
+ }
80
+ end
81
+
82
+ def to_h
83
+ {
84
+ integrity: @integrity.round(10),
85
+ tempering_level: @tempering_level.round(10),
86
+ effective_capacity: effective_capacity,
87
+ fragile: fragile?,
88
+ breaking: breaking?
89
+ }
90
+ end
91
+
92
+ private
93
+
94
+ def wear!(amount)
95
+ delta = (amount * Constants::WEAR_RATE).clamp(0.0, @integrity)
96
+ @integrity = (@integrity - delta).clamp(0.0, 1.0).round(10)
97
+ @total_wear = (@total_wear + delta).round(10)
98
+ end
99
+
100
+ def temper!(amount)
101
+ delta = amount.clamp(0.0, 1.0 - @tempering_level)
102
+ @tempering_level = (@tempering_level + delta).clamp(0.0, 1.0).round(10)
103
+ end
104
+
105
+ def record_event(type, data)
106
+ prune_events
107
+ @events << { type: type, data: data, timestamp: Time.now.utc.iso8601 }
108
+ end
109
+
110
+ def prune_stressors
111
+ @stressors.shift while @stressors.size >= Constants::MAX_STRESSORS
112
+ end
113
+
114
+ def prune_events
115
+ @events.shift while @events.size >= Constants::MAX_EVENTS
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveWeathering
6
+ module Runners
7
+ module CognitiveWeathering
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ def apply_stressor(description:, stressor_type: :cognitive_overload, intensity: 0.5,
12
+ duration: 3600, domain: nil, **)
13
+ stressor = Helpers::Stressor.new(
14
+ description: description,
15
+ stressor_type: stressor_type,
16
+ intensity: intensity,
17
+ duration: duration,
18
+ domain: domain
19
+ )
20
+
21
+ result = weathering_engine.apply_stressor(stressor)
22
+ Legion::Logging.debug "[cognitive_weathering] stressor applied: type=#{stressor_type} " \
23
+ "intensity=#{intensity} impact=#{stressor.cumulative_impact.round(4)} " \
24
+ "integrity=#{result[:integrity].round(4)} fragile=#{result[:fragile]}"
25
+ result.merge(stressor: stressor.to_h)
26
+ end
27
+
28
+ def recover(amount: 1.0, **)
29
+ result = weathering_engine.recover!(amount)
30
+ Legion::Logging.debug "[cognitive_weathering] recovery: amount=#{amount} integrity=#{result[:integrity].round(4)}"
31
+ result
32
+ end
33
+
34
+ def rest(amount: 1.0, **)
35
+ result = weathering_engine.rest!(amount)
36
+ Legion::Logging.debug "[cognitive_weathering] rest: amount=#{amount} integrity=#{result[:integrity].round(4)}"
37
+ result
38
+ end
39
+
40
+ def weathering_report(**)
41
+ report = weathering_engine.weathering_report
42
+ Legion::Logging.debug "[cognitive_weathering] report: integrity=#{report[:integrity_label]} " \
43
+ "capacity=#{report[:effective_capacity].round(4)} " \
44
+ "stressors=#{report[:stressor_count]}"
45
+ report
46
+ end
47
+
48
+ def integrity_status(**)
49
+ engine = weathering_engine
50
+ {
51
+ integrity: engine.integrity.round(10),
52
+ integrity_label: Helpers::Constants.integrity_label(engine.integrity),
53
+ tempering_level: engine.tempering_level.round(10),
54
+ weathering_label: Helpers::Constants.weathering_label(engine.tempering_level),
55
+ effective_capacity: engine.effective_capacity,
56
+ fragile: engine.fragile?,
57
+ breaking: engine.breaking?
58
+ }
59
+ end
60
+
61
+ private
62
+
63
+ def weathering_engine
64
+ @weathering_engine ||= Helpers::WeatheringEngine.new
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveWeathering
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/cognitive_weathering/version'
4
+ require 'legion/extensions/cognitive_weathering/helpers/constants'
5
+ require 'legion/extensions/cognitive_weathering/helpers/stressor'
6
+ require 'legion/extensions/cognitive_weathering/helpers/weathering_engine'
7
+ require 'legion/extensions/cognitive_weathering/runners/cognitive_weathering'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module CognitiveWeathering
12
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/cognitive_weathering/client'
4
+
5
+ RSpec.describe Legion::Extensions::CognitiveWeathering::Client do
6
+ let(:client) { described_class.new }
7
+
8
+ it 'responds to apply_stressor' do
9
+ expect(client).to respond_to(:apply_stressor)
10
+ end
11
+
12
+ it 'responds to recover' do
13
+ expect(client).to respond_to(:recover)
14
+ end
15
+
16
+ it 'responds to rest' do
17
+ expect(client).to respond_to(:rest)
18
+ end
19
+
20
+ it 'responds to weathering_report' do
21
+ expect(client).to respond_to(:weathering_report)
22
+ end
23
+
24
+ it 'responds to integrity_status' do
25
+ expect(client).to respond_to(:integrity_status)
26
+ end
27
+
28
+ it 'starts with pristine integrity' do
29
+ status = client.integrity_status
30
+ expect(status[:integrity_label]).to eq('pristine')
31
+ end
32
+
33
+ it 'round-trips a full weathering cycle' do
34
+ client.apply_stressor(description: 'Sprint overload', stressor_type: :time_pressure,
35
+ intensity: 0.85, duration: 7200)
36
+ client.apply_stressor(description: 'Repeated decisions', stressor_type: :decision_fatigue,
37
+ intensity: 0.7, duration: 3600)
38
+ client.apply_stressor(description: 'Mild task', stressor_type: :monotony,
39
+ intensity: 0.2, duration: 1800)
40
+
41
+ report = client.weathering_report
42
+ expect(report[:stressor_count]).to eq(3)
43
+ expect(report[:integrity]).to be < 1.0
44
+ expect(report[:tempering_level]).to be > 0.0
45
+
46
+ client.rest(amount: 1.0)
47
+ after_rest = client.integrity_status
48
+ expect(after_rest[:integrity]).to be > report[:integrity]
49
+ end
50
+
51
+ it 'effective_capacity increases with tempering' do
52
+ 20.times do
53
+ client.apply_stressor(description: 'Manageable', stressor_type: :complexity,
54
+ intensity: 0.3, duration: 1800)
55
+ end
56
+ status = client.integrity_status
57
+ expect(status[:tempering_level]).to be > 0.0
58
+ expect(status[:effective_capacity]).to be > 0.0
59
+ end
60
+
61
+ it 'each client instance has independent state' do
62
+ client_a = described_class.new
63
+ client_b = described_class.new
64
+
65
+ client_a.apply_stressor(description: 'only a', intensity: 0.9, duration: 7200)
66
+
67
+ expect(client_a.integrity_status[:integrity]).to be < 1.0
68
+ expect(client_b.integrity_status[:integrity]).to eq(1.0)
69
+ end
70
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveWeathering::Helpers::Constants do
4
+ describe 'numeric constants' do
5
+ it 'defines MAX_STRESSORS' do
6
+ expect(described_class::MAX_STRESSORS).to eq(200)
7
+ end
8
+
9
+ it 'defines MAX_EVENTS' do
10
+ expect(described_class::MAX_EVENTS).to eq(500)
11
+ end
12
+
13
+ it 'defines DEFAULT_INTEGRITY as 1.0' do
14
+ expect(described_class::DEFAULT_INTEGRITY).to eq(1.0)
15
+ end
16
+
17
+ it 'defines WEAR_RATE' do
18
+ expect(described_class::WEAR_RATE).to eq(0.02)
19
+ end
20
+
21
+ it 'defines RECOVERY_RATE' do
22
+ expect(described_class::RECOVERY_RATE).to eq(0.01)
23
+ end
24
+
25
+ it 'defines TEMPERING_RATE' do
26
+ expect(described_class::TEMPERING_RATE).to eq(0.03)
27
+ end
28
+
29
+ it 'defines TEMPERING_THRESHOLD' do
30
+ expect(described_class::TEMPERING_THRESHOLD).to eq(0.4)
31
+ end
32
+
33
+ it 'defines CRITICAL_INTEGRITY' do
34
+ expect(described_class::CRITICAL_INTEGRITY).to eq(0.3)
35
+ end
36
+
37
+ it 'defines BREAKDOWN_INTEGRITY' do
38
+ expect(described_class::BREAKDOWN_INTEGRITY).to eq(0.1)
39
+ end
40
+ end
41
+
42
+ describe 'STRESSOR_TYPES' do
43
+ it 'contains all 8 stressor types' do
44
+ expect(described_class::STRESSOR_TYPES.size).to eq(8)
45
+ end
46
+
47
+ it 'includes :cognitive_overload' do
48
+ expect(described_class::STRESSOR_TYPES).to include(:cognitive_overload)
49
+ end
50
+
51
+ it 'includes :emotional_strain' do
52
+ expect(described_class::STRESSOR_TYPES).to include(:emotional_strain)
53
+ end
54
+
55
+ it 'includes :decision_fatigue' do
56
+ expect(described_class::STRESSOR_TYPES).to include(:decision_fatigue)
57
+ end
58
+
59
+ it 'includes :conflict_exposure' do
60
+ expect(described_class::STRESSOR_TYPES).to include(:conflict_exposure)
61
+ end
62
+
63
+ it 'includes :uncertainty' do
64
+ expect(described_class::STRESSOR_TYPES).to include(:uncertainty)
65
+ end
66
+
67
+ it 'includes :time_pressure' do
68
+ expect(described_class::STRESSOR_TYPES).to include(:time_pressure)
69
+ end
70
+
71
+ it 'includes :monotony' do
72
+ expect(described_class::STRESSOR_TYPES).to include(:monotony)
73
+ end
74
+
75
+ it 'includes :complexity' do
76
+ expect(described_class::STRESSOR_TYPES).to include(:complexity)
77
+ end
78
+
79
+ it 'is frozen' do
80
+ expect(described_class::STRESSOR_TYPES).to be_frozen
81
+ end
82
+ end
83
+
84
+ describe '.integrity_label' do
85
+ it 'returns pristine for 1.0' do
86
+ expect(described_class.integrity_label(1.0)).to eq('pristine')
87
+ end
88
+
89
+ it 'returns pristine for 0.8' do
90
+ expect(described_class.integrity_label(0.8)).to eq('pristine')
91
+ end
92
+
93
+ it 'returns strong for 0.7' do
94
+ expect(described_class.integrity_label(0.7)).to eq('strong')
95
+ end
96
+
97
+ it 'returns strong for 0.6' do
98
+ expect(described_class.integrity_label(0.6)).to eq('strong')
99
+ end
100
+
101
+ it 'returns worn for 0.5' do
102
+ expect(described_class.integrity_label(0.5)).to eq('worn')
103
+ end
104
+
105
+ it 'returns fragile for 0.25' do
106
+ expect(described_class.integrity_label(0.25)).to eq('fragile')
107
+ end
108
+
109
+ it 'returns breaking for 0.1' do
110
+ expect(described_class.integrity_label(0.1)).to eq('breaking')
111
+ end
112
+
113
+ it 'returns breaking for 0.0' do
114
+ expect(described_class.integrity_label(0.0)).to eq('breaking')
115
+ end
116
+ end
117
+
118
+ describe '.weathering_label' do
119
+ it 'returns tempered for 0.9' do
120
+ expect(described_class.weathering_label(0.9)).to eq('tempered')
121
+ end
122
+
123
+ it 'returns tempered for 0.7' do
124
+ expect(described_class.weathering_label(0.7)).to eq('tempered')
125
+ end
126
+
127
+ it 'returns resilient for 0.6' do
128
+ expect(described_class.weathering_label(0.6)).to eq('resilient')
129
+ end
130
+
131
+ it 'returns stable for 0.4' do
132
+ expect(described_class.weathering_label(0.4)).to eq('stable')
133
+ end
134
+
135
+ it 'returns weathered for 0.2' do
136
+ expect(described_class.weathering_label(0.2)).to eq('weathered')
137
+ end
138
+
139
+ it 'returns eroded for 0.05' do
140
+ expect(described_class.weathering_label(0.05)).to eq('eroded')
141
+ end
142
+
143
+ it 'returns eroded for 0.0' do
144
+ expect(described_class.weathering_label(0.0)).to eq('eroded')
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveWeathering::Helpers::Stressor do
4
+ let(:stressor) do
5
+ described_class.new(
6
+ description: 'Heavy parallel task load',
7
+ stressor_type: :cognitive_overload,
8
+ intensity: 0.7,
9
+ duration: 3600,
10
+ domain: 'work'
11
+ )
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'assigns a UUID id' do
16
+ expect(stressor.id).to match(/\A[0-9a-f-]{36}\z/)
17
+ end
18
+
19
+ it 'assigns description' do
20
+ expect(stressor.description).to eq('Heavy parallel task load')
21
+ end
22
+
23
+ it 'assigns stressor_type' do
24
+ expect(stressor.stressor_type).to eq(:cognitive_overload)
25
+ end
26
+
27
+ it 'assigns intensity' do
28
+ expect(stressor.intensity).to eq(0.7)
29
+ end
30
+
31
+ it 'assigns duration' do
32
+ expect(stressor.duration).to eq(3600)
33
+ end
34
+
35
+ it 'assigns domain' do
36
+ expect(stressor.domain).to eq('work')
37
+ end
38
+
39
+ it 'records a timestamp' do
40
+ expect(stressor.recorded_at).to be_a(Time)
41
+ end
42
+
43
+ it 'clamps intensity above 1.0 to 1.0' do
44
+ s = described_class.new(description: 'test', stressor_type: :monotony, intensity: 1.5, duration: 60)
45
+ expect(s.intensity).to eq(1.0)
46
+ end
47
+
48
+ it 'clamps intensity below 0.0 to 0.0' do
49
+ s = described_class.new(description: 'test', stressor_type: :monotony, intensity: -0.3, duration: 60)
50
+ expect(s.intensity).to eq(0.0)
51
+ end
52
+
53
+ it 'defaults domain to nil when not provided' do
54
+ s = described_class.new(description: 'test', stressor_type: :complexity, intensity: 0.5, duration: 60)
55
+ expect(s.domain).to be_nil
56
+ end
57
+
58
+ it 'falls back to :cognitive_overload for unknown stressor type' do
59
+ s = described_class.new(description: 'test', stressor_type: :banana, intensity: 0.5, duration: 60)
60
+ expect(s.stressor_type).to eq(:cognitive_overload)
61
+ end
62
+
63
+ it 'accepts string stressor type and converts to symbol' do
64
+ s = described_class.new(description: 'test', stressor_type: 'monotony', intensity: 0.5, duration: 60)
65
+ expect(s.stressor_type).to eq(:monotony)
66
+ end
67
+
68
+ it 'floors negative duration to 0' do
69
+ s = described_class.new(description: 'test', stressor_type: :uncertainty, intensity: 0.3, duration: -100)
70
+ expect(s.duration).to eq(0.0)
71
+ end
72
+ end
73
+
74
+ describe '#cumulative_impact' do
75
+ it 'computes intensity * (duration / 3600)' do
76
+ expect(stressor.cumulative_impact).to be_within(0.0001).of(0.7)
77
+ end
78
+
79
+ it 'rounds to 10 decimal places' do
80
+ expect(stressor.cumulative_impact.to_s).to match(/\A\d+\.\d+\z/)
81
+ end
82
+
83
+ it 'clamps at 1.0 for very long durations' do
84
+ s = described_class.new(description: 'long', stressor_type: :time_pressure, intensity: 1.0, duration: 100_000)
85
+ expect(s.cumulative_impact).to eq(1.0)
86
+ end
87
+
88
+ it 'returns 0 for zero duration' do
89
+ s = described_class.new(description: 'instant', stressor_type: :uncertainty, intensity: 0.9, duration: 0)
90
+ expect(s.cumulative_impact).to eq(0.0)
91
+ end
92
+ end
93
+
94
+ describe '#manageable?' do
95
+ it 'returns true when intensity is at or below TEMPERING_THRESHOLD' do
96
+ s = described_class.new(description: 'mild', stressor_type: :monotony, intensity: 0.4, duration: 60)
97
+ expect(s.manageable?).to be(true)
98
+ end
99
+
100
+ it 'returns false when intensity exceeds TEMPERING_THRESHOLD' do
101
+ s = described_class.new(description: 'heavy', stressor_type: :cognitive_overload, intensity: 0.6, duration: 60)
102
+ expect(s.manageable?).to be(false)
103
+ end
104
+ end
105
+
106
+ describe '#overwhelming?' do
107
+ it 'returns true when intensity >= 0.8' do
108
+ s = described_class.new(description: 'extreme', stressor_type: :conflict_exposure, intensity: 0.9, duration: 60)
109
+ expect(s.overwhelming?).to be(true)
110
+ end
111
+
112
+ it 'returns false when intensity < 0.8' do
113
+ s = described_class.new(description: 'moderate', stressor_type: :complexity, intensity: 0.7, duration: 60)
114
+ expect(s.overwhelming?).to be(false)
115
+ end
116
+ end
117
+
118
+ describe '#to_h' do
119
+ subject(:hash) { stressor.to_h }
120
+
121
+ it 'includes id' do
122
+ expect(hash[:id]).to match(/\A[0-9a-f-]{36}\z/)
123
+ end
124
+
125
+ it 'includes description' do
126
+ expect(hash[:description]).to eq('Heavy parallel task load')
127
+ end
128
+
129
+ it 'includes stressor_type' do
130
+ expect(hash[:stressor_type]).to eq(:cognitive_overload)
131
+ end
132
+
133
+ it 'includes intensity' do
134
+ expect(hash[:intensity]).to eq(0.7)
135
+ end
136
+
137
+ it 'includes duration' do
138
+ expect(hash[:duration]).to eq(3600)
139
+ end
140
+
141
+ it 'includes domain' do
142
+ expect(hash[:domain]).to eq('work')
143
+ end
144
+
145
+ it 'includes cumulative_impact' do
146
+ expect(hash[:cumulative_impact]).to be_a(Float)
147
+ end
148
+
149
+ it 'includes manageable flag' do
150
+ expect(hash[:manageable]).to be(false)
151
+ end
152
+
153
+ it 'includes overwhelming flag' do
154
+ expect(hash[:overwhelming]).to be(false)
155
+ end
156
+
157
+ it 'includes recorded_at as ISO8601 string' do
158
+ expect(hash[:recorded_at]).to match(/\d{4}-\d{2}-\d{2}T/)
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,242 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveWeathering::Helpers::WeatheringEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ let(:mild_stressor) do
7
+ Legion::Extensions::CognitiveWeathering::Helpers::Stressor.new(
8
+ description: 'Mild task',
9
+ stressor_type: :monotony,
10
+ intensity: 0.3,
11
+ duration: 1800
12
+ )
13
+ end
14
+
15
+ let(:heavy_stressor) do
16
+ Legion::Extensions::CognitiveWeathering::Helpers::Stressor.new(
17
+ description: 'Extreme overload',
18
+ stressor_type: :cognitive_overload,
19
+ intensity: 0.9,
20
+ duration: 7200
21
+ )
22
+ end
23
+
24
+ describe '#initialize' do
25
+ it 'starts with full integrity' do
26
+ expect(engine.integrity).to eq(1.0)
27
+ end
28
+
29
+ it 'starts with zero tempering_level' do
30
+ expect(engine.tempering_level).to eq(0.0)
31
+ end
32
+
33
+ it 'starts with zero total_wear' do
34
+ expect(engine.total_wear).to eq(0.0)
35
+ end
36
+
37
+ it 'starts with zero total_recovery' do
38
+ expect(engine.total_recovery).to eq(0.0)
39
+ end
40
+ end
41
+
42
+ describe '#apply_stressor' do
43
+ it 'reduces integrity after a heavy stressor' do
44
+ engine.apply_stressor(heavy_stressor)
45
+ expect(engine.integrity).to be < 1.0
46
+ end
47
+
48
+ it 'increases total_wear' do
49
+ engine.apply_stressor(heavy_stressor)
50
+ expect(engine.total_wear).to be > 0.0
51
+ end
52
+
53
+ it 'does not increase tempering for overwhelming stressor' do
54
+ engine.apply_stressor(heavy_stressor)
55
+ expect(engine.tempering_level).to eq(0.0)
56
+ end
57
+
58
+ it 'increases tempering for manageable stressor' do
59
+ engine.apply_stressor(mild_stressor)
60
+ expect(engine.tempering_level).to be > 0.0
61
+ end
62
+
63
+ it 'returns a hash with integrity key' do
64
+ result = engine.apply_stressor(heavy_stressor)
65
+ expect(result).to have_key(:integrity)
66
+ end
67
+
68
+ it 'returns a hash with breaking key' do
69
+ result = engine.apply_stressor(heavy_stressor)
70
+ expect(result).to have_key(:breaking)
71
+ end
72
+
73
+ it 'increments stressor_count' do
74
+ engine.apply_stressor(mild_stressor)
75
+ expect(engine.stressor_count).to eq(1)
76
+ end
77
+
78
+ it 'wear scales with cumulative impact' do
79
+ small = Legion::Extensions::CognitiveWeathering::Helpers::Stressor.new(
80
+ description: 'tiny', stressor_type: :monotony, intensity: 0.1, duration: 60
81
+ )
82
+ large = Legion::Extensions::CognitiveWeathering::Helpers::Stressor.new(
83
+ description: 'large', stressor_type: :cognitive_overload, intensity: 0.9, duration: 7200
84
+ )
85
+ engine_a = described_class.new
86
+ engine_b = described_class.new
87
+ engine_a.apply_stressor(small)
88
+ engine_b.apply_stressor(large)
89
+ expect(engine_b.total_wear).to be > engine_a.total_wear
90
+ end
91
+ end
92
+
93
+ describe '#recover!' do
94
+ before { engine.apply_stressor(heavy_stressor) }
95
+
96
+ it 'increases integrity' do
97
+ before = engine.integrity
98
+ engine.recover!(1.0)
99
+ expect(engine.integrity).to be > before
100
+ end
101
+
102
+ it 'increases total_recovery' do
103
+ engine.recover!(1.0)
104
+ expect(engine.total_recovery).to be > 0.0
105
+ end
106
+
107
+ it 'returns a hash with integrity' do
108
+ result = engine.recover!(1.0)
109
+ expect(result).to have_key(:integrity)
110
+ end
111
+
112
+ it 'clamps amount above 1.0' do
113
+ expect { engine.recover!(5.0) }.not_to raise_error
114
+ end
115
+
116
+ it 'does not exceed 1.0 integrity' do
117
+ 10.times { engine.recover!(1.0) }
118
+ expect(engine.integrity).to be <= 1.0
119
+ end
120
+ end
121
+
122
+ describe '#rest!' do
123
+ before { 5.times { engine.apply_stressor(heavy_stressor) } }
124
+
125
+ it 'increases integrity more than recover' do
126
+ engine_a = described_class.new
127
+ engine_b = described_class.new
128
+ 5.times { engine_a.apply_stressor(heavy_stressor) }
129
+ 5.times { engine_b.apply_stressor(heavy_stressor) }
130
+ integrity_before = engine_a.integrity
131
+
132
+ engine_a.recover!(1.0)
133
+ engine_b.rest!(1.0)
134
+
135
+ recovery_delta = engine_a.integrity - integrity_before
136
+ rest_delta = engine_b.integrity - integrity_before
137
+ expect(rest_delta).to be > recovery_delta
138
+ end
139
+
140
+ it 'does not exceed 1.0 integrity' do
141
+ 10.times { engine.rest!(1.0) }
142
+ expect(engine.integrity).to be <= 1.0
143
+ end
144
+
145
+ it 'increases total_recovery' do
146
+ engine.rest!(1.0)
147
+ expect(engine.total_recovery).to be > 0.0
148
+ end
149
+ end
150
+
151
+ describe '#effective_capacity' do
152
+ it 'starts at 1.0 with no tempering' do
153
+ expect(engine.effective_capacity).to be_within(0.001).of(1.0)
154
+ end
155
+
156
+ it 'increases above base when tempering is present' do
157
+ 20.times { engine.apply_stressor(mild_stressor) }
158
+ expect(engine.tempering_level).to be > 0.0
159
+ expect(engine.effective_capacity).to be > (engine.integrity * 1.0)
160
+ end
161
+
162
+ it 'is capped at 1.2' do
163
+ 100.times { engine.apply_stressor(mild_stressor) }
164
+ expect(engine.effective_capacity).to be <= 1.2
165
+ end
166
+
167
+ it 'decreases as integrity drops' do
168
+ base = engine.effective_capacity
169
+ 10.times { engine.apply_stressor(heavy_stressor) }
170
+ expect(engine.effective_capacity).to be < base
171
+ end
172
+ end
173
+
174
+ describe '#fragile?' do
175
+ it 'returns false at full integrity' do
176
+ expect(engine.fragile?).to be(false)
177
+ end
178
+
179
+ it 'returns true when integrity is at or below CRITICAL_INTEGRITY' do
180
+ 100.times { engine.apply_stressor(heavy_stressor) }
181
+ expect(engine.fragile?).to be(true)
182
+ end
183
+ end
184
+
185
+ describe '#breaking?' do
186
+ it 'returns false at full integrity' do
187
+ expect(engine.breaking?).to be(false)
188
+ end
189
+
190
+ it 'returns true when integrity is at or below BREAKDOWN_INTEGRITY' do
191
+ 500.times { engine.apply_stressor(heavy_stressor) }
192
+ expect(engine.breaking?).to be(true)
193
+ end
194
+ end
195
+
196
+ describe '#weathering_report' do
197
+ it 'returns all expected keys' do
198
+ report = engine.weathering_report
199
+ expect(report).to have_key(:integrity)
200
+ expect(report).to have_key(:integrity_label)
201
+ expect(report).to have_key(:tempering_level)
202
+ expect(report).to have_key(:weathering_label)
203
+ expect(report).to have_key(:effective_capacity)
204
+ expect(report).to have_key(:total_wear)
205
+ expect(report).to have_key(:total_recovery)
206
+ expect(report).to have_key(:stressor_count)
207
+ expect(report).to have_key(:fragile)
208
+ expect(report).to have_key(:breaking)
209
+ expect(report).to have_key(:recent_stressors)
210
+ end
211
+
212
+ it 'includes integrity_label as a string' do
213
+ expect(engine.weathering_report[:integrity_label]).to eq('pristine')
214
+ end
215
+
216
+ it 'caps recent_stressors at 5' do
217
+ 10.times { engine.apply_stressor(mild_stressor) }
218
+ expect(engine.weathering_report[:recent_stressors].size).to eq(5)
219
+ end
220
+ end
221
+
222
+ describe '#to_h' do
223
+ it 'includes integrity, tempering_level, effective_capacity, fragile, breaking' do
224
+ h = engine.to_h
225
+ expect(h).to have_key(:integrity)
226
+ expect(h).to have_key(:tempering_level)
227
+ expect(h).to have_key(:effective_capacity)
228
+ expect(h).to have_key(:fragile)
229
+ expect(h).to have_key(:breaking)
230
+ end
231
+ end
232
+
233
+ describe 'MAX_STRESSORS pruning' do
234
+ it 'does not exceed MAX_STRESSORS in memory' do
235
+ constants = Legion::Extensions::CognitiveWeathering::Helpers::Constants
236
+ (constants::MAX_STRESSORS + 10).times do
237
+ engine.apply_stressor(mild_stressor)
238
+ end
239
+ expect(engine.stressor_count).to be <= constants::MAX_STRESSORS
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/cognitive_weathering/client'
4
+
5
+ RSpec.describe Legion::Extensions::CognitiveWeathering::Runners::CognitiveWeathering do
6
+ let(:client) { Legion::Extensions::CognitiveWeathering::Client.new }
7
+
8
+ describe '#apply_stressor' do
9
+ it 'returns a hash with integrity' do
10
+ result = client.apply_stressor(description: 'Heavy load', stressor_type: :cognitive_overload,
11
+ intensity: 0.8, duration: 3600)
12
+ expect(result).to have_key(:integrity)
13
+ end
14
+
15
+ it 'includes stressor details in result' do
16
+ result = client.apply_stressor(description: 'Test stressor', stressor_type: :monotony,
17
+ intensity: 0.3, duration: 1800)
18
+ expect(result[:stressor][:description]).to eq('Test stressor')
19
+ end
20
+
21
+ it 'uses defaults when optional params omitted' do
22
+ result = client.apply_stressor(description: 'minimal')
23
+ expect(result).to have_key(:integrity)
24
+ end
25
+
26
+ it 'reduces integrity for high-intensity stressor' do
27
+ client.apply_stressor(description: 'overload', intensity: 0.9, duration: 7200)
28
+ status = client.integrity_status
29
+ expect(status[:integrity]).to be < 1.0
30
+ end
31
+
32
+ it 'includes breaking flag' do
33
+ result = client.apply_stressor(description: 'test', intensity: 0.5, duration: 3600)
34
+ expect(result).to have_key(:breaking)
35
+ end
36
+ end
37
+
38
+ describe '#recover' do
39
+ before { client.apply_stressor(description: 'stress', intensity: 0.9, duration: 7200) }
40
+
41
+ it 'increases integrity after recovery' do
42
+ before = client.integrity_status[:integrity]
43
+ client.recover(amount: 1.0)
44
+ after = client.integrity_status[:integrity]
45
+ expect(after).to be >= before
46
+ end
47
+
48
+ it 'returns a hash with integrity' do
49
+ result = client.recover(amount: 1.0)
50
+ expect(result).to have_key(:integrity)
51
+ end
52
+
53
+ it 'uses default amount of 1.0' do
54
+ expect { client.recover }.not_to raise_error
55
+ end
56
+ end
57
+
58
+ describe '#rest' do
59
+ before { client.apply_stressor(description: 'stress', intensity: 0.9, duration: 7200) }
60
+
61
+ it 'increases integrity' do
62
+ before = client.integrity_status[:integrity]
63
+ client.rest(amount: 1.0)
64
+ after = client.integrity_status[:integrity]
65
+ expect(after).to be >= before
66
+ end
67
+
68
+ it 'returns a hash with integrity' do
69
+ result = client.rest(amount: 1.0)
70
+ expect(result).to have_key(:integrity)
71
+ end
72
+ end
73
+
74
+ describe '#weathering_report' do
75
+ it 'returns a comprehensive report' do
76
+ report = client.weathering_report
77
+ expect(report).to have_key(:integrity)
78
+ expect(report).to have_key(:integrity_label)
79
+ expect(report).to have_key(:effective_capacity)
80
+ end
81
+
82
+ it 'reflects stressor history' do
83
+ client.apply_stressor(description: 'first', intensity: 0.5, duration: 3600)
84
+ report = client.weathering_report
85
+ expect(report[:stressor_count]).to eq(1)
86
+ end
87
+ end
88
+
89
+ describe '#integrity_status' do
90
+ it 'returns all status keys' do
91
+ status = client.integrity_status
92
+ expect(status).to have_key(:integrity)
93
+ expect(status).to have_key(:integrity_label)
94
+ expect(status).to have_key(:tempering_level)
95
+ expect(status).to have_key(:weathering_label)
96
+ expect(status).to have_key(:effective_capacity)
97
+ expect(status).to have_key(:fragile)
98
+ expect(status).to have_key(:breaking)
99
+ end
100
+
101
+ it 'starts at pristine with full integrity' do
102
+ status = client.integrity_status
103
+ expect(status[:integrity_label]).to eq('pristine')
104
+ expect(status[:integrity]).to eq(1.0)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ module Legion
6
+ module Logging
7
+ def self.debug(_msg); end
8
+ def self.info(_msg); end
9
+ def self.warn(_msg); end
10
+ def self.error(_msg); end
11
+ end
12
+ end
13
+
14
+ require 'legion/extensions/cognitive_weathering'
15
+
16
+ RSpec.configure do |config|
17
+ config.example_status_persistence_file_path = '.rspec_status'
18
+ config.disable_monkey_patching!
19
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
20
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-cognitive-weathering
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Esity
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: legion-gaia
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ description: Models long-term cognitive wear from sustained workloads based on allostatic
27
+ load theory
28
+ email:
29
+ - matthewdiverson@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - Gemfile
35
+ - LICENSE
36
+ - README.md
37
+ - lex-cognitive-weathering.gemspec
38
+ - lib/legion/extensions/cognitive_weathering.rb
39
+ - lib/legion/extensions/cognitive_weathering/client.rb
40
+ - lib/legion/extensions/cognitive_weathering/helpers/constants.rb
41
+ - lib/legion/extensions/cognitive_weathering/helpers/stressor.rb
42
+ - lib/legion/extensions/cognitive_weathering/helpers/weathering_engine.rb
43
+ - lib/legion/extensions/cognitive_weathering/runners/cognitive_weathering.rb
44
+ - lib/legion/extensions/cognitive_weathering/version.rb
45
+ - spec/legion/extensions/cognitive_weathering/client_spec.rb
46
+ - spec/legion/extensions/cognitive_weathering/helpers/constants_spec.rb
47
+ - spec/legion/extensions/cognitive_weathering/helpers/stressor_spec.rb
48
+ - spec/legion/extensions/cognitive_weathering/helpers/weathering_engine_spec.rb
49
+ - spec/legion/extensions/cognitive_weathering/runners/cognitive_weathering_spec.rb
50
+ - spec/spec_helper.rb
51
+ homepage: https://github.com/LegionIO/lex-cognitive-weathering
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ homepage_uri: https://github.com/LegionIO/lex-cognitive-weathering
56
+ source_code_uri: https://github.com/LegionIO/lex-cognitive-weathering
57
+ documentation_uri: https://github.com/LegionIO/lex-cognitive-weathering
58
+ changelog_uri: https://github.com/LegionIO/lex-cognitive-weathering
59
+ bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-weathering/issues
60
+ rubygems_mfa_required: 'true'
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.6.9
76
+ specification_version: 4
77
+ summary: LEX Cognitive Weathering
78
+ test_files: []