HIP Creative · Paid Media

AI Quality Checks Spec

Every recurring check bucketed onto a cadence spine, split by team. Each check is tagged Binary (automated pass/fail → alert or gate) or Recommendation (human judgment → task), with trigger, data source, owner, and per-check logic. Two platforms, two tabs.

Version Draft v2
Date Jul 21, 2026
Design ION (light)
Tabs Google Paid Search · Meta Paid Social
Binary Deterministic yes/no → auto-alert or gate.
Recommendation Human judgment → task to review.
Fail = the condition that trips the check.

Values in [brackets] are thresholds to confirm before build. Auto-remediation is called out explicitly; everything else flags, never fixes — a mismatch could mean the setup is wrong or the plan is wrong, and only a human knows which.

The cadence spine — 5 jobs + wrapper

Daily
1 · Delivery & Money Sweep
Binary · Delivery rotation
2× / week
2 · Creative & Content QA
Mixed · Account specialist
Weekly
3 · Config & Targeting Integrity
Binary · Specialist + Sawyer
Weekly
4 · Performance → Sawyer
Recommendation · Team-lowest
Biweekly
5 · Specialist "Unders" Prep
Recommendation · Specialist
Every cycle
⊚ Coverage Wrapper
Binary · System guardrail
1

Delivery & Money Sweep

Daily
Type: Binary → morning digest
Owner: Delivery rotation
Data: Google Ads API (spend, status, billing, conversions) · ClickUp · GHL / PracticeBeacon
Output: One Slack digest; accountability items auto-create ClickUp tasks
Two data sources, one report. Money & delivery and measurement integrity run in the same daily pass and surface as two sections of the same morning digest.
CheckTypeFail conditionData sourceOn fail
Section A — Money & delivery
Payment method downBinFail if account billing status = declined / primary card failure.Ads API — billing setupAlert + task
Account suspended / limitedBinFail if account serving status = suspended, under review, or limited.Ads API — customer statusAlert + task
Budget pacing off-trackBinFail if projected month-end spend deviates from plan by [±10%] vs. pace to hit budget.MTD cost vs. MX budgetAlert + auto task
Pacing about to overspendBinFail if run-rate projects ≥100% of budget before period end. References existing auto-pause automation.Run-rate vs. remaining budget/daysAlert; task if not auto-paused
Not spending 2+ daysBinFail if daily cost = $0 for ≥2 consecutive days on a live account/campaign.Ads API — daily costAlert + task
HIP / active naming spend ruleBinFail if spend > $0 in a campaign whose name contains HIP and the account name does not contain active.Campaign + account name + costAlert + task
Spend anomalyBinFail if today's spend deviates from trailing [7–14 day] average by [±50%].Daily cost vs. baselineAlert
Zero-conversion spendBinFail if account/campaign spent ≥ [$X] over last [N] days with 0 conversions.Cost + conversions windowedAlert + task
Zero serving adsBinFail if a live ad group has 0 eligible/serving ads (all disapproved or paused) — the gap "not spending" misses.Ads API — ad_group_ad statusAlert + task
Ad / asset disapprovalsBinFail if any ad or asset policy status = disapproved.Ads API — policy_summaryAlert
Section B — Measurement integrity
Conversion heartbeatBinFail if a primary conversion action shows "no recent conversions" or last-received > [N] days.Ads API — conversion_actionAlert + task
Conversion firing (absence)BinFail if today's conversions = 0 where trailing average > 0. Detects absence via expected-vs-actual.Conversions vs. baselineAlert
Lead reconciliationBinFail if Google-reported conversions ≠ GHL/PB leads for the same window beyond [±tolerance]. The "+1 in PB but no +1 in UI" match.Ads API vs. GHL / PracticeBeaconAlert + task
MLs + $0 opportunitiesBinFail if manual leads / opportunities are logged with $0 value where a value is expected.PracticeBeacon / GHLAlert
2

Creative & Content QA

