feat: decompose DataSyncService into RuntimeQueryService and TelemetryQueryService#334
feat: decompose DataSyncService into RuntimeQueryService and TelemetryQueryService#334NodeJSmith merged 9 commits intomainfrom
Conversation
…yQueryService (#267) Splits the monolithic DataSyncService into two focused services: - RuntimeQueryService: in-memory data layer for the web UI — event buffer, log buffer, app status snapshot, and WebSocket broadcast. No I/O on reads. - TelemetryQueryService: SQLite-backed historical telemetry — listener invocation counts, job execution counts, last error, last run. Served from real database queries via DatabaseService write queue. Other changes: - Set aiosqlite row_factory once at connection level in DatabaseService (eliminates per-method repetition) - Fix N+1 query pattern in bus_page using asyncio.gather with return_exceptions=True - Add session-scoped last_err subquery in get_listener_summary - Guard state_proxy.is_ready() call in get_system_status against AttributeError/RuntimeError during startup - Update FastAPI DI aliases: RuntimeDep, TelemetryDep replace DataSyncDep - Remove DataSyncService, DataSyncDep, and related stubs from test_utils - Update TESTING.md, web_mocks.py, and all integration test fixtures
There was a problem hiding this comment.
Pull request overview
This PR decomposes the former DataSyncService web-facing facade into two services: RuntimeQueryService for live in-memory UI/API state and TelemetryQueryService for SQLite-backed historical telemetry, and migrates the web layer/tests to the new DI aliases.
Changes:
- Introduces
RuntimeQueryServiceandTelemetryQueryService, wiring both intoHassetteand updatingDatabaseServiceto useaiosqlite.Row. - Migrates FastAPI routes, UI routers/partials, templates, and test helpers from
DataSyncDep/data_sync_servicetoRuntimeDep/TelemetryDep/SchedulerDep. - Adds integration tests for
TelemetryQueryServicewith a real SQLite database and updates/renames unit/integration/e2e tests accordingly.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/core/test_web_ui_watcher.py | Updates watcher tests to use runtime_query_service broadcast. |
| tests/unit/core/test_runtime_query_service.py | Adds unit coverage for RuntimeQueryService behaviors (logs/events/ws/system status). |
| tests/unit/core/test_data_sync_service.py | Removes obsolete DataSyncService unit tests. |
| tests/integration/test_ws_endpoint.py | Updates WS integration tests to target RuntimeQueryService. |
| tests/integration/test_web_ui_watcher.py | Updates integration watcher tests to use runtime_query_service. |
| tests/integration/test_web_ui.py | Updates UI integration tests and log patch targets; adjusts bus-listener expectations for new deps. |
| tests/integration/test_web_api.py | Updates API integration tests to use RuntimeQueryService and adjusts bus-related expectations. |
| tests/integration/test_telemetry_query_service.py | Adds integration tests validating SQL-backed telemetry queries against SQLite. |
| tests/integration/test_database_service.py | Updates assertions to account for aiosqlite.Row row_factory behavior. |
| tests/integration/test_core.py | Updates core wiring assertions for new services. |
| tests/integration/conftest.py | Renames fixture to runtime_query_service and updates FastAPI app fixture wiring. |
| tests/e2e/conftest.py | Updates e2e wiring to RuntimeQueryService and stubs telemetry returns in new dict format. |
| tests/TESTING.md | Updates docs for new test helpers (create_mock_runtime_query_service) and DI split. |
| src/hassette/web/ui/router.py | Migrates full-page UI routes to new deps; introduces job serialization helper and telemetry-driven bus/app pages. |
| src/hassette/web/ui/partials.py | Migrates HTMX partials to RuntimeDep/TelemetryDep/SchedulerDep; updates scheduler/bus partial parameter shapes. |
| src/hassette/web/ui/context.py | Updates alert context helper to accept RuntimeQueryService. |
| src/hassette/web/templates/partials/scheduler_jobs.html | Updates scheduler job owner links to derive from app_key/instance_index fields. |
| src/hassette/web/templates/partials/scheduler_history.html | Updates scheduler history owner links to use app_key/instance_index when present. |
| src/hassette/web/templates/partials/bus_listeners.html | Updates bus listener template to use telemetry schema fields (handler_method, app_key). |
| src/hassette/web/templates/partials/app_detail_listeners.html | Removes instance-owner map rendering (template partially migrated). |
| src/hassette/web/templates/partials/app_detail_jobs.html | Removes instance-owner map rendering (template partially migrated). |
| src/hassette/web/routes/ws.py | Switches WS endpoint to register clients on runtime_query_service. |
| src/hassette/web/routes/scheduler.py | Migrates scheduler routes to new deps and serializes scheduled jobs. |
| src/hassette/web/routes/logs.py | Switches logs API route to RuntimeDep. |
| src/hassette/web/routes/health.py | Switches health API route to RuntimeDep. |
| src/hassette/web/routes/events.py | Switches events API route to RuntimeDep. |
| src/hassette/web/routes/entities.py | Removes entity endpoints. |
| src/hassette/web/routes/bus.py | Migrates bus routes to TelemetryDep and changes query parameter contract. |
| src/hassette/web/routes/apps.py | Switches apps API routes to RuntimeDep. |
| src/hassette/web/dependencies.py | Replaces DataSyncDep with RuntimeDep/TelemetryDep/SchedulerDep. |
| src/hassette/web/app.py | Removes entities router registration. |
| src/hassette/web/CLAUDE.md | Updates web-layer contributor docs for new DI aliases and responsibilities. |
| src/hassette/test_utils/web_mocks.py | Renames mock factory to create_mock_runtime_query_service and stubs telemetry methods. |
| src/hassette/test_utils/web_helpers.py | Updates job fixture helper to use real trigger types for _job_to_dict isinstance checks. |
| src/hassette/test_utils/init.py | Re-exports updated test helper names. |
| src/hassette/logging_.py | Updates docs/comments referring to RuntimeQueryService instead of DataSyncService. |
| src/hassette/core/web_ui_watcher.py | Broadcasts dev-reload via runtime_query_service. |
| src/hassette/core/web_api_service.py | Waits for RuntimeQueryService readiness instead of DataSyncService. |
| src/hassette/core/telemetry_query_service.py | Implements SQLite-backed telemetry queries (listeners/jobs/errors/sessions). |
| src/hassette/core/scheduler_service.py | Removes deprecated execution-history stub. |
| src/hassette/core/runtime_query_service.py | Introduces renamed/slimmed runtime query service (drops telemetry/entity concerns). |
| src/hassette/core/database_service.py | Sets SQLite connection row_factory to aiosqlite.Row. |
| src/hassette/core/core.py | Wires RuntimeQueryService and TelemetryQueryService into the core and exposes properties. |
| src/hassette/core/bus_service.py | Removes deprecated listener-metrics stub methods. |
| src/hassette/config/config.py | Updates config docstring to refer to RuntimeQueryService buffer. |
| design/specs/004-decompose-datasyncservice/tasks/WP02.md | Adds completed work package record for telemetry SQL + tests. |
| design/specs/004-decompose-datasyncservice/tasks/WP01b.md | Adds completed work package record for web-layer migration and template updates. |
| design/specs/004-decompose-datasyncservice/tasks/WP01.md | Adds completed work package record for core service split. |
| design/specs/004-decompose-datasyncservice/spec.md | Adds feature spec skeleton. |
| design/specs/004-decompose-datasyncservice/design.md | Adds design document capturing goals, architecture, and migration plan. |
| CHANGELOG.md | Documents addition of the two new services and DB-backed telemetry. |
Comments suppressed due to low confidence (1)
src/hassette/web/routes/scheduler.py:63
/scheduler/historydeclaresresponse_model=list[JobExecutionResponse], but returnsTelemetryQueryService.get_job_summary()rows (aggregate job summaries) which do not include required execution fields (started_at,duration_ms,status, etc.). This will cause response validation errors once real telemetry is returned. Return per-execution rows (or change the response model + endpoint semantics).
@router.get("/scheduler/history", response_model=list[JobExecutionResponse])
async def get_job_history(
telemetry: TelemetryDep,
limit: Annotated[int, Query(ge=1, le=1000)] = 50, # noqa: ARG001
app_key: Annotated[str | None, Query()] = None,
instance_index: Annotated[int, Query()] = 0,
) -> list[dict]:
if app_key is None:
return []
return await telemetry.get_job_summary(app_key=app_key, instance_index=instance_index)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #334 +/- ##
==========================================
- Coverage 80.15% 80.03% -0.13%
==========================================
Files 140 141 +1
Lines 9969 10034 +65
Branches 981 985 +4
==========================================
+ Hits 7991 8031 +40
- Misses 1583 1608 +25
Partials 395 395 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR completes the split of the former DataSyncService responsibilities into two focused services: RuntimeQueryService (live/in-memory UI state + WS broadcasting) and TelemetryQueryService (SQLite-backed historical telemetry queries). It updates the FastAPI + UI layers to use the new dependency injection aliases and adds real SQL-backed telemetry queries with integration tests.
Changes:
- Replaces
DataSyncServiceusage across core/web/tests withRuntimeQueryService+ new DI aliases (RuntimeDep,TelemetryDep,SchedulerDep). - Implements
TelemetryQueryServicewith real SQL queries and adds end-to-end integration tests against SQLite. - Adjusts DB initialization to set
row_factoryonce at connection time and updates affected tests.
Reviewed changes
Copilot reviewed 52 out of 52 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/core/test_web_ui_watcher.py | Updates watcher tests to use runtime_query_service.broadcast. |
| tests/unit/core/test_runtime_query_service.py | Adds unit coverage for RuntimeQueryService (events/logs/system status/WS). |
| tests/unit/core/test_data_sync_service.py | Removes old DataSyncService unit tests (service deleted/renamed). |
| tests/integration/test_ws_endpoint.py | Migrates WS endpoint tests to RuntimeQueryService. |
| tests/integration/test_web_ui_watcher.py | Migrates integration watcher tests to RuntimeQueryService. |
| tests/integration/test_web_ui.py | Updates UI integration tests for new DI + removes listener-metric expectations that depended on old stubs. |
| tests/integration/test_web_api.py | Updates API integration tests for new DI; removes entity + old bus metric assertions. |
| tests/integration/test_telemetry_query_service.py | Adds SQLite integration tests covering all telemetry query methods. |
| tests/integration/test_database_service.py | Updates assertions to match aiosqlite.Row row factory behavior. |
| tests/integration/test_core.py | Updates constructor wiring expectations for new services. |
| tests/integration/conftest.py | Renames shared fixture to runtime_query_service and updates app wiring. |
| tests/e2e/conftest.py | Updates e2e wiring/patches for runtime + telemetry stubs. |
| tests/TESTING.md | Updates testing docs to reference runtime mocks instead of data-sync mocks. |
| src/hassette/web/ui/router.py | Migrates full-page UI routes to new deps; uses telemetry for bus/app listener data. |
| src/hassette/web/ui/partials.py | Migrates HTMX partial routes to new deps; routes now call telemetry/scheduler/runtime services. |
| src/hassette/web/ui/context.py | Updates alert_context to accept RuntimeQueryService. |
| src/hassette/web/templates/partials/scheduler_jobs.html | Switches link strategy to app_key/instance_index-based fields. |
| src/hassette/web/templates/partials/scheduler_history.html | Switches owner link strategy to app_key/instance_index-based fields. |
| src/hassette/web/templates/partials/bus_listeners.html | Updates template to render telemetry-format listener rows. |
| src/hassette/web/templates/partials/app_detail_listeners.html | Removes instance-owner-map column/logic. |
| src/hassette/web/templates/partials/app_detail_jobs.html | Removes instance-owner-map column/logic. |
| src/hassette/web/routes/ws.py | Uses runtime_query_service for WS registration + system status. |
| src/hassette/web/routes/scheduler.py | Reworks scheduler endpoints to use scheduler + telemetry deps. |
| src/hassette/web/routes/logs.py | Reworks logs endpoint to use RuntimeDep. |
| src/hassette/web/routes/health.py | Reworks health endpoint to use RuntimeDep. |
| src/hassette/web/routes/events.py | Reworks events endpoint to use RuntimeDep. |
| src/hassette/web/routes/entities.py | Deletes entity endpoints (no longer supported). |
| src/hassette/web/routes/bus.py | Reworks bus endpoints to use TelemetryDep and removes old in-memory summary behavior. |
| src/hassette/web/routes/apps.py | Reworks apps endpoints to use RuntimeDep. |
| src/hassette/web/dependencies.py | Replaces DataSyncDep with RuntimeDep/TelemetryDep/SchedulerDep. |
| src/hassette/web/app.py | Removes entities router registration. |
| src/hassette/web/CLAUDE.md | Updates web-layer guidance to reference new dependency aliases. |
| src/hassette/test_utils/web_mocks.py | Renames mock factory to create_mock_runtime_query_service and wires telemetry stubs. |
| src/hassette/test_utils/web_helpers.py | Updates scheduler job fixture helper to use real trigger classes. |
| src/hassette/test_utils/init.py | Re-exports updated mock factory name. |
| src/hassette/state_manager/state_manager.pyi | Adjusts DomainStates iterator typing. |
| src/hassette/logging_.py | Updates comments referencing runtime service as broadcaster. |
| src/hassette/core/web_ui_watcher.py | Broadcasts dev-reload events via runtime_query_service. |
| src/hassette/core/web_api_service.py | Waits on runtime service readiness (instead of data sync). |
| src/hassette/core/telemetry_query_service.py | Adds real SQL-backed telemetry query service implementation. |
| src/hassette/core/scheduler_service.py | Removes stub execution-history method. |
| src/hassette/core/runtime_query_service.py | Renames/slims service to runtime-only functionality. |
| src/hassette/core/database_service.py | Sets SQLite row_factory at connect time. |
| src/hassette/core/core.py | Wires in new runtime + telemetry query services and removes data sync service. |
| src/hassette/core/bus_service.py | Removes stub listener-metrics accessors. |
| src/hassette/config/config.py | Updates config docs to refer to runtime event buffer. |
| design/specs/004-decompose-datasyncservice/tasks/WP02.md | Adds completed work package documentation for telemetry queries + tests. |
| design/specs/004-decompose-datasyncservice/tasks/WP01b.md | Adds completed work package documentation for web layer migration. |
| design/specs/004-decompose-datasyncservice/tasks/WP01.md | Adds completed work package documentation for core service split. |
| design/specs/004-decompose-datasyncservice/spec.md | Adds initial spec scaffold. |
| design/specs/004-decompose-datasyncservice/design.md | Adds design doc describing split + migration plan. |
| CHANGELOG.md | Documents the addition of runtime + telemetry services. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
…rialization - Fix `app_detail_listeners.html` using `l.handler_name` → `l.handler_method` - Rename `ListenerMetrics.handler_name` → `handler_method` (field + `to_dict()`) and `ListenerMetricsResponse.handler_name` → `handler_method` for consistency with DB column - Add `l.id AS listener_id`, `l.app_key`, `l.instance_index` to `get_listener_summary()` SELECT so templates and the Pydantic model have the correct field names - Replace `telemetry.get_job_summary()` calls in partials with live scheduler jobs (`scheduler_jobs_partial`, `app_detail_jobs_partial`, `instance_jobs_partial`) — the template expects live fields (name, next_run, cancelled) not historical aggregates - `scheduler_history_partial` stubs with `[]` until per-execution query is available - Extract `resolve_trigger()` into `web/utils.py` (neutral layer) and `job_to_dict()` into `web/ui/context.py`, eliminating the three duplicate `_job_to_dict` copies across `ui/router.py`, `ui/partials.py`, and `routes/scheduler.py` - Fix test teardown: `db.close()` → `db_service.on_shutdown()` to drain write queue - Update `make_listener_metric`, `test_metrics.py`, and `tests/TESTING.md` to use `handler_method` throughout
- Fix e2e conftest lambda to use `**_` instead of positional `_idx`/`_sid`, preventing TypeError when `get_listener_summary` is called with keyword args - Fix job filter in `app_detail_page` and `app_instance_detail_page` to compare `j.owner == instance.owner_id` instead of `j.owner == app_key`; jobs now appear correctly in the app detail view - Add `app_keys` context to scheduler and bus pages; rename filter `name="owner"` → `name="app_key"` so HTMX requests match the partial endpoints - Replace `owner: str` with `app_key: str` + `instance_index: int = 0` in `ListenerMetricsResponse`, matching the shape `TelemetryQueryService` produces - Add COALESCE defaults to duration aggregates in `get_listener_summary` and `get_job_summary` so NULL durations don't fail Pydantic validation - Stub `get_job_history` to return `[]` unconditionally; `get_job_summary` returns per-job aggregates incompatible with `JobExecutionResponse` - Fix `is defined` Jinja2 guards in scheduler_jobs, bus_listeners, and scheduler_history partials to use truthiness checks - Update `make_listener_metric` factory to use `app_key`/`instance_index` instead of `owner`, aligning with production data contract - Add TODO comments to three known-broken `j.owner == app_key` filters in `partials.py` (deferred to follow-up owner_id cleanup issue) - Fix `DomainStates.__iter__` stub to use 3-param `Generator` type
There was a problem hiding this comment.
Pull request overview
This PR completes the DataSyncService decomposition by introducing two focused services: RuntimeQueryService (in-memory/live UI state + WS broadcast) and TelemetryQueryService (SQLite-backed historical telemetry). It updates the web layer DI, routes, templates, and test infrastructure accordingly, and implements real SQL telemetry queries with integration coverage.
Changes:
- Replace
DataSyncServiceusage withRuntimeQueryService+TelemetryQueryServiceacross core + web DI, routes, and templates. - Implement real SQLite queries in
TelemetryQueryServiceand add integration tests validating all query methods. - Clean up related plumbing: remove old entity routes, update listener metrics naming (
handler_method), and set SQLiterow_factoryonce on connect.
Reviewed changes
Copilot reviewed 57 out of 57 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/core/test_web_ui_watcher.py | Updates watcher tests to use runtime_query_service.broadcast. |
| tests/unit/core/test_runtime_query_service.py | New unit tests covering RuntimeQueryService retained behaviors. |
| tests/unit/core/test_data_sync_service.py | Removes DataSyncService unit tests (service deleted/superseded). |
| tests/unit/bus/test_metrics.py | Renames handler_name → handler_method in listener metrics tests. |
| tests/integration/test_ws_endpoint.py | Updates WS integration tests to use RuntimeQueryService. |
| tests/integration/test_web_ui_watcher.py | Updates integration watcher tests to use runtime_query_service.broadcast. |
| tests/integration/test_web_ui.py | Updates UI integration tests for new deps and stubbed telemetry behavior. |
| tests/integration/test_web_api.py | Updates API integration tests for new deps and changed bus/scheduler expectations. |
| tests/integration/test_telemetry_query_service.py | New integration tests validating TelemetryQueryService SQL against real SQLite. |
| tests/integration/test_database_service.py | Updates assertions to work with aiosqlite.Row row_factory. |
| tests/integration/test_core.py | Updates core wiring expectations for new services. |
| tests/integration/conftest.py | Switches shared fixture from data_sync_service to runtime_query_service. |
| tests/e2e/conftest.py | Updates e2e stubs/mocks to new runtime/telemetry services and listener dict format. |
| tests/TESTING.md | Updates testing docs to reference new mock helpers and names. |
| src/hassette/web/utils.py | Adds shared trigger serialization helper (resolve_trigger). |
| src/hassette/web/ui/router.py | Migrates UI pages to RuntimeDep/TelemetryDep/SchedulerDep; parallelizes telemetry fetch for bus page. |
| src/hassette/web/ui/partials.py | Migrates HTMX partials to new deps; stubs out some telemetry/scheduler history paths. |
| src/hassette/web/ui/context.py | Updates alert_context to runtime service; adds job_to_dict for templates. |
| src/hassette/web/templates/partials/scheduler_jobs.html | Switches job link rendering to app_key/instance_index fields. |
| src/hassette/web/templates/partials/scheduler_history.html | Switches history link rendering to app_key/instance_index fields. |
| src/hassette/web/templates/partials/bus_listeners.html | Switches listener rendering to handler_method + app_key/instance_index. |
| src/hassette/web/templates/partials/app_detail_listeners.html | Updates listener table to use handler_method and drops owner-map columns. |
| src/hassette/web/templates/partials/app_detail_jobs.html | Drops owner-map columns and relies on serialized job fields. |
| src/hassette/web/templates/pages/scheduler.html | Updates scheduler filter dropdown to pass app_key. |
| src/hassette/web/templates/pages/bus.html | Updates bus filter dropdown to pass app_key. |
| src/hassette/web/routes/ws.py | Switches WS endpoint to runtime_query_service. |
| src/hassette/web/routes/scheduler.py | Reworks scheduler endpoints to query SchedulerService directly; stubs history. |
| src/hassette/web/routes/logs.py | Switches logs endpoint to RuntimeDep. |
| src/hassette/web/routes/health.py | Switches health endpoint to RuntimeDep. |
| src/hassette/web/routes/events.py | Switches events endpoint to RuntimeDep. |
| src/hassette/web/routes/entities.py | Removes entity routes entirely. |
| src/hassette/web/routes/bus.py | Reworks bus endpoints to use TelemetryDep; stubs metrics summary. |
| src/hassette/web/routes/apps.py | Switches apps endpoints to RuntimeDep. |
| src/hassette/web/models.py | Updates listener response schema to app_key/instance_index + handler_method. |
| src/hassette/web/dependencies.py | Replaces DataSyncDep with RuntimeDep/TelemetryDep/SchedulerDep. |
| src/hassette/web/app.py | Removes entities router registration. |
| src/hassette/web/CLAUDE.md | Updates web-layer guidance to new dependency aliases. |
| src/hassette/test_utils/web_mocks.py | Renames mock factory to create_mock_runtime_query_service; wires telemetry stubs. |
| src/hassette/test_utils/web_helpers.py | Updates listener metric helper signature; uses real trigger objects in job fixtures. |
| src/hassette/test_utils/init.py | Re-exports updated mock helper names. |
| src/hassette/logging_.py | Updates documentation/comments to reference RuntimeQueryService. |
| src/hassette/core/web_ui_watcher.py | Broadcasts dev reload via runtime_query_service. |
| src/hassette/core/web_api_service.py | Waits on RuntimeQueryService readiness instead of DataSync. |
| src/hassette/core/telemetry_query_service.py | Adds DB-backed telemetry query service with real SQL implementations. |
| src/hassette/core/scheduler_service.py | Removes stubbed execution history accessor. |
| src/hassette/core/runtime_query_service.py | Renames/slims runtime UI aggregation service; adds readiness guards. |
| src/hassette/core/database_service.py | Sets aiosqlite.Row row_factory once on connect. |
| src/hassette/core/core.py | Wires new services as children and exposes new properties. |
| src/hassette/core/bus_service.py | Removes stubbed in-memory listener metrics accessors. |
| src/hassette/config/config.py | Updates docstring to reference RuntimeQueryService. |
| src/hassette/bus/metrics.py | Renames handler_name → handler_method in metrics dataclass + serialization. |
| design/specs/004-decompose-datasyncservice/tasks/WP02.md | Adds completed work package notes for telemetry query implementation/tests. |
| design/specs/004-decompose-datasyncservice/tasks/WP01b.md | Adds completed work package notes for web DI/template migration. |
| design/specs/004-decompose-datasyncservice/tasks/WP01.md | Adds completed work package notes for initial service split and cleanup. |
| design/specs/004-decompose-datasyncservice/spec.md | Introduces spec scaffold for the feature. |
| design/specs/004-decompose-datasyncservice/design.md | Adds the design doc capturing architecture and migration plan. |
| CHANGELOG.md | Documents the service split and related web/telemetry changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- get_job_summary: add `sj.id AS job_id`, `sj.app_key`, `sj.instance_index` to SELECT list for consistency with get_listener_summary (#334) - bus_page: log BaseException results from asyncio.gather at WARNING instead of silently dropping them (#334) - tests: assert job_id, app_key, instance_index in get_job_summary results
…uler - Fix di_failures counter: change SQL '= DependencyError' to 'LIKE Dependency%' to match actual subclass names (DependencyInjectionError, DependencyResolutionError) - Fix empty-string app_key handling: change 'is not None' to truthiness checks in partials.py and routes/scheduler.py so 'All Apps' dropdown works correctly - Fix bus_listeners_partial and /api/bus/listeners returning [] when unfiltered: enumerate all app instances via gather pattern instead of returning empty list - Extract gather_all_listeners() to web/utils.py, shared by bus_page, bus listeners partial, and bus listeners API endpoint
Summary
DataSyncServiceintoRuntimeQueryService(in-memory web UI state) andTelemetryQueryService(SQLite-backed historical telemetry), resolving the mixed-responsibility design that blocked real telemetry from reaching the UITelemetryQueryServiceserves real listener/job telemetry from the database — invocation counts, execution counts, last error, last run — replacing the stubTODOmethods that previously returned empty listsrow_factoryset per-method instead of once at connection level, unguardedstate_proxy.is_ready()calls, and unused FastAPI DI parameters throughout the web routes