Data Fetch Agent — fetches raw performance data from Google Ads, Meta Ads Manager, Google Analytics 4, and HubSpot on schedule, then writes structured tables to the staging Google Sheet. Complexity: Moderate. Estimated build time: 14 hours.
ID
Scenario
Input
Expected Output
Pass Criteria
T01
Happy path: Google Ads API fetch
Scheduled trigger fires; sandbox Google Ads OAuth token; date range = last 7 days; synthetic campaign data available
Campaign, ad group, and conversion rows written to the Google Ads tab of the staging sheet with correct date range and field alignment
Row count matches synthetic fixture; all required fields (campaign_id, spend, clicks, conversions, date) present; no null values in mandatory columns
T02
Happy path: Meta Ads Manager API fetch
Sandbox Meta system user token; date range = last 7 days; synthetic ad set and creative data available
Spend, impressions, clicks, and conversions written to the Meta tab of the staging sheet
All four metric fields populated; date range boundaries match input; currency field returns USD
T03
Happy path: Google Analytics 4 API fetch
Sandbox GA4 property; reporting API call for source/medium dimension; date range = last 7 days
Source/medium rows with sessions and goal completions written to the GA4 tab
Source/medium dimension populated; sessions and conversions non-null; date range aligns with ad platform fetch
T04
Happy path: HubSpot deal source fetch
Sandbox HubSpot private app token; deal filter: closedate within last 7 days and dealstage = closedwon
Closed deal records with original source, lifecycle stage, and deal amount written to the HubSpot tab
Deal records contain hs_original_source, amount, and closedate; records outside date range excluded; no duplicate deal IDs
T05
Google Ads API auth failure
Expired or revoked sandbox OAuth token injected
Agent logs authentication error, marks the Google Ads fetch as failed, and halts further steps pending retry
Error event written to the run log with error_code and timestamp; no partial data written to the sheet; downstream agents do not fire
T06
Meta Ads API rate limit hit
Stub response returns HTTP 429 after the first page of results
Agent pauses, applies exponential backoff (30 s, 60 s, 120 s), retries up to three times, then logs a rate-limit failure if all retries are exhausted
Backoff intervals logged; retry count recorded; if all retries fail, fetch marked incomplete and operator alert triggered; no silent failure
T07
GA4 API returns empty dataset
Sandbox property has no events in the requested date range
Agent writes an empty-result marker to the GA4 tab and logs a data-gap warning
Empty-result marker present; warning log entry created; Attribution and Merge Agent does not proceed using a blank GA4 input without acknowledgement
T08
HubSpot API pagination incomplete
Stub returns three pages but the fourth page returns a 500 error mid-pagination
Agent logs the pagination failure at page 4, writes the records retrieved up to page 3, and flags the fetch as partial
Partial flag set on HubSpot fetch status; records from pages 1 to 3 written correctly; page 4 gap logged with offset value for retry
Attribution and Merge Agent — normalises UTM and source labels, merges all platform data into the master Google Sheet, and applies the configured attribution model to produce per-channel CPA and ROAS. Complexity: Moderate. Estimated build time: 16 hours.
ID
Scenario
Input
Expected Output
Pass Criteria
T09
Happy path: merge and attribution model applied
All four platform tabs populated in the staging sheet; UTM labels consistent across sources; attribution model = last-touch
Merged attribution table written with CPA and ROAS calculated per channel; source labels normalised to the canonical set
CPA and ROAS values present for every channel row; source labels match the normalisation dictionary; no duplicate channel rows; sheet marked complete
T10
UTM normalisation: mixed-case and variant labels
Synthetic data contains utm_source values: 'google', 'Google', 'google_ads', 'GoogleAds'
All four variants normalised to 'google_ads' in the canonical source column
Canonical source column contains only 'google_ads' for all four input variants; original raw label preserved in a separate raw_source column
T11
Attribution model: linear distribution
Same merged dataset; attribution model switched to linear in the agent configuration
Conversion credit distributed equally across all touchpoints in the path; CPA recalculated accordingly
Sum of attributed conversions per channel equals total conversions; CPA figures differ from last-touch output by expected proportion
T12
Merge with missing Meta data
Meta Ads tab is empty (fetch marked incomplete in T06 failure scenario)
Agent writes a data-gap flag for the Meta channel in the merged table; CPA and ROAS for Meta left as null; all other channels calculated normally
Meta rows present with null metric values and a data_gap flag; no formula errors propagated to other channel rows; sheet still marked complete with a warning
T13
Duplicate campaign rows in source data
Synthetic Google Ads input contains two identical rows for the same campaign_id and date
Agent deduplicates on (campaign_id, date) before merge; only one row retained per key
Merged sheet contains exactly one row per (campaign_id, date) combination; deduplication event logged with count of removed rows
T14
Attribution model misconfiguration
Attribution model field in agent config is blank or contains an unrecognised string
Agent halts before writing to the attribution table and raises a configuration error
Configuration error logged with the invalid model value; no partial attribution rows written; operator alert sent
Summary and Delivery Agent — reads the completed attribution table, identifies the top-performing channel and any anomalies, writes a plain-language summary, and posts the report link to Slack. Complexity: Simple. Estimated build time: 8 hours.
ID
Scenario
Input
Expected Output
Pass Criteria
T15
Happy path: summary generated and posted to Slack
Attribution table complete with data for all four channels; no anomaly flags; sandbox Slack webhook configured
Plain-language summary paragraph posted to the sandbox Slack channel with the Google Sheet link; top channel identified by ROAS
Slack message received in the sandbox channel; message body contains the sheet URL, top channel name, and at least one metric value; delivery timestamp logged
T16
Anomaly detected: ROAS drop greater than 30%
Meta channel ROAS drops from 4.2 to 2.1 week-over-week in the synthetic dataset
Summary flags the Meta ROAS anomaly with the percentage drop; Slack message includes an anomaly callout alongside the standard summary
Anomaly section present in the Slack message; percentage drop value accurate to one decimal place; no other channels incorrectly flagged
T17
Slack webhook unreachable
Sandbox Slack endpoint returns HTTP 503
Agent retries the post twice with a 30-second interval; if all retries fail, logs a delivery failure and writes the summary text to the error log for manual retrieval
Retry count and timestamps logged; delivery failure entry present in the run log; summary text accessible in the log even though Slack post did not succeed