2× / week
Type: Mixed → per-account QA report
Owner: Account specialist
Data: Live RSA text · LP HTML (desktop + mobile) · ClickUp offer subtask & notes · website
Output: QA report; real errors become tasks
Scope: live ads, in live ad groups, in live campaigns only. Deeper than the real-time URL-down alert — catches a URL that resolves but is wrong, and copy/LP drifted off the current offer.
CheckTypeFail / flag conditionData sourceOn fail
RSA spellingBinFail on spelling error in a live headline/description (dictionary + brand/offer allowlist).RSA assetsTask
LP spelling (desktop + mobile)BinFail on spelling error on the rendered landing page, both viewports.LP HTML — dual renderTask
TruncationBinFail if headline > 30 chars or description > 90 chars, or visibly truncated in preview.RSA asset lengthsTask
Broken final URLBinFail if final or mobile URL returns non-200, a redirect chain, or a soft-404.HTTP check on live URLsTask
Offer / theme matchBinFail if the live offer in ad copy or LP ≠ the current "campaign running" offer subtask / important notes. (Offer = binary; theme = recommendation.)Ad + LP vs. ClickUpTask
Address / location accuracyBinFail if # of addresses in copy/LP ≠ # of locations in ClickUp, or location-asset count ≠ website count.Copy + ClickUp + websiteTask
Images match offerRecFlag if image assets don't reflect the current offer/theme.Image assets vs. offerReview flag
LP mobile vs. desktop parityRecFlag if key content (offer, price, CTA, phone) differs between mobile and desktop.Dual render diffReview flag
GrammarRecFlag likely grammar issues in live copy/LP (not a clean yes/no).Ad + LPReview flag
3

Config & Targeting Integrity

