lex-expectation-violation 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/README.md +56 -0
- data/lib/legion/extensions/expectation_violation/helpers/client.rb +13 -0
- data/lib/legion/extensions/expectation_violation/helpers/constants.rb +43 -0
- data/lib/legion/extensions/expectation_violation/helpers/expectation.rb +78 -0
- data/lib/legion/extensions/expectation_violation/helpers/violation_engine.rb +122 -0
- data/lib/legion/extensions/expectation_violation/runners/expectation_violation.rb +72 -0
- data/lib/legion/extensions/expectation_violation/version.rb +9 -0
- data/lib/legion/extensions/expectation_violation.rb +16 -0
- metadata +70 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 36d95c00c9874f88a704e09c66272d6c53d15f0ef0dba263d96bdb4c89aca09d
|
|
4
|
+
data.tar.gz: fe5b4796fb94a4f90b01cbb2568f6819ddf49f5e0cc0f1841473cf9f340c6c0d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 24e930f5b5beec88c7e8c6356f897c0444fc121dac4f84d6d714606e48de5869901222ca1b6125ec45a69206cd15c31e519a20615e4cde12cf3c3515a68bc758
|
|
7
|
+
data.tar.gz: 060b4374e7d6d3df5089bd01c6fd3fa0972c7d65edb26895d0040138a8e6a1b11fd4e854da1ad9049c8efaef85a7c2806d6da619116cf45379f44d68da5277de
|
data/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# lex-expectation-violation
|
|
2
|
+
|
|
3
|
+
Expectation violation modeling for the LegionIO brain-modeled cognitive architecture.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Detects and processes mismatches between what the agent predicts and what actually happens. Computes violation magnitude, classifies violations as positive surprise, negative surprise, schema mismatch, or neutral, and selects adaptive responses: belief updating, heightened attention, or curiosity-driven exploration. The attention boost from significant violations ensures unexpected events receive more processing.
|
|
8
|
+
|
|
9
|
+
Based on predictive processing theory (Clark, Friston) and violation of expectation research.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
client = Legion::Extensions::ExpectationViolation::Client.new
|
|
15
|
+
|
|
16
|
+
# Register an expectation before acting
|
|
17
|
+
client.register_expectation(
|
|
18
|
+
domain: :networking,
|
|
19
|
+
predicted: :success,
|
|
20
|
+
confidence: 0.85
|
|
21
|
+
)
|
|
22
|
+
# => { success: true, expectation_id: "...", domain: :networking }
|
|
23
|
+
|
|
24
|
+
# Check the expectation after observing the outcome
|
|
25
|
+
client.check_expectation(expectation_id: '...', actual: :timeout)
|
|
26
|
+
# => { success: true, violation_detected: true, magnitude: 0.85,
|
|
27
|
+
# violation_type: :negative_surprise, response_mode: :update_belief,
|
|
28
|
+
# surprise_label: :surprising }
|
|
29
|
+
|
|
30
|
+
# Process the violation (executes the response mode)
|
|
31
|
+
client.process_violation(violation_id: '...')
|
|
32
|
+
# => { processed: true, belief_updated: true, attention_boost: 0.25, exploration_triggered: false }
|
|
33
|
+
|
|
34
|
+
# Check current attention level
|
|
35
|
+
client.attention_level
|
|
36
|
+
# => { attention: 0.7, attention_label: :alert, heightened: true }
|
|
37
|
+
|
|
38
|
+
# Expectation accuracy over a domain
|
|
39
|
+
client.expectation_accuracy(domain: :networking)
|
|
40
|
+
# => { accuracy_rate: 0.72, total_checked: 25, violations_count: 7 }
|
|
41
|
+
|
|
42
|
+
# Periodic maintenance
|
|
43
|
+
client.update_expectation_violation
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
bundle install
|
|
50
|
+
bundle exec rspec
|
|
51
|
+
bundle exec rubocop
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module ExpectationViolation
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
VIOLATION_TYPES = %i[positive negative neutral].freeze
|
|
9
|
+
|
|
10
|
+
VIOLATION_LABELS = {
|
|
11
|
+
(0.8..) => :extreme_positive,
|
|
12
|
+
(0.3...0.8) => :positive,
|
|
13
|
+
(-0.3...0.3) => :neutral,
|
|
14
|
+
(-0.8...-0.3) => :negative,
|
|
15
|
+
(..-0.8) => :extreme_negative
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
AROUSAL_LABELS = {
|
|
19
|
+
(0.8..) => :highly_aroused,
|
|
20
|
+
(0.6...0.8) => :aroused,
|
|
21
|
+
(0.4...0.6) => :moderate,
|
|
22
|
+
(0.2...0.4) => :calm,
|
|
23
|
+
(..0.2) => :unaffected
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
MAX_EXPECTATIONS = 200
|
|
27
|
+
MAX_VIOLATIONS = 500
|
|
28
|
+
MAX_HISTORY = 500
|
|
29
|
+
|
|
30
|
+
DEFAULT_EXPECTATION = 0.5
|
|
31
|
+
EXPECTATION_FLOOR = 0.0
|
|
32
|
+
EXPECTATION_CEILING = 1.0
|
|
33
|
+
|
|
34
|
+
AROUSAL_BASE = 0.3
|
|
35
|
+
AROUSAL_MULTIPLIER = 0.7
|
|
36
|
+
|
|
37
|
+
ADAPTATION_RATE = 0.1
|
|
38
|
+
DECAY_RATE = 0.02
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module ExpectationViolation
|
|
8
|
+
module Helpers
|
|
9
|
+
class Expectation
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :context, :domain, :expected_value, :tolerance,
|
|
13
|
+
:violation_count, :adaptation_count, :created_at
|
|
14
|
+
|
|
15
|
+
def initialize(context:, domain:, expected_value: DEFAULT_EXPECTATION, tolerance: 0.2)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@context = context
|
|
18
|
+
@domain = domain
|
|
19
|
+
@expected_value = expected_value.clamp(EXPECTATION_FLOOR, EXPECTATION_CEILING)
|
|
20
|
+
@tolerance = tolerance.clamp(0.01, 0.5)
|
|
21
|
+
@violation_count = 0
|
|
22
|
+
@adaptation_count = 0
|
|
23
|
+
@created_at = Time.now.utc
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def evaluate(actual_value:)
|
|
27
|
+
deviation = actual_value - @expected_value
|
|
28
|
+
violated = deviation.abs > @tolerance
|
|
29
|
+
|
|
30
|
+
if violated
|
|
31
|
+
@violation_count += 1
|
|
32
|
+
arousal = compute_arousal(deviation)
|
|
33
|
+
violation_type = deviation.positive? ? :positive : :negative
|
|
34
|
+
{ violated: true, deviation: deviation.round(3), type: violation_type,
|
|
35
|
+
arousal: arousal.round(3), arousal_label: arousal_label(arousal) }
|
|
36
|
+
else
|
|
37
|
+
{ violated: false, deviation: deviation.round(3), type: :neutral,
|
|
38
|
+
arousal: 0.0, arousal_label: :unaffected }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def adapt!(actual_value:)
|
|
43
|
+
@expected_value += (actual_value - @expected_value) * ADAPTATION_RATE
|
|
44
|
+
@expected_value = @expected_value.clamp(EXPECTATION_FLOOR, EXPECTATION_CEILING)
|
|
45
|
+
@adaptation_count += 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def violation_label(deviation)
|
|
49
|
+
VIOLATION_LABELS.find { |range, _| range.cover?(deviation) }&.last || :neutral
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_h
|
|
53
|
+
{
|
|
54
|
+
id: @id,
|
|
55
|
+
context: @context,
|
|
56
|
+
domain: @domain,
|
|
57
|
+
expected_value: @expected_value.round(3),
|
|
58
|
+
tolerance: @tolerance,
|
|
59
|
+
violation_count: @violation_count,
|
|
60
|
+
adaptation_count: @adaptation_count,
|
|
61
|
+
created_at: @created_at
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def compute_arousal(deviation)
|
|
68
|
+
(AROUSAL_BASE + (deviation.abs * AROUSAL_MULTIPLIER)).clamp(0.0, 1.0)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def arousal_label(arousal)
|
|
72
|
+
AROUSAL_LABELS.find { |range, _| range.cover?(arousal) }&.last || :moderate
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module ExpectationViolation
|
|
6
|
+
module Helpers
|
|
7
|
+
class ViolationEngine
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :history
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@expectations = {}
|
|
14
|
+
@violations = []
|
|
15
|
+
@history = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_expectation(context:, domain:, expected_value: DEFAULT_EXPECTATION, tolerance: 0.2)
|
|
19
|
+
evict_oldest if @expectations.size >= MAX_EXPECTATIONS
|
|
20
|
+
|
|
21
|
+
expectation = Expectation.new(
|
|
22
|
+
context: context,
|
|
23
|
+
domain: domain,
|
|
24
|
+
expected_value: expected_value,
|
|
25
|
+
tolerance: tolerance
|
|
26
|
+
)
|
|
27
|
+
@expectations[expectation.id] = expectation
|
|
28
|
+
record_history(:created, expectation.id)
|
|
29
|
+
expectation
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def evaluate_against(expectation_id:, actual_value:)
|
|
33
|
+
expectation = @expectations[expectation_id]
|
|
34
|
+
return { success: false, reason: :not_found } unless expectation
|
|
35
|
+
|
|
36
|
+
result = expectation.evaluate(actual_value: actual_value)
|
|
37
|
+
|
|
38
|
+
if result[:violated]
|
|
39
|
+
@violations << {
|
|
40
|
+
expectation_id: expectation_id,
|
|
41
|
+
type: result[:type],
|
|
42
|
+
deviation: result[:deviation],
|
|
43
|
+
arousal: result[:arousal],
|
|
44
|
+
at: Time.now.utc
|
|
45
|
+
}
|
|
46
|
+
trim_violations
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
record_history(:evaluated, expectation_id)
|
|
50
|
+
{ success: true }.merge(result)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def adapt_expectation(expectation_id:, actual_value:)
|
|
54
|
+
expectation = @expectations[expectation_id]
|
|
55
|
+
return { success: false, reason: :not_found } unless expectation
|
|
56
|
+
|
|
57
|
+
expectation.adapt!(actual_value: actual_value)
|
|
58
|
+
record_history(:adapted, expectation_id)
|
|
59
|
+
{ success: true, new_expected: expectation.expected_value.round(3) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def recent_violations(limit: 10)
|
|
63
|
+
@violations.last(limit)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def violations_by_type(type:)
|
|
67
|
+
@violations.select { |vio| vio[:type] == type }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def expectations_by_domain(domain:)
|
|
71
|
+
@expectations.values.select { |exp| exp.domain == domain }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def most_violated(limit: 5)
|
|
75
|
+
@expectations.values.sort_by { |exp| -exp.violation_count }.first(limit)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def violation_rate
|
|
79
|
+
total = @expectations.values.sum(&:violation_count)
|
|
80
|
+
evals = @history.count { |entry| entry[:event] == :evaluated }
|
|
81
|
+
return 0.0 if evals.zero?
|
|
82
|
+
|
|
83
|
+
(total.to_f / evals).round(3)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def positive_violation_ratio
|
|
87
|
+
return 0.0 if @violations.empty?
|
|
88
|
+
|
|
89
|
+
positive = @violations.count { |vio| vio[:type] == :positive }
|
|
90
|
+
(positive.to_f / @violations.size).round(3)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def to_h
|
|
94
|
+
{
|
|
95
|
+
total_expectations: @expectations.size,
|
|
96
|
+
total_violations: @violations.size,
|
|
97
|
+
violation_rate: violation_rate,
|
|
98
|
+
positive_ratio: positive_violation_ratio,
|
|
99
|
+
history_count: @history.size
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def evict_oldest
|
|
106
|
+
oldest_id = @expectations.min_by { |_id, exp| exp.created_at }&.first
|
|
107
|
+
@expectations.delete(oldest_id) if oldest_id
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def trim_violations
|
|
111
|
+
@violations.shift while @violations.size > MAX_VIOLATIONS
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def record_history(event, expectation_id)
|
|
115
|
+
@history << { event: event, expectation_id: expectation_id, at: Time.now.utc }
|
|
116
|
+
@history.shift while @history.size > MAX_HISTORY
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module ExpectationViolation
|
|
6
|
+
module Runners
|
|
7
|
+
module ExpectationViolation
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def create_expectation(context:, domain:, expected_value: nil, tolerance: 0.2, **)
|
|
12
|
+
exp = engine.create_expectation(
|
|
13
|
+
context: context,
|
|
14
|
+
domain: domain.to_sym,
|
|
15
|
+
expected_value: expected_value || Helpers::Constants::DEFAULT_EXPECTATION,
|
|
16
|
+
tolerance: tolerance
|
|
17
|
+
)
|
|
18
|
+
Legion::Logging.debug "[expectation_violation] create id=#{exp.id[0..7]} " \
|
|
19
|
+
"ctx=#{context} expected=#{exp.expected_value}"
|
|
20
|
+
{ success: true, expectation: exp.to_h }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def evaluate_expectation(expectation_id:, actual_value:, **)
|
|
24
|
+
result = engine.evaluate_against(expectation_id: expectation_id, actual_value: actual_value)
|
|
25
|
+
Legion::Logging.debug "[expectation_violation] evaluate id=#{expectation_id[0..7]} " \
|
|
26
|
+
"violated=#{result[:violated]} type=#{result[:type]}"
|
|
27
|
+
result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def adapt_expectation_value(expectation_id:, actual_value:, **)
|
|
31
|
+
result = engine.adapt_expectation(expectation_id: expectation_id, actual_value: actual_value)
|
|
32
|
+
Legion::Logging.debug "[expectation_violation] adapt id=#{expectation_id[0..7]} " \
|
|
33
|
+
"new=#{result[:new_expected]}"
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def recent_violations_report(limit: 10, **)
|
|
38
|
+
violations = engine.recent_violations(limit: limit)
|
|
39
|
+
Legion::Logging.debug "[expectation_violation] recent count=#{violations.size}"
|
|
40
|
+
{ success: true, violations: violations, count: violations.size }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def violations_by_type_report(type:, **)
|
|
44
|
+
violations = engine.violations_by_type(type: type.to_sym)
|
|
45
|
+
Legion::Logging.debug '[expectation_violation] by_type ' \
|
|
46
|
+
"type=#{type} count=#{violations.size}"
|
|
47
|
+
{ success: true, violations: violations, count: violations.size }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def most_violated_expectations(limit: 5, **)
|
|
51
|
+
exps = engine.most_violated(limit: limit)
|
|
52
|
+
Legion::Logging.debug "[expectation_violation] most_violated count=#{exps.size}"
|
|
53
|
+
{ success: true, expectations: exps.map(&:to_h), count: exps.size }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def expectation_violation_stats(**)
|
|
57
|
+
stats = engine.to_h
|
|
58
|
+
Legion::Logging.debug '[expectation_violation] stats ' \
|
|
59
|
+
"total=#{stats[:total_expectations]}"
|
|
60
|
+
{ success: true }.merge(stats)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def engine
|
|
66
|
+
@engine ||= Helpers::ViolationEngine.new
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'expectation_violation/version'
|
|
4
|
+
require_relative 'expectation_violation/helpers/constants'
|
|
5
|
+
require_relative 'expectation_violation/helpers/expectation'
|
|
6
|
+
require_relative 'expectation_violation/helpers/violation_engine'
|
|
7
|
+
require_relative 'expectation_violation/runners/expectation_violation'
|
|
8
|
+
require_relative 'expectation_violation/helpers/client'
|
|
9
|
+
|
|
10
|
+
module Legion
|
|
11
|
+
module Extensions
|
|
12
|
+
module ExpectationViolation
|
|
13
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-expectation-violation
|
|
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 expectations with tolerance bands and detects violations. Positive
|
|
27
|
+
violations strengthen trust, negative violations damage it. Based on Burgoon (1978)
|
|
28
|
+
Expectancy Violations Theory.
|
|
29
|
+
email:
|
|
30
|
+
- matthewdiverson@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- README.md
|
|
36
|
+
- lib/legion/extensions/expectation_violation.rb
|
|
37
|
+
- lib/legion/extensions/expectation_violation/helpers/client.rb
|
|
38
|
+
- lib/legion/extensions/expectation_violation/helpers/constants.rb
|
|
39
|
+
- lib/legion/extensions/expectation_violation/helpers/expectation.rb
|
|
40
|
+
- lib/legion/extensions/expectation_violation/helpers/violation_engine.rb
|
|
41
|
+
- lib/legion/extensions/expectation_violation/runners/expectation_violation.rb
|
|
42
|
+
- lib/legion/extensions/expectation_violation/version.rb
|
|
43
|
+
homepage: https://github.com/LegionIO/lex-expectation-violation
|
|
44
|
+
licenses:
|
|
45
|
+
- MIT
|
|
46
|
+
metadata:
|
|
47
|
+
homepage_uri: https://github.com/LegionIO/lex-expectation-violation
|
|
48
|
+
source_code_uri: https://github.com/LegionIO/lex-expectation-violation
|
|
49
|
+
documentation_uri: https://github.com/LegionIO/lex-expectation-violation
|
|
50
|
+
changelog_uri: https://github.com/LegionIO/lex-expectation-violation/blob/master/CHANGELOG.md
|
|
51
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-expectation-violation/issues
|
|
52
|
+
rubygems_mfa_required: 'true'
|
|
53
|
+
rdoc_options: []
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '3.4'
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
requirements: []
|
|
67
|
+
rubygems_version: 3.6.9
|
|
68
|
+
specification_version: 4
|
|
69
|
+
summary: Expectancy violation theory for LegionIO
|
|
70
|
+
test_files: []
|