lex-argument-mapping 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: ee2b8b06421ea9635bf67560d2ed64c9294e13f081ed9d018e0c06234c2bc16d
4
+ data.tar.gz: a1cc040fe37b5da71c9732db6b305b200f5c07aecb0da077bec9aaa37d574c84
5
+ SHA512:
6
+ metadata.gz: 6720dd8283e689b26b6039aa75dbc0ecf2a650b054903e5b07021be556dae64bbf79755b2299b4b864b4bd27941f384c937944dd4ca8313c8a1700c5689c5bfc
7
+ data.tar.gz: 4d62f7b556c652ecc930f369c0cae717d9a1091f986531052fdbf33ae766d487fc82d27ae2ecaec077c5a7abf668ad0f8864422b0c3825e738b520afbf0739c5
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'runners/argument_mapping'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module ArgumentMapping
8
+ class Client
9
+ include Runners::ArgumentMapping
10
+
11
+ def initialize(**); end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ArgumentMapping
6
+ module Helpers
7
+ class Argument
8
+ include Constants
9
+
10
+ attr_reader :id, :claim, :grounds, :warrant, :backing,
11
+ :qualifier, :rebuttals, :created_at, :domain
12
+
13
+ def initialize(id:, claim:, domain: :general, warrant: nil, qualifier: :presumably)
14
+ @id = id
15
+ @claim = claim
16
+ @domain = domain
17
+ @warrant = warrant
18
+ @qualifier = qualifier
19
+ @grounds = []
20
+ @backing = []
21
+ @rebuttals = []
22
+ @created_at = Time.now.utc
23
+ end
24
+
25
+ def add_ground(ground:)
26
+ @grounds << ground
27
+ end
28
+
29
+ def add_backing(backing:)
30
+ @backing << backing
31
+ end
32
+
33
+ def add_rebuttal(content:, impact: 0.5)
34
+ @rebuttals << { content: content, impact: impact.clamp(0.0, 1.0) }
35
+ end
36
+
37
+ def strength
38
+ raw = (ground_score * GROUND_WEIGHT) +
39
+ (warrant_score * WARRANT_WEIGHT) +
40
+ (backing_score * BACKING_WEIGHT) -
41
+ (rebuttal_score * REBUTTAL_PENALTY)
42
+ raw.clamp(0.0, 1.0)
43
+ end
44
+
45
+ def strength_label
46
+ ARGUMENT_STRENGTHS.find { |range, _| range.cover?(strength) }&.last
47
+ end
48
+
49
+ def sound?
50
+ strength >= 0.6 && !@warrant.nil? && !@grounds.empty?
51
+ end
52
+
53
+ def rebutted?
54
+ @rebuttals.any? { |r| r[:impact] > 0.5 }
55
+ end
56
+
57
+ def to_h
58
+ {
59
+ id: @id,
60
+ claim: @claim,
61
+ domain: @domain,
62
+ grounds: @grounds,
63
+ warrant: @warrant,
64
+ backing: @backing,
65
+ qualifier: @qualifier,
66
+ rebuttals: @rebuttals,
67
+ strength: strength,
68
+ strength_label: strength_label,
69
+ sound: sound?,
70
+ rebutted: rebutted?,
71
+ created_at: @created_at
72
+ }
73
+ end
74
+
75
+ private
76
+
77
+ def ground_score
78
+ [@grounds.size / 3.0, 1.0].min
79
+ end
80
+
81
+ def warrant_score
82
+ @warrant.nil? ? 0.0 : 0.8
83
+ end
84
+
85
+ def backing_score
86
+ [@backing.size / 2.0, 1.0].min
87
+ end
88
+
89
+ def rebuttal_score
90
+ return 0.0 if @rebuttals.empty?
91
+
92
+ @rebuttals.sum { |r| r[:impact] } / @rebuttals.size
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ArgumentMapping
6
+ module Helpers
7
+ class ArgumentEngine
8
+ include Constants
9
+
10
+ attr_reader :arguments, :history
11
+
12
+ def initialize
13
+ @arguments = {}
14
+ @history = []
15
+ end
16
+
17
+ def create_argument(claim:, domain: :general, warrant: nil, qualifier: :presumably)
18
+ return { success: false, reason: :max_arguments_reached } if @arguments.size >= MAX_ARGUMENTS
19
+
20
+ id = generate_id('arg')
21
+ argument = Argument.new(id: id, claim: claim, domain: domain,
22
+ warrant: warrant, qualifier: qualifier)
23
+ @arguments[id] = argument
24
+ add_history(type: :created, argument_id: id, claim: claim, domain: domain)
25
+ { success: true, argument: argument.to_h }
26
+ end
27
+
28
+ def add_ground(argument_id:, ground:)
29
+ argument = @arguments[argument_id]
30
+ return { success: false, reason: :not_found } unless argument
31
+
32
+ argument.add_ground(ground: ground)
33
+ add_history(type: :ground_added, argument_id: argument_id)
34
+ { success: true, argument: argument.to_h }
35
+ end
36
+
37
+ def add_backing(argument_id:, backing:)
38
+ argument = @arguments[argument_id]
39
+ return { success: false, reason: :not_found } unless argument
40
+
41
+ argument.add_backing(backing: backing)
42
+ add_history(type: :backing_added, argument_id: argument_id)
43
+ { success: true, argument: argument.to_h }
44
+ end
45
+
46
+ def add_rebuttal(argument_id:, content:, impact: 0.5)
47
+ argument = @arguments[argument_id]
48
+ return { success: false, reason: :not_found } unless argument
49
+
50
+ argument.add_rebuttal(content: content, impact: impact)
51
+ add_history(type: :rebuttal_added, argument_id: argument_id, impact: impact)
52
+ { success: true, argument: argument.to_h }
53
+ end
54
+
55
+ def assess_argument(argument_id:)
56
+ argument = @arguments[argument_id]
57
+ return { success: false, reason: :not_found } unless argument
58
+
59
+ {
60
+ success: true,
61
+ argument_id: argument_id,
62
+ claim: argument.claim,
63
+ domain: argument.domain,
64
+ strength: argument.strength,
65
+ strength_label: argument.strength_label,
66
+ sound: argument.sound?,
67
+ rebutted: argument.rebutted?,
68
+ ground_count: argument.grounds.size,
69
+ backing_count: argument.backing.size,
70
+ rebuttal_count: argument.rebuttals.size
71
+ }
72
+ end
73
+
74
+ def sound_arguments
75
+ @arguments.values.select(&:sound?)
76
+ end
77
+
78
+ def rebutted_arguments
79
+ @arguments.values.select(&:rebutted?)
80
+ end
81
+
82
+ def arguments_by_domain(domain:)
83
+ @arguments.values.select { |a| a.domain == domain }
84
+ end
85
+
86
+ def strongest_arguments(limit: 5)
87
+ @arguments.values.sort_by { |a| -a.strength }.first(limit)
88
+ end
89
+
90
+ def weakest_arguments(limit: 5)
91
+ @arguments.values.sort_by(&:strength).first(limit)
92
+ end
93
+
94
+ def decay_all
95
+ @arguments.each_value do |argument|
96
+ next unless argument.instance_variable_defined?(:@base_strength)
97
+
98
+ current = argument.instance_variable_get(:@base_strength)
99
+ argument.instance_variable_set(:@base_strength, [current - DECAY_RATE, 0.0].max)
100
+ end
101
+ @arguments.size
102
+ end
103
+
104
+ def to_h
105
+ {
106
+ total_arguments: @arguments.size,
107
+ sound_arguments: sound_arguments.size,
108
+ rebutted_arguments: rebutted_arguments.size,
109
+ history_entries: @history.size
110
+ }
111
+ end
112
+
113
+ private
114
+
115
+ def add_history(entry)
116
+ @history << entry.merge(timestamp: Time.now.utc)
117
+ @history.shift if @history.size > MAX_HISTORY
118
+ end
119
+
120
+ def generate_id(prefix)
121
+ "#{prefix}_#{Time.now.utc.to_f}_#{rand(10_000)}"
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ArgumentMapping
6
+ module Helpers
7
+ module Constants
8
+ ARGUMENT_STRENGTHS = {
9
+ (0.8..) => :compelling,
10
+ (0.6...0.8) => :strong,
11
+ (0.4...0.6) => :moderate,
12
+ (0.2...0.4) => :weak,
13
+ (..0.2) => :fallacious
14
+ }.freeze
15
+
16
+ QUALIFIER_TYPES = %i[certainly presumably probably possibly apparently].freeze
17
+
18
+ REBUTTAL_IMPACT_LABELS = {
19
+ (0.8..) => :devastating,
20
+ (0.6...0.8) => :significant,
21
+ (0.4...0.6) => :moderate,
22
+ (0.2...0.4) => :minor,
23
+ (..0.2) => :negligible
24
+ }.freeze
25
+
26
+ MAX_ARGUMENTS = 200
27
+ MAX_HISTORY = 500
28
+
29
+ DEFAULT_STRENGTH = 0.5
30
+ GROUND_WEIGHT = 0.3
31
+ WARRANT_WEIGHT = 0.3
32
+ BACKING_WEIGHT = 0.2
33
+ REBUTTAL_PENALTY = 0.2
34
+
35
+ DECAY_RATE = 0.02
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ArgumentMapping
6
+ module Runners
7
+ module ArgumentMapping
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ def create_argument(claim:, domain: :general, warrant: nil, qualifier: :presumably, **)
12
+ Legion::Logging.info "[argument_mapping] create_argument: claim=#{claim} domain=#{domain}"
13
+ engine.create_argument(claim: claim, domain: domain, warrant: warrant, qualifier: qualifier)
14
+ end
15
+
16
+ def add_argument_ground(argument_id:, ground:, **)
17
+ Legion::Logging.debug "[argument_mapping] add_ground: id=#{argument_id}"
18
+ engine.add_ground(argument_id: argument_id, ground: ground)
19
+ end
20
+
21
+ def add_argument_backing(argument_id:, backing:, **)
22
+ Legion::Logging.debug "[argument_mapping] add_backing: id=#{argument_id}"
23
+ engine.add_backing(argument_id: argument_id, backing: backing)
24
+ end
25
+
26
+ def add_argument_rebuttal(argument_id:, content:, impact: 0.5, **)
27
+ Legion::Logging.info "[argument_mapping] add_rebuttal: id=#{argument_id} impact=#{impact}"
28
+ engine.add_rebuttal(argument_id: argument_id, content: content, impact: impact)
29
+ end
30
+
31
+ def assess_argument_strength(argument_id:, **)
32
+ Legion::Logging.debug "[argument_mapping] assess: id=#{argument_id}"
33
+ engine.assess_argument(argument_id: argument_id)
34
+ end
35
+
36
+ def sound_arguments_report(**)
37
+ Legion::Logging.debug '[argument_mapping] sound_arguments_report'
38
+ arguments = engine.sound_arguments
39
+ { success: true, arguments: arguments.map(&:to_h), count: arguments.size }
40
+ end
41
+
42
+ def rebutted_arguments_report(**)
43
+ Legion::Logging.debug '[argument_mapping] rebutted_arguments_report'
44
+ arguments = engine.rebutted_arguments
45
+ { success: true, arguments: arguments.map(&:to_h), count: arguments.size }
46
+ end
47
+
48
+ def strongest_arguments_report(limit: 5, **)
49
+ Legion::Logging.debug "[argument_mapping] strongest_arguments: limit=#{limit}"
50
+ arguments = engine.strongest_arguments(limit: limit)
51
+ { success: true, arguments: arguments.map(&:to_h), count: arguments.size }
52
+ end
53
+
54
+ def update_argument_mapping(**)
55
+ Legion::Logging.debug '[argument_mapping] decay_all'
56
+ decayed = engine.decay_all
57
+ { success: true, arguments_processed: decayed }
58
+ end
59
+
60
+ def argument_mapping_stats(**)
61
+ Legion::Logging.debug '[argument_mapping] stats'
62
+ { success: true }.merge(engine.to_h)
63
+ end
64
+
65
+ private
66
+
67
+ def engine
68
+ @engine ||= Helpers::ArgumentEngine.new
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ArgumentMapping
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'argument_mapping/version'
4
+ require_relative 'argument_mapping/helpers/constants'
5
+ require_relative 'argument_mapping/helpers/argument'
6
+ require_relative 'argument_mapping/helpers/argument_engine'
7
+ require_relative 'argument_mapping/runners/argument_mapping'
8
+ require_relative 'argument_mapping/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module ArgumentMapping
13
+ extend Legion::Extensions::Core if defined?(Legion::Extensions::Core)
14
+ end
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-argument-mapping
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: Toulmin-model argument mapping for LegionIO — claim/grounds/warrant/backing/qualifier/rebuttal
27
+ argument construction, strength assessment, and soundness evaluation
28
+ email:
29
+ - matthewdiverson@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/legion/extensions/argument_mapping.rb
35
+ - lib/legion/extensions/argument_mapping/client.rb
36
+ - lib/legion/extensions/argument_mapping/helpers/argument.rb
37
+ - lib/legion/extensions/argument_mapping/helpers/argument_engine.rb
38
+ - lib/legion/extensions/argument_mapping/helpers/constants.rb
39
+ - lib/legion/extensions/argument_mapping/runners/argument_mapping.rb
40
+ - lib/legion/extensions/argument_mapping/version.rb
41
+ homepage: https://github.com/LegionIO/lex-argument-mapping
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ homepage_uri: https://github.com/LegionIO/lex-argument-mapping
46
+ source_code_uri: https://github.com/LegionIO/lex-argument-mapping
47
+ documentation_uri: https://github.com/LegionIO/lex-argument-mapping
48
+ changelog_uri: https://github.com/LegionIO/lex-argument-mapping
49
+ bug_tracker_uri: https://github.com/LegionIO/lex-argument-mapping/issues
50
+ rubygems_mfa_required: 'true'
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '3.4'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.6.9
66
+ specification_version: 4
67
+ summary: LegionIO argument mapping extension
68
+ test_files: []