fix(notifications): inject llm_backend into build_pipeline

build_pipeline previously constructed its own LLMBackend from
config.llm, which:
  - duplicated main.py's already-running backend instance
  - failed to inherit env-loaded LLM_API_KEY when called from
    short-lived scripts (eyeball checks, tests), forcing fallback
  - prevented pipeline components from sharing the live backend

build_pipeline and build_pipeline_components now require an
llm_backend parameter. main.py passes the same instance it
constructed for its primary responder. Tests pass mocks. The
digest accumulator now uses the live, authenticated backend.

Added test_build_pipeline_uses_provided_backend to lock in the
injection contract.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
K7ZVX 2026-05-15 03:08:31 +00:00
commit a4cb29002d
3 changed files with 47 additions and 40 deletions

View file

@ -50,6 +50,13 @@ class FailingLLMBackend:
raise RuntimeError("LLM unavailable")
def _make_mock_backend():
"""Create a standard mock LLM backend for tests."""
mock = MagicMock()
mock.generate = AsyncMock(return_value="stub summary")
return mock
# ============================================================
# ACCUMULATOR EVENT LOGGING TESTS
# ============================================================
@ -478,7 +485,7 @@ def test_pipeline_routes_event_to_accumulator():
"""Events via bus.emit end up in DigestAccumulator."""
config = Config()
bus, inhibitor, grouper, toggle_filter, dispatcher, accumulator = \
build_pipeline_components(config)
build_pipeline_components(config, _make_mock_backend())
event = make_event(
source="test",
@ -499,7 +506,7 @@ def test_pipeline_routes_immediate_to_both():
"""Immediate events go to both dispatcher and accumulator in Phase 2.4."""
config = Config()
bus, inhibitor, grouper, toggle_filter, dispatcher, accumulator = \
build_pipeline_components(config)
build_pipeline_components(config, _make_mock_backend())
event = make_event(
source="test",