lex-cognitive-triage 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bf115104e45fd4f342847472fb98867351280610072bb62c78b1ef4bb4e756bd
4
+ data.tar.gz: d474d79895e4100c895667618175e79c7a0588ed73b8b7ccbef3c6a331b26791
5
+ SHA512:
6
+ metadata.gz: 487a5574ef1b037ae3c10aaf6e38430177033e7f4875d8ccc86a10784fefd245632ae206a6b0e0d01bc7509d6679a2414f2effee11f1b58d7b7ddbd23f86b5c8
7
+ data.tar.gz: dce224d41e81c12b73a93363c8ddc6a1e99aad237515ff2384fb639c30cb8eb3bd549101a1049fa2c4525dc35bd8de82c2ca9a83349cf918557488b92ea3a6e7
@@ -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
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.gem
10
+ Gemfile.lock
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,41 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 3.4
4
+ SuggestExtensions: false
5
+
6
+ Style/Documentation:
7
+ Enabled: false
8
+
9
+ Naming/PredicateMethod:
10
+ Enabled: false
11
+
12
+ Naming/PredicatePrefix:
13
+ Enabled: false
14
+
15
+ Metrics/ClassLength:
16
+ Max: 150
17
+
18
+ Metrics/MethodLength:
19
+ Max: 25
20
+
21
+ Metrics/AbcSize:
22
+ Max: 25
23
+
24
+ Metrics/ParameterLists:
25
+ Max: 8
26
+ MaxOptionalParameters: 8
27
+
28
+ Layout/HashAlignment:
29
+ EnforcedHashRocketStyle: table
30
+ EnforcedColonStyle: table
31
+
32
+ Metrics/BlockLength:
33
+ Exclude:
34
+ - 'spec/**/*'
35
+
36
+ Style/FrozenStringLiteralComment:
37
+ Enabled: true
38
+
39
+ Style/OneClassPerFile:
40
+ Exclude:
41
+ - 'spec/spec_helper.rb'
data/CLAUDE.md ADDED
@@ -0,0 +1,122 @@
1
+ # lex-cognitive-triage
2
+
3
+ **Level 3 Leaf Documentation**
4
+ - **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
5
+ - **Gem**: `lex-cognitive-triage`
6
+ - **Version**: 0.1.0
7
+ - **Namespace**: `Legion::Extensions::CognitiveTriage`
8
+
9
+ ## Purpose
10
+
11
+ Models cognitive demand management as a triage system. Demands are incoming cognitive tasks or stimuli with severity and urgency levels. A priority score is computed and demands are color-coded (red/orange/yellow/green/white). Adding demands drains cognitive capacity; completing or dropping them restores it. When capacity falls below the overload threshold, the system is flagged as overloaded.
12
+
13
+ ## Gem Info
14
+
15
+ - **Gemspec**: `lex-cognitive-triage.gemspec`
16
+ - **Require**: `lex-cognitive-triage`
17
+ - **Ruby**: >= 3.4
18
+ - **License**: MIT
19
+ - **Homepage**: https://github.com/LegionIO/lex-cognitive-triage
20
+
21
+ ## File Structure
22
+
23
+ ```
24
+ lib/legion/extensions/cognitive_triage/
25
+ version.rb
26
+ helpers/
27
+ constants.rb # Severity/urgency levels and weights, triage/capacity/queue label tables
28
+ demand.rb # Demand class — one cognitive demand with triage score and lifecycle
29
+ triage_engine.rb # TriageEngine — demand registry with capacity management
30
+ runners/
31
+ cognitive_triage.rb # Runner module — public API
32
+ client.rb
33
+ ```
34
+
35
+ ## Key Constants
36
+
37
+ | Constant | Value | Meaning |
38
+ |---|---|---|
39
+ | `MAX_DEMANDS` | 500 | Hard cap; oldest completed (or lowest score) pruned |
40
+ | `MAX_QUEUE_SIZE` | 100 | Reference for queue pressure calculation |
41
+ | `CAPACITY_DEFAULT` | 1.0 | Starting cognitive capacity |
42
+ | `CAPACITY_DRAIN` | 0.05 | Max capacity drain per demand add (multiplied by triage score) |
43
+ | `CAPACITY_RESTORE` | 0.03 | Capacity restored per complete or drop |
44
+ | `OVERLOAD_THRESHOLD` | 0.2 | Capacity <= this = overloaded |
45
+
46
+ Triage score formula: `severity_weight * 0.6 + urgency_weight * 0.4`
47
+
48
+ `SEVERITY_LEVELS`: `[:critical, :major, :moderate, :minor, :trivial]` with weights `[1.0, 0.8, 0.5, 0.3, 0.1]`
49
+
50
+ `URGENCY_LEVELS`: `[:immediate, :urgent, :soon, :deferred, :indefinite]` with weights `[1.0, 0.8, 0.5, 0.3, 0.1]`
51
+
52
+ Triage color labels: `0.8+` = `:red`, `0.6..0.8` = `:orange`, `0.4..0.6` = `:yellow`, `0.2..0.4` = `:green`, `<0.2` = `:white`
53
+
54
+ Capacity labels: `0.8+` = `:fresh`, `0.6..0.8` = `:engaged`, `0.4..0.6` = `:strained`, `0.2..0.4` = `:depleted`, `<0.2` = `:overloaded`
55
+
56
+ Queue labels (by `active / MAX_QUEUE_SIZE`): `0.8+` = `:overwhelmed`, `0.6..0.8` = `:heavy`, `0.4..0.6` = `:moderate`, `0.2..0.4` = `:light`, `<0.2` = `:empty`
57
+
58
+ ## Key Classes
59
+
60
+ ### `Helpers::Demand`
61
+
62
+ One cognitive demand with a lifecycle.
63
+
64
+ - `triage!` / `defer!` / `process!` / `complete!` / `drop!` — state transitions
65
+ - `active?` — status in `[:pending, :triaged, :processing]`
66
+ - `red?` — triage_score >= 0.8
67
+ - `triage_label` — color label for triage score
68
+ - `triage_score` — computed at init: `severity_weight * 0.6 + urgency_weight * 0.4`; immutable
69
+ - Invalid severity/urgency silently defaults to `:moderate`/`:soon`
70
+
71
+ ### `Helpers::TriageEngine`
72
+
73
+ Demand registry with capacity tracking.
74
+
75
+ - `add_demand(description:, domain:, severity:, urgency:)` — prunes if at `MAX_DEMANDS`; drains capacity by `triage_score * CAPACITY_DRAIN`; auto-calls `triage!`
76
+ - `process_demand(demand_id:)` — sets to `:processing`; fails if not active
77
+ - `complete_demand(demand_id:)` — sets to `:completed`; restores `CAPACITY_RESTORE`
78
+ - `defer_demand(demand_id:)` — sets to `:deferred`; restores `CAPACITY_RESTORE * 0.5`
79
+ - `drop_demand(demand_id:)` — sets to `:dropped`; restores `CAPACITY_RESTORE`
80
+ - `next_demand` — active demand with highest triage score
81
+ - `red_demands` — all demands with score >= 0.8
82
+ - `overloaded?` — capacity <= `OVERLOAD_THRESHOLD`
83
+ - `queue_pressure` — `active_count / MAX_QUEUE_SIZE`
84
+ - `triage_report` — full status hash
85
+ - `prune_if_needed` (private) — removes oldest completed demand; if none, removes lowest-score demand
86
+
87
+ ## Runners
88
+
89
+ Module: `Legion::Extensions::CognitiveTriage::Runners::CognitiveTriage`
90
+
91
+ | Runner | Key Args | Returns |
92
+ |---|---|---|
93
+ | `add_demand` | `description:`, `domain:`, `severity:`, `urgency:` | `{ success:, demand:, capacity: }` |
94
+ | `process_demand` | `demand_id:` | `{ success:, demand: }` or error |
95
+ | `complete_demand` | `demand_id:` | `{ success:, demand:, capacity: }` or error |
96
+ | `defer_demand` | `demand_id:` | `{ success:, demand:, capacity: }` or error |
97
+ | `drop_demand` | `demand_id:` | `{ success:, demand:, capacity: }` or error |
98
+ | `next_demand` | — | `{ success:, found:, demand: }` |
99
+ | `active_demands` | — | `{ success:, demands:, count: }` |
100
+ | `red_demands` | — | `{ success:, demands:, count: }` |
101
+ | `demands_by_severity` | `severity:` | `{ success:, demands:, count: }` |
102
+ | `demands_by_domain` | `domain:` | `{ success:, demands:, count: }` |
103
+ | `capacity_status` | — | `{ success:, capacity:, capacity_label:, overloaded:, queue_pressure:, queue_label: }` |
104
+ | `triage_report` | — | `{ success:, report: }` |
105
+
106
+ All runners accept optional `engine:` keyword for test injection.
107
+
108
+ ## Integration Points
109
+
110
+ - No actors defined; driven by external task events or `lex-tick` phases
111
+ - `add_demand` is the entry point for all incoming cognitive demands
112
+ - `next_demand` feeds into `lex-tick`'s `action_selection` phase — selects highest-priority demand
113
+ - `overloaded?` can gate new commitments or trigger `lex-consent` escalation
114
+ - All state is in-memory per `TriageEngine` instance
115
+
116
+ ## Development Notes
117
+
118
+ - Capacity drain per demand is `triage_score * CAPACITY_DRAIN`, not a flat `CAPACITY_DRAIN` — critical/immediate demands drain 5x more than trivial/indefinite
119
+ - `add_demand` automatically calls `triage!` after creation — demand moves from `:pending` to `:triaged` immediately
120
+ - `prune_if_needed` prefers to evict completed demands; only evicts active if no completed exist
121
+ - Demand IDs are UUID strings, not sequential symbols
122
+ - `demands_by_severity` and `demands_by_domain` return ALL demands (including completed/dropped), not only active ones
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ group :development, :test do
8
+ gem 'rspec', '~> 3.13'
9
+ gem 'rubocop', '~> 1.75'
10
+ gem 'rubocop-rspec'
11
+ end
12
+
13
+ gem 'legion-gaia', path: '../../legion-gaia'
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # lex-cognitive-triage
2
+
3
+ A LegionIO cognitive architecture extension that models cognitive demand management as a triage system. Incoming demands are scored by severity and urgency, color-coded by priority, and managed through a lifecycle as capacity allows.
4
+
5
+ ## What It Does
6
+
7
+ Tracks **demands** — cognitive tasks or stimuli requiring attention. Each demand has:
8
+
9
+ - A severity (`:critical`, `:major`, `:moderate`, `:minor`, `:trivial`)
10
+ - An urgency (`:immediate`, `:urgent`, `:soon`, `:deferred`, `:indefinite`)
11
+ - A triage score: `severity * 0.6 + urgency * 0.4`
12
+ - A color label: `:red` (0.8+), `:orange`, `:yellow`, `:green`, `:white`
13
+
14
+ Adding a demand drains cognitive capacity. Completing or dropping demands restores it. When capacity drops below 0.2, the system is overloaded.
15
+
16
+ ## Usage
17
+
18
+ ```ruby
19
+ require 'lex-cognitive-triage'
20
+
21
+ client = Legion::Extensions::CognitiveTriage::Client.new
22
+
23
+ # Register an incoming demand
24
+ result = client.add_demand(
25
+ description: 'Ethical conflict detected in action plan',
26
+ domain: :safety,
27
+ severity: :critical,
28
+ urgency: :immediate
29
+ )
30
+ # => { success: true, demand: { triage_score: 1.0, triage_label: :red, status: :triaged, ... }, capacity: 0.95 }
31
+
32
+ demand_id = result[:demand][:id]
33
+
34
+ # What should be worked on next?
35
+ client.next_demand
36
+ # => { success: true, found: true, demand: { triage_score: 1.0, triage_label: :red, ... } }
37
+
38
+ # All red-priority demands
39
+ client.red_demands
40
+ # => { success: true, demands: [...], count: 1 }
41
+
42
+ # Begin processing
43
+ client.process_demand(demand_id: demand_id)
44
+ # => { success: true, demand: { status: :processing, ... } }
45
+
46
+ # Mark complete — restores capacity
47
+ client.complete_demand(demand_id: demand_id)
48
+ # => { success: true, demand: { status: :completed, ... }, capacity: 0.98 }
49
+
50
+ # Defer a lower-priority demand
51
+ d2 = client.add_demand(description: 'Schedule review', severity: :minor, urgency: :deferred)
52
+ client.defer_demand(demand_id: d2[:demand][:id])
53
+ # => { success: true, demand: { status: :deferred, ... }, capacity: 0.965 }
54
+
55
+ # Check capacity state
56
+ client.capacity_status
57
+ # => { success: true, capacity: 0.965, capacity_label: :fresh, overloaded: false, queue_pressure: 0.0, queue_label: :empty }
58
+
59
+ # Full report
60
+ client.triage_report
61
+ # => { success: true, report: { total_demands: 2, active_count: 0, red_count: 0, capacity: 0.965, overloaded: false, ... } }
62
+ ```
63
+
64
+ ## Development
65
+
66
+ ```bash
67
+ bundle install
68
+ bundle exec rspec
69
+ bundle exec rubocop
70
+ ```
71
+
72
+ ## License
73
+
74
+ MIT
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/legion/extensions/cognitive_triage/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'lex-cognitive-triage'
7
+ spec.version = Legion::Extensions::CognitiveTriage::VERSION
8
+ spec.authors = ['Esity']
9
+ spec.email = ['matthewdiverson@gmail.com']
10
+
11
+ spec.summary = 'Emergency cognitive prioritization for LegionIO'
12
+ spec.description = 'Triage system for cognitive overload. Classifies incoming demands by severity ' \
13
+ 'and urgency, routes to appropriate processing queues, and manages cognitive ' \
14
+ 'capacity under pressure.'
15
+ spec.homepage = 'https://github.com/LegionIO/lex-cognitive-triage'
16
+ spec.license = 'MIT'
17
+
18
+ spec.required_ruby_version = '>= 3.4'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-triage'
22
+ spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-triage/blob/master/README.md'
23
+ spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-triage/blob/master/CHANGELOG.md'
24
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-triage/issues'
25
+ spec.metadata['rubygems_mfa_required'] = 'true'
26
+
27
+ spec.files = Dir.chdir(__dir__) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
29
+ end
30
+ spec.require_paths = ['lib']
31
+ spec.add_development_dependency 'legion-gaia'
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveTriage
6
+ class Client
7
+ include Runners::CognitiveTriage
8
+
9
+ def initialize(engine: nil)
10
+ @default_engine = engine || Helpers::TriageEngine.new
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveTriage
6
+ module Helpers
7
+ module Constants
8
+ MAX_DEMANDS = 500
9
+ MAX_QUEUE_SIZE = 100
10
+ CAPACITY_DEFAULT = 1.0
11
+ CAPACITY_DRAIN = 0.05
12
+ CAPACITY_RESTORE = 0.03
13
+ OVERLOAD_THRESHOLD = 0.2
14
+
15
+ SEVERITY_LEVELS = %i[critical major moderate minor trivial].freeze
16
+ URGENCY_LEVELS = %i[immediate urgent soon deferred indefinite].freeze
17
+
18
+ SEVERITY_WEIGHTS = {
19
+ critical: 1.0,
20
+ major: 0.8,
21
+ moderate: 0.5,
22
+ minor: 0.3,
23
+ trivial: 0.1
24
+ }.freeze
25
+
26
+ URGENCY_WEIGHTS = {
27
+ immediate: 1.0,
28
+ urgent: 0.8,
29
+ soon: 0.5,
30
+ deferred: 0.3,
31
+ indefinite: 0.1
32
+ }.freeze
33
+
34
+ TRIAGE_LABELS = {
35
+ (0.8..) => :red,
36
+ (0.6...0.8) => :orange,
37
+ (0.4...0.6) => :yellow,
38
+ (0.2...0.4) => :green,
39
+ (..0.2) => :white
40
+ }.freeze
41
+
42
+ CAPACITY_LABELS = {
43
+ (0.8..) => :fresh,
44
+ (0.6...0.8) => :engaged,
45
+ (0.4...0.6) => :strained,
46
+ (0.2...0.4) => :depleted,
47
+ (..0.2) => :overloaded
48
+ }.freeze
49
+
50
+ QUEUE_LABELS = {
51
+ (0.8..) => :overwhelmed,
52
+ (0.6...0.8) => :heavy,
53
+ (0.4...0.6) => :moderate,
54
+ (0.2...0.4) => :light,
55
+ (..0.2) => :empty
56
+ }.freeze
57
+
58
+ def self.label_for(labels, value)
59
+ match = labels.find { |range, _| range.cover?(value) }
60
+ match&.last
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module CognitiveTriage
8
+ module Helpers
9
+ class Demand
10
+ include Constants
11
+
12
+ attr_reader :id, :description, :domain, :severity, :urgency,
13
+ :triage_score, :status, :created_at, :triaged_at
14
+
15
+ def initialize(description:, domain: :general, severity: :moderate, urgency: :soon)
16
+ @id = SecureRandom.uuid
17
+ @description = description
18
+ @domain = domain.to_sym
19
+ @severity = validate_level(severity, SEVERITY_LEVELS, :moderate)
20
+ @urgency = validate_level(urgency, URGENCY_LEVELS, :soon)
21
+ @triage_score = compute_triage_score
22
+ @status = :pending
23
+ @created_at = Time.now.utc
24
+ @triaged_at = nil
25
+ end
26
+
27
+ def triage!
28
+ @status = :triaged
29
+ @triaged_at = Time.now.utc
30
+ self
31
+ end
32
+
33
+ def defer!
34
+ @status = :deferred
35
+ self
36
+ end
37
+
38
+ def process!
39
+ @status = :processing
40
+ self
41
+ end
42
+
43
+ def complete!
44
+ @status = :completed
45
+ self
46
+ end
47
+
48
+ def drop!
49
+ @status = :dropped
50
+ self
51
+ end
52
+
53
+ def active?
54
+ %i[pending triaged processing].include?(@status)
55
+ end
56
+
57
+ def triage_label
58
+ Constants.label_for(TRIAGE_LABELS, @triage_score)
59
+ end
60
+
61
+ def red?
62
+ @triage_score >= 0.8
63
+ end
64
+
65
+ def to_h
66
+ {
67
+ id: @id,
68
+ description: @description,
69
+ domain: @domain,
70
+ severity: @severity,
71
+ urgency: @urgency,
72
+ triage_score: @triage_score,
73
+ triage_label: triage_label,
74
+ status: @status,
75
+ red: red?,
76
+ created_at: @created_at,
77
+ triaged_at: @triaged_at
78
+ }
79
+ end
80
+
81
+ private
82
+
83
+ def validate_level(level, valid_levels, default)
84
+ sym = level.to_sym
85
+ valid_levels.include?(sym) ? sym : default
86
+ end
87
+
88
+ def compute_triage_score
89
+ sev = SEVERITY_WEIGHTS.fetch(@severity, 0.5)
90
+ urg = URGENCY_WEIGHTS.fetch(@urgency, 0.5)
91
+ ((sev * 0.6) + (urg * 0.4)).round(10)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveTriage
6
+ module Helpers
7
+ class TriageEngine
8
+ include Constants
9
+
10
+ attr_reader :capacity
11
+
12
+ def initialize
13
+ @demands = {}
14
+ @capacity = CAPACITY_DEFAULT
15
+ end
16
+
17
+ def add_demand(description:, domain: :general, severity: :moderate, urgency: :soon)
18
+ prune_if_needed
19
+ demand = Demand.new(
20
+ description: description, domain: domain, severity: severity, urgency: urgency
21
+ )
22
+ @demands[demand.id] = demand
23
+ drain_capacity!(demand.triage_score * CAPACITY_DRAIN)
24
+ demand.triage!
25
+ demand
26
+ end
27
+
28
+ def process_demand(demand_id:)
29
+ demand = @demands[demand_id]
30
+ return nil unless demand&.active?
31
+
32
+ demand.process!
33
+ demand
34
+ end
35
+
36
+ def complete_demand(demand_id:)
37
+ demand = @demands[demand_id]
38
+ return nil unless demand
39
+
40
+ demand.complete!
41
+ restore_capacity!(CAPACITY_RESTORE)
42
+ demand
43
+ end
44
+
45
+ def defer_demand(demand_id:)
46
+ demand = @demands[demand_id]
47
+ return nil unless demand&.active?
48
+
49
+ demand.defer!
50
+ restore_capacity!(CAPACITY_RESTORE * 0.5)
51
+ demand
52
+ end
53
+
54
+ def drop_demand(demand_id:)
55
+ demand = @demands[demand_id]
56
+ return nil unless demand&.active?
57
+
58
+ demand.drop!
59
+ restore_capacity!(CAPACITY_RESTORE)
60
+ demand
61
+ end
62
+
63
+ def next_demand
64
+ active_demands.max_by(&:triage_score)
65
+ end
66
+
67
+ def active_demands = @demands.values.select(&:active?)
68
+ def red_demands = @demands.values.select(&:red?)
69
+ def completed_demands = @demands.values.select { |d| d.status == :completed }
70
+ def dropped_demands = @demands.values.select { |d| d.status == :dropped }
71
+ def deferred_demands = @demands.values.select { |d| d.status == :deferred }
72
+
73
+ def demands_by_severity(severity:)
74
+ @demands.values.select { |d| d.severity == severity.to_sym }
75
+ end
76
+
77
+ def demands_by_domain(domain:)
78
+ @demands.values.select { |d| d.domain == domain.to_sym }
79
+ end
80
+
81
+ def overloaded?
82
+ @capacity <= OVERLOAD_THRESHOLD
83
+ end
84
+
85
+ def queue_pressure
86
+ return 0.0 if @demands.empty?
87
+
88
+ (active_demands.size.to_f / MAX_QUEUE_SIZE).clamp(0.0, 1.0).round(10)
89
+ end
90
+
91
+ def capacity_label = Constants.label_for(CAPACITY_LABELS, @capacity)
92
+ def queue_label = Constants.label_for(QUEUE_LABELS, queue_pressure)
93
+
94
+ def restore_capacity!(amount = CAPACITY_RESTORE)
95
+ @capacity = (@capacity + amount).clamp(0.0, 1.0).round(10)
96
+ self
97
+ end
98
+
99
+ def triage_report
100
+ {
101
+ total_demands: @demands.size,
102
+ active_count: active_demands.size,
103
+ red_count: red_demands.size,
104
+ completed: completed_demands.size,
105
+ dropped: dropped_demands.size,
106
+ deferred: deferred_demands.size,
107
+ capacity: @capacity,
108
+ capacity_label: capacity_label,
109
+ overloaded: overloaded?,
110
+ queue_pressure: queue_pressure,
111
+ queue_label: queue_label,
112
+ next_demand: next_demand&.to_h
113
+ }
114
+ end
115
+
116
+ def to_h
117
+ {
118
+ total_demands: @demands.size,
119
+ active: active_demands.size,
120
+ capacity: @capacity,
121
+ overloaded: overloaded?
122
+ }
123
+ end
124
+
125
+ private
126
+
127
+ def drain_capacity!(amount)
128
+ @capacity = (@capacity - amount).clamp(0.0, 1.0).round(10)
129
+ end
130
+
131
+ def prune_if_needed
132
+ return if @demands.size < MAX_DEMANDS
133
+
134
+ oldest_completed = completed_demands.min_by(&:created_at)
135
+ if oldest_completed
136
+ @demands.delete(oldest_completed.id)
137
+ else
138
+ lowest = @demands.values.min_by(&:triage_score)
139
+ @demands.delete(lowest.id) if lowest
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveTriage
6
+ module Runners
7
+ module CognitiveTriage
8
+ include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
9
+
10
+ def add_demand(description:, domain: :general, severity: :moderate, urgency: :soon, engine: nil, **)
11
+ eng = engine || default_engine
12
+ demand = eng.add_demand(
13
+ description: description, domain: domain, severity: severity, urgency: urgency
14
+ )
15
+ { success: true, demand: demand.to_h, capacity: eng.capacity }
16
+ end
17
+
18
+ def process_demand(demand_id:, engine: nil, **)
19
+ eng = engine || default_engine
20
+ demand = eng.process_demand(demand_id: demand_id)
21
+ return { success: false, error: 'demand not found or not active' } unless demand
22
+
23
+ { success: true, demand: demand.to_h }
24
+ end
25
+
26
+ def complete_demand(demand_id:, engine: nil, **)
27
+ eng = engine || default_engine
28
+ demand = eng.complete_demand(demand_id: demand_id)
29
+ return { success: false, error: 'demand not found' } unless demand
30
+
31
+ { success: true, demand: demand.to_h, capacity: eng.capacity }
32
+ end
33
+
34
+ def defer_demand(demand_id:, engine: nil, **)
35
+ eng = engine || default_engine
36
+ demand = eng.defer_demand(demand_id: demand_id)
37
+ return { success: false, error: 'demand not found or not active' } unless demand
38
+
39
+ { success: true, demand: demand.to_h, capacity: eng.capacity }
40
+ end
41
+
42
+ def drop_demand(demand_id:, engine: nil, **)
43
+ eng = engine || default_engine
44
+ demand = eng.drop_demand(demand_id: demand_id)
45
+ return { success: false, error: 'demand not found or not active' } unless demand
46
+
47
+ { success: true, demand: demand.to_h, capacity: eng.capacity }
48
+ end
49
+
50
+ def next_demand(engine: nil, **)
51
+ eng = engine || default_engine
52
+ demand = eng.next_demand
53
+ return { success: true, found: false } unless demand
54
+
55
+ { success: true, found: true, demand: demand.to_h }
56
+ end
57
+
58
+ def active_demands(engine: nil, **)
59
+ eng = engine || default_engine
60
+ { success: true, demands: eng.active_demands.map(&:to_h), count: eng.active_demands.size }
61
+ end
62
+
63
+ def red_demands(engine: nil, **)
64
+ eng = engine || default_engine
65
+ { success: true, demands: eng.red_demands.map(&:to_h), count: eng.red_demands.size }
66
+ end
67
+
68
+ def demands_by_severity(severity:, engine: nil, **)
69
+ eng = engine || default_engine
70
+ demands = eng.demands_by_severity(severity: severity)
71
+ { success: true, demands: demands.map(&:to_h), count: demands.size }
72
+ end
73
+
74
+ def demands_by_domain(domain:, engine: nil, **)
75
+ eng = engine || default_engine
76
+ demands = eng.demands_by_domain(domain: domain)
77
+ { success: true, demands: demands.map(&:to_h), count: demands.size }
78
+ end
79
+
80
+ def capacity_status(engine: nil, **)
81
+ eng = engine || default_engine
82
+ {
83
+ success: true,
84
+ capacity: eng.capacity,
85
+ capacity_label: eng.capacity_label,
86
+ overloaded: eng.overloaded?,
87
+ queue_pressure: eng.queue_pressure,
88
+ queue_label: eng.queue_label
89
+ }
90
+ end
91
+
92
+ def triage_report(engine: nil, **)
93
+ eng = engine || default_engine
94
+ { success: true, report: eng.triage_report }
95
+ end
96
+
97
+ private
98
+
99
+ def default_engine
100
+ @default_engine ||= Helpers::TriageEngine.new
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveTriage
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'cognitive_triage/version'
4
+ require_relative 'cognitive_triage/helpers/constants'
5
+ require_relative 'cognitive_triage/helpers/demand'
6
+ require_relative 'cognitive_triage/helpers/triage_engine'
7
+ require_relative 'cognitive_triage/runners/cognitive_triage'
8
+ require_relative 'cognitive_triage/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module CognitiveTriage
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-cognitive-triage
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: Triage system for cognitive overload. Classifies incoming demands by
27
+ severity and urgency, routes to appropriate processing queues, and manages cognitive
28
+ capacity under pressure.
29
+ email:
30
+ - matthewdiverson@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".github/workflows/ci.yml"
36
+ - ".gitignore"
37
+ - ".rspec"
38
+ - ".rubocop.yml"
39
+ - CLAUDE.md
40
+ - Gemfile
41
+ - README.md
42
+ - lex-cognitive-triage.gemspec
43
+ - lib/legion/extensions/cognitive_triage.rb
44
+ - lib/legion/extensions/cognitive_triage/client.rb
45
+ - lib/legion/extensions/cognitive_triage/helpers/constants.rb
46
+ - lib/legion/extensions/cognitive_triage/helpers/demand.rb
47
+ - lib/legion/extensions/cognitive_triage/helpers/triage_engine.rb
48
+ - lib/legion/extensions/cognitive_triage/runners/cognitive_triage.rb
49
+ - lib/legion/extensions/cognitive_triage/version.rb
50
+ homepage: https://github.com/LegionIO/lex-cognitive-triage
51
+ licenses:
52
+ - MIT
53
+ metadata:
54
+ homepage_uri: https://github.com/LegionIO/lex-cognitive-triage
55
+ source_code_uri: https://github.com/LegionIO/lex-cognitive-triage
56
+ documentation_uri: https://github.com/LegionIO/lex-cognitive-triage/blob/master/README.md
57
+ changelog_uri: https://github.com/LegionIO/lex-cognitive-triage/blob/master/CHANGELOG.md
58
+ bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-triage/issues
59
+ rubygems_mfa_required: 'true'
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.4'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.6.9
75
+ specification_version: 4
76
+ summary: Emergency cognitive prioritization for LegionIO
77
+ test_files: []