- Fix GoogleCampaignID matching with comma delimiters (exact word boundary)
- Remove attr_utm_medium filter (campaign ID filter is specific enough)
- Fix get_campaign_metrics: accumulate all daily rows for monthly totals
- Fix SPRINT urgency: only trigger when capping > 0
- Add Log field to GACampaignMes with Airtable vs Google Ads discrepancy info
- batch_update_gacampaignmes_advice now also updates Log field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add get_monthly_metrics_all() in GoogleAdsClient: fetches
conversions and cost for all campaigns in one query
- sync_campaigns_from_google_ads() now accepts monthly_metrics
and updates ConvMes and CosteMes fields in Airtable
- run.py fetches monthly metrics before sync and passes them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before each run, fetch all non-removed campaigns from Google Ads
and upsert them into the Airtable campaigns table: new campaigns
are created (Activa=False, pending manual PPL/Cap/CPA setup) and
existing ones get their name updated if it changed.
https://claude.ai/code/session_01WEcdWPxGWZKk8FGwBRLGR2