legionio 1.6.36 → 1.6.37

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd73445976635c61163ac93a058fd3253bb164956fff00d8b791817b1dd16ddb
4
- data.tar.gz: 218c4b3975aa59cb4c0eec3735c2cdbe185cf23f85429b4268d4335a8cb7fdf9
3
+ metadata.gz: 3a187a818bb06029a4b03e5eb47c75af63e2fe85f997d157ce7f36dad924307b
4
+ data.tar.gz: 77005d16734961543c5cf5bd81d615f7387686e731725f510e2f56c72a49613a
5
5
  SHA512:
6
- metadata.gz: 247d06dcfb4d405c1a156bac4c9a4a0aaa00eedd0cf2f3bfef74da95f9027acb39f303bc9afda3dbf50d2f14dee2a41eafd10d5522dbf074017548489f69ebd0
7
- data.tar.gz: 840d3c68d9e48e11e3c92a40cf2a0d849079d5ab68aa39629368f88a75615d1dca151b952987de9a882517c84569bcc7aff9c93becbd9d8277b98152a5fdc942
6
+ metadata.gz: 856b38fdb0200c467538ed0c7b79863be85d0a14ea44d0ae52f0e13a6f655089cfb4e905b94f42a89b893809c183b81366789bf531a1f1023b9ba0c44523920d
7
+ data.tar.gz: a23b1bc63408859994b6c315aa38f7dba5a43e5a64bfdd7d0e8f51dc9a3ce4eac96d12d0bf98a2241e9bd7c507953d9733bb4e6b857186f8e3789f2a99db3206
data/.rubocop.yml CHANGED
@@ -29,7 +29,7 @@ Metrics/ModuleLength:
29
29
  - 'lib/legion/api/openapi.rb'
30
30
 
31
31
  Metrics/BlockLength:
32
- Max: 40
32
+ Max: 52
33
33
  Exclude:
34
34
  - 'spec/**/*'
35
35
  - 'integration/**/*'
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.6.37] - 2026-03-30
6
+
7
+ ### Added
8
+ - TBI Patterns API: `POST /api/tbi/patterns/export`, `GET /api/tbi/patterns`, `GET /api/tbi/patterns/:id`, `PATCH /api/tbi/patterns/:id/score`, `GET /api/tbi/patterns/discover` (501 stub)
9
+ - TBI Pattern model and local migration (`create_tbi_patterns`)
10
+ - OpenInference telemetry integration (`Legion::Telemetry::OpenInference`)
11
+
12
+ ### Fixed
13
+ - Governance lifecycle integration specs expanded and hardened
14
+
5
15
  ## [1.6.36] - 2026-03-29
6
16
 
7
17
  ### Added
@@ -26,7 +26,7 @@ module Legion
26
26
  end
27
27
  end
28
28
 
29
- helpers do # rubocop:disable Metrics/BlockLength
29
+ helpers do
30
30
  def build_catalog_manifest(name, entry)
