lex-cognitive-blindspot 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 +3 -0
- data/.rubocop.yml +40 -0
- data/CLAUDE.md +81 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +78 -0
- data/README.md +40 -0
- data/lex-cognitive-blindspot.gemspec +33 -0
- data/lib/legion/extensions/cognitive_blindspot/client.rb +15 -0
- data/lib/legion/extensions/cognitive_blindspot/helpers/blindspot.rb +94 -0
- data/lib/legion/extensions/cognitive_blindspot/helpers/blindspot_engine.rb +170 -0
- data/lib/legion/extensions/cognitive_blindspot/helpers/constants.rb +59 -0
- data/lib/legion/extensions/cognitive_blindspot/helpers/knowledge_boundary.rb +58 -0
- data/lib/legion/extensions/cognitive_blindspot/runners/cognitive_blindspot.rb +99 -0
- data/lib/legion/extensions/cognitive_blindspot/version.rb +9 -0
- data/lib/legion/extensions/cognitive_blindspot.rb +17 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 70f03cdc2eef30b1868b9f42870fb55b50ad4ebbdfebfcfe21c745a00ef7a838
|
|
4
|
+
data.tar.gz: 07bf45977e84481f64ce514a200eeb2f6b10c7495079204df988865dc61da9db
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 31569326fc31e1fb955be407e857f748e3f52824451b584f59052c15f3748a34948139d2c91653c32d6a064ea6195806eb8d60751a79dea9d6acd83f82abc18e
|
|
7
|
+
data.tar.gz: 70ecbaac03f808079e9ca8385a2bfe62538f869b94eba230e09d096150a19f745b7c3de92951be703771c09d7f83155d818a162811dee5047c44ced83bcd47d7
|
|
@@ -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
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
TargetRubyVersion: 3.4
|
|
4
|
+
|
|
5
|
+
Style/Documentation:
|
|
6
|
+
Enabled: false
|
|
7
|
+
|
|
8
|
+
Naming/PredicateMethod:
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
Naming/PredicatePrefix:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
Metrics/ClassLength:
|
|
15
|
+
Max: 150
|
|
16
|
+
|
|
17
|
+
Metrics/MethodLength:
|
|
18
|
+
Max: 25
|
|
19
|
+
|
|
20
|
+
Metrics/AbcSize:
|
|
21
|
+
Max: 25
|
|
22
|
+
|
|
23
|
+
Metrics/ParameterLists:
|
|
24
|
+
Max: 8
|
|
25
|
+
MaxOptionalParameters: 8
|
|
26
|
+
|
|
27
|
+
Layout/HashAlignment:
|
|
28
|
+
EnforcedHashRocketStyle: table
|
|
29
|
+
EnforcedColonStyle: table
|
|
30
|
+
|
|
31
|
+
Metrics/BlockLength:
|
|
32
|
+
Exclude:
|
|
33
|
+
- 'spec/**/*'
|
|
34
|
+
|
|
35
|
+
Style/FrozenStringLiteralComment:
|
|
36
|
+
Enabled: true
|
|
37
|
+
|
|
38
|
+
Style/OneClassPerFile:
|
|
39
|
+
Exclude:
|
|
40
|
+
- 'spec/spec_helper.rb'
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# lex-cognitive-blindspot
|
|
2
|
+
|
|
3
|
+
**Level 3 Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
- **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Johari Window for AI. Tracks unknown-unknowns, manages knowledge boundaries, and scores agent awareness with blindspot acknowledgement and mitigation strategies. Models the progression from unknown-unknown (active blindspot) to known-unknown (acknowledged) to mitigated to resolved.
|
|
10
|
+
|
|
11
|
+
## Gem Info
|
|
12
|
+
|
|
13
|
+
- **Gem name**: `lex-cognitive-blindspot`
|
|
14
|
+
- **Version**: `0.1.0`
|
|
15
|
+
- **Module**: `Legion::Extensions::CognitiveBlindspot`
|
|
16
|
+
- **Ruby**: `>= 3.4`
|
|
17
|
+
- **License**: MIT
|
|
18
|
+
|
|
19
|
+
## File Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
lib/legion/extensions/cognitive_blindspot/
|
|
23
|
+
cognitive_blindspot.rb
|
|
24
|
+
version.rb
|
|
25
|
+
client.rb
|
|
26
|
+
helpers/
|
|
27
|
+
constants.rb
|
|
28
|
+
blindspot.rb
|
|
29
|
+
knowledge_boundary.rb
|
|
30
|
+
blindspot_engine.rb
|
|
31
|
+
runners/
|
|
32
|
+
cognitive_blindspot.rb
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Constants
|
|
36
|
+
|
|
37
|
+
From `helpers/constants.rb`:
|
|
38
|
+
|
|
39
|
+
- `DISCOVERY_METHODS` — `%i[error_analysis peer_feedback cross_domain_check contradiction_detection confidence_calibration external_audit self_reflection unknown]`
|
|
40
|
+
- `MAX_BLINDSPOTS` = `300`, `MAX_BOUNDARIES` = `50`
|
|
41
|
+
- `DEFAULT_SEVERITY` = `0.5`, `SEVERITY_BOOST` = `0.1`
|
|
42
|
+
- `AWARENESS_THRESHOLD` = `0.6`
|
|
43
|
+
- `SEVERITY_LABELS` — `0.8+` = `:critical`, `0.6` = `:high`, `0.4` = `:moderate`, `0.2` = `:low`, below = `:negligible`
|
|
44
|
+
- `AWARENESS_LABELS` — `0.8+` = `:highly_aware` through below `0.2` = `:unaware`
|
|
45
|
+
- `COVERAGE_LABELS` — `0.8+` = `:comprehensive` through below `0.2` = `:minimal`
|
|
46
|
+
- `STATUS_LABELS` — describes each state: `active` = unknown-unknown, `acknowledged` = known-unknown, `mitigated` = partial coverage, `resolved` = fully addressed
|
|
47
|
+
|
|
48
|
+
## Runners
|
|
49
|
+
|
|
50
|
+
All methods in `Runners::CognitiveBlindspot`:
|
|
51
|
+
|
|
52
|
+
- `register_blindspot(domain:, discovered_by:, description:, severity: DEFAULT_SEVERITY)` — records a new blindspot in `active` state
|
|
53
|
+
- `acknowledge_blindspot(blindspot_id:)` — transitions from `active` to `acknowledged` (unknown-unknown -> known-unknown)
|
|
54
|
+
- `mitigate_blindspot(blindspot_id:, boost: SEVERITY_BOOST)` — applies mitigation; reduces severity by boost amount
|
|
55
|
+
- `resolve_blindspot(blindspot_id:)` — marks as fully resolved
|
|
56
|
+
- `set_knowledge_boundary(domain:, confidence:, coverage_estimate:)` — establishes a domain-level knowledge boundary
|
|
57
|
+
- `detect_boundary_gap(domain:, error_occurred: false)` — checks if errors in a domain indicate boundary gaps
|
|
58
|
+
- `active_blindspots_report` — all unacknowledged or unresolved blindspots
|
|
59
|
+
- `most_severe_report(limit: 5)` — top blindspots by severity
|
|
60
|
+
- `mitigation_strategies_report(domain: nil)` — recommended strategies per domain
|
|
61
|
+
- `coverage_report` — all knowledge boundaries with coverage estimates
|
|
62
|
+
- `johari_report` — full Johari Window breakdown: known-knowns, known-unknowns, unknown-unknowns counts
|
|
63
|
+
- `awareness_score_report` — scalar awareness score, label, and awareness gap
|
|
64
|
+
|
|
65
|
+
## Helpers
|
|
66
|
+
|
|
67
|
+
- `BlindspotEngine` — stores blindspots and knowledge boundaries; computes awareness score as ratio of acknowledged/mitigated/resolved to total.
|
|
68
|
+
- `Blindspot` — individual blindspot with `domain`, `discovered_by`, `description`, `severity`, `status`. State machine: `active` -> `acknowledged` -> `mitigated` -> `resolved`.
|
|
69
|
+
- `KnowledgeBoundary` — domain-level confidence and coverage estimate; gap detection on error events.
|
|
70
|
+
|
|
71
|
+
## Integration Points
|
|
72
|
+
|
|
73
|
+
- `lex-cognitive-debugging` detects reasoning errors; those errors are natural inputs to `register_blindspot` (via `discovered_by: :error_analysis`).
|
|
74
|
+
- `lex-tick` can call awareness score checks in the `identity_entropy_check` phase to flag low-awareness domains.
|
|
75
|
+
- `detect_boundary_gap` is meant to be called when errors occur — the caller passes `error_occurred: true` to trigger gap analysis for the relevant domain.
|
|
76
|
+
|
|
77
|
+
## Development Notes
|
|
78
|
+
|
|
79
|
+
- Blindspot state progression is one-directional: `active` -> `acknowledged` -> `mitigated` -> `resolved`. No regression.
|
|
80
|
+
- `awareness_score` is computed as `(acknowledged + mitigated + resolved) / total_blindspots`. An agent with no registered blindspots returns `0.0` (unaware, not aware).
|
|
81
|
+
- `johari_report` maps: `active` = unknown-unknown quadrant; `acknowledged/mitigated` = known-unknown quadrant; no explicit known-known tracking (that would require a separate knowledge model).
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lex-cognitive-blindspot (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
addressable (2.8.9)
|
|
10
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
11
|
+
ast (2.4.3)
|
|
12
|
+
bigdecimal (4.0.1)
|
|
13
|
+
diff-lcs (1.6.2)
|
|
14
|
+
json (2.19.1)
|
|
15
|
+
json-schema (6.2.0)
|
|
16
|
+
addressable (~> 2.8)
|
|
17
|
+
bigdecimal (>= 3.1, < 5)
|
|
18
|
+
language_server-protocol (3.17.0.5)
|
|
19
|
+
lint_roller (1.1.0)
|
|
20
|
+
mcp (0.8.0)
|
|
21
|
+
json-schema (>= 4.1)
|
|
22
|
+
parallel (1.27.0)
|
|
23
|
+
parser (3.3.10.2)
|
|
24
|
+
ast (~> 2.4.1)
|
|
25
|
+
racc
|
|
26
|
+
prism (1.9.0)
|
|
27
|
+
public_suffix (7.0.5)
|
|
28
|
+
racc (1.8.1)
|
|
29
|
+
rainbow (3.1.1)
|
|
30
|
+
regexp_parser (2.11.3)
|
|
31
|
+
rspec (3.13.2)
|
|
32
|
+
rspec-core (~> 3.13.0)
|
|
33
|
+
rspec-expectations (~> 3.13.0)
|
|
34
|
+
rspec-mocks (~> 3.13.0)
|
|
35
|
+
rspec-core (3.13.6)
|
|
36
|
+
rspec-support (~> 3.13.0)
|
|
37
|
+
rspec-expectations (3.13.5)
|
|
38
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
39
|
+
rspec-support (~> 3.13.0)
|
|
40
|
+
rspec-mocks (3.13.8)
|
|
41
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
42
|
+
rspec-support (~> 3.13.0)
|
|
43
|
+
rspec-support (3.13.7)
|
|
44
|
+
rubocop (1.85.1)
|
|
45
|
+
json (~> 2.3)
|
|
46
|
+
language_server-protocol (~> 3.17.0.2)
|
|
47
|
+
lint_roller (~> 1.1.0)
|
|
48
|
+
mcp (~> 0.6)
|
|
49
|
+
parallel (~> 1.10)
|
|
50
|
+
parser (>= 3.3.0.2)
|
|
51
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
52
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
53
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
54
|
+
ruby-progressbar (~> 1.7)
|
|
55
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
56
|
+
rubocop-ast (1.49.1)
|
|
57
|
+
parser (>= 3.3.7.2)
|
|
58
|
+
prism (~> 1.7)
|
|
59
|
+
rubocop-rspec (3.9.0)
|
|
60
|
+
lint_roller (~> 1.1)
|
|
61
|
+
rubocop (~> 1.81)
|
|
62
|
+
ruby-progressbar (1.13.0)
|
|
63
|
+
unicode-display_width (3.2.0)
|
|
64
|
+
unicode-emoji (~> 4.1)
|
|
65
|
+
unicode-emoji (4.2.0)
|
|
66
|
+
|
|
67
|
+
PLATFORMS
|
|
68
|
+
arm64-darwin-25
|
|
69
|
+
ruby
|
|
70
|
+
|
|
71
|
+
DEPENDENCIES
|
|
72
|
+
lex-cognitive-blindspot!
|
|
73
|
+
rspec (~> 3.13)
|
|
74
|
+
rubocop (~> 1.75)
|
|
75
|
+
rubocop-rspec
|
|
76
|
+
|
|
77
|
+
BUNDLED WITH
|
|
78
|
+
2.6.9
|
data/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# lex-cognitive-blindspot
|
|
2
|
+
|
|
3
|
+
Cognitive blindspot detection for LegionIO agents. Johari Window for AI — tracks unknown-unknowns, manages knowledge boundaries, and scores agent awareness with blindspot acknowledgement and mitigation strategies.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Models the progression from unknown-unknown (active blindspot: the agent doesn't know what it doesn't know) to known-unknown (acknowledged: now visible but not addressed) to mitigated (partial coverage) to resolved. Discovery methods include error analysis, peer feedback, contradiction detection, confidence calibration, and self-reflection.
|
|
8
|
+
|
|
9
|
+
A parallel knowledge boundary system tracks domain-level confidence and coverage estimates, with gap detection triggered by error events in a domain.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
client = Legion::Extensions::CognitiveBlindspot::Client.new
|
|
15
|
+
|
|
16
|
+
spot = client.register_blindspot(
|
|
17
|
+
domain: :temporal_reasoning,
|
|
18
|
+
discovered_by: :error_analysis,
|
|
19
|
+
description: 'Consistently misjudges elapsed time in multi-step plans',
|
|
20
|
+
severity: 0.7
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
client.acknowledge_blindspot(blindspot_id: spot[:id])
|
|
24
|
+
client.mitigate_blindspot(blindspot_id: spot[:id], boost: 0.15)
|
|
25
|
+
|
|
26
|
+
client.johari_report
|
|
27
|
+
client.awareness_score_report
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bundle install
|
|
34
|
+
bundle exec rspec
|
|
35
|
+
bundle exec rubocop
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_blindspot/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-blindspot'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveBlindspot::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Cognitive blindspot detection for LegionIO agents'
|
|
12
|
+
spec.description = 'Johari Window for AI — tracks unknown-unknowns, ' \
|
|
13
|
+
'manages knowledge boundaries, and scores agent awareness ' \
|
|
14
|
+
'with blindspot acknowledgement and mitigation strategies.'
|
|
15
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-blindspot'
|
|
16
|
+
spec.license = 'MIT'
|
|
17
|
+
spec.required_ruby_version = '>= 3.4'
|
|
18
|
+
|
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
20
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
21
|
+
spec.metadata['documentation_uri'] = "#{spec.homepage}/blob/main/README.md"
|
|
22
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
23
|
+
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
|
24
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
25
|
+
|
|
26
|
+
spec.files = Dir.chdir(__dir__) do
|
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
28
|
+
f.match(%r{\A(?:test|spec|features)/})
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
spec.require_paths = ['lib']
|
|
32
|
+
spec.add_development_dependency 'legion-gaia'
|
|
33
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveBlindspot
|
|
8
|
+
module Helpers
|
|
9
|
+
class Blindspot
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :domain, :discovered_by, :severity, :description,
|
|
13
|
+
:status, :created_at, :acknowledged_at, :mitigated_at, :resolved_at
|
|
14
|
+
|
|
15
|
+
def initialize(domain:, discovered_by:, description:, severity: DEFAULT_SEVERITY)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@domain = domain.to_sym
|
|
18
|
+
@discovered_by = discovered_by.to_sym
|
|
19
|
+
@description = description.to_s
|
|
20
|
+
@severity = severity.to_f.clamp(0.0, 1.0)
|
|
21
|
+
@status = :active
|
|
22
|
+
@created_at = Time.now.utc
|
|
23
|
+
@acknowledged_at = nil
|
|
24
|
+
@mitigated_at = nil
|
|
25
|
+
@resolved_at = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def severity_label
|
|
29
|
+
Constants.label_for(SEVERITY_LABELS, @severity) || :negligible
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def active?
|
|
33
|
+
@status == :active
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def acknowledged?
|
|
37
|
+
@status == :acknowledged || @status == :mitigated || @status == :resolved
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def resolved?
|
|
41
|
+
@status == :resolved
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def acknowledge!
|
|
45
|
+
return self if @status != :active
|
|
46
|
+
|
|
47
|
+
@status = :acknowledged
|
|
48
|
+
@acknowledged_at = Time.now.utc
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def mitigate!(boost: SEVERITY_BOOST)
|
|
53
|
+
acknowledge! if @status == :active
|
|
54
|
+
@status = :mitigated
|
|
55
|
+
@mitigated_at = Time.now.utc
|
|
56
|
+
@severity = (@severity - boost).clamp(0.0, 1.0).round(10)
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def resolve!
|
|
61
|
+
acknowledge! if @status == :active
|
|
62
|
+
@status = :resolved
|
|
63
|
+
@resolved_at = Time.now.utc
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def boost_severity!(amount: SEVERITY_BOOST)
|
|
68
|
+
@severity = (@severity + amount).clamp(0.0, 1.0).round(10)
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def to_h
|
|
73
|
+
{
|
|
74
|
+
id: @id,
|
|
75
|
+
domain: @domain,
|
|
76
|
+
discovered_by: @discovered_by,
|
|
77
|
+
description: @description,
|
|
78
|
+
severity: @severity,
|
|
79
|
+
severity_label: severity_label,
|
|
80
|
+
status: @status,
|
|
81
|
+
active: active?,
|
|
82
|
+
acknowledged: acknowledged?,
|
|
83
|
+
resolved: resolved?,
|
|
84
|
+
created_at: @created_at,
|
|
85
|
+
acknowledged_at: @acknowledged_at,
|
|
86
|
+
mitigated_at: @mitigated_at,
|
|
87
|
+
resolved_at: @resolved_at
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveBlindspot
|
|
6
|
+
module Helpers
|
|
7
|
+
class BlindspotEngine
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :awareness_score
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@blindspots = {}
|
|
14
|
+
@boundaries = {}
|
|
15
|
+
@awareness_score = 1.0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def register_blindspot(domain:, discovered_by:, description:, severity: DEFAULT_SEVERITY)
|
|
19
|
+
prune_blindspots_if_needed
|
|
20
|
+
blindspot = Blindspot.new(domain: domain, discovered_by: discovered_by,
|
|
21
|
+
description: description, severity: severity)
|
|
22
|
+
@blindspots[blindspot.id] = blindspot
|
|
23
|
+
recalculate_awareness
|
|
24
|
+
blindspot
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def acknowledge_blindspot(blindspot_id:)
|
|
28
|
+
blindspot = @blindspots.fetch(blindspot_id, nil)
|
|
29
|
+
return { found: false, blindspot_id: blindspot_id } unless blindspot
|
|
30
|
+
|
|
31
|
+
blindspot.acknowledge!
|
|
32
|
+
recalculate_awareness
|
|
33
|
+
{ found: true, blindspot_id: blindspot_id, status: blindspot.status,
|
|
34
|
+
awareness_score: @awareness_score.round(10) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def mitigate_blindspot(blindspot_id:, boost: SEVERITY_BOOST)
|
|
38
|
+
blindspot = @blindspots.fetch(blindspot_id, nil)
|
|
39
|
+
return { found: false, blindspot_id: blindspot_id } unless blindspot
|
|
40
|
+
|
|
41
|
+
blindspot.mitigate!(boost: boost)
|
|
42
|
+
recalculate_awareness
|
|
43
|
+
{ found: true, blindspot_id: blindspot_id, status: blindspot.status,
|
|
44
|
+
severity: blindspot.severity, awareness_score: @awareness_score.round(10) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def resolve_blindspot(blindspot_id:)
|
|
48
|
+
blindspot = @blindspots.fetch(blindspot_id, nil)
|
|
49
|
+
return { found: false, blindspot_id: blindspot_id } unless blindspot
|
|
50
|
+
|
|
51
|
+
blindspot.resolve!
|
|
52
|
+
recalculate_awareness
|
|
53
|
+
{ found: true, blindspot_id: blindspot_id, status: blindspot.status,
|
|
54
|
+
awareness_score: @awareness_score.round(10) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def set_boundary(domain:, confidence: 0.5, coverage_estimate: 0.5)
|
|
58
|
+
prune_boundaries_if_needed
|
|
59
|
+
existing = boundary_for_domain(domain)
|
|
60
|
+
return update_boundary!(existing, confidence, coverage_estimate) if existing
|
|
61
|
+
|
|
62
|
+
boundary = KnowledgeBoundary.new(domain: domain, confidence: confidence,
|
|
63
|
+
coverage_estimate: coverage_estimate)
|
|
64
|
+
@boundaries[boundary.id] = boundary
|
|
65
|
+
boundary
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def detect_boundary_gap(domain:, error_occurred: false)
|
|
69
|
+
boundary = boundary_for_domain(domain)
|
|
70
|
+
return { gap_detected: false, domain: domain, reason: :no_boundary } unless boundary
|
|
71
|
+
|
|
72
|
+
{ gap_detected: boundary.gap_detected?(error_occurred: error_occurred),
|
|
73
|
+
domain: domain, confidence: boundary.confidence,
|
|
74
|
+
coverage: boundary.coverage_estimate }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def blindspots_by_domain(domain)
|
|
78
|
+
d = domain.to_sym
|
|
79
|
+
@blindspots.values.select { |b| b.domain == d }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def active_blindspots = @blindspots.values.select(&:active?)
|
|
83
|
+
def acknowledged_blindspots = @blindspots.values.select { |b| b.status == :acknowledged }
|
|
84
|
+
def resolved_blindspots = @blindspots.values.select(&:resolved?)
|
|
85
|
+
|
|
86
|
+
def most_severe(limit: 5)
|
|
87
|
+
@blindspots.values.sort_by { |b| -b.severity }.first(limit)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def mitigation_strategies(domain: nil)
|
|
91
|
+
spots = domain ? blindspots_by_domain(domain) : @blindspots.values
|
|
92
|
+
spots.select(&:active?).map do |b|
|
|
93
|
+
{ blindspot_id: b.id, domain: b.domain, severity: b.severity, strategy: strategy_for(b) }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def coverage_report = @boundaries.values.map(&:to_h)
|
|
98
|
+
def awareness_label = Constants.label_for(AWARENESS_LABELS, @awareness_score) || :unaware
|
|
99
|
+
def awareness_gap = (1.0 - @awareness_score).clamp(0.0, 1.0).round(10)
|
|
100
|
+
|
|
101
|
+
def johari_report
|
|
102
|
+
{ total_blindspots: @blindspots.size,
|
|
103
|
+
active: active_blindspots.size,
|
|
104
|
+
acknowledged: acknowledged_blindspots.size,
|
|
105
|
+
resolved: resolved_blindspots.size,
|
|
106
|
+
awareness_score: @awareness_score.round(10),
|
|
107
|
+
awareness_label: awareness_label,
|
|
108
|
+
awareness_gap: awareness_gap,
|
|
109
|
+
boundaries_tracked: @boundaries.size,
|
|
110
|
+
most_severe: most_severe(limit: 3).map(&:to_h) }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def to_h
|
|
114
|
+
{ total_blindspots: @blindspots.size,
|
|
115
|
+
active: active_blindspots.size,
|
|
116
|
+
acknowledged: acknowledged_blindspots.size,
|
|
117
|
+
resolved: resolved_blindspots.size,
|
|
118
|
+
awareness_score: @awareness_score.round(10),
|
|
119
|
+
awareness_label: awareness_label }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def update_boundary!(boundary, confidence, coverage_estimate)
|
|
125
|
+
boundary.update_confidence!(confidence)
|
|
126
|
+
boundary.update_coverage!(coverage_estimate)
|
|
127
|
+
boundary
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def boundary_for_domain(domain)
|
|
131
|
+
d = domain.to_sym
|
|
132
|
+
@boundaries.values.find { |b| b.domain == d }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def recalculate_awareness
|
|
136
|
+
total = @blindspots.size.to_f
|
|
137
|
+
return @awareness_score = 1.0 if total.zero?
|
|
138
|
+
|
|
139
|
+
not_active = @blindspots.values.count { |b| !b.active? }.to_f
|
|
140
|
+
@awareness_score = (not_active / total).clamp(0.0, 1.0).round(10)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def strategy_for(blindspot)
|
|
144
|
+
case blindspot.severity
|
|
145
|
+
when (0.8..) then :immediate_external_audit
|
|
146
|
+
when (0.6...0.8) then :cross_domain_check
|
|
147
|
+
when (0.4...0.6) then :peer_feedback
|
|
148
|
+
else :self_reflection
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def prune_blindspots_if_needed
|
|
153
|
+
return if @blindspots.size < MAX_BLINDSPOTS
|
|
154
|
+
|
|
155
|
+
target = resolved_blindspots.min_by(&:created_at) ||
|
|
156
|
+
@blindspots.values.min_by(&:severity)
|
|
157
|
+
@blindspots.delete(target.id) if target
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def prune_boundaries_if_needed
|
|
161
|
+
return if @boundaries.size < MAX_BOUNDARIES
|
|
162
|
+
|
|
163
|
+
oldest = @boundaries.values.min_by(&:created_at)
|
|
164
|
+
@boundaries.delete(oldest.id) if oldest
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveBlindspot
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
MAX_BLINDSPOTS = 300
|
|
9
|
+
MAX_BOUNDARIES = 50
|
|
10
|
+
DEFAULT_SEVERITY = 0.5
|
|
11
|
+
SEVERITY_BOOST = 0.1
|
|
12
|
+
AWARENESS_THRESHOLD = 0.6
|
|
13
|
+
|
|
14
|
+
DISCOVERY_METHODS = %i[
|
|
15
|
+
error_analysis peer_feedback cross_domain_check
|
|
16
|
+
contradiction_detection confidence_calibration
|
|
17
|
+
external_audit self_reflection unknown
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
SEVERITY_LABELS = {
|
|
21
|
+
(0.8..) => :critical,
|
|
22
|
+
(0.6...0.8) => :high,
|
|
23
|
+
(0.4...0.6) => :moderate,
|
|
24
|
+
(0.2...0.4) => :low,
|
|
25
|
+
(..0.2) => :negligible
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
AWARENESS_LABELS = {
|
|
29
|
+
(0.8..) => :highly_aware,
|
|
30
|
+
(0.6...0.8) => :aware,
|
|
31
|
+
(0.4...0.6) => :partially_blind,
|
|
32
|
+
(0.2...0.4) => :mostly_blind,
|
|
33
|
+
(..0.2) => :unaware
|
|
34
|
+
}.freeze
|
|
35
|
+
|
|
36
|
+
COVERAGE_LABELS = {
|
|
37
|
+
(0.8..) => :comprehensive,
|
|
38
|
+
(0.6...0.8) => :substantial,
|
|
39
|
+
(0.4...0.6) => :partial,
|
|
40
|
+
(0.2...0.4) => :limited,
|
|
41
|
+
(..0.2) => :minimal
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
STATUS_LABELS = {
|
|
45
|
+
active: 'Unknown unknown — not yet surfaced to awareness',
|
|
46
|
+
acknowledged: 'Known unknown — surfaced, not yet mitigated',
|
|
47
|
+
mitigated: 'Known unknown — mitigated with partial coverage',
|
|
48
|
+
resolved: 'Known unknown — fully addressed'
|
|
49
|
+
}.freeze
|
|
50
|
+
|
|
51
|
+
def self.label_for(labels, value)
|
|
52
|
+
match = labels.find { |range, _| range.cover?(value) }
|
|
53
|
+
match&.last
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveBlindspot
|
|
8
|
+
module Helpers
|
|
9
|
+
class KnowledgeBoundary
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :domain, :confidence, :coverage_estimate, :created_at, :updated_at
|
|
13
|
+
|
|
14
|
+
def initialize(domain:, confidence: 0.5, coverage_estimate: 0.5)
|
|
15
|
+
@id = SecureRandom.uuid
|
|
16
|
+
@domain = domain.to_sym
|
|
17
|
+
@confidence = confidence.to_f.clamp(0.0, 1.0)
|
|
18
|
+
@coverage_estimate = coverage_estimate.to_f.clamp(0.0, 1.0)
|
|
19
|
+
@created_at = Time.now.utc
|
|
20
|
+
@updated_at = Time.now.utc
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def coverage_label
|
|
24
|
+
Constants.label_for(COVERAGE_LABELS, @coverage_estimate) || :minimal
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def gap_detected?(error_occurred: false)
|
|
28
|
+
error_occurred && @confidence >= AWARENESS_THRESHOLD
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def update_confidence!(new_confidence)
|
|
32
|
+
@confidence = new_confidence.to_f.clamp(0.0, 1.0)
|
|
33
|
+
@updated_at = Time.now.utc
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def update_coverage!(new_coverage)
|
|
38
|
+
@coverage_estimate = new_coverage.to_f.clamp(0.0, 1.0)
|
|
39
|
+
@updated_at = Time.now.utc
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_h
|
|
44
|
+
{
|
|
45
|
+
id: @id,
|
|
46
|
+
domain: @domain,
|
|
47
|
+
confidence: @confidence,
|
|
48
|
+
coverage_estimate: @coverage_estimate,
|
|
49
|
+
coverage_label: coverage_label,
|
|
50
|
+
created_at: @created_at,
|
|
51
|
+
updated_at: @updated_at
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveBlindspot
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveBlindspot
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
9
|
+
|
|
10
|
+
def register_blindspot(domain:, discovered_by:, description:,
|
|
11
|
+
severity: nil, **)
|
|
12
|
+
sev = severity || Helpers::Constants::DEFAULT_SEVERITY
|
|
13
|
+
spot = engine.register_blindspot(
|
|
14
|
+
domain: domain,
|
|
15
|
+
discovered_by: discovered_by,
|
|
16
|
+
description: description,
|
|
17
|
+
severity: sev
|
|
18
|
+
)
|
|
19
|
+
{ success: true }.merge(spot.to_h)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def acknowledge_blindspot(blindspot_id:, **)
|
|
23
|
+
result = engine.acknowledge_blindspot(blindspot_id: blindspot_id)
|
|
24
|
+
return { success: false, error: 'blindspot not found' } unless result[:found]
|
|
25
|
+
|
|
26
|
+
{ success: true }.merge(result)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def mitigate_blindspot(blindspot_id:, boost: nil, **)
|
|
30
|
+
b = boost || Helpers::Constants::SEVERITY_BOOST
|
|
31
|
+
result = engine.mitigate_blindspot(blindspot_id: blindspot_id, boost: b)
|
|
32
|
+
return { success: false, error: 'blindspot not found' } unless result[:found]
|
|
33
|
+
|
|
34
|
+
{ success: true }.merge(result)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def resolve_blindspot(blindspot_id:, **)
|
|
38
|
+
result = engine.resolve_blindspot(blindspot_id: blindspot_id)
|
|
39
|
+
return { success: false, error: 'blindspot not found' } unless result[:found]
|
|
40
|
+
|
|
41
|
+
{ success: true }.merge(result)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def set_knowledge_boundary(domain:, confidence: 0.5, coverage_estimate: 0.5, **)
|
|
45
|
+
boundary = engine.set_boundary(
|
|
46
|
+
domain: domain,
|
|
47
|
+
confidence: confidence,
|
|
48
|
+
coverage_estimate: coverage_estimate
|
|
49
|
+
)
|
|
50
|
+
{ success: true }.merge(boundary.to_h)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def detect_boundary_gap(domain:, error_occurred: false, **)
|
|
54
|
+
result = engine.detect_boundary_gap(domain: domain, error_occurred: error_occurred)
|
|
55
|
+
{ success: true }.merge(result)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def active_blindspots_report(**)
|
|
59
|
+
spots = engine.active_blindspots
|
|
60
|
+
{ success: true, count: spots.size, blindspots: spots.map(&:to_h) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def most_severe_report(limit: 5, **)
|
|
64
|
+
spots = engine.most_severe(limit: limit)
|
|
65
|
+
{ success: true, limit: limit, blindspots: spots.map(&:to_h) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def mitigation_strategies_report(domain: nil, **)
|
|
69
|
+
strategies = engine.mitigation_strategies(domain: domain)
|
|
70
|
+
{ success: true, count: strategies.size, strategies: strategies }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def coverage_report(**)
|
|
74
|
+
boundaries = engine.coverage_report
|
|
75
|
+
{ success: true, count: boundaries.size, boundaries: boundaries }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def johari_report(**)
|
|
79
|
+
engine.johari_report
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def awareness_score_report(**)
|
|
83
|
+
score = engine.awareness_score
|
|
84
|
+
{
|
|
85
|
+
success: true,
|
|
86
|
+
awareness_score: score.round(10),
|
|
87
|
+
awareness_label: engine.awareness_label,
|
|
88
|
+
awareness_gap: engine.awareness_gap
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def blindspot_stats(**)
|
|
93
|
+
engine.to_h
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'cognitive_blindspot/version'
|
|
4
|
+
require_relative 'cognitive_blindspot/helpers/constants'
|
|
5
|
+
require_relative 'cognitive_blindspot/helpers/blindspot'
|
|
6
|
+
require_relative 'cognitive_blindspot/helpers/knowledge_boundary'
|
|
7
|
+
require_relative 'cognitive_blindspot/helpers/blindspot_engine'
|
|
8
|
+
require_relative 'cognitive_blindspot/runners/cognitive_blindspot'
|
|
9
|
+
require_relative 'cognitive_blindspot/client'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module CognitiveBlindspot
|
|
14
|
+
extend Legion::Extensions::Core if defined?(Legion::Extensions::Core)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-blindspot
|
|
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: Johari Window for AI — tracks unknown-unknowns, manages knowledge boundaries,
|
|
27
|
+
and scores agent awareness with blindspot acknowledgement and mitigation strategies.
|
|
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-blindspot.gemspec
|
|
43
|
+
- lib/legion/extensions/cognitive_blindspot.rb
|
|
44
|
+
- lib/legion/extensions/cognitive_blindspot/client.rb
|
|
45
|
+
- lib/legion/extensions/cognitive_blindspot/helpers/blindspot.rb
|
|
46
|
+
- lib/legion/extensions/cognitive_blindspot/helpers/blindspot_engine.rb
|
|
47
|
+
- lib/legion/extensions/cognitive_blindspot/helpers/constants.rb
|
|
48
|
+
- lib/legion/extensions/cognitive_blindspot/helpers/knowledge_boundary.rb
|
|
49
|
+
- lib/legion/extensions/cognitive_blindspot/runners/cognitive_blindspot.rb
|
|
50
|
+
- lib/legion/extensions/cognitive_blindspot/version.rb
|
|
51
|
+
homepage: https://github.com/LegionIO/lex-cognitive-blindspot
|
|
52
|
+
licenses:
|
|
53
|
+
- MIT
|
|
54
|
+
metadata:
|
|
55
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-blindspot
|
|
56
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-blindspot
|
|
57
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-blindspot/blob/main/README.md
|
|
58
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-blindspot/blob/main/CHANGELOG.md
|
|
59
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-blindspot/issues
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.4'
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 3.6.9
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: Cognitive blindspot detection for LegionIO agents
|
|
78
|
+
test_files: []
|