lex-cognitive-fermentation 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 +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +37 -0
- data/CLAUDE.md +117 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +78 -0
- data/README.md +53 -0
- data/lex-cognitive-fermentation.gemspec +29 -0
- data/lib/legion/extensions/cognitive_fermentation/client.rb +15 -0
- data/lib/legion/extensions/cognitive_fermentation/helpers/batch.rb +71 -0
- data/lib/legion/extensions/cognitive_fermentation/helpers/constants.rb +74 -0
- data/lib/legion/extensions/cognitive_fermentation/helpers/fermentation_engine.rb +143 -0
- data/lib/legion/extensions/cognitive_fermentation/helpers/substrate.rb +104 -0
- data/lib/legion/extensions/cognitive_fermentation/runners/cognitive_fermentation.rb +56 -0
- data/lib/legion/extensions/cognitive_fermentation/version.rb +9 -0
- data/lib/legion/extensions/cognitive_fermentation.rb +18 -0
- data/spec/legion/extensions/cognitive_fermentation/client_spec.rb +36 -0
- data/spec/legion/extensions/cognitive_fermentation/helpers/batch_spec.rb +72 -0
- data/spec/legion/extensions/cognitive_fermentation/helpers/fermentation_engine_spec.rb +138 -0
- data/spec/legion/extensions/cognitive_fermentation/helpers/substrate_spec.rb +146 -0
- data/spec/spec_helper.rb +28 -0
- metadata +83 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveFermentation
|
|
6
|
+
module Helpers
|
|
7
|
+
class Substrate
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :id, :substrate_type, :domain, :content, :potency,
|
|
11
|
+
:maturity, :volatility, :stage, :created_at, :catalysts_applied
|
|
12
|
+
|
|
13
|
+
def initialize(substrate_type:, domain:, content: '', potency: nil, volatility: nil)
|
|
14
|
+
@id = SecureRandom.uuid
|
|
15
|
+
@substrate_type = substrate_type.to_sym
|
|
16
|
+
@domain = domain.to_sym
|
|
17
|
+
@content = content
|
|
18
|
+
@potency = (potency || DEFAULT_POTENCY).to_f.clamp(0.0, 1.0)
|
|
19
|
+
@maturity = 0.0
|
|
20
|
+
@volatility = (volatility || 0.5).to_f.clamp(0.0, 1.0)
|
|
21
|
+
@stage = :inoculation
|
|
22
|
+
@catalysts_applied = []
|
|
23
|
+
@created_at = Time.now.utc
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ferment!(rate = MATURATION_RATE)
|
|
27
|
+
@maturity = (@maturity + rate).clamp(0.0, 1.0).round(10)
|
|
28
|
+
@volatility = (@volatility - VOLATILITY_DECAY).clamp(0.0, 1.0).round(10)
|
|
29
|
+
advance_stage!
|
|
30
|
+
@potency = compute_potency
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def catalyze!(catalyst_type)
|
|
34
|
+
@catalysts_applied << catalyst_type.to_sym
|
|
35
|
+
@potency = (@potency + CATALYSIS_BOOST).clamp(0.0, 1.0).round(10)
|
|
36
|
+
@volatility = (@volatility + 0.05).clamp(0.0, 1.0).round(10)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def spoil!
|
|
40
|
+
@potency = (@potency * 0.5).round(10)
|
|
41
|
+
@stage = :over_fermented
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ripe? = @potency >= RIPE_THRESHOLD && @maturity >= 0.5
|
|
45
|
+
def peak? = @potency >= PEAK_THRESHOLD && @stage == :peak
|
|
46
|
+
def spoiled? = @potency < SPOILAGE_THRESHOLD
|
|
47
|
+
def raw? = @stage == :inoculation
|
|
48
|
+
def aging? = @stage == :aging
|
|
49
|
+
def over_fermented? = @stage == :over_fermented
|
|
50
|
+
def multi_catalyzed? = @catalysts_applied.uniq.size >= 3
|
|
51
|
+
|
|
52
|
+
STAGE_THRESHOLDS = {
|
|
53
|
+
(0.0...0.1) => :inoculation,
|
|
54
|
+
(0.1...0.25) => :primary_fermentation,
|
|
55
|
+
(0.25...0.4) => :secondary_fermentation,
|
|
56
|
+
(0.4...0.55) => :conditioning,
|
|
57
|
+
(0.55...0.7) => :maturation,
|
|
58
|
+
(0.7...0.85) => :aging,
|
|
59
|
+
(0.85...0.95) => :peak,
|
|
60
|
+
(0.95..) => :over_fermented
|
|
61
|
+
}.freeze
|
|
62
|
+
|
|
63
|
+
def age
|
|
64
|
+
((Time.now.utc - @created_at) / 60.0).round(2)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def to_h
|
|
68
|
+
{
|
|
69
|
+
id: @id,
|
|
70
|
+
substrate_type: @substrate_type,
|
|
71
|
+
domain: @domain,
|
|
72
|
+
content: @content,
|
|
73
|
+
potency: @potency.round(10),
|
|
74
|
+
maturity: @maturity.round(10),
|
|
75
|
+
volatility: @volatility.round(10),
|
|
76
|
+
stage: @stage,
|
|
77
|
+
ripe: ripe?,
|
|
78
|
+
peak: peak?,
|
|
79
|
+
spoiled: spoiled?,
|
|
80
|
+
catalysts_applied: @catalysts_applied.uniq,
|
|
81
|
+
age_minutes: age,
|
|
82
|
+
created_at: @created_at.iso8601
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def advance_stage!
|
|
89
|
+
@stage = STAGE_THRESHOLDS.each do |range, stage|
|
|
90
|
+
break stage if range.cover?(@maturity)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def compute_potency
|
|
95
|
+
base = @potency
|
|
96
|
+
base += 0.02 if @stage == :peak
|
|
97
|
+
base -= OVER_FERMENTED_DECAY if @stage == :over_fermented
|
|
98
|
+
base.clamp(0.0, 1.0).round(10)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveFermentation
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveFermentation
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
9
|
+
|
|
10
|
+
def create_substrate(substrate_type:, domain:, content: '', potency: nil,
|
|
11
|
+
volatility: nil, engine: nil, **)
|
|
12
|
+
eng = engine || @default_engine
|
|
13
|
+
sub = eng.create_substrate(substrate_type: substrate_type, domain: domain,
|
|
14
|
+
content: content, potency: potency, volatility: volatility)
|
|
15
|
+
{ success: true, substrate: sub.to_h }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ferment(substrate_id:, rate: nil, engine: nil, **)
|
|
19
|
+
eng = engine || @default_engine
|
|
20
|
+
sub = eng.ferment(substrate_id: substrate_id,
|
|
21
|
+
rate: rate || Helpers::Constants::MATURATION_RATE)
|
|
22
|
+
return { success: false, error: 'substrate not found' } unless sub
|
|
23
|
+
|
|
24
|
+
{ success: true, substrate: sub.to_h }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def catalyze(substrate_id:, catalyst_type:, engine: nil, **)
|
|
28
|
+
eng = engine || @default_engine
|
|
29
|
+
sub = eng.catalyze(substrate_id: substrate_id, catalyst_type: catalyst_type)
|
|
30
|
+
return { success: false, error: 'substrate not found' } unless sub
|
|
31
|
+
|
|
32
|
+
{ success: true, substrate: sub.to_h }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ferment_all(rate: nil, engine: nil, **)
|
|
36
|
+
eng = engine || @default_engine
|
|
37
|
+
eng.ferment_all!(rate: rate || Helpers::Constants::MATURATION_RATE)
|
|
38
|
+
{ success: true }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def list_ripe(engine: nil, **)
|
|
42
|
+
eng = engine || @default_engine
|
|
43
|
+
ripe = eng.ripe_substrates
|
|
44
|
+
{ success: true, count: ripe.size, substrates: ripe.map(&:to_h) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fermentation_status(engine: nil, **)
|
|
48
|
+
eng = engine || @default_engine
|
|
49
|
+
report = eng.fermentation_report
|
|
50
|
+
{ success: true, **report }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
require_relative 'cognitive_fermentation/version'
|
|
6
|
+
require_relative 'cognitive_fermentation/helpers/constants'
|
|
7
|
+
require_relative 'cognitive_fermentation/helpers/substrate'
|
|
8
|
+
require_relative 'cognitive_fermentation/helpers/batch'
|
|
9
|
+
require_relative 'cognitive_fermentation/helpers/fermentation_engine'
|
|
10
|
+
require_relative 'cognitive_fermentation/runners/cognitive_fermentation'
|
|
11
|
+
require_relative 'cognitive_fermentation/client'
|
|
12
|
+
|
|
13
|
+
module Legion
|
|
14
|
+
module Extensions
|
|
15
|
+
module CognitiveFermentation
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveFermentation::Client do
|
|
4
|
+
subject(:client) { described_class.new }
|
|
5
|
+
|
|
6
|
+
it 'responds to runner methods' do
|
|
7
|
+
expect(client).to respond_to(:create_substrate, :ferment, :catalyze, :fermentation_status)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'runs a full fermentation lifecycle' do
|
|
11
|
+
result = client.create_substrate(substrate_type: :raw_idea, domain: :cognitive, content: 'test')
|
|
12
|
+
sub_id = result[:substrate][:id]
|
|
13
|
+
|
|
14
|
+
client.catalyze(substrate_id: sub_id, catalyst_type: :analogy)
|
|
15
|
+
10.times { client.ferment(substrate_id: sub_id) }
|
|
16
|
+
|
|
17
|
+
status = client.fermentation_status
|
|
18
|
+
expect(status[:total_substrates]).to eq(1)
|
|
19
|
+
expect(status[:success]).to be true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'lists ripe substrates' do
|
|
23
|
+
result = client.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.8)
|
|
24
|
+
sub_id = result[:substrate][:id]
|
|
25
|
+
15.times { client.ferment(substrate_id: sub_id, rate: 0.05) }
|
|
26
|
+
ripe = client.list_ripe
|
|
27
|
+
expect(ripe[:success]).to be true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'ferments all substrates' do
|
|
31
|
+
client.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
32
|
+
client.create_substrate(substrate_type: :raw_idea, domain: :emotional)
|
|
33
|
+
result = client.ferment_all
|
|
34
|
+
expect(result[:success]).to be true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveFermentation::Helpers::Batch do
|
|
4
|
+
subject(:batch) { described_class.new(domain: :cognitive) }
|
|
5
|
+
|
|
6
|
+
let(:substrate_class) { Legion::Extensions::CognitiveFermentation::Helpers::Substrate }
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'assigns a uuid id' do
|
|
10
|
+
expect(batch.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'stores domain' do
|
|
14
|
+
expect(batch.domain).to eq(:cognitive)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'starts with empty substrates' do
|
|
18
|
+
expect(batch.substrates).to be_empty
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#add_substrate' do
|
|
23
|
+
it 'adds substrate to batch' do
|
|
24
|
+
sub = substrate_class.new(substrate_type: :raw_idea, domain: :cognitive)
|
|
25
|
+
batch.add_substrate(sub)
|
|
26
|
+
expect(batch.substrates.size).to eq(1)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#ferment_all!' do
|
|
31
|
+
it 'ferments all substrates' do
|
|
32
|
+
sub = substrate_class.new(substrate_type: :raw_idea, domain: :cognitive)
|
|
33
|
+
batch.add_substrate(sub)
|
|
34
|
+
batch.ferment_all!
|
|
35
|
+
expect(sub.maturity).to be > 0.0
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '#average_potency' do
|
|
40
|
+
it 'returns 0.0 for empty batch' do
|
|
41
|
+
expect(batch.average_potency).to eq(0.0)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'computes average' do
|
|
45
|
+
s1 = substrate_class.new(substrate_type: :raw_idea, domain: :cognitive, potency: 0.6)
|
|
46
|
+
s2 = substrate_class.new(substrate_type: :raw_idea, domain: :cognitive, potency: 0.4)
|
|
47
|
+
batch.add_substrate(s1)
|
|
48
|
+
batch.add_substrate(s2)
|
|
49
|
+
expect(batch.average_potency).to eq(0.5)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#yield_rate' do
|
|
54
|
+
it 'returns 0.0 for empty batch' do
|
|
55
|
+
expect(batch.yield_rate).to eq(0.0)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe '#ready_to_harvest?' do
|
|
60
|
+
it 'returns false when no ripe substrates' do
|
|
61
|
+
expect(batch).not_to be_ready_to_harvest
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#to_h' do
|
|
66
|
+
it 'returns hash with batch stats' do
|
|
67
|
+
h = batch.to_h
|
|
68
|
+
expect(h).to include(:id, :domain, :substrate_count, :average_potency,
|
|
69
|
+
:average_maturity, :ripe_count, :yield_rate)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveFermentation::Helpers::FermentationEngine do
|
|
4
|
+
subject(:engine) { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe '#create_substrate' do
|
|
7
|
+
it 'creates and returns a substrate' do
|
|
8
|
+
sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
9
|
+
expect(sub).to be_a(Legion::Extensions::CognitiveFermentation::Helpers::Substrate)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'adds substrate to a batch' do
|
|
13
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
14
|
+
report = engine.fermentation_report
|
|
15
|
+
expect(report[:total_batches]).to eq(1)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'reuses batch for same domain' do
|
|
19
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
20
|
+
engine.create_substrate(substrate_type: :dormant_association, domain: :cognitive)
|
|
21
|
+
expect(engine.fermentation_report[:total_batches]).to eq(1)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'creates separate batches per domain' do
|
|
25
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
26
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :emotional)
|
|
27
|
+
expect(engine.fermentation_report[:total_batches]).to eq(2)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#ferment' do
|
|
32
|
+
it 'ferments an existing substrate' do
|
|
33
|
+
sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
34
|
+
result = engine.ferment(substrate_id: sub.id)
|
|
35
|
+
expect(result.maturity).to be > 0.0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns nil for unknown substrate' do
|
|
39
|
+
expect(engine.ferment(substrate_id: 'nonexistent')).to be_nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#catalyze' do
|
|
44
|
+
it 'catalyzes an existing substrate' do
|
|
45
|
+
sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.3)
|
|
46
|
+
result = engine.catalyze(substrate_id: sub.id, catalyst_type: :analogy)
|
|
47
|
+
expect(result.potency).to be > 0.3
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'returns nil for unknown substrate' do
|
|
51
|
+
expect(engine.catalyze(substrate_id: 'x', catalyst_type: :analogy)).to be_nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#ferment_all!' do
|
|
56
|
+
it 'advances all substrates' do
|
|
57
|
+
s1 = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
58
|
+
s2 = engine.create_substrate(substrate_type: :raw_idea, domain: :emotional)
|
|
59
|
+
engine.ferment_all!
|
|
60
|
+
expect(s1.maturity).to be > 0.0
|
|
61
|
+
expect(s2.maturity).to be > 0.0
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe 'query methods' do
|
|
66
|
+
before do
|
|
67
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.5)
|
|
68
|
+
engine.create_substrate(substrate_type: :dormant_association, domain: :emotional, potency: 0.3)
|
|
69
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.8)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'filters by domain' do
|
|
73
|
+
expect(engine.substrates_by_domain(domain: :cognitive).size).to eq(2)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'filters by type' do
|
|
77
|
+
expect(engine.substrates_by_type(type: :raw_idea).size).to eq(2)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'filters by stage' do
|
|
81
|
+
expect(engine.substrates_by_stage(stage: :inoculation).size).to eq(3)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'returns raw substrates' do
|
|
85
|
+
expect(engine.raw_substrates.size).to eq(3)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'returns most potent' do
|
|
89
|
+
results = engine.most_potent(limit: 2)
|
|
90
|
+
expect(results.size).to eq(2)
|
|
91
|
+
expect(results.first.potency).to be >= results.last.potency
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe 'aggregate metrics' do
|
|
96
|
+
it 'returns 0.0 overall_potency for empty engine' do
|
|
97
|
+
expect(engine.overall_potency).to eq(0.0)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'computes overall_potency' do
|
|
101
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.6)
|
|
102
|
+
expect(engine.overall_potency).to be > 0.0
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'computes overall_maturity' do
|
|
106
|
+
sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
107
|
+
engine.ferment(substrate_id: sub.id)
|
|
108
|
+
expect(engine.overall_maturity).to be > 0.0
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'computes yield_rate' do
|
|
112
|
+
expect(engine.yield_rate).to eq(0.0)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'computes stage_distribution' do
|
|
116
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
|
|
117
|
+
dist = engine.stage_distribution
|
|
118
|
+
expect(dist[:inoculation]).to eq(1)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe '#fermentation_report' do
|
|
123
|
+
it 'returns comprehensive report' do
|
|
124
|
+
engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.5)
|
|
125
|
+
report = engine.fermentation_report
|
|
126
|
+
expect(report).to include(:total_substrates, :total_batches, :overall_potency,
|
|
127
|
+
:potency_label, :overall_maturity, :maturity_label,
|
|
128
|
+
:yield_rate, :stage_distribution, :batches, :most_potent)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe '#to_h' do
|
|
133
|
+
it 'returns summary hash' do
|
|
134
|
+
h = engine.to_h
|
|
135
|
+
expect(h).to include(:total_substrates, :total_batches, :potency, :maturity, :volatility)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveFermentation::Helpers::Substrate do
|
|
4
|
+
subject(:substrate) do
|
|
5
|
+
described_class.new(substrate_type: :raw_idea, domain: :cognitive, content: 'test idea')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'assigns a uuid id' do
|
|
10
|
+
expect(substrate.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'stores substrate_type as symbol' do
|
|
14
|
+
expect(substrate.substrate_type).to eq(:raw_idea)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'stores domain as symbol' do
|
|
18
|
+
expect(substrate.domain).to eq(:cognitive)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'stores content' do
|
|
22
|
+
expect(substrate.content).to eq('test idea')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'defaults potency' do
|
|
26
|
+
expect(substrate.potency).to eq(0.3)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'starts at inoculation stage' do
|
|
30
|
+
expect(substrate.stage).to eq(:inoculation)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'starts with zero maturity' do
|
|
34
|
+
expect(substrate.maturity).to eq(0.0)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'starts with empty catalysts' do
|
|
38
|
+
expect(substrate.catalysts_applied).to be_empty
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'clamps potency to valid range' do
|
|
42
|
+
s = described_class.new(substrate_type: :raw_idea, domain: :cognitive, potency: 1.5)
|
|
43
|
+
expect(s.potency).to eq(1.0)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#ferment!' do
|
|
48
|
+
it 'increases maturity' do
|
|
49
|
+
substrate.ferment!
|
|
50
|
+
expect(substrate.maturity).to be > 0.0
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'decreases volatility' do
|
|
54
|
+
initial = substrate.volatility
|
|
55
|
+
substrate.ferment!
|
|
56
|
+
expect(substrate.volatility).to be < initial
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'advances stage with enough fermentation' do
|
|
60
|
+
5.times { substrate.ferment!(0.1) }
|
|
61
|
+
expect(substrate.stage).not_to eq(:inoculation)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'reaches peak stage' do
|
|
65
|
+
18.times { substrate.ferment!(0.05) }
|
|
66
|
+
expect(substrate.stage).to eq(:peak)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'reaches over_fermented stage' do
|
|
70
|
+
25.times { substrate.ferment!(0.05) }
|
|
71
|
+
expect(substrate.stage).to eq(:over_fermented)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe '#catalyze!' do
|
|
76
|
+
it 'boosts potency' do
|
|
77
|
+
initial = substrate.potency
|
|
78
|
+
substrate.catalyze!(:analogy)
|
|
79
|
+
expect(substrate.potency).to be > initial
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'records catalyst type' do
|
|
83
|
+
substrate.catalyze!(:dream_residue)
|
|
84
|
+
expect(substrate.catalysts_applied).to include(:dream_residue)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'slightly increases volatility' do
|
|
88
|
+
initial = substrate.volatility
|
|
89
|
+
substrate.catalyze!(:analogy)
|
|
90
|
+
expect(substrate.volatility).to be > initial
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe '#spoil!' do
|
|
95
|
+
it 'halves potency' do
|
|
96
|
+
initial = substrate.potency
|
|
97
|
+
substrate.spoil!
|
|
98
|
+
expect(substrate.potency).to be < initial
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'sets stage to over_fermented' do
|
|
102
|
+
substrate.spoil!
|
|
103
|
+
expect(substrate.stage).to eq(:over_fermented)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe 'predicate methods' do
|
|
108
|
+
it 'reports ripe when potency and maturity are high' do
|
|
109
|
+
s = described_class.new(substrate_type: :raw_idea, domain: :cognitive, potency: 0.8)
|
|
110
|
+
10.times { s.ferment!(0.06) }
|
|
111
|
+
expect(s).to be_ripe
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'reports spoiled when potency is very low' do
|
|
115
|
+
s = described_class.new(substrate_type: :raw_idea, domain: :cognitive, potency: 0.05)
|
|
116
|
+
s.spoil!
|
|
117
|
+
expect(s).to be_spoiled
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'reports raw at inoculation' do
|
|
121
|
+
expect(substrate).to be_raw
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'reports multi_catalyzed with 3+ catalysts' do
|
|
125
|
+
substrate.catalyze!(:analogy)
|
|
126
|
+
substrate.catalyze!(:contrast)
|
|
127
|
+
substrate.catalyze!(:dream_residue)
|
|
128
|
+
expect(substrate).to be_multi_catalyzed
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe '#age' do
|
|
133
|
+
it 'returns age in minutes' do
|
|
134
|
+
expect(substrate.age).to be >= 0.0
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe '#to_h' do
|
|
139
|
+
it 'returns hash with all fields' do
|
|
140
|
+
h = substrate.to_h
|
|
141
|
+
expect(h).to include(:id, :substrate_type, :domain, :content, :potency,
|
|
142
|
+
:maturity, :volatility, :stage, :ripe, :peak,
|
|
143
|
+
:spoiled, :catalysts_applied, :created_at)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_fermentation'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Helpers
|
|
8
|
+
module Lex; end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Logging
|
|
13
|
+
def self.method_missing(_, *) = nil
|
|
14
|
+
def self.respond_to_missing?(_, _ = false) = true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
RSpec.configure do |config|
|
|
19
|
+
config.expect_with :rspec do |expectations|
|
|
20
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
21
|
+
end
|
|
22
|
+
config.mock_with :rspec do |mocks|
|
|
23
|
+
mocks.verify_partial_doubles = true
|
|
24
|
+
end
|
|
25
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
26
|
+
config.order = :random
|
|
27
|
+
Kernel.srand config.seed
|
|
28
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-fermentation
|
|
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 cognitive fermentation — the slow transformation of raw ideas
|
|
27
|
+
into refined insights through unconscious incubation and catalysis
|
|
28
|
+
email:
|
|
29
|
+
- matthewdiverson@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- ".github/workflows/ci.yml"
|
|
35
|
+
- ".gitignore"
|
|
36
|
+
- ".rspec"
|
|
37
|
+
- ".rubocop.yml"
|
|
38
|
+
- CLAUDE.md
|
|
39
|
+
- Gemfile
|
|
40
|
+
- Gemfile.lock
|
|
41
|
+
- README.md
|
|
42
|
+
- lex-cognitive-fermentation.gemspec
|
|
43
|
+
- lib/legion/extensions/cognitive_fermentation.rb
|
|
44
|
+
- lib/legion/extensions/cognitive_fermentation/client.rb
|
|
45
|
+
- lib/legion/extensions/cognitive_fermentation/helpers/batch.rb
|
|
46
|
+
- lib/legion/extensions/cognitive_fermentation/helpers/constants.rb
|
|
47
|
+
- lib/legion/extensions/cognitive_fermentation/helpers/fermentation_engine.rb
|
|
48
|
+
- lib/legion/extensions/cognitive_fermentation/helpers/substrate.rb
|
|
49
|
+
- lib/legion/extensions/cognitive_fermentation/runners/cognitive_fermentation.rb
|
|
50
|
+
- lib/legion/extensions/cognitive_fermentation/version.rb
|
|
51
|
+
- spec/legion/extensions/cognitive_fermentation/client_spec.rb
|
|
52
|
+
- spec/legion/extensions/cognitive_fermentation/helpers/batch_spec.rb
|
|
53
|
+
- spec/legion/extensions/cognitive_fermentation/helpers/fermentation_engine_spec.rb
|
|
54
|
+
- spec/legion/extensions/cognitive_fermentation/helpers/substrate_spec.rb
|
|
55
|
+
- spec/spec_helper.rb
|
|
56
|
+
homepage: https://github.com/LegionIO/lex-cognitive-fermentation
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
metadata:
|
|
60
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-fermentation
|
|
61
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-fermentation
|
|
62
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-fermentation/blob/master/README.md
|
|
63
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-fermentation/blob/master/CHANGELOG.md
|
|
64
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-fermentation/issues
|
|
65
|
+
rubygems_mfa_required: 'true'
|
|
66
|
+
rdoc_options: []
|
|
67
|
+
require_paths:
|
|
68
|
+
- lib
|
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '3.4'
|
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '0'
|
|
79
|
+
requirements: []
|
|
80
|
+
rubygems_version: 3.6.9
|
|
81
|
+
specification_version: 4
|
|
82
|
+
summary: Slow unconscious cognitive processing for LegionIO agents
|
|
83
|
+
test_files: []
|