You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
negative_context/core.py defines _SIGNAL_CATEGORY, a SignalType -> NegativeContextCategory map. It reads as the authoritative place where a signal's negative-context category is declared. It is not.
The map has exactly two readers:
core.py:103 — _policy_uncovered_signal_types(), which uses only .keys() as a signal inventory, never the values
generators.py:1236 — _gen_fallback(), the generic generator for signals without a dedicated generator:
Every one of the 24 dedicated generators hardcodes its own category instead:
@_register(SignalType.PHANTOM_REFERENCE)def_gen_phr(finding: Finding) ->list[NegativeContext]:
return [NegativeContext(
category=NegativeContextCategory.AI_QUALITY, # <- the value that actually ships
...
The measurable consequence
entries in _SIGNAL_CATEGORY : 24
of those, with own generator: 24 -> dead for output
reachable via _gen_fallback : 0
@_register(...) count is 24 and category=NegativeContextCategory. count in generators.py is also 24 — one per generator. So the map's values never reach the output at all. A signal only reaches _gen_fallback if it has no registered generator, and all 24 mapped signals have one. The .get() on line 1236 can therefore only ever return its default, ARCHITECTURE.
Why it matters
Two sources of truth, one of which is silently inert:
Changing a category in _SIGNAL_CATEGORY alone has no effect on output — a plausible and undetectable mistake.
Tests that assert on the map look behavioural but are not. fix: classify phantom references under AI quality #754 added test_phantom_reference_uses_ai_quality_category, which asserts _SIGNAL_CATEGORY[PHANTOM_REFERENCE] == AI_QUALITY. It passes whether or not the generator agrees. The real guard in that PR is test_phr_finding_generates_ai_quality_item.
A — Make the map authoritative: drop the hardcoded category= from all 24 generators and have the NegativeContext construction read _SIGNAL_CATEGORY. Removes the duplication; one place to change.
B — Make the generators authoritative: rename the map to something honest about its only real use (a signal inventory for the policy-coverage check) and drop its values entirely.
C — Keep both, add a consistency guard asserting every registered generator's emitted category equals _SIGNAL_CATEGORY[signal]. Cheapest, keeps the redundancy but makes drift impossible.
A is the smallest surface long-term; C is the smallest change now.
Notes
Found while reviewing #754. No user-visible bug today — the two sources currently agree for every signal. This is about preventing a silent divergence, and about tests that assert on something inert.
Problem
negative_context/core.pydefines_SIGNAL_CATEGORY, aSignalType -> NegativeContextCategorymap. It reads as the authoritative place where a signal's negative-context category is declared. It is not.The map has exactly two readers:
core.py:103—_policy_uncovered_signal_types(), which uses only.keys()as a signal inventory, never the valuesgenerators.py:1236—_gen_fallback(), the generic generator for signals without a dedicated generator:Every one of the 24 dedicated generators hardcodes its own category instead:
The measurable consequence
@_register(...)count is 24 andcategory=NegativeContextCategory.count ingenerators.pyis also 24 — one per generator. So the map's values never reach the output at all. A signal only reaches_gen_fallbackif it has no registered generator, and all 24 mapped signals have one. The.get()on line 1236 can therefore only ever return its default,ARCHITECTURE.Why it matters
Two sources of truth, one of which is silently inert:
_SIGNAL_CATEGORYalone has no effect on output — a plausible and undetectable mistake.test_phantom_reference_uses_ai_quality_category, which asserts_SIGNAL_CATEGORY[PHANTOM_REFERENCE] == AI_QUALITY. It passes whether or not the generator agrees. The real guard in that PR istest_phr_finding_generates_ai_quality_item.COMPLETENESSwhilesignal_registry.pyfiled PHR underai_quality.Options
category=from all 24 generators and have theNegativeContextconstruction read_SIGNAL_CATEGORY. Removes the duplication; one place to change._SIGNAL_CATEGORY[signal]. Cheapest, keeps the redundancy but makes drift impossible.A is the smallest surface long-term; C is the smallest change now.
Notes
Found while reviewing #754. No user-visible bug today — the two sources currently agree for every signal. This is about preventing a silent divergence, and about tests that assert on something inert.