feat(analytics): wire built-in google_ads/meta_ads adapters to live clients (#120)#138
Merged
Merged
Conversation
467f2df to
895bacb
Compare
… clients (#120) Follow-up to the analytics-module Protocol PR. The built-in adapters were registered with capability advertisements but their `detect_anomalies` returned `()` and `diagnose_performance` returned a stub headline. This PR wires them to the real Google Ads / Meta Ads clients via a new lazy-import fetcher layer. New: `mureo/analytics/builtin/_live_clients.py` - `fetch_google_ads_metrics` / `fetch_meta_ads_metrics` — fetch the trailing-window + baseline performance reports, aggregate to account-level `CampaignMetrics`, feed the pure anomaly detector. - `fetch_google_ads_performance_rows` / `fetch_meta_ads_performance_rows` — same fetcher shape for `diagnose_performance`. - `_open_*_client` helpers centralise creds + BYOD routing; the factory layer (`mureo/mcp/_client_factory.py`) already chooses live vs BYOD so the fetcher delegates rather than duplicating the check. - `NoCredentialsError` raised uniformly in live mode when creds are missing. Adapter changes (`google_ads.py`, `meta_ads.py`): - `detect_anomalies` defaults to the live fetcher; catches `NoCredentialsError` and returns an empty tuple (config error, not an anomaly). - `diagnose_performance` defaults to the live performance-rows fetcher; catches `NoCredentialsError` and renders a sentinel `PerformanceDiagnosis` with a credentials-specific headline so the workflow can branch uniformly across both methods. - Meta `diagnose_performance` adds a `_detect_cv_definition_mismatch` finding when an account mixes click-style and conversion-style result indicators across campaigns — preview of the deep CV-mismatch analysis surfaced by `meta_ads_insights_report`. - `PerformanceFetcher` type alias deduped to `_common.py`. Tests (45 new): - `test_live_clients.py` — aggregation helpers, missing-creds raises, BYOD routing, sentinel rendering, plus a regression test pinning the Phase-1 known limitation (account-level aggregation can mask per-campaign anomalies). - `test_diagnose_performance.py` — pure summariser shapes, CV-mismatch classifier precedence, adapter delegation through injected fetchers, sentinel headline on missing creds. Coverage: 97.1% on `mureo/analytics/*`. Zero regressions vs the prior branch. Lint clean. Code-review findings addressed: HIGH (mock patch-site documentation, dead `except NoCredentialsError`, asymmetric missing-creds semantics), MEDIUM (duplicate `PerformanceFetcher` alias, redundant `byod_has` check at fetcher layer, known-limitation regression test). Refs #120
895bacb to
d128bb2
Compare
hyoshi
added a commit
that referenced
this pull request
May 23, 2026
…atforms (#120) (#142) Bump version across pyproject.toml / mureo/__init__.py / .claude-plugin/plugin.json and add the 0.9.9 CHANGELOG entry summarising the five PRs that shipped the analytics-module work (#137, #138, #139, #140, #141). Headline: - opt-in `AnalyticsModule` Protocol + registry + entry-point group `mureo.analytics`, so external-integration platforms (official MCPs and third-party plugins) can plug into mureo's deep analytics on the same terms as the built-in adapters - built-in google_ads / meta_ads adapters wired against live + BYOD clients with sentinel handling for missing credentials - per-campaign fan-out for `detect_anomalies`, full implementations of `audit_creative` and `analyze_budget_efficiency`, and DEEP scope drilldown for `diagnose_performance` - 10 row-shape TypedDicts re-exported from `mureo.analytics` for plugin-side typing - skill prompts (daily-check, rescue, _mureo-shared) consult the new `mureo_analytics_modules_list` MCP tool and report `analytics_not_available_for_<platform>` honestly when a module is absent Refs #120
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the protocol/registry PR. The built-in
google_ads/meta_adsadapters previously returned empty tuples / stub headlines; this PR wires them to the real platform clients via a lazy-import fetcher layer.Also fixes a silent-zero bug discovered during end-to-end validation: the aggregators assumed the live row shape (metrics nested under
row["metrics"]for Google, conversions inrow["actions"]for Meta) but BYOD clients return flat shapes — silently producingcost=0/conversions=0in BYOD mode.What ships
mureo/analytics/builtin/_live_clients.py—fetch_*_metrics/fetch_*_performance_rows, lazy auth lookup, BYOD-routing via the existing_client_factory, uniformNoCredentialsErrordetect_anomalies+diagnose_performancenow run against live (or BYOD) data; missing creds rendered as sentinelPerformanceDiagnosis("credentials not configured"); type-safe shape-tolerance helpersValidated post-fix against the local BYOD bundle:
google_ads: 4 campaigns, spend 4,256,000, CV 478.4, CPA 8,895meta_ads: 4 campaigns, spend 854,000, CV 306.6, CPA 2,785Test plan
except NoCredentialsError/ asymmetric missing-creds) + MEDIUM (dedupePerformanceFetcher, redundantbyod_has, known-limit regression) addressedmainStacked on #PR1 (
feat/analytics-module-protocol-120).Refs #120