legionio 1.4.47 → 1.4.48

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: 61d1b58d973cadaa88f3236a2d191452324ce20721fb6a41bf9b08488e077754
4
- data.tar.gz: '09129066576304957d34a58a8c54731e8228b3d5a45603592ee9b9ce10f72c55'
3
+ metadata.gz: d7a08e02740d6be6ecb76c91c3ee6f3a2ed8f594801994e8005c1ec3e3a3b47c
4
+ data.tar.gz: c45901fb93e4e97063e3044eee0d5646a50447acb818055ff75428a6c5f490a8
5
5
  SHA512:
6
- metadata.gz: 4e9bfacc58941fb83fe9725779d8a500b514e483dfd84dc759a7184e548b43379252c638007ced10de99164ee749cc9dd7a33134e31e4c0bd8605e6307648d8f
7
- data.tar.gz: 989f282c012adb51747e8bbb143e29eabf1c213fd0ad7b531737f98cb948791a6e163c13fa5c1a73d0a5da20efa4cfabad237d90e0e3adbaa21d05c2a8cbc5dc
6
+ metadata.gz: 23eb01d19c9e38ab19d0bf28f5f2f9d32cb7bd64a47abd1fa0833b2e7d7ba13963c62eda860b43d5745cc54d77e4bacd94086e4749351e0b3af0489dd7ee5dc5
7
+ data.tar.gz: f436f935e81de29c1364022aad090c0e7c8bd7f1ee9419a1b33aaf1bb66800ffa117f699047ed02f314498161db79ad82193863893f5f538e9e08cf0147272b1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Legion Changelog
2
2
 
3
+ ## [1.4.48] - 2026-03-17
4
+
5
+ ### Added
6
+ - `Legion::Capacity::Model`: workforce capacity calculation (throughput, utilization, forecast, per-worker stats)
7
+ - `GET /api/capacity`: aggregate capacity across active workers
8
+ - `GET /api/capacity/forecast`: projected capacity with configurable growth rate and period
9
+ - `GET /api/capacity/workers`: per-worker capacity breakdown
10
+
3
11
  ## [1.4.47] - 2026-03-17
4
12
 
5
13
  ### Fixed
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../capacity/model'
4
+
5
+ module Legion
6
+ class API < Sinatra::Base
7
+ module Routes
8
+ module Capacity
9
+ def self.registered(app)
10
+ app.get '/api/capacity' do
11
+ workers = Routes::Capacity.fetch_worker_list
12
+ model = Legion::Capacity::Model.new(workers: workers)
13
+ json_response(model.aggregate)
14
+ end
15
+
16
+ app.get '/api/capacity/forecast' do
17
+ workers = Routes::Capacity.fetch_worker_list
18
+ model = Legion::Capacity::Model.new(workers: workers)
19
+ forecast = model.forecast(
20
+ days: (params[:days] || 30).to_i,
21
+ growth_rate: (params[:growth_rate] || 0).to_f
22
+ )
23
+ json_response(forecast)
24
+ end
25
+
26
+ app.get '/api/capacity/workers' do
27
+ workers = Routes::Capacity.fetch_worker_list
28
+ model = Legion::Capacity::Model.new(workers: workers)
29
+ json_response(model.per_worker_stats)
30
+ end
31
+ end
32
+
33
+ def self.fetch_worker_list
34
+ return [] unless defined?(Legion::Data::Model::DigitalWorker)
35
+
36
+ Legion::Data::Model::DigitalWorker.all.map do |w|
37
+ { worker_id: w.worker_id, status: w.lifecycle_state }
38
+ end
39
+ rescue StandardError
40
+ []
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/legion/api.rb CHANGED
@@ -29,6 +29,7 @@ require_relative 'api/rbac'
29
29
  require_relative 'api/auth'
30
30
  require_relative 'api/auth_worker'
31
31
  require_relative 'api/auth_human'
32
+ require_relative 'api/capacity'
32
33
  require_relative 'api/audit'
33
34
  require_relative 'api/metrics'
34
35
 
@@ -102,6 +103,7 @@ module Legion
102
103
  register Routes::Auth
103
104
  register Routes::AuthWorker
104
105
  register Routes::AuthHuman
106
+ register Routes::Capacity
105
107
  register Routes::Audit
106
108
  register Routes::Metrics
107
109
 
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Capacity
5
+ class Model
6
+ DEFAULTS = {
7
+ tasks_per_second: 10,
8
+ utilization_target: 0.7,
9
+ availability_hours: 24,
10
+ overhead_factor: 0.15
11
+ }.freeze
12
+
13
+ def initialize(workers:, config: {})
14
+ @workers = Array(workers)
15
+ @config = DEFAULTS.merge(config)
16
+ end
17
+
18
+ def aggregate
19
+ active = @workers.select { |w| active_worker?(w) }
20
+ tps = @config[:tasks_per_second]
21
+ {
22
+ total_workers: @workers.size,
23
+ active_workers: active.size,
24
+ max_throughput_tps: active.size * tps,
25
+ effective_throughput_tps: (active.size * tps * @config[:utilization_target]).round,
26
+ utilization_target: @config[:utilization_target],
27
+ availability_hours: @config[:availability_hours]
28
+ }
29
+ end
30
+
31
+ def forecast(days: 30, growth_rate: 0.0)
32
+ current = aggregate
33
+ projected = (current[:active_workers] * (1 + (growth_rate * days / 30.0))).ceil
34
+ tps = @config[:tasks_per_second]
35
+ {
36
+ period_days: days,
37
+ growth_rate: growth_rate,
38
+ current_workers: current[:active_workers],
39
+ projected_workers: projected,
40
+ projected_max_tps: projected * tps,
41
+ projected_effective_tps: (projected * tps * @config[:utilization_target]).round
42
+ }
43
+ end
44
+
45
+ def per_worker_stats
46
+ @workers.map do |w|
47
+ id = w[:worker_id] || w[:id] || 'unknown'
48
+ {
49
+ worker_id: id,
50
+ status: w[:status] || w[:lifecycle_state] || 'unknown',
51
+ capacity_tps: active_worker?(w) ? @config[:tasks_per_second] : 0
52
+ }
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def active_worker?(worker)
59
+ status = (worker[:status] || worker[:lifecycle_state]).to_s
60
+ %w[active running].include?(status)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.4.47'
4
+ VERSION = '1.4.48'
5
5
  end
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.4.47
4
+ version: 1.4.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -320,6 +320,7 @@ files:
320
320
  - lib/legion/api/auth.rb
321
321
  - lib/legion/api/auth_human.rb
322
322
  - lib/legion/api/auth_worker.rb
323
+ - lib/legion/api/capacity.rb
323
324
  - lib/legion/api/chains.rb
324
325
  - lib/legion/api/coldstart.rb
325
326
  - lib/legion/api/events.rb
@@ -348,6 +349,7 @@ files:
348
349
  - lib/legion/audit.rb
349
350
  - lib/legion/audit/hash_chain.rb
350
351
  - lib/legion/audit/siem_export.rb
352
+ - lib/legion/capacity/model.rb
351
353
  - lib/legion/catalog.rb
352
354
  - lib/legion/chat/notification_bridge.rb
353
355
  - lib/legion/chat/notification_queue.rb