Weekly
Type: Binary → reconciliation report
Owner: Specialist, spot-checked by Sawyer
Data: Google Ads API settings + change history vs. MX · recommendations page
Output: Mismatch report → tasks (flag, don't auto-fix, except where noted)
The "does the live setup match the declared plan (MX)" reconciliation — the Google twin of the Meta naming-as-config audit, at campaign / ad-group / keyword level.
CheckTypeFail conditionData sourceOn fail
Geo presence settingBinFail if location option = "Presence or interest" (should be Presence only).campaign.geo_target_typeTask
Geo / radius matchBinFail if targeted geo/radius ≠ service area defined in the MX.Location targets vs. MXTask
Network settingsBinFail if a Search campaign has Display expansion on or Search Partners on when the MX says off.campaign.network_settingsTask
Bid strategy matchBinFail if bid strategy type, or tCPA/tROAS target, ≠ MX or changed from baseline.Bidding config + change historyTask
Missing negative listBinFail if the required shared negative-keyword list is not attached to the campaign.Campaign shared setsTask
Conflicting negativesBinFail if conflicting-negatives % > 0% in the recommendations column.Recommendations page / APIAuto-remediate + post names to paid search internal
Conversion setup integrityBinFail if > 1 primary conversion action risks double-counting, or "include in Conversions" is misconfigured.Ads API — conversion_action configTask
Automation guardrailBinFail if auto-apply recommendations is ON, auto-created assets is ON (when unwanted), or a new Google auto-feature was switched on.Account settings + change historyTask; auto-off where safe
Naming ↔ config reconciliationBinUmbrella: parse campaign/ad-group name tokens and validate each against actual settings (objective, geo, offer).Names vs. live settingsTask
4

Performance Flags → Sawyer Tasks

Weekly
Type: Recommendation → tasks (team-lowest)
Owner: System → tasks assigned to Sawyer
Data: Google Ads metrics · PracticeBeacon (starts, schedules, ROAS) · ClickUp (MX, AGL)
Output: One task per triggered account, with context
The judgment layer. Exclusions apply across the top three: skip an account if the last MX wasn't working on schedule rate / wasn't taken seriously for 2+ MX in a row.
CheckTypeFlag conditionExclusionsOn flag
No starts L90RecFlag accounts with 0 starts in the last 90 days.ROAS exception = filled and AGL within 30 daysTask → Sawyer
No schedules L30RecFlag accounts with 0 schedules in the last 30 days.(MX seriousness layer)Task → Sawyer
Search CPL > $200 L60RecFlag accounts with search CPL > $200 over the last 60 days.Exclude AGL < 60 daysTask → Sawyer
Budget-limited / Lost IS (budget)RecFlag strong campaigns capped by budget — the opposite of overpacing, leaving volume on the table.search_budget_lost_impression_shareTask / review
Lost IS (rank)RecFlag high lost impression share due to rank (bid / Quality Score).search_rank_lost_impression_shareReview
Ad strength poorRecFlag ad groups with "poor" ad strength.Ads API — ad_strengthReview
Search-term wasted spendRecFlag spend on irrelevant/junk queries above [$X]; suggest negatives.Ads API — search_term_viewReview + negatives
Brand drift + brand defenseRecFlag brand spend-share drift, or a competitor showing on your brand terms.Brand-labeled campaigns + auction insightsReview
5

Specialist "Unders" Prep

Biweekly
Type: Recommendation → specialist task → Sawyer subtask
Owner: Specialist (self-prep), reviewed by Sawyer
Data: Google Ads metrics · PracticeBeacon
Output: Biweekly prep task listing each specialist's unders
Flow: task populates for the specialist to prep their unders → when they write their update, it auto-assigns a review subtask to Sawyer → Sawyer returns ideas.
CheckTypeFlag conditionData sourceOn flag
UnderpacersRecAccounts pacing below plan for the period.Cost vs. MX budgetPrep item
Low schedule rateRecAccounts below [schedule-rate threshold].Schedules / leads (PB)Prep item
Low ROASRecAccounts below [ROAS threshold].Revenue / cost (PB)Prep item
0 ROASRecAccounts returning zero over the window.Revenue / cost (PB)Prep item

Coverage Wrapper

Every cycle
Type: Binary → system guardrail
Owner: System
Data: ClickUp active-account list vs. each job's run manifest
Output: Alert if any active account went unchecked
The check that makes the others trustworthy: is every active account actually in the checked set this cycle? Nothing silently drops out of monitoring.
CheckTypeFail conditionData sourceOn fail
Account coverageBinFail if any account marked "active" in ClickUp is absent from the checked set for the cycle.ClickUp active list vs. run manifestAlert to lead

Deliberately NOT new jobs — defer to existing alerts

These already fire in real time. The system references them; it does not rebuild them.
Existing signalWhere it livesNote
Verifications neededSlack alertIf yes, it already names them. No new check.
URLs down (hard down)Existing alertReal-time catches hard-downs. Creative QA (Job 2) adds the deeper twice-weekly "wrong URL that still resolves" check.
Pacing overage → auto-pauseExisting automationJob 1 references it; only tasks when the automation didn't act.

What moved cadence in this rebucket

Four checks changed beat: conflicting negatives and conversion-setup integrity dropped from ad-hoc into the weekly integrity audit; zero-serving-ads was added into the daily sweep; and creative QA moved from launch-only to a fixed twice-weekly beat. (Offline-import, duplicate-keywords, and RSA-count checks were removed as not needed.)

Glossary & thresholds to confirm

MX — the media plan / declared spec each check reconciles the live account against.

AGL — account go-live date; drives the "new account" exclusions.

PB (PracticeBeacon) — source of truth for leads, starts, schedules, ROAS.

GHL — CRM used in lead reconciliation against Google-reported conversions.

CU (ClickUp) — offer subtasks, important notes, account "active" status, MX.

Starts / schedules — patient starts and booked appointments (downstream outcomes).

Schedule rate — schedules ÷ leads; a primary "unders" measure.

Thresholds to lock: pacing ±%, spend-anomaly ±%, zero-conv $/days, CPL ceiling, schedule-rate & ROAS floors, heartbeat day-windows.

Meta is the simpler build. Same cadence spine, but it collapses to 3 jobs + wrapper. No search terms, negatives, network settings, or impression share; no team-lowest / specialist-unders accountability layer; pixel checks scoped to the rare web/LP campaigns; and the disclaimer check and Advantage+ automation guardrail are intentionally out (per your call — instant forms, and you sometimes want Advantage+ on).

The cadence spine — 3 jobs + wrapper

Daily
1 · Delivery & Money Sweep
Binary · Delivery rotation
2× / week
2 · Creative & Content QA
Mixed · Account specialist
Weekly
3 · Config & Targeting Integrity
Mixed · Specialist + lead
Every cycle
⊚ Coverage Wrapper
Binary · System guardrail
1

Delivery & Money Sweep

Daily
Type: Binary → morning digest
Owner: Paid Social delivery rotation
Data: Meta Marketing API (spend, status, delivery, disapprovals, leads) · ClickUp · GHL
Output: One Slack digest; accountability items auto-create ClickUp tasks
Measurement section is scoped to web/LP conversion campaigns only — for instant-form-only accounts, no pixel is expected, so pixel/CAPI checks are skipped rather than flagged.
CheckTypeFail conditionData sourceOn fail
Section A — Money & delivery
Payment method downBinFail if the ad account funding source is declined / billing has failed.Meta API — ad account fundingAlert + task
Ad account restricted / in reviewBinFail if account_status = disabled / unsettled / in-review, or the account is policy-restricted.Meta API — account_status / disable_reasonAlert + task
Budget pacing off-trackBinFail if projected spend deviates from plan by [±10%] vs. pace to hit budget.MTD spend vs. MX budgetAlert + auto task
Not spending 2+ daysBinFail if spend = $0 for ≥2 consecutive days on a live ad set/campaign.Meta API — insights (daily spend)Alert + task
Spend anomalyBinFail if today's spend deviates from trailing [7–14 day] average by [±50%].Daily spend vs. baselineAlert
Zero-result spendBinFail if a campaign spent ≥ [$X] over [N] days with 0 results (leads / purchases per objective).Spend + results windowedAlert + task
Ad / creative disapprovalsBinFail if any ad effective_status = DISAPPROVED or WITH_ISSUES.Meta API — ad review statusAlert
Zero delivering adsBinFail if a live ad set has 0 delivering ads (all rejected or off) — the delivery gap "not spending" misses.Meta API — ad set + ad effective_statusAlert + task
Section B — Measurement integrity · web / LP campaigns only
Pixel / CAPI heartbeatBinFail if a web/LP conversion campaign's pixel/CAPI shows no events received > [N] days. Skipped for instant-form-only accounts.Meta pixel / dataset statsAlert + task
Conversion firing (absence)BinFail if a web/LP campaign's tracked conversions = 0 where trailing average > 0. Same web-only scope.Conversions vs. baselineAlert
Lead reconciliationBinFail if Meta-reported leads ≠ GHL leads for the same window beyond [±tolerance]. Applies to instant forms too.Meta leads vs. GHLAlert + task
MLs + $0 opportunitiesBinFail if manual leads / opportunities are logged with $0 value where a value is expected.PracticeBeacon / GHLAlert
2

Creative & Content QA

2× / week
Type: Mixed → per-account QA report
Owner: Account specialist
Data: Live ad copy + creative · LP HTML or instant-form definition · ClickUp offer subtask & notes · website
Output: QA report; real errors become tasks
Instant-form aware: where an ad has no landing page, the checks run against the instant form (intro, questions, disclaimer, thank-you screen, privacy link) instead of an LP.
CheckTypeFail / flag conditionData sourceOn fail
Ad copy spellingBinFail on spelling error in live primary text, headline, or description.Ad creativeTask
LP / instant-form spellingBinFail on spelling error on the LP (desktop + mobile) for web ads, or across the instant form for lead ads.LP HTML / form definitionTask
TruncationBinFail if primary text or headline is cut off in-feed on key placements.Ad creative + placement previewTask
Broken linkBinFail if a web ad's final URL is non-200/redirect; for lead ads, if the form's privacy-policy link or post-submit CTA link is broken.HTTP checkTask
Offer / theme matchBinFail if the live offer in copy / LP / form ≠ the current "campaign running" offer subtask / important notes. (Offer = binary; theme = recommendation.)Ad + LP/form vs. ClickUpTask
Address / location accuracyBinFail if # of addresses in copy ≠ # of locations in ClickUp / on the website.Copy + ClickUp + websiteTask
Creative matches offerRecFlag if the image/video doesn't reflect the current offer/theme.Creative vs. offerReview flag
LP mobile vs. desktop parityRecFlag if key content differs between mobile and desktop (web ads only).Dual render diffReview flag
GrammarRecFlag likely grammar issues in live copy / LP / form (not a clean yes/no).Ad + LP/formReview flag
3

Config & Targeting Integrity

Weekly
Type: Mixed → reconciliation report + health flags
Owner: Specialist, spot-checked by lead
Data: Meta Marketing API settings vs. MX (declared plan)
Output: Mismatch report → tasks; health flags → review
The naming-as-config audit — the name is a declared spec, reconciled against actual settings at campaign / ad-set / ad level. Config checks are binary; a short delivery-health section adds recommendation flags.
CheckTypeFail / flag conditionData sourceOn fail
Section A — Config reconciliation (name ↔ setup)
Objective matches nameBinFail if campaign objective ≠ the name token (e.g., Leads → OUTCOME_LEADS, not Traffic/Engagement).campaign.objectiveTask
Budget type (CBO / ABO)BinFail if Advantage campaign budget on/off ≠ what the name declares.campaign budget configTask
Geo / radius matchBinFail if ad-set geo is whole-US or ≠ the service area in the MX. (Folds the targeting check in here.)ad set targeting — geo_locationsTask
Optimization eventBinFail if optimization_goal ≠ intended (e.g., LEAD / OFFSITE_CONVERSIONS, not LINK_CLICKS). The one that quietly torches performance.ad set.optimization_goalTask
Placements as intendedBinFail if Advantage+ vs. manual placements ≠ what the name / plan declares.ad set targeting — placementsTask
Special ad categoryBinFail if special_ad_categories isn't set as intended for the account.campaign.special_ad_categoriesTask
Destination correctBinFail if the ad routes to the wrong destination — wrong instant form, or LP when a form was intended (or vice-versa).ad creative — destination / form idTask
Naming ↔ config reconciliationBinUmbrella: parse campaign / ad-set / ad name tokens and validate each against the actual setting. Flag any token that lies.Names vs. live settingsTask
Section B — Delivery health (recommendation)
Frequency too highRecFlag ad sets with frequency > [threshold] (audience fatigue).Meta API — insights (frequency)Review flag

Coverage Wrapper

Every cycle
Type: Binary → system guardrail
Owner: System
Data: ClickUp active-account list vs. each job's run manifest
Output: Alert if any active account went unchecked
Same guardrail as Google: is every active Meta account in the checked set this cycle? Nothing silently drops out of monitoring.
CheckTypeFail conditionData sourceOn fail
Account coverageBinFail if any account marked "active" in ClickUp is absent from the checked set for the cycle.ClickUp active list vs. run manifestAlert to lead

What's intentionally out (and why)

DroppedReason
Pixel/CAPI as an always-on checkScoped to web/LP campaigns only — instant-form-only accounts have no pixel to expect, so absence is fine, not a failure.
Health-claim / disclaimer checkSo much of the mix runs through instant forms that a standalone disclaimer gate isn't worth the noise.
Advantage+ automation guardrailYou sometimes want these features on, so an auto-flag would fight the strategy.
Performance / accountability layer (Jobs 4 & 5)The team-lowest + specialist-unders system is a Paid Search / Sawyer structure; not run for social.
HIP / active naming spend ruleGoogle-only.

Glossary & thresholds to confirm

MX — the media plan / declared spec each check reconciles the live account against.

Instant form — Meta's native lead form; the QA target when an ad has no landing page.

CAPI — Conversions API; the server-side event feed checked only on web/LP campaigns.

CBO / ABO — campaign vs. ad-set budget optimization (Advantage campaign budget on/off).

GHL — CRM used to reconcile against Meta-reported leads.

CU (ClickUp) — offer subtasks, important notes, account "active" status, MX.

PB (PracticeBeacon) — source for logged leads / opportunities.

Thresholds to lock: pacing ±%, spend-anomaly ±%, zero-result $/days, pixel/lead-recon day-windows, audience-overlap %, frequency ceiling.