correlation: rules decide, one cheap LLM call only when ambiguous; drop the consensus tiebreak (server-26#299)
The rules engine now commits every confident decision alone. _run_decision marks a decision ambiguous (new_with_candidates, unfit_tg_candidate, unverified_unit_link) and only then does upload._correlate make ONE llm_correlator.decide call; a usable answer is committed, otherwise the rules decision stands. Removed: _correlate_with_consensus, llm_correlator.tiebreak / decisions_agree / tiebreak prompt, corr_smart_model, the correlation_smart health tier, the LLM-orphan gate (_call_is_substanceless, effectively dead: it could only fire on minor-severity untyped calls) and its sweep budget. corr_consensus is now rules_only | llm | rules_fallback | rules_guard, with corr_band naming why; admin debug and replay metrics read the new values. Section fixes in the same pass: - #115: no tiebreaker left to manufacture incidents; an LLM orphan of a rules "new" is honoured only for untyped, substanceless, routine/minor calls. - #86: divergence veto bar moved to config (embedding_divergence_threshold); the band between it and the match bar is ambiguous, not a silent merge. - #103: a unit link with no embedding is "unit_overlap_unverified" -> ambiguous, instead of skipping the veto and linking as verified. - #189: unit-only and LLM links refused once an incident is open 90 min; unit links on incidents open >30 min are ambiguous; LLM links distance- guarded (incident_max_spread_km) and only to shown candidates. - #190: severity steps down on an explicit stand-down phrase; new severity_peak keeps the monotonic max. - #88: parse_llm_bool fails closed on "false"; scene closures honoured only on confident links or the incident the scene opened. - #27: sweep budget is the scan window (wall clock), not 3 attempts. - LLM prompt: "Reserve new" bullet no longer contradicts the #189 EXCEPT. - updated_at never moves backward on a back-dated link. Unmeasured: no live AI or replay (credits unfunded); band frequency, F1 and thresholds are unverified. Must be re-scored on both answer keys in Replay before merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f4d78aba77
commit
3246fc97b0
@@ -136,15 +136,15 @@ async def test_transient_failure_alerts_once_threshold_crossed():
|
||||
async def test_recovery_alerts_once_after_an_alerted_episode():
|
||||
with patch.object(ai_health, "_post_webhook", new=AsyncMock()) as webhook:
|
||||
await ai_health.report_degraded(
|
||||
"correlation_smart", "gemini", "gemini-1.5-pro",
|
||||
"correlation_cheap", "gemini", "gemini-3.6-flash",
|
||||
"the Gemini account is out of credit", "top up billing", permanent=True,
|
||||
)
|
||||
webhook.reset_mock()
|
||||
|
||||
await ai_health.report_healthy("correlation_smart")
|
||||
await ai_health.report_healthy("correlation_cheap")
|
||||
|
||||
webhook.assert_awaited_once()
|
||||
state = ai_health.snapshot()["correlation_smart"]
|
||||
state = ai_health.snapshot()["correlation_cheap"]
|
||||
assert state["degraded"] is False
|
||||
assert state["alerted"] is False
|
||||
assert state["consecutive_failures"] == 0
|
||||
|
||||
Reference in New Issue
Block a user