31
31
  {
32
32
  name: name,
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/json'
4
+ require 'legion/api/events'
4
5
 
5
6
  module Legion
6
7
  class API < Sinatra::Base
@@ -922,7 +923,7 @@ module Legion
922
923
  summary: 'Get recent events from ring buffer',
923
924
  operationId: 'getRecentEvents',
924
925
  parameters: [
925
- { name: 'count', in: 'query', description: "Number of events (max #{Routes::Events::BUFFER_SIZE})",
926
+ { name: 'count', in: 'query', description: "Number of events (max #{Legion::API::Routes::Events::BUFFER_SIZE})",
926
927
  required: false, schema: { type: 'integer', default: 25 } }
927
928
  ],
928
929
  responses: {
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Legion
6
+ class API < Sinatra::Base
7
+ module Routes
8
+ module TbiPatterns
9
+ MAX_DESCRIPTION_BYTES = 1024
10
+ MAX_PAYLOAD_SHAPE_BYTES = 65_536
11
+ VALID_TIERS = %w[tier1 tier2 tier3 tier4 tier5].freeze
12
+
13
+ def self.registered(app)
14
+ register_export(app)
15
+ register_discover(app)
16
+ register_all(app)
17
+ register_score(app)
18
+ register_fetch(app)
19
+ end
20
+
21
+ # POST /api/tbi/patterns/export — anonymously export a learned behavioral pattern
22
+ def self.register_export(app) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
23
+ app.post '/api/tbi/patterns/export' do
24
+ require_data!
25
+ body = parse_request_body
26
+
27
+ if body[:pattern_type].to_s.strip.empty?
28
+ Legion::Logging.warn 'API POST /api/tbi/patterns/export returned 422: pattern_type is required' if defined?(Legion::Logging)
29
+ halt 422, json_error('missing_field', 'pattern_type is required', status_code: 422)
30
+ end
31
+ if body[:description].to_s.strip.empty?
32
+ Legion::Logging.warn 'API POST /api/tbi/patterns/export returned 422: description is required' if defined?(Legion::Logging)
33
+ halt 422, json_error('missing_field', 'description is required', status_code: 422)
34
+ end
35
+ if body[:pattern_data].to_s.strip.empty?
36
+ Legion::Logging.warn 'API POST /api/tbi/patterns/export returned 422: pattern_data is required' if defined?(Legion::Logging)
37
+ halt 422, json_error('missing_field', 'pattern_data is required', status_code: 422)
38
+ end
39
+ if body[:tier].to_s.strip.empty?
40
+ Legion::Logging.warn 'API POST /api/tbi/patterns/export returned 422: tier is required' if defined?(Legion::Logging)
41
+ halt 422, json_error('missing_field', 'tier is required', status_code: 422)
42
+ end
43
+
44
+ if body[:description].to_s.bytesize > MAX_DESCRIPTION_BYTES
45
+ halt 422, json_error('field_too_large', "description exceeds #{MAX_DESCRIPTION_BYTES} bytes", status_code: 422)
46
+ end
47
+
48
+ pattern_data_str = Routes::TbiPatterns.serialize_pattern_data(body[:pattern_data])
49
+ if pattern_data_str.bytesize > MAX_PAYLOAD_SHAPE_BYTES
50
+ halt 422, json_error('field_too_large', "pattern_data exceeds #{MAX_PAYLOAD_SHAPE_BYTES} bytes", status_code: 422)
51
+ end
52
+
53
+ unless VALID_TIERS.include?(body[:tier].to_s)
54
+ halt 422, json_error('invalid_field', "tier must be one of: #{VALID_TIERS.join(', ')}", status_code: 422)
55
+ end
56
+
57
+ # Anonymize: strip any identifying keys before persisting
58
+ anonymous_data = Routes::TbiPatterns.anonymize(body)
59
+
60
+ invocation_count = Routes::TbiPatterns.parse_integer(body[:invocation_count], 0)
61
+ success_rate = Routes::TbiPatterns.parse_float(body[:success_rate], 0.0)
62
+ quality_score = Routes::TbiPatterns.compute_quality(
63
+ invocation_count: invocation_count,
64
+ success_rate: success_rate,
65
+ tier: body[:tier].to_s
66
+ )
67
+
68
+ record = Legion::Data::Model::TbiPattern.create(
69
+ pattern_type: body[:pattern_type].to_s,
70
+ description: body[:description].to_s,
71
+ tier: body[:tier].to_s,
72
+ pattern_data: pattern_data_str,
73
+ quality_score: quality_score,
74
+ invocation_count: invocation_count,
75
+ success_rate: success_rate,
76
+ source_hash: anonymous_data[:source_hash]
77
+ )
78
+ Legion::Logging.info "API: exported TBI pattern id=#{record.id} tier=#{record.tier}" if defined?(Legion::Logging)
79
+ json_response(record.values, status_code: 201)
80
+ rescue StandardError => e
81
+ Legion::Logging.error "API POST /api/tbi/patterns/export: #{e.class} — #{e.message}" if defined?(Legion::Logging)
82
+ json_error('export_error', e.message, status_code: 500)
83
+ end
84
+ end
85
+
86
+ # GET /api/tbi/patterns/:id — fetch a single pattern by integer ID
87
+ def self.register_fetch(app)
88
+ app.get '/api/tbi/patterns/:id' do
89
+ require_data!
90
+ id_val = params[:id].to_i
91
+ halt 422, json_error('invalid_id', 'id must be a positive integer', status_code: 422) if id_val <= 0
92
+
93
+ record = Legion::Data::Model::TbiPattern.first(id: id_val)
94
+ halt 404, json_error('not_found', "TBI pattern #{params[:id]} not found", status_code: 404) unless record
95
+
96
+ json_response(record.values)
97
+ rescue StandardError => e
98
+ Legion::Logging.error "API GET /api/tbi/patterns/#{params[:id]}: #{e.class} — #{e.message}" if defined?(Legion::Logging)
99
+ json_error('fetch_error', e.message, status_code: 500)
100
+ end
101
+ end
102
+
103
+ # GET /api/tbi/patterns — list patterns with optional tier/type filter
104
+ def self.register_all(app)
105
+ app.get '/api/tbi/patterns' do
106
+ require_data!
107
+ dataset = Legion::Data::Model::TbiPattern.order(Sequel.desc(:quality_score))
108
+ dataset = dataset.where(tier: params[:tier]) if params[:tier]
109
+ dataset = dataset.where(pattern_type: params[:type]) if params[:type]
110
+ json_collection(dataset)
111
+ rescue StandardError => e
112
+ Legion::Logging.error "API GET /api/tbi/patterns: #{e.class} — #{e.message}" if defined?(Legion::Logging)
113
+ json_error('list_error', e.message, status_code: 500)
114
+ end
115
+ end
116
+
117
+ # PATCH /api/tbi/patterns/:id/score — update quality score with new usage metadata
118
+ def self.register_score(app)
119
+ app.patch '/api/tbi/patterns/:id/score' do
120
+ require_data!
121
+ id_val = params[:id].to_i
122
+ halt 422, json_error('invalid_id', 'id must be a positive integer', status_code: 422) if id_val <= 0
123
+
124
+ record = Legion::Data::Model::TbiPattern.first(id: id_val)
125
+ halt 404, json_error('not_found', "TBI pattern #{params[:id]} not found", status_code: 404) unless record
126
+
127
+ body = parse_request_body
128
+ invocation_count = Routes::TbiPatterns.parse_integer(body[:invocation_count], record.invocation_count)
129
+ success_rate = Routes::TbiPatterns.parse_float(body[:success_rate], record.success_rate)
130
+ quality_score = Routes::TbiPatterns.compute_quality(
131
+ invocation_count: invocation_count,
132
+ success_rate: success_rate,
133
+ tier: record.tier
134
+ )
135
+
136
+ record.update(
137
+ invocation_count: invocation_count,
138
+ success_rate: success_rate,
139
+ quality_score: quality_score
140
+ )
141
+ Legion::Logging.info "API: rescored TBI pattern id=#{record.id} quality=#{quality_score}" if defined?(Legion::Logging)
142
+ json_response(record.values)
143
+ rescue StandardError => e
144
+ Legion::Logging.error "API PATCH /api/tbi/patterns/#{params[:id]}/score: #{e.class} — #{e.message}" if defined?(Legion::Logging)
145
+ json_error('score_error', e.message, status_code: 500)
146
+ end
147
+ end
148
+
149
+ # GET /api/tbi/patterns/discover — cross-instance pattern discovery (P3/TBI Phase 6)
150
+ # TODO: implement cross-instance discovery
151
+ def self.register_discover(app)
152
+ app.get '/api/tbi/patterns/discover' do
153
+ halt 501, json_error('not_implemented', 'cross-instance pattern discovery is not yet available', status_code: 501)
154
+ end
155
+ end
156
+
157
+ # --- helpers ---
158
+
159
+ # Anonymize pattern export: remove instance-identifying fields, compute a
160
+ # one-way hash for deduplication without fingerprinting.
161
+ def self.anonymize(body)
162
+ identifying_keys = %i[node_id instance_id hostname ip_address worker_id]
163
+ sanitized = body.reject { |k, _v| identifying_keys.include?(k.to_sym) }
164
+ # Remove both string and symbol variants
165
+ sanitized = sanitized.reject { |k, _v| identifying_keys.map(&:to_s).include?(k.to_s) }
166
+
167
+ salt_source = "#{body[:pattern_type]}:#{body[:tier]}:#{body[:description]}"
168
+ source_hash = Digest::SHA256.hexdigest(salt_source)[0, 16]
169
+
170
+ sanitized.merge(source_hash: source_hash)
171
+ end
172
+
173
+ def self.serialize_pattern_data(pattern_data)
174
+ return pattern_data.to_s if pattern_data.is_a?(String)
175
+
176
+ Legion::JSON.dump(pattern_data)
177
+ rescue StandardError
178
+ Legion::JSON.dump(pattern_data.to_s)
179
+ end
180
+
181
+ def self.compute_quality(invocation_count:, success_rate:, tier:)
182
+ # tier weight: higher tiers (closer to tier5) earn a modest bonus
183
+ tier_num = tier.to_s.gsub(/[^0-9]/, '').to_i.clamp(1, 5)
184
+ tier_weight = tier_num / 5.0
185
+
186
+ count_score = [invocation_count.to_f / 100.0, 1.0].min
187
+ success_score = success_rate.to_f.clamp(0.0, 1.0)
188
+
189
+ ((count_score * 0.4) + (success_score * 0.5) + (tier_weight * 0.1)).round(4)
190
+ end
191
+
192
+ # Parse an integer from user input; return default if blank or invalid.
193
+ def self.parse_integer(value, default)
194
+ return default if value.nil?
195
+ return default if value.to_s.strip.empty?
196
+ raise ArgumentError, 'not numeric' unless value.to_s =~ /\A-?\d+\z/
197
+
198
+ [value.to_i, 0].max
199
+ rescue ArgumentError
200
+ default
201
+ end
202
+
203
+ # Parse a float from user input; return default if blank or invalid.
204
+ def self.parse_float(value, default)
205
+ return default if value.nil?
206
+ return default if value.to_s.strip.empty?
207
+ raise ArgumentError, 'not numeric' unless value.to_s =~ /\A-?\d+(\.\d+)?\z/
208
+
209
+ value.to_f.clamp(0.0, 1.0)
210
+ rescue ArgumentError
211
+ default
212
+ end
213
+
214
+ private_class_method :register_export, :register_fetch, :register_all,
215
+ :register_score, :register_discover
216
+ end
217
+ end
218
+ end
219
+ end
data/lib/legion/api.rb CHANGED
@@ -52,6 +52,7 @@ require_relative 'api/router'
52
52
  require_relative 'api/library_routes'
53
53
  require_relative 'api/sync_dispatch'
54
54
  require_relative 'api/lex_dispatch'
55
+ require_relative 'api/tbi_patterns'
55
56
  require_relative 'api/graphql' if defined?(GraphQL)
56
57
 
57
58
  module Legion
@@ -176,6 +177,7 @@ module Legion
176
177
  register Routes::Absorbers
177
178
  register Routes::Codegen
178
179
  register Routes::Logs
180
+ register Routes::TbiPatterns
179
181
  register Routes::GraphQL if defined?(Routes::GraphQL)
180
182
 
181
183
  use Legion::API::Middleware::RequestLogger
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table?(:tbi_patterns) do
6
+ primary_key :id
7
+ String :pattern_type, null: false
8
+ String :description, null: false
9
+ String :tier, null: false
10
+ # TEXT column holds JSON-encoded behavioral pattern data (up to 64KB)
11
+ String :pattern_data, text: true, null: false
12
+ Float :quality_score, null: false, default: 0.0
13
+ Integer :invocation_count, null: false, default: 0
14
+ Float :success_rate, null: false, default: 0.0
15
+ # one-way SHA-256 prefix derived from pattern_type+tier+description; not reversible to the submitting instance
16
+ String :source_hash
17
+ Time :created_at, null: false
18
+ Time :updated_at, null: false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Sequel)
4
+ module Legion
5
+ module Data
6
+ module Model
7
+ class TbiPattern < Sequel::Model(:tbi_patterns)
8
+ plugin :timestamps, update_on_create: true
9
+
10
+ def validate
11
+ super
12
+ errors.add(:pattern_type, 'is required') if !pattern_type || pattern_type.to_s.strip.empty?
13
+ errors.add(:description, 'is required') if !description || description.to_s.strip.empty?
14
+ errors.add(:pattern_data, 'is required') if !pattern_data || pattern_data.to_s.strip.empty?
15
+ errors.add(:tier, 'is required') if !tier || tier.to_s.strip.empty?
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -141,6 +141,51 @@ module Legion
141
141
  Legion::Telemetry.with_span("agent.#{name}", kind: :internal, attributes: attrs, &)
142
142
  end
143
143
 
144
+ def retriever_span(name:, query: nil, top_k: nil, &)
145
+ unless open_inference_enabled?
146
+ return yield(nil) if block_given?
147
+
148
+ return
149
+ end
150
+
151
+ attrs = base_attrs('RETRIEVER').merge('retriever.name' => name)
152
+ attrs['retriever.top_k'] = top_k if top_k
153
+ attrs['input.value'] = truncate_value(query.to_s) if query && include_io?
154
+
155
+ Legion::Telemetry.with_span("retriever.#{name}", kind: :client, attributes: attrs, &)
156
+ end
157
+
158
+ def reranker_span(model:, query: nil, top_k: nil, &)
159
+ unless open_inference_enabled?
160
+ return yield(nil) if block_given?
161
+
162
+ return
163
+ end
164
+
165
+ attrs = base_attrs('RERANKER').merge('reranker.model_name' => model)
166
+ attrs['reranker.top_k'] = top_k if top_k
167
+ attrs['input.value'] = truncate_value(query.to_s) if query && include_io?
168
+
169
+ Legion::Telemetry.with_span("reranker.#{model}", kind: :internal, attributes: attrs, &)
170
+ end
171
+
172
+ def guardrail_span(name:, input: nil)
173
+ unless open_inference_enabled?
174
+ return yield(nil) if block_given?
175
+
176
+ return
177
+ end
178
+
179
+ attrs = base_attrs('GUARDRAIL').merge('guardrail.name' => name)
180
+ attrs['input.value'] = truncate_value(input.to_s) if input && include_io?
181
+
182
+ Legion::Telemetry.with_span("guardrail.#{name}", kind: :internal, attributes: attrs) do |span|
183
+ result = yield(span)
184
+ annotate_guardrail_result(span, result) if span && result.is_a?(Hash)
185
+ result
186
+ end
187
+ end
188
+
144
189
  def truncate_value(str, max: nil)
145
190
  limit = max || truncate_limit
146
191
  str.length > limit ? str[0...limit] : str
@@ -181,6 +226,17 @@ module Legion
181
226
  Legion::Logging.debug "OpenInference#annotate_eval_result failed: #{e.message}" if defined?(Legion::Logging)
182
227
  nil
183
228
  end
229
+
230
+ def annotate_guardrail_result(span, result)
231
+ return unless span.respond_to?(:set_attribute)
232
+
233
+ span.set_attribute('guardrail.passed', result[:passed]) unless result[:passed].nil?
234
+ span.set_attribute('guardrail.score', result[:score]) unless result[:score].nil?
235
+ span.set_attribute('output.value', truncate_value(result[:explanation].to_s)) if include_io? && result[:explanation]
236
+ rescue StandardError => e
237
+ Legion::Logging.debug "OpenInference#annotate_guardrail_result failed: #{e.message}" if defined?(Legion::Logging)
238
+ nil
239
+ end
184
240
  end
185
241
  end
186
242
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.6.36'
4
+ VERSION = '1.6.37'
5
5
  end
@@ -0,0 +1,58 @@
1
+ name: autofix-pipeline
2
+ version: 0.1.0
3
+ description: >
4
+ Log event triage → GitHub issue → LLM fix → PR creation.
5
+ Triggered by batched exception log events.
6
+
7
+ requires:
8
+ - lex-autofix
9
+ - lex-github
10
+
11
+ relationships:
12
+ - name: triage-to-diagnose
13
+ trigger:
14
+ extension: autofix
15
+ runner: triage
16
+ function: batch_triage
17
+ action:
18
+ extension: autofix
19
+ runner: diagnose
20
+ function: check_github
21
+ conditions:
22
+ all:
23
+ - fact: success
24
+ operator: equal
25
+ value: true
26
+
27
+ - name: diagnose-to-fix
28
+ trigger:
29
+ extension: autofix
30
+ runner: diagnose
31
+ function: check_github
32
+ action:
33
+ extension: autofix
34
+ runner: fix
35
+ function: attempt_fix
36
+ conditions:
37
+ all:
38
+ - fact: success
39
+ operator: equal
40
+ value: true
41
+ - fact: action
42
+ operator: not_equal
43
+ value: skipped
44
+
45
+ - name: fix-to-ship
46
+ trigger:
47
+ extension: autofix
48
+ runner: fix
49
+ function: attempt_fix
50
+ action:
51
+ extension: autofix
52
+ runner: ship
53
+ function: ship
54
+ conditions:
55
+ all:
56
+ - fact: success
57
+ operator: equal
58
+ value: true
@@ -0,0 +1,25 @@
1
+ name: factory-develop-codegen
2
+ version: 0.1.0
3
+ description: >
4
+ Factory develop stage delegates code generation to lex-codegen.
5
+ Each spec requirement becomes a codegen task.
6
+
7
+ requires:
8
+ - lex-factory
9
+ - lex-codegen
10
+
11
+ relationships:
12
+ - name: develop-to-codegen
13
+ trigger:
14
+ extension: factory
15
+ runner: factory
16
+ function: run_pipeline
17
+ action:
18
+ extension: codegen
19
+ runner: from_gap
20
+ function: generate
21
+ conditions:
22
+ all:
23
+ - fact: success
24
+ operator: equal
25
+ value: true
@@ -0,0 +1,88 @@
1
+ name: mind-growth-build
2
+ version: 0.1.0
3
+ description: >
4
+ Extension build pipeline: scaffold → implement → test → validate → register.
5
+ Runs locally on the build node. Task relationships provide observability
6
+ and conditional retry on test failure.
7
+
8
+ requires:
9
+ - lex-mind-growth
10
+ - lex-codegen
11
+ - lex-eval
12
+ - lex-exec
13
+
14
+ relationships:
15
+ - name: scaffold-to-implement
16
+ trigger:
17
+ extension: mind_growth
18
+ runner: builder
19
+ function: scaffold_stage
20
+ action:
21
+ extension: mind_growth
22
+ runner: builder
23
+ function: implement_stage
24
+ conditions:
25
+ all:
26
+ - fact: success
27
+ operator: equal
28
+ value: true
29
+
30
+ - name: implement-to-test
31
+ trigger:
32
+ extension: mind_growth
33
+ runner: builder
34
+ function: implement_stage
35
+ action:
36
+ extension: mind_growth
37
+ runner: builder
38
+ function: test_stage
39
+ conditions:
40
+ all:
41
+ - fact: success
42
+ operator: equal
43
+ value: true
44
+
45
+ - name: test-pass-to-validate
46
+ trigger:
47
+ extension: mind_growth
48
+ runner: builder
49
+ function: test_stage
50
+ action:
51
+ extension: mind_growth
52
+ runner: builder
53
+ function: validate_stage
54
+ conditions:
55
+ all:
56
+ - fact: success
57
+ operator: equal
58
+ value: true
59
+
60
+ - name: test-fail-to-implement-retry
61
+ trigger:
62
+ extension: mind_growth
63
+ runner: builder
64
+ function: test_stage
65
+ action:
66
+ extension: mind_growth
67
+ runner: builder
68
+ function: implement_stage
69
+ conditions:
70
+ all:
71
+ - fact: success
72
+ operator: equal
73
+ value: false
74
+
75
+ - name: validate-to-register
76
+ trigger:
77
+ extension: mind_growth
78
+ runner: builder
79
+ function: validate_stage
80
+ action:
81
+ extension: mind_growth
82
+ runner: builder
83
+ function: register_stage
84
+ conditions:
85
+ all:
86
+ - fact: success
87
+ operator: equal
88
+ value: true
@@ -0,0 +1,42 @@
1
+ name: mind-growth-swarm-parallel-build
2
+ version: 0.1.0
3
+ description: >
4
+ Swarm-orchestrated parallel build: create swarm → build proposals → complete.
5
+
6
+ requires:
7
+ - lex-mind-growth
8
+ - lex-swarm
9
+
10
+ relationships:
11
+ - name: create-to-build
12
+ trigger:
13
+ extension: mind_growth
14
+ runner: swarm_builder
15
+ function: create_build_swarm
16
+ action:
17
+ extension: mind_growth
18
+ runner: swarm_builder
19
+ function: execute_parallel_build
20
+ conditions:
21
+ all:
22
+ - fact: success
23
+ operator: equal
24
+ value: true
25
+ - fact: charter_type
26
+ operator: equal
27
+ value: parallel_build
28
+
29
+ - name: build-to-complete
30
+ trigger:
31
+ extension: mind_growth
32
+ runner: swarm_builder
33
+ function: execute_parallel_build
34
+ action:
35
+ extension: swarm
36
+ runner: swarm
37
+ function: complete_swarm
38
+ conditions:
39
+ all:
40
+ - fact: success
41
+ operator: equal
42
+ value: true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legionio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.36
4
+ version: 1.6.37
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -513,6 +513,7 @@ files:
513
513
  - lib/legion/api/stats.rb
514
514
  - lib/legion/api/sync_dispatch.rb
515
515
  - lib/legion/api/tasks.rb
516
+ - lib/legion/api/tbi_patterns.rb
516
517
  - lib/legion/api/tenants.rb
517
518
  - lib/legion/api/token.rb
518
519
  - lib/legion/api/traces.rb
@@ -759,8 +760,10 @@ files:
759
760
  - lib/legion/compliance/phi_erasure.rb
760
761
  - lib/legion/compliance/phi_tag.rb
761
762
  - lib/legion/context.rb
763
+ - lib/legion/data/local_migrations/20250601000001_create_tbi_patterns.rb
762
764
  - lib/legion/data/local_migrations/20260319000001_create_extension_catalog.rb
763
765
  - lib/legion/data/local_migrations/20260319000002_create_extension_permissions.rb
766
+ - lib/legion/data/models/tbi_pattern.rb
764
767
  - lib/legion/digital_worker.rb
765
768
  - lib/legion/digital_worker/airb.rb
766
769
  - lib/legion/digital_worker/lifecycle.rb
@@ -872,7 +875,11 @@ files:
872
875
  - public/workflow/index.html
873
876
  - scripts/rollout-ci-workflow.sh
874
877
  - scripts/sync-github-labels-topics.sh
878
+ - workflows/autofix-pipeline.yml
875
879
  - workflows/autonomous-github-lifecycle.yml
880
+ - workflows/factory-develop-codegen.yml
881
+ - workflows/mind-growth-build.yml
882
+ - workflows/mind-growth-swarm-parallel-build.yml
876
883
  homepage: https://github.com/LegionIO/LegionIO
877
884
  licenses:
878
885
  - Apache-2.0