lex-cognitive-catalyst 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/.github/workflows/ci.yml +16 -0
- data/.gitignore +17 -0
- data/.rspec +4 -0
- data/.rubocop.yml +29 -0
- data/CLAUDE.md +78 -0
- data/Gemfile +11 -0
- data/README.md +44 -0
- data/lex-cognitive-catalyst.gemspec +31 -0
- data/lib/legion/extensions/cognitive_catalyst/client.rb +11 -0
- data/lib/legion/extensions/cognitive_catalyst/helpers/catalyst.rb +83 -0
- data/lib/legion/extensions/cognitive_catalyst/helpers/catalyst_engine.rb +149 -0
- data/lib/legion/extensions/cognitive_catalyst/helpers/constants.rb +51 -0
- data/lib/legion/extensions/cognitive_catalyst/helpers/reaction.rb +83 -0
- data/lib/legion/extensions/cognitive_catalyst/runners/cognitive_catalyst.rb +103 -0
- data/lib/legion/extensions/cognitive_catalyst/version.rb +9 -0
- data/lib/legion/extensions/cognitive_catalyst.rb +19 -0
- data/spec/legion/extensions/cognitive_catalyst/client_spec.rb +58 -0
- data/spec/legion/extensions/cognitive_catalyst/helpers/catalyst_engine_spec.rb +263 -0
- data/spec/legion/extensions/cognitive_catalyst/helpers/catalyst_spec.rb +214 -0
- data/spec/legion/extensions/cognitive_catalyst/helpers/reaction_spec.rb +223 -0
- data/spec/legion/extensions/cognitive_catalyst/runners/cognitive_catalyst_spec.rb +217 -0
- data/spec/legion/extensions/cognitive_catalyst_spec.rb +49 -0
- data/spec/spec_helper.rb +34 -0
- metadata +86 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '0831b554c585e8335d544e63f5a141d04c795876c99f9123e5d9117bf65a8cd2'
|
|
4
|
+
data.tar.gz: bf6d4293e8d91d75a90ca92f01f273d9d651f2970077562416a13079f8da7ddf
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1de51909f167df0bab5a81c5719e01ec1394b318fdc12bee119e55854a0d204896696d340090a4e0c37e55b8a8f584042cdd2536f1b7380035f7c9c443f7ccd2
|
|
7
|
+
data.tar.gz: 6f7c198df94bdbffb1a389d3e444d52f5f8d13083a8db4c07890b7d88c36e88c8881a7fb3b5cae7201f99adf87c8abface4558efa9d31c69175cc72ab97606ca
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
10
|
+
|
|
11
|
+
release:
|
|
12
|
+
needs: ci
|
|
13
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
|
+
secrets:
|
|
16
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
TargetRubyVersion: 3.4
|
|
4
|
+
Style/Documentation:
|
|
5
|
+
Enabled: false
|
|
6
|
+
Naming/PredicateMethod:
|
|
7
|
+
Enabled: false
|
|
8
|
+
Naming/PredicatePrefix:
|
|
9
|
+
Enabled: false
|
|
10
|
+
Metrics/ClassLength:
|
|
11
|
+
Max: 150
|
|
12
|
+
Metrics/MethodLength:
|
|
13
|
+
Max: 25
|
|
14
|
+
Metrics/AbcSize:
|
|
15
|
+
Max: 25
|
|
16
|
+
Metrics/ParameterLists:
|
|
17
|
+
Max: 8
|
|
18
|
+
MaxOptionalParameters: 8
|
|
19
|
+
Layout/HashAlignment:
|
|
20
|
+
EnforcedColonStyle: table
|
|
21
|
+
EnforcedHashRocketStyle: table
|
|
22
|
+
Metrics/BlockLength:
|
|
23
|
+
Exclude:
|
|
24
|
+
- 'spec/**/*'
|
|
25
|
+
Style/FrozenStringLiteralComment:
|
|
26
|
+
Enabled: true
|
|
27
|
+
Style/OneClassPerFile:
|
|
28
|
+
Exclude:
|
|
29
|
+
- 'spec/spec_helper.rb'
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# lex-cognitive-catalyst
|
|
2
|
+
|
|
3
|
+
**Level 3 Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
- **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Models how certain thoughts and experiences act as chemical catalysts — accelerating cognitive reactions without being consumed. Catalysts lower the activation energy required for synthesis, decomposition, exchange, neutralization, and precipitation reactions between ideas. A potent catalyst enables reactions that would otherwise stall from insufficient energy input.
|
|
10
|
+
|
|
11
|
+
## Gem Info
|
|
12
|
+
|
|
13
|
+
- **Gem name**: `lex-cognitive-catalyst`
|
|
14
|
+
- **Version**: `0.1.0`
|
|
15
|
+
- **Module**: `Legion::Extensions::CognitiveCatalyst`
|
|
16
|
+
- **Ruby**: `>= 3.4`
|
|
17
|
+
- **License**: MIT
|
|
18
|
+
|
|
19
|
+
## File Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
lib/legion/extensions/cognitive_catalyst/
|
|
23
|
+
cognitive_catalyst.rb
|
|
24
|
+
version.rb
|
|
25
|
+
client.rb
|
|
26
|
+
helpers/
|
|
27
|
+
constants.rb
|
|
28
|
+
catalyst.rb
|
|
29
|
+
catalyst_engine.rb
|
|
30
|
+
reaction.rb
|
|
31
|
+
runners/
|
|
32
|
+
cognitive_catalyst.rb
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Constants
|
|
36
|
+
|
|
37
|
+
From `helpers/constants.rb`:
|
|
38
|
+
|
|
39
|
+
- `CATALYST_TYPES` — `%i[experience insight analogy pattern emotion]`
|
|
40
|
+
- `REACTION_TYPES` — `%i[synthesis decomposition exchange neutralization precipitation]`
|
|
41
|
+
- `MAX_CATALYSTS` = `500`, `MAX_REACTIONS` = `200`
|
|
42
|
+
- `ACTIVATION_ENERGY` = `0.6` (minimum energy to complete a reaction without a catalyst)
|
|
43
|
+
- `CATALYST_REDUCTION` = `0.3` (how much a catalyst lowers the activation energy threshold)
|
|
44
|
+
- `POTENCY_DECAY` = `0.02` (environmental wear — not from use)
|
|
45
|
+
- `SPECIFICITY_BONUS` = `0.15` (bonus when catalyst domain matches reaction domain)
|
|
46
|
+
- `POTENCY_LABELS` — `0.8+` = `:powerful`, `0.6` = `:strong`, `0.4` = `:moderate`, `0.2` = `:weak`, below = `:inert`
|
|
47
|
+
- `YIELD_LABELS` — `0.8+` = `:excellent` through below `0.2` = `:negligible`
|
|
48
|
+
|
|
49
|
+
## Runners
|
|
50
|
+
|
|
51
|
+
All methods in `Runners::CognitiveCatalyst`:
|
|
52
|
+
|
|
53
|
+
- `create_catalyst(catalyst_type:, domain:, potency: nil, specificity: nil)` — registers a new catalyst; validates against `CATALYST_TYPES`
|
|
54
|
+
- `create_reaction(reaction_type:, reactants:, activation_energy: nil)` — creates a pending reaction; validates against `REACTION_TYPES`
|
|
55
|
+
- `apply_catalyst(catalyst_id:, reaction_id:)` — associates a catalyst with a reaction, lowering effective activation energy
|
|
56
|
+
- `attempt_reaction(reaction_id:, energy_input:)` — attempts to complete a reaction; succeeds if `energy_input >= effective_threshold`; returns yield score
|
|
57
|
+
- `recharge(catalyst_id:, amount:)` — restores potency to a catalyst
|
|
58
|
+
- `list_catalysts` — all catalysts with current potency
|
|
59
|
+
- `catalyst_status` — aggregate report: totals, catalyzed rate, most potent
|
|
60
|
+
|
|
61
|
+
## Helpers
|
|
62
|
+
|
|
63
|
+
- `CatalystEngine` — manages catalysts and reactions. `apply_catalyst` attaches a catalyst to a reaction; `attempt_reaction` evaluates whether energy input meets the (optionally reduced) threshold.
|
|
64
|
+
- `Catalyst` — has `catalyst_type`, `domain`, `potency`, `specificity`. `potency` decays over time (environmental wear). Not consumed on use.
|
|
65
|
+
- `Reaction` — has `reaction_type`, `reactants`, `activation_energy`. Stores applied catalyst IDs. Effective threshold = `activation_energy - (CATALYST_REDUCTION * catalyst_potency) + SPECIFICITY_BONUS` if domains match.
|
|
66
|
+
|
|
67
|
+
## Integration Points
|
|
68
|
+
|
|
69
|
+
- `lex-cognitive-coherence` can provide the constraint network that reactions operate within — catalysts accelerate coherence maximization by lowering the cost of belief integration.
|
|
70
|
+
- `lex-memory` trace retrieval during `lex-dream` is a natural catalyst source: high-strength traces become experience catalysts for synthesis reactions during dream phases.
|
|
71
|
+
- `recharge` enables explicit catalyst maintenance — callers can recharge important catalysts (e.g., a core analogy) to keep them potent.
|
|
72
|
+
|
|
73
|
+
## Development Notes
|
|
74
|
+
|
|
75
|
+
- Catalyst potency decays from environmental wear (not from use) — catalysts are not consumed. `POTENCY_DECAY = 0.02` per decay cycle.
|
|
76
|
+
- `SPECIFICITY_BONUS` is added when catalyst domain matches reaction domain — rewarding domain-specific knowledge application.
|
|
77
|
+
- Invalid `catalyst_type` or `reaction_type` raises `ArgumentError` (from constants validation in the runner).
|
|
78
|
+
- Runners log all operations via `Legion::Logging.debug`/`warn`.
|
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# lex-cognitive-catalyst
|
|
2
|
+
|
|
3
|
+
Cognitive catalysis acceleration for LegionIO. Models how certain thoughts and experiences act as chemical catalysts — accelerating cognitive reactions without being consumed.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Catalysts lower the activation energy required for cognitive reactions. An insight, analogy, or recurring pattern can make otherwise-stalled synthesis reactions complete with much less energy. Unlike consumed reagents, catalysts remain available for repeated use (though their potency decays from environmental wear).
|
|
8
|
+
|
|
9
|
+
Five reaction types are supported: synthesis (combining ideas), decomposition (breaking down assumptions), exchange (swapping belief components), neutralization (resolving opposing forces), and precipitation (crystallizing vague concepts into concrete ones). Applying the right catalyst — especially one with matching domain specificity — dramatically increases reaction yield.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
client = Legion::Extensions::CognitiveCatalyst::Client.new
|
|
15
|
+
|
|
16
|
+
catalyst = client.create_catalyst(
|
|
17
|
+
catalyst_type: :analogy,
|
|
18
|
+
domain: :problem_solving,
|
|
19
|
+
potency: 0.9,
|
|
20
|
+
specificity: 0.8
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
reaction = client.create_reaction(
|
|
24
|
+
reaction_type: :synthesis,
|
|
25
|
+
reactants: ['concept_a', 'concept_b'],
|
|
26
|
+
activation_energy: 0.7
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
client.apply_catalyst(catalyst_id: catalyst[:catalyst][:id],
|
|
30
|
+
reaction_id: reaction[:reaction][:id])
|
|
31
|
+
client.attempt_reaction(reaction_id: reaction[:reaction][:id], energy_input: 0.5)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Development
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bundle install
|
|
38
|
+
bundle exec rspec
|
|
39
|
+
bundle exec rubocop
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_catalyst/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-catalyst'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveCatalyst::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Cognitive catalysis acceleration for LegionIO agentic architecture'
|
|
12
|
+
spec.description = 'Models how certain thoughts and experiences act as chemical catalysts — ' \
|
|
13
|
+
'accelerating cognitive reactions without being consumed. Catalysts lower ' \
|
|
14
|
+
'the activation energy for synthesis, decomposition, exchange, neutralization, ' \
|
|
15
|
+
'and precipitation reactions between ideas.'
|
|
16
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-catalyst'
|
|
17
|
+
spec.license = 'MIT'
|
|
18
|
+
|
|
19
|
+
spec.required_ruby_version = '>= 3.4'
|
|
20
|
+
|
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
22
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-catalyst'
|
|
23
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-catalyst'
|
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-catalyst'
|
|
25
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-catalyst/issues'
|
|
26
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
27
|
+
|
|
28
|
+
spec.files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
|
|
29
|
+
spec.require_paths = ['lib']
|
|
30
|
+
spec.add_development_dependency 'legion-gaia'
|
|
31
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveCatalyst
|
|
8
|
+
module Helpers
|
|
9
|
+
class Catalyst
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :catalyst_type, :domain, :potency, :specificity,
|
|
13
|
+
:uses_count, :created_at
|
|
14
|
+
|
|
15
|
+
def initialize(catalyst_type:, domain:, potency: 0.5, specificity: 0.5)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@catalyst_type = catalyst_type
|
|
18
|
+
@domain = domain
|
|
19
|
+
@potency = potency.clamp(0.0, 1.0)
|
|
20
|
+
@specificity = specificity.clamp(0.0, 1.0)
|
|
21
|
+
@uses_count = 0
|
|
22
|
+
@created_at = Time.now.utc
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Apply this catalyst to a reaction — increments uses_count but does NOT reduce potency
|
|
26
|
+
# Catalysts are not consumed by use; they are reusable accelerators
|
|
27
|
+
# Returns activation_reduction = potency * specificity
|
|
28
|
+
def catalyze!(_reaction_type)
|
|
29
|
+
@uses_count += 1
|
|
30
|
+
(@potency * @specificity).round(10)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Degrade from environmental wear (not from use)
|
|
34
|
+
def degrade!
|
|
35
|
+
@potency = (@potency - POTENCY_DECAY).clamp(0.0, 1.0).round(10)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Recharge by increasing potency
|
|
39
|
+
def recharge!(amount)
|
|
40
|
+
@potency = (@potency + amount).clamp(0.0, 1.0).round(10)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def powerful?
|
|
44
|
+
@potency >= 0.8
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def inert?
|
|
48
|
+
@potency < 0.2
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def specific?
|
|
52
|
+
@specificity >= 0.7
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def broad?
|
|
56
|
+
@specificity < 0.3
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def potency_label
|
|
60
|
+
POTENCY_LABELS.find { |range, _| range.cover?(@potency) }&.last || :inert
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_h
|
|
64
|
+
{
|
|
65
|
+
id: @id,
|
|
66
|
+
catalyst_type: @catalyst_type,
|
|
67
|
+
domain: @domain,
|
|
68
|
+
potency: @potency,
|
|
69
|
+
specificity: @specificity,
|
|
70
|
+
uses_count: @uses_count,
|
|
71
|
+
potency_label: potency_label,
|
|
72
|
+
powerful: powerful?,
|
|
73
|
+
inert: inert?,
|
|
74
|
+
specific: specific?,
|
|
75
|
+
broad: broad?,
|
|
76
|
+
created_at: @created_at
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveCatalyst
|
|
6
|
+
module Helpers
|
|
7
|
+
class CatalystEngine
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@catalysts = {}
|
|
12
|
+
@reactions = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_catalyst(catalyst_type:, domain:, potency: 0.5, specificity: 0.5, **)
|
|
16
|
+
unless CATALYST_TYPES.include?(catalyst_type.to_sym)
|
|
17
|
+
raise ArgumentError,
|
|
18
|
+
"invalid catalyst_type: #{catalyst_type}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
evict_oldest_catalyst if @catalysts.size >= MAX_CATALYSTS
|
|
22
|
+
catalyst = Catalyst.new(
|
|
23
|
+
catalyst_type: catalyst_type.to_sym,
|
|
24
|
+
domain: domain,
|
|
25
|
+
potency: potency,
|
|
26
|
+
specificity: specificity
|
|
27
|
+
)
|
|
28
|
+
@catalysts[catalyst.id] = catalyst
|
|
29
|
+
catalyst
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_reaction(reaction_type:, reactants:, activation_energy: ACTIVATION_ENERGY, **)
|
|
33
|
+
unless REACTION_TYPES.include?(reaction_type.to_sym)
|
|
34
|
+
raise ArgumentError,
|
|
35
|
+
"invalid reaction_type: #{reaction_type}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
evict_oldest_reaction if @reactions.size >= MAX_REACTIONS
|
|
39
|
+
reaction = Reaction.new(
|
|
40
|
+
reaction_type: reaction_type.to_sym,
|
|
41
|
+
reactants: reactants,
|
|
42
|
+
activation_energy: activation_energy
|
|
43
|
+
)
|
|
44
|
+
@reactions[reaction.id] = reaction
|
|
45
|
+
reaction
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def apply_catalyst(catalyst_id:, reaction_id:)
|
|
49
|
+
catalyst = @catalysts[catalyst_id]
|
|
50
|
+
reaction = @reactions[reaction_id]
|
|
51
|
+
|
|
52
|
+
return { success: false, reason: :catalyst_not_found } unless catalyst
|
|
53
|
+
return { success: false, reason: :reaction_not_found } unless reaction
|
|
54
|
+
return { success: false, reason: :already_completed } if reaction.complete?
|
|
55
|
+
|
|
56
|
+
reaction.apply_catalyst!(catalyst)
|
|
57
|
+
{
|
|
58
|
+
success: true,
|
|
59
|
+
activation_energy: reaction.activation_energy,
|
|
60
|
+
catalyst_id: catalyst_id,
|
|
61
|
+
reaction_id: reaction_id
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def attempt_reaction(reaction_id:, energy_input:)
|
|
66
|
+
reaction = @reactions[reaction_id]
|
|
67
|
+
return { success: false, reason: :not_found } unless reaction
|
|
68
|
+
return { success: false, reason: :already_completed } if reaction.complete?
|
|
69
|
+
|
|
70
|
+
completed = reaction.attempt!(energy_input)
|
|
71
|
+
{
|
|
72
|
+
success: true,
|
|
73
|
+
completed: completed,
|
|
74
|
+
yield_value: reaction.yield_value,
|
|
75
|
+
yield_label: reaction.yield_label,
|
|
76
|
+
catalyzed: reaction.catalyzed?,
|
|
77
|
+
activation_energy: reaction.activation_energy
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def degrade_all!
|
|
82
|
+
@catalysts.each_value(&:degrade!)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def recharge_catalyst(catalyst_id:, amount:)
|
|
86
|
+
catalyst = @catalysts[catalyst_id]
|
|
87
|
+
return { success: false, reason: :not_found } unless catalyst
|
|
88
|
+
|
|
89
|
+
catalyst.recharge!(amount)
|
|
90
|
+
{ success: true, potency: catalyst.potency, potency_label: catalyst.potency_label }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def all_catalysts
|
|
94
|
+
@catalysts.values
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def all_reactions
|
|
98
|
+
@reactions.values
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def completed_reactions
|
|
102
|
+
@reactions.values.select(&:complete?)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def catalyzed_rate
|
|
106
|
+
completed = completed_reactions
|
|
107
|
+
return 0.0 if completed.empty?
|
|
108
|
+
|
|
109
|
+
catalyzed_count = completed.count(&:catalyzed?)
|
|
110
|
+
(catalyzed_count.to_f / completed.size).round(10)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def catalyst_report
|
|
114
|
+
completed = completed_reactions
|
|
115
|
+
catalyzed_cnt = completed.count(&:catalyzed?)
|
|
116
|
+
avg_potency = if @catalysts.empty?
|
|
117
|
+
0.0
|
|
118
|
+
else
|
|
119
|
+
(@catalysts.values.sum(&:potency) / @catalysts.size).round(10)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
total_catalysts: @catalysts.size,
|
|
124
|
+
total_reactions: @reactions.size,
|
|
125
|
+
completed: completed.size,
|
|
126
|
+
catalyzed_count: catalyzed_cnt,
|
|
127
|
+
catalyzed_rate: catalyzed_rate,
|
|
128
|
+
avg_potency: avg_potency,
|
|
129
|
+
powerful_count: @catalysts.values.count(&:powerful?),
|
|
130
|
+
inert_count: @catalysts.values.count(&:inert?)
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
def evict_oldest_catalyst
|
|
137
|
+
oldest_id = @catalysts.min_by { |_id, c| c.created_at }&.first
|
|
138
|
+
@catalysts.delete(oldest_id) if oldest_id
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def evict_oldest_reaction
|
|
142
|
+
oldest_id = @reactions.min_by { |_id, r| r.created_at }&.first
|
|
143
|
+
@reactions.delete(oldest_id) if oldest_id
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveCatalyst
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
# Catalyst types — categories of experiences/insights that accelerate reactions
|
|
9
|
+
CATALYST_TYPES = %i[experience insight analogy pattern emotion].freeze
|
|
10
|
+
|
|
11
|
+
# Reaction types — categories of cognitive transformations
|
|
12
|
+
REACTION_TYPES = %i[synthesis decomposition exchange neutralization precipitation].freeze
|
|
13
|
+
|
|
14
|
+
# Storage limits
|
|
15
|
+
MAX_CATALYSTS = 500
|
|
16
|
+
MAX_REACTIONS = 200
|
|
17
|
+
|
|
18
|
+
# Activation energy — minimum energy to complete a reaction without a catalyst
|
|
19
|
+
ACTIVATION_ENERGY = 0.6
|
|
20
|
+
|
|
21
|
+
# How much a catalyst lowers the activation energy threshold
|
|
22
|
+
CATALYST_REDUCTION = 0.3
|
|
23
|
+
|
|
24
|
+
# Potency degradation rate from environmental wear (not from use)
|
|
25
|
+
POTENCY_DECAY = 0.02
|
|
26
|
+
|
|
27
|
+
# Bonus added when catalyst specificity matches reaction domain
|
|
28
|
+
SPECIFICITY_BONUS = 0.15
|
|
29
|
+
|
|
30
|
+
# Potency labels — range-based classification of catalyst strength
|
|
31
|
+
POTENCY_LABELS = {
|
|
32
|
+
(0.8..) => :powerful,
|
|
33
|
+
(0.6...0.8) => :strong,
|
|
34
|
+
(0.4...0.6) => :moderate,
|
|
35
|
+
(0.2...0.4) => :weak,
|
|
36
|
+
(..0.2) => :inert
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
# Yield labels — range-based classification of reaction output quality
|
|
40
|
+
YIELD_LABELS = {
|
|
41
|
+
(0.8..) => :excellent,
|
|
42
|
+
(0.6...0.8) => :good,
|
|
43
|
+
(0.4...0.6) => :fair,
|
|
44
|
+
(0.2...0.4) => :poor,
|
|
45
|
+
(..0.2) => :negligible
|
|
46
|
+
}.freeze
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveCatalyst
|
|
8
|
+
module Helpers
|
|
9
|
+
class Reaction
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :reaction_type, :reactants, :activation_energy,
|
|
13
|
+
:yield_value, :catalyzed, :catalyst_id, :completed, :created_at
|
|
14
|
+
|
|
15
|
+
def initialize(reaction_type:, reactants:, activation_energy: ACTIVATION_ENERGY)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@reaction_type = reaction_type
|
|
18
|
+
@reactants = Array(reactants)
|
|
19
|
+
@activation_energy = activation_energy.clamp(0.0, 1.0)
|
|
20
|
+
@yield_value = 0.0
|
|
21
|
+
@catalyzed = false
|
|
22
|
+
@catalyst_id = nil
|
|
23
|
+
@completed = false
|
|
24
|
+
@created_at = Time.now.utc
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Apply a catalyst to lower the activation energy threshold
|
|
28
|
+
def apply_catalyst!(catalyst)
|
|
29
|
+
reduction = catalyst.catalyze!(@reaction_type)
|
|
30
|
+
@activation_energy = (@activation_energy - reduction).clamp(0.0, 1.0).round(10)
|
|
31
|
+
@catalyzed = true
|
|
32
|
+
@catalyst_id = catalyst.id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Attempt to complete the reaction with given energy input
|
|
36
|
+
# Completes if energy_input >= activation_energy; yield based on energy surplus
|
|
37
|
+
def attempt!(energy_input)
|
|
38
|
+
return false if @completed
|
|
39
|
+
return false if energy_input < @activation_energy
|
|
40
|
+
|
|
41
|
+
@completed = true
|
|
42
|
+
surplus = (energy_input - @activation_energy).clamp(0.0, 1.0)
|
|
43
|
+
@yield_value = (0.5 + (surplus * 0.5)).clamp(0.0, 1.0).round(10)
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def complete?
|
|
48
|
+
@completed
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def catalyzed?
|
|
52
|
+
@catalyzed
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Completed spontaneously — without a catalyst
|
|
56
|
+
def spontaneous?
|
|
57
|
+
@completed && !@catalyzed
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def yield_label
|
|
61
|
+
YIELD_LABELS.find { |range, _| range.cover?(@yield_value) }&.last || :negligible
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_h
|
|
65
|
+
{
|
|
66
|
+
id: @id,
|
|
67
|
+
reaction_type: @reaction_type,
|
|
68
|
+
reactants: @reactants,
|
|
69
|
+
activation_energy: @activation_energy,
|
|
70
|
+
yield_value: @yield_value,
|
|
71
|
+
yield_label: yield_label,
|
|
72
|
+
catalyzed: @catalyzed,
|
|
73
|
+
catalyst_id: @catalyst_id,
|
|
74
|
+
completed: @completed,
|
|
75
|
+
spontaneous: spontaneous?,
|
|
76
|
+
created_at: @created_at
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|