lex-cognitive-cocoon 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.
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveCocoon::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ describe 'runner interface' do
7
+ it 'responds to create_cocoon' do
8
+ expect(client).to respond_to(:create_cocoon)
9
+ end
10
+
11
+ it 'responds to gestate_all' do
12
+ expect(client).to respond_to(:gestate_all)
13
+ end
14
+
15
+ it 'responds to harvest_ready' do
16
+ expect(client).to respond_to(:harvest_ready)
17
+ end
18
+
19
+ it 'responds to force_emerge' do
20
+ expect(client).to respond_to(:force_emerge)
21
+ end
22
+
23
+ it 'responds to cocoon_status' do
24
+ expect(client).to respond_to(:cocoon_status)
25
+ end
26
+
27
+ it 'responds to list_by_stage' do
28
+ expect(client).to respond_to(:list_by_stage)
29
+ end
30
+ end
31
+
32
+ describe '#create_cocoon' do
33
+ it 'returns success true' do
34
+ result = client.create_cocoon(cocoon_type: :chrysalis, domain: :cognitive, content: 'idea')
35
+ expect(result[:success]).to be true
36
+ end
37
+
38
+ it 'returns cocoon hash' do
39
+ result = client.create_cocoon(cocoon_type: :silk, domain: :emotional)
40
+ expect(result[:cocoon]).to include(:id, :cocoon_type, :domain, :maturity, :stage)
41
+ end
42
+ end
43
+
44
+ describe '#gestate_all' do
45
+ it 'returns success true' do
46
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
47
+ result = client.gestate_all
48
+ expect(result[:success]).to be true
49
+ end
50
+
51
+ it 'accepts a custom rate' do
52
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
53
+ result = client.gestate_all(rate: 0.2)
54
+ expect(result[:success]).to be true
55
+ end
56
+ end
57
+
58
+ describe '#harvest_ready' do
59
+ it 'returns success true with empty emerged when nothing ready' do
60
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
61
+ result = client.harvest_ready
62
+ expect(result[:success]).to be true
63
+ expect(result[:count]).to eq(0)
64
+ end
65
+
66
+ it 'harvests ready cocoons' do
67
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive, maturity: 1.0)
68
+ result = client.harvest_ready
69
+ expect(result[:count]).to eq(1)
70
+ expect(result[:emerged].first[:success]).to be true
71
+ end
72
+ end
73
+
74
+ describe '#force_emerge' do
75
+ it 'force-emerges a valid cocoon' do
76
+ create_result = client.create_cocoon(cocoon_type: :shell, domain: :cognitive)
77
+ id = create_result[:cocoon][:id]
78
+ result = client.force_emerge(id: id)
79
+ expect(result[:success]).to be true
80
+ end
81
+
82
+ it 'returns failure for unknown id' do
83
+ result = client.force_emerge(id: 'bad-id')
84
+ expect(result[:success]).to be false
85
+ end
86
+ end
87
+
88
+ describe '#cocoon_status' do
89
+ it 'returns success true' do
90
+ result = client.cocoon_status
91
+ expect(result[:success]).to be true
92
+ end
93
+
94
+ it 'includes total_cocoons' do
95
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
96
+ result = client.cocoon_status
97
+ expect(result[:total_cocoons]).to eq(1)
98
+ end
99
+
100
+ it 'includes maturity_label' do
101
+ result = client.cocoon_status
102
+ expect(result).to have_key(:maturity_label)
103
+ end
104
+ end
105
+
106
+ describe '#list_by_stage' do
107
+ it 'returns success true' do
108
+ result = client.list_by_stage(stage: :encapsulating)
109
+ expect(result[:success]).to be true
110
+ end
111
+
112
+ it 'returns the requested stage name' do
113
+ result = client.list_by_stage(stage: :encapsulating)
114
+ expect(result[:stage]).to eq(:encapsulating)
115
+ end
116
+
117
+ it 'returns cocoons in the given stage' do
118
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
119
+ result = client.list_by_stage(stage: :encapsulating)
120
+ expect(result[:count]).to eq(1)
121
+ end
122
+
123
+ it 'returns cocoon hashes' do
124
+ client.create_cocoon(cocoon_type: :silk, domain: :cognitive)
125
+ result = client.list_by_stage(stage: :encapsulating)
126
+ expect(result[:cocoons].first).to include(:id, :cocoon_type, :stage)
127
+ end
128
+ end
129
+
130
+ describe 'full lifecycle' do
131
+ it 'creates, gestates, and harvests a cocoon' do
132
+ client.create_cocoon(cocoon_type: :chrysalis, domain: :cognitive, content: 'deep insight')
133
+ 10.times { client.gestate_all(rate: 0.1) }
134
+ result = client.harvest_ready
135
+ expect(result[:count]).to eq(1)
136
+ expect(result[:emerged].first[:content]).to eq('deep insight')
137
+ end
138
+
139
+ it 'correctly reports status after gestation' do
140
+ client.create_cocoon(cocoon_type: :pod, domain: :emotional, content: 'growing concept')
141
+ 5.times { client.gestate_all(rate: 0.1) }
142
+ status = client.cocoon_status
143
+ expect(status[:average_maturity]).to be_within(0.01).of(0.5)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveCocoon::Helpers::Cocoon do
4
+ subject(:cocoon) do
5
+ described_class.new(cocoon_type: :chrysalis, domain: :cognitive, content: 'a fragile idea')
6
+ end
7
+
8
+ describe '#initialize' do
9
+ it 'assigns a uuid id' do
10
+ expect(cocoon.id).to match(/\A[0-9a-f-]{36}\z/)
11
+ end
12
+
13
+ it 'stores cocoon_type as symbol' do
14
+ expect(cocoon.cocoon_type).to eq(:chrysalis)
15
+ end
16
+
17
+ it 'stores domain as symbol' do
18
+ expect(cocoon.domain).to eq(:cognitive)
19
+ end
20
+
21
+ it 'stores content' do
22
+ expect(cocoon.content).to eq('a fragile idea')
23
+ end
24
+
25
+ it 'starts with zero maturity by default' do
26
+ expect(cocoon.maturity).to eq(0.0)
27
+ end
28
+
29
+ it 'assigns protection from PROTECTION_BY_TYPE for chrysalis' do
30
+ expect(cocoon.protection).to eq(0.8)
31
+ end
32
+
33
+ it 'starts in encapsulating stage' do
34
+ expect(cocoon.stage).to eq(:encapsulating)
35
+ end
36
+
37
+ it 'records created_at as utc' do
38
+ expect(cocoon.created_at).to be_a(Time)
39
+ end
40
+
41
+ it 'clamps maturity to 0..1 when overridden' do
42
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 1.5)
43
+ expect(c.maturity).to eq(1.0)
44
+ end
45
+
46
+ it 'clamps protection to 0..1 when overridden' do
47
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, protection: 2.0)
48
+ expect(c.protection).to eq(1.0)
49
+ end
50
+
51
+ it 'uses fallback protection of 0.7 for unknown type via fetch default' do
52
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, protection: 0.7)
53
+ expect(c.protection).to eq(0.7)
54
+ end
55
+
56
+ it 'assigns silk protection correctly' do
57
+ c = described_class.new(cocoon_type: :silk, domain: :semantic)
58
+ expect(c.protection).to eq(0.6)
59
+ end
60
+
61
+ it 'assigns shell protection correctly' do
62
+ c = described_class.new(cocoon_type: :shell, domain: :semantic)
63
+ expect(c.protection).to eq(0.9)
64
+ end
65
+
66
+ it 'assigns pod protection correctly' do
67
+ c = described_class.new(cocoon_type: :pod, domain: :semantic)
68
+ expect(c.protection).to eq(0.7)
69
+ end
70
+
71
+ it 'assigns web protection correctly' do
72
+ c = described_class.new(cocoon_type: :web, domain: :semantic)
73
+ expect(c.protection).to eq(0.5)
74
+ end
75
+
76
+ it 'enters developing stage when maturity starts at 0.5' do
77
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 0.5)
78
+ expect(c.stage).to eq(:developing)
79
+ end
80
+
81
+ it 'enters transforming stage when maturity starts at 0.8' do
82
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 0.8)
83
+ expect(c.stage).to eq(:transforming)
84
+ end
85
+
86
+ it 'enters ready stage when maturity starts at 1.0' do
87
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 1.0)
88
+ expect(c.stage).to eq(:ready)
89
+ end
90
+ end
91
+
92
+ describe '#gestate!' do
93
+ it 'increases maturity by MATURITY_RATE by default' do
94
+ cocoon.gestate!
95
+ expect(cocoon.maturity).to be_within(0.001).of(0.1)
96
+ end
97
+
98
+ it 'accepts a custom rate' do
99
+ cocoon.gestate!(0.2)
100
+ expect(cocoon.maturity).to be_within(0.001).of(0.2)
101
+ end
102
+
103
+ it 'does not exceed maturity 1.0' do
104
+ 20.times { cocoon.gestate! }
105
+ expect(cocoon.maturity).to eq(1.0)
106
+ end
107
+
108
+ it 'transitions to developing stage' do
109
+ 4.times { cocoon.gestate!(0.1) }
110
+ expect(cocoon.stage).to eq(:developing)
111
+ end
112
+
113
+ it 'transitions to transforming stage' do
114
+ 8.times { cocoon.gestate!(0.1) }
115
+ expect(cocoon.stage).to eq(:transforming)
116
+ end
117
+
118
+ it 'transitions to ready stage at 1.0' do
119
+ 10.times { cocoon.gestate!(0.1) }
120
+ expect(cocoon.stage).to eq(:ready)
121
+ end
122
+
123
+ it 'returns self for chaining' do
124
+ expect(cocoon.gestate!).to be(cocoon)
125
+ end
126
+
127
+ it 'does not advance an emerged cocoon' do
128
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 1.0)
129
+ c.emerge!
130
+ before_maturity = c.maturity
131
+ c.gestate!
132
+ expect(c.maturity).to eq(before_maturity)
133
+ end
134
+ end
135
+
136
+ describe '#ready?' do
137
+ it 'returns false for a new cocoon' do
138
+ expect(cocoon).not_to be_ready
139
+ end
140
+
141
+ it 'returns true when maturity reaches 1.0' do
142
+ 10.times { cocoon.gestate!(0.1) }
143
+ expect(cocoon).to be_ready
144
+ end
145
+ end
146
+
147
+ describe '#premature?' do
148
+ it 'returns true for a new cocoon' do
149
+ expect(cocoon).to be_premature
150
+ end
151
+
152
+ it 'returns false once cocoon is ready' do
153
+ 10.times { cocoon.gestate!(0.1) }
154
+ expect(cocoon).not_to be_premature
155
+ end
156
+
157
+ it 'returns false after emergence' do
158
+ c = described_class.new(cocoon_type: :silk, domain: :emotional, maturity: 1.0)
159
+ c.emerge!
160
+ expect(c).not_to be_premature
161
+ end
162
+ end
163
+
164
+ describe '#emerge!' do
165
+ context 'when ready' do
166
+ before { 10.times { cocoon.gestate!(0.1) } }
167
+
168
+ it 'returns success true' do
169
+ expect(cocoon.emerge![:success]).to be true
170
+ end
171
+
172
+ it 'returns the content' do
173
+ expect(cocoon.emerge![:content]).to eq('a fragile idea')
174
+ end
175
+
176
+ it 'reports not damaged' do
177
+ expect(cocoon.emerge![:damaged]).to be false
178
+ end
179
+
180
+ it 'sets stage to emerged' do
181
+ cocoon.emerge!
182
+ expect(cocoon.stage).to eq(:emerged)
183
+ end
184
+ end
185
+
186
+ context 'when not ready' do
187
+ it 'returns success false' do
188
+ expect(cocoon.emerge![:success]).to be false
189
+ end
190
+
191
+ it 'reports not damaged' do
192
+ expect(cocoon.emerge![:damaged]).to be false
193
+ end
194
+
195
+ it 'returns an error message' do
196
+ expect(cocoon.emerge![:error]).to eq('not ready')
197
+ end
198
+
199
+ it 'does not change the stage' do
200
+ cocoon.emerge!
201
+ expect(cocoon.stage).to eq(:encapsulating)
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#expose!' do
207
+ context 'when premature' do
208
+ it 'returns success true' do
209
+ expect(cocoon.expose![:success]).to be true
210
+ end
211
+
212
+ it 'reports the idea is damaged' do
213
+ expect(cocoon.expose![:damaged]).to be true
214
+ end
215
+
216
+ it 'sets stage to emerged' do
217
+ cocoon.expose!
218
+ expect(cocoon.stage).to eq(:emerged)
219
+ end
220
+
221
+ it 'applies the premature penalty to maturity' do
222
+ cocoon.gestate!(0.4)
223
+ cocoon.expose!
224
+ expect(cocoon.maturity).to be_within(0.001).of(0.4 * 0.5)
225
+ end
226
+ end
227
+
228
+ context 'when ready' do
229
+ before { 10.times { cocoon.gestate!(0.1) } }
230
+
231
+ it 'returns success true' do
232
+ expect(cocoon.expose![:success]).to be true
233
+ end
234
+
235
+ it 'reports not damaged' do
236
+ expect(cocoon.expose![:damaged]).to be false
237
+ end
238
+
239
+ it 'sets stage to emerged' do
240
+ cocoon.expose!
241
+ expect(cocoon.stage).to eq(:emerged)
242
+ end
243
+ end
244
+ end
245
+
246
+ describe '#age_seconds' do
247
+ it 'returns a non-negative float' do
248
+ expect(cocoon.age_seconds).to be >= 0.0
249
+ end
250
+ end
251
+
252
+ describe '#to_h' do
253
+ it 'returns a hash with all expected keys' do
254
+ h = cocoon.to_h
255
+ expect(h).to include(
256
+ :id, :cocoon_type, :domain, :content, :maturity, :stage,
257
+ :protection, :ready, :premature, :maturity_label, :age_seconds, :created_at
258
+ )
259
+ end
260
+
261
+ it 'includes the correct cocoon_type' do
262
+ expect(cocoon.to_h[:cocoon_type]).to eq(:chrysalis)
263
+ end
264
+
265
+ it 'includes the correct domain' do
266
+ expect(cocoon.to_h[:domain]).to eq(:cognitive)
267
+ end
268
+
269
+ it 'includes maturity rounded to 10 decimal places' do
270
+ cocoon.gestate!(0.123456789012)
271
+ expect(cocoon.to_h[:maturity].to_s.split('.').last.length).to be <= 10
272
+ end
273
+
274
+ it 'includes the maturity_label' do
275
+ expect(cocoon.to_h[:maturity_label]).to eq(:newly_formed)
276
+ end
277
+
278
+ it 'includes created_at as iso8601' do
279
+ expect(cocoon.to_h[:created_at]).to match(/\d{4}-\d{2}-\d{2}T/)
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::CognitiveCocoon::Helpers::Constants do
4
+ describe 'GESTATION_STAGES' do
5
+ it 'is an array of symbols' do
6
+ expect(described_class::GESTATION_STAGES).to all(be_a(Symbol))
7
+ end
8
+
9
+ it 'contains the five expected stages' do
10
+ expect(described_class::GESTATION_STAGES).to eq(%i[encapsulating developing transforming ready emerged])
11
+ end
12
+
13
+ it 'is frozen' do
14
+ expect(described_class::GESTATION_STAGES).to be_frozen
15
+ end
16
+ end
17
+
18
+ describe 'COCOON_TYPES' do
19
+ it 'is an array of symbols' do
20
+ expect(described_class::COCOON_TYPES).to all(be_a(Symbol))
21
+ end
22
+
23
+ it 'contains the five expected types' do
24
+ expect(described_class::COCOON_TYPES).to eq(%i[silk chrysalis shell pod web])
25
+ end
26
+
27
+ it 'is frozen' do
28
+ expect(described_class::COCOON_TYPES).to be_frozen
29
+ end
30
+ end
31
+
32
+ describe 'MAX_COCOONS' do
33
+ it 'equals 100' do
34
+ expect(described_class::MAX_COCOONS).to eq(100)
35
+ end
36
+ end
37
+
38
+ describe 'MATURITY_RATE' do
39
+ it 'equals 0.1' do
40
+ expect(described_class::MATURITY_RATE).to eq(0.1)
41
+ end
42
+ end
43
+
44
+ describe 'PREMATURE_PENALTY' do
45
+ it 'equals 0.5' do
46
+ expect(described_class::PREMATURE_PENALTY).to eq(0.5)
47
+ end
48
+ end
49
+
50
+ describe 'PROTECTION_BY_TYPE' do
51
+ it 'has an entry for every cocoon type' do
52
+ described_class::COCOON_TYPES.each do |type|
53
+ expect(described_class::PROTECTION_BY_TYPE).to have_key(type)
54
+ end
55
+ end
56
+
57
+ it 'assigns highest protection to shell' do
58
+ expect(described_class::PROTECTION_BY_TYPE[:shell]).to eq(0.9)
59
+ end
60
+
61
+ it 'assigns lowest protection to web' do
62
+ expect(described_class::PROTECTION_BY_TYPE[:web]).to eq(0.5)
63
+ end
64
+ end
65
+
66
+ describe 'MATURITY_LABELS' do
67
+ it 'is a hash' do
68
+ expect(described_class::MATURITY_LABELS).to be_a(Hash)
69
+ end
70
+
71
+ it 'is frozen' do
72
+ expect(described_class::MATURITY_LABELS).to be_frozen
73
+ end
74
+ end
75
+
76
+ describe '.label_for' do
77
+ it 'returns fully_gestated for maturity 0.95' do
78
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.95)).to eq(:fully_gestated)
79
+ end
80
+
81
+ it 'returns nearly_ready for maturity 0.8' do
82
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.8)).to eq(:nearly_ready)
83
+ end
84
+
85
+ it 'returns mid_gestation for maturity 0.6' do
86
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.6)).to eq(:mid_gestation)
87
+ end
88
+
89
+ it 'returns early_gestation for maturity 0.4' do
90
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.4)).to eq(:early_gestation)
91
+ end
92
+
93
+ it 'returns just_encapsulated for maturity 0.2' do
94
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.2)).to eq(:just_encapsulated)
95
+ end
96
+
97
+ it 'returns newly_formed for maturity 0.05' do
98
+ expect(described_class.label_for(described_class::MATURITY_LABELS, 0.05)).to eq(:newly_formed)
99
+ end
100
+
101
+ it 'returns unknown for an empty hash' do
102
+ expect(described_class.label_for({}, 0.5)).to eq(:unknown)
103
+ end
104
+ end
105
+ end