feat(meta_ads): operator-specified canonical conversion event (#342)#345
Merged
Conversation
#340 made the Meta conversion counter count only a fixed deduped generic set ({lead, purchase, complete_registration}). That under-counts two account setups: a custom-event advertiser (offsite_conversion.custom.<id>, who reports 0 conversions), and an account that only emits a component row (offsite_conversion.fb_pixel_lead) with no generic aggregate. Let the operator declare, per Meta ad account, EXACTLY which action_type(s) count as conversions — overriding the default (replacement semantics; the listed types are the complete set, never summed on top of the generic set, so overlapping aliases can't double-count). Unset keeps the built-in default, so nothing changes for accounts that report it. - Storage: STATE.json platforms[<platform>].conversion_action_types (mureo/context/models.py PlatformState + state.py parse/serialize; preserved across upsert_campaign / set_platform_metrics like totals). - Setter: new MCP tool mureo_state_set_conversion_events (mureo/mcp/{tools,_handlers}_mureo_context.py). Empty list clears it. - Counter: count_conversions_from_actions(actions, conversion_action_types=...) — override replaces the default; an empty collection falls back to default so a cleared setting never zeroes every conversion. - Resolver: state.load_conversion_action_types(account_id) reads the ACTIVE workspace STATE.json via the runtime context (the SAME file the MCP tool writes — agency/alternate-StateStore safe), tolerant of the act_ prefix, and never raises (a malformed file yields None rather than breaking a live report). Threaded into ALL FIVE live Meta conversion counters so they apply the override consistently. - Skill: _mureo-meta-ads gains a "conversion definition" section telling the agent to look up the account's real action_type labels, confirm with the operator, then call the tool (avoids mistyped custom slugs). Mirrored to mureo/_data/skills/. - docs/mcp-server.md tool count 188 -> 189. Known follow-up (out of the declared five-site scope): the Protocol adapter's daily_report path (mureo/adapters/meta_ads/mappers.py) uses its own hardcoded conversion set and is not yet covered by the override. Reviewed by python-reviewer; fixed the read/write path mismatch, the never-raises contract on non-object JSON, the act_ prefix-match footgun, and a str char-split edge — each with a regression test. Closes #342 Claude-Session: https://claude.ai/code/session_011rAu94b1o1xWYZhARk1VmL
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 #340. The Meta conversion counter counts only a fixed deduped
generic set (
{lead, purchase, complete_registration}), which under-countstwo account setups:
event (
offsite_conversion.custom.<id>) reports 0 conversions, so CPAcan't compute and daily-check / budget decisions go wrong.
(
offsite_conversion.fb_pixel_lead) with no generic aggregate counts 0.This lets the operator declare, per Meta ad account, exactly which
action_type(s) count as conversions, overriding the default.Design
— never summed on top of the generic set, so overlapping aliases can't
double-count (preserves the bug(meta_ads): meta_row_conversions が action_type の部分一致でコンバージョンを過大計上(別名の重複+ViewContent混入) #340 fix). Unset → built-in default (no change
for accounts that report it). Empty → falls back to default (a cleared
setting never zeroes everything).
STATE.jsonplatforms[<platform>].conversion_action_types(preserved across
upsert_campaign/set_platform_metrics).mureo_state_set_conversion_events.load_conversion_action_types(account_id)reads the activeworkspace STATE.json via the runtime context (the same file the tool
writes — agency / alternate-
StateStoresafe), tolerant of theact_prefix, and never raises (a malformed file →
None, never breaks a livereport). Threaded into all five live Meta conversion counters
(
meta_row_conversions,_extract_cv,_insightsbreakdown,_budget_efficiency,_live_clientsaggregate/per-campaign,_summarise_meta_performance)._mureo-meta-adsgains a "conversion definition" section tellingthe agent to look up the account's real
action_typelabels (viameta_ads_insights_report/_breakdown), confirm with the operator, thenset the exact string(s) — so custom slugs aren't mistyped. No configure-UI
change (operator-via-agent flow, per design discussion).
Test plan
count_conversions_from_actionsoverride (replace / empty-fallback /component-only).
set_conversion_action_types+load_conversion_action_typesround-trip,clear, account mismatch, never-raises on malformed/non-object JSON,
act_prefix tolerance, preservation across upsert/metrics, parse↔render.the runtime context.
ruff+blackclean onmureo/;mypy --strictclean on changedmodules; 1336 relevant tests pass (only the known installed-plugin
env-gating noise excluded). Tool-count assertions + docs updated (188 → 189).
path mismatch, never-raises contract) + the
act_footgun + a str char-splitedge — each with a regression test.
Known follow-up (out of scope)
The Protocol adapter's
daily_reportpath (mureo/adapters/meta_ads/mappers.py)uses its own hardcoded conversion set and is not yet covered by the override.
Closes #342
https://claude.ai/code/session_011rAu94b1o1xWYZhARk1VmL