rubocop-legion 0.1.9 → 0.1.10
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/config/default.yml +35 -0
- data/lib/rubocop/cop/legion/llm/taxonomy_enum.rb +38 -13
- data/lib/rubocop/legion/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d9316d83d8676fe5adb80fd7500f3daece09203ece25f0ce0c81887d19982ca
|
|
4
|
+
data.tar.gz: 646cab78aebc73b233882dcfc594d6c0efbea0acb3e2881e02a1f888ec5513e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83f63897f48898014d992e98b11cdfd9f2b830e405b2fd49bff484acffdaaeafd853dea8016baaa280787302a0c15a701e2f1d0c71274d1bf0fa04761574e8bd
|
|
7
|
+
data.tar.gz: 69aa65b8634cef75041fe37a57b87ca54bdc911a59fc12710193a66550b71c01926831618ef9100b775c5fc498d0705d8eaab50af11c5c1446d36ab801be51ae
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.10] - 2026-07-31
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- `Legion/Llm/TaxonomyEnum` no longer over-matches: `:type` is only validated when it appears alongside `:tier` or `:circuit_state` in the same hash (taxonomy context). Previously any `{ type: :string }` or schema hash triggered a false positive.
|
|
7
|
+
- Added `Legion/Llm` department to `config/default.yml` — all four cops (`TaxonomyEnum`, `SettingsAccessPath`, `NoLoopDo`, `RescueLogLevel`) were loaded but never registered in the config, causing consumer repos to report "unrecognized cop" when referencing `Legion/Llm/TaxonomyEnum`.
|
|
8
|
+
- `TaxonomyEnum` is now Include-scoped to `lib/legion/llm/**/*.rb` and `lib/legion/extensions/llm/**/*.rb` so it only runs on LLM routing code.
|
|
9
|
+
|
|
3
10
|
## [0.1.8] - 2026-06-16
|
|
4
11
|
|
|
5
12
|
### Added
|
data/config/default.yml
CHANGED
|
@@ -363,3 +363,38 @@ Legion/Framework/NoShapeDuckTyping:
|
|
|
363
363
|
Severity: convention
|
|
364
364
|
VersionAdded: '0.1.8'
|
|
365
365
|
Safe: false
|
|
366
|
+
|
|
367
|
+
# Legion/Llm — cops specific to legion-llm and lex-llm-* provider pipelines
|
|
368
|
+
|
|
369
|
+
Legion/Llm:
|
|
370
|
+
Enabled: true
|
|
371
|
+
Include:
|
|
372
|
+
- 'lib/legion/llm/**/*.rb'
|
|
373
|
+
- 'lib/legion/extensions/llm/**/*.rb'
|
|
374
|
+
|
|
375
|
+
Legion/Llm/TaxonomyEnum:
|
|
376
|
+
Description: 'Validate :tier, :type, and :circuit_state literals against LegionIO taxonomy enums.'
|
|
377
|
+
Enabled: true
|
|
378
|
+
Severity: convention
|
|
379
|
+
VersionAdded: '0.1.9'
|
|
380
|
+
Include:
|
|
381
|
+
- 'lib/legion/llm/**/*.rb'
|
|
382
|
+
- 'lib/legion/extensions/llm/**/*.rb'
|
|
383
|
+
|
|
384
|
+
Legion/Llm/SettingsAccessPath:
|
|
385
|
+
Description: 'Use `Legion::Settings.dig(...)` instead of `Legion::Settings.loader.settings[...][...]`.'
|
|
386
|
+
Enabled: true
|
|
387
|
+
Severity: convention
|
|
388
|
+
VersionAdded: '0.1.9'
|
|
389
|
+
|
|
390
|
+
Legion/Llm/NoLoopDo:
|
|
391
|
+
Description: 'Ban `loop do` — use bounded iteration (`N.times`, `each`, or `while` with explicit bound).'
|
|
392
|
+
Enabled: true
|
|
393
|
+
Severity: warning
|
|
394
|
+
VersionAdded: '0.1.9'
|
|
395
|
+
|
|
396
|
+
Legion/Llm/RescueLogLevel:
|
|
397
|
+
Description: 'Minimum log level for `handle_exception` in rescue blocks is `:warn`.'
|
|
398
|
+
Enabled: true
|
|
399
|
+
Severity: warning
|
|
400
|
+
VersionAdded: '0.1.9'
|
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
|
8
8
|
# Flags `:tier`, `:type`, and `:circuit_state` literals that are not in
|
|
9
9
|
# the known-valid sets, catching typos at lint time.
|
|
10
10
|
#
|
|
11
|
+
# `:tier` and `:circuit_state` are domain-specific keys and are always
|
|
12
|
+
# validated. `:type` is only validated when it appears in a hash that
|
|
13
|
+
# also contains `:tier` or `:circuit_state`, since `:type` alone is too
|
|
14
|
+
# common in non-taxonomy contexts.
|
|
15
|
+
#
|
|
11
16
|
# Valid values (from Inventory::DEFAULT_PROVIDER_TIERS and the SSOT design):
|
|
12
17
|
# tier: :local, :fleet, :cloud, :frontier, :direct
|
|
13
18
|
# type: :inference, :embedding, :moderation, :rerank, :image
|
|
@@ -17,15 +22,24 @@ module RuboCop
|
|
|
17
22
|
# # bad (typo)
|
|
18
23
|
# { tier: :fronteir }
|
|
19
24
|
# health[:circuit_state] = :half_opened
|
|
25
|
+
# { tier: :cloud, type: :inferencing }
|
|
20
26
|
#
|
|
21
27
|
# # good
|
|
22
28
|
# { tier: :frontier }
|
|
23
29
|
# health[:circuit_state] = :half_open
|
|
30
|
+
# { tier: :cloud, type: :inference }
|
|
31
|
+
#
|
|
32
|
+
# # ignored (`:type` alone, no taxonomy context)
|
|
33
|
+
# { type: :string }
|
|
34
|
+
# { type: :integer }
|
|
24
35
|
class TaxonomyEnum < Base
|
|
25
36
|
VALID_TIERS = %i[local fleet cloud frontier direct].freeze
|
|
26
37
|
VALID_TYPES = %i[inference embedding moderation rerank image].freeze
|
|
27
38
|
VALID_CIRCUIT_STATES = %i[closed open half_open].freeze
|
|
28
39
|
|
|
40
|
+
TAXONOMY_KEYS = %i[tier type circuit_state].freeze
|
|
41
|
+
CONTEXT_KEYS = %i[tier circuit_state].freeze
|
|
42
|
+
|
|
29
43
|
MSG_TIER = 'Unknown tier `%<val>s`. Valid: %<valid>s.'
|
|
30
44
|
MSG_TYPE = 'Unknown type `%<val>s`. Valid: %<valid>s.'
|
|
31
45
|
MSG_CIRCUIT = 'Unknown circuit_state `%<val>s`. Valid: %<valid>s.'
|
|
@@ -38,7 +52,6 @@ module RuboCop
|
|
|
38
52
|
end
|
|
39
53
|
|
|
40
54
|
def on_send(node)
|
|
41
|
-
# health[:circuit_state] = :bad_value
|
|
42
55
|
return unless node.method_name == :[]=
|
|
43
56
|
return unless node.arguments.size == 2
|
|
44
57
|
|
|
@@ -54,22 +67,34 @@ module RuboCop
|
|
|
54
67
|
val = val_node.value
|
|
55
68
|
case key
|
|
56
69
|
when :tier
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
return if VALID_TIERS.include?(val)
|
|
71
|
+
|
|
72
|
+
add_offense(parent_node,
|
|
73
|
+
message: format(MSG_TIER, val: val, valid: VALID_TIERS.join(', ')))
|
|
61
74
|
when :type
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
return if VALID_TYPES.include?(val)
|
|
76
|
+
return unless taxonomy_context?(parent_node)
|
|
77
|
+
|
|
78
|
+
add_offense(parent_node,
|
|
79
|
+
message: format(MSG_TYPE, val: val, valid: VALID_TYPES.join(', ')))
|
|
66
80
|
when :circuit_state
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
return if VALID_CIRCUIT_STATES.include?(val)
|
|
82
|
+
|
|
83
|
+
add_offense(parent_node,
|
|
84
|
+
message: format(MSG_CIRCUIT, val: val, valid: VALID_CIRCUIT_STATES.join(', ')))
|
|
71
85
|
end
|
|
72
86
|
end
|
|
87
|
+
|
|
88
|
+
def taxonomy_context?(pair_node)
|
|
89
|
+
hash_node = pair_node.parent
|
|
90
|
+
return false unless hash_node&.hash_type?
|
|
91
|
+
|
|
92
|
+
sibling_keys = hash_node.pairs.filter_map do |pair|
|
|
93
|
+
pair.key.value if pair.key.sym_type?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
sibling_keys.intersect?(CONTEXT_KEYS)
|
|
97
|
+
end
|
|
73
98
|
end
|
|
74
99
|
end
|
|
75
100
|
end
|