Back to Skills
mbfinotti/advertising-skillsCheck passed

SKILL DETAIL

ad-budget-pacing

mbfinotti/advertising-skills/ad-budget-pacing

Track daily and weekly spend against a single campaign or account budget and flag under-pacing or over-pacing before it hurts results, reporting the pacing ratio, projected period spend, and the corrective daily spend behind every alert. Use whenever the user mentions budget pacing, spend tracking, burn rate, spend vs budget, projected month-end spend, underspending or overspending, or asks whether a campaign is on pace - even if they never say 'pacing'. Covers any ad platform, B2B and B2C, calendar-month or fixed-date flights. It flags and recommends; it never changes budgets or bids. Do NOT use to plan a scale-up (mbfinotti/advertising-skills@paid-media-scaling) or to set CAC/ROAS thresholds (mbfinotti/advertising-skills@ad-spend-guardrails).

Installs · 178View source

Installation

npx skills add https://github.com/mbfinotti/advertising-skills --skill ad-budget-pacing

Skill files

SKILL.md

Last synced · Sep 24, 2026

evals/evals.json›
{
  "skill_name": "ad-budget-pacing",
  "evals": [
    {
      "id": 1,
      "prompt": "I run paid search at Brightpath Legal, a B2B legal-intake software company. Our Google Ads campaign has a $24,000 budget for September - calendar month, and it's a target, not a contractual commitment. Through September 18 we've spent $10,800, and the trailing 7-day average is $560/day against an $800 daily budget. The account has run since spring with no seasonality and pretty even weekday/weekend delivery. Nobody has touched settings in over two weeks and I'm looking at yesterday's finalized numbers. Search impression share lost to rank is 38% and lost to budget is 2%. I'm clearly behind - should I raise the daily budget from $800 to $1,100 to catch up before month end? Give me the full pacing picture and what to change.",
      "expected_output": "A pacing report that computes the full arithmetic (ratio 0.75, projection $18,000, required daily $1,100, adjust +$540/day), passes the false-alarm gate, reads the impression-share pair as a rank/bid constraint, refuses the budget raise, and recommends a bid-side change packet handed to a named owner.",
      "files": [],
      "expectations": [
        "Computes the pacing ratio as approximately 0.75, from $10,800 spent against a $14,400 expected-to-date (18 of 30 days of $24,000).",
        "Reports a projected period spend of $18,000 if nothing changes.",
        "Reports the required daily spend of $1,100 over the 12 remaining days alongside the projection, not the projection alone.",
        "Reports a signed corrective figure of approximately +$540/day, the gap between the $1,100 required daily and the $560 trailing 7-day average.",
        "Classifies the deviation as urgent (ratio below 0.85) while labelling the on-pace/urgent bands a practitioner convention to recalibrate against this account's history, not a platform rule.",
        "States an explicit false-alarm gate result before alerting, confirming the deviation is not explained by a first/last partial day, a trivial denominator, a recent budget edit, or intra-day figures.",
        "Reads the 38% impression share lost to rank against 2% lost to budget as bid competitiveness or quality being the binding constraint, not budget.",
        "Advises against raising the daily budget from $800 to $1,100, stating that adding budget will not close a rank-constrained gap.",
        "Recommends a bid-side remedy (bid or target adjustment) as the corrective action instead of a budget change.",
        "Shapes the recommendation as a change packet showing current and proposed values with a rationale.",
        "The change packet includes a verification date and a rollback trigger.",
        "Names a specific owner role or person to execute the change and explicitly hands off rather than executing or promising to execute the change itself.",
        "Keeps the correction to the smallest reversible change: a single variable and a modest step, not a campaign restructure."
      ]
    },
    {
      "id": 2,
      "prompt": "Quick sanity check. I manage Google Ads for Nordic Sleepwear, a B2C ecommerce bedding brand. Our October budget is $15,500 and the campaign daily budget is $500. Yesterday, October 9, Google spent $970 - nearly double the daily budget. Total spend through October 9 is $4,410. My plan is to cut the daily budget to $400 to compensate and file for a refund of the $470 overage. Can you check the pacing and confirm the plan?",
      "expected_output": "A report that judges spend cumulatively (ratio 0.98, on pace), explains Google's documented 2x daily overdelivery and 30.4x monthly billing cap, suppresses the alert under the overdelivery gate check, ships the report with an ON PACE (deviation suppressed) status, and declines both the budget cut and the refund claim.",
      "files": [],
      "expectations": [
        "Judges cumulative spend against the prorated period budget ($4,500 expected by day 9 of 31) rather than judging yesterday's $970 against the $500 daily budget.",
        "Computes the cumulative pacing ratio as approximately 0.98 and concludes the campaign is on pace.",
        "States that Google may deliberately spend up to 2x the average daily budget in a single day.",
        "States Google's monthly billing cap of 30.4x the average daily budget, with overdelivery beyond it credited.",
        "Concludes no refund claim is needed because overdelivery past the cap is credited rather than billed, distinguishing served from billed spend.",
        "Suppresses the alert under the platform-overdelivery gate check and records the suppression reason in the report.",
        "Still delivers a full report despite the suppression, with a status equivalent to ON PACE (deviation suppressed).",
        "Makes no corrective recommendation while suppressed, and specifically does not endorse cutting the daily budget to $400.",
        "States that single-day overdelivery is designed platform behaviour and that only cumulative deviation counts.",
        "Warns that the proposed budget edit would itself force the delivery system to relearn, adding volatility rather than fixing anything.",
        "Includes report header fields (campaign, period, budget) and a status line rather than answering in loose prose."
      ]
    },
    {
      "id": 3,
      "prompt": "Monday morning check-in on Ferrostat Systems' LinkedIn lead-gen campaign - we sell B2B industrial sensors. The September budget is $18,000 for the calendar month. Today is Monday September 14 and finalized spend through Sunday the 13th is $6,700, trailing 7-day average $610/day. The account delivers almost entirely on weekdays and we have three full months of delivery history. We also have just 4 leads so far against a 25-lead monthly plan, and our sales cycle means conversions typically report about three weeks late. My quick math says we're 14% behind budget and way behind on leads - should I push bids up today to catch up? Walk me through where we actually stand.",
      "expected_output": "A both-curves report showing the flat calendar ratio 0.86 against a business-day ratio 0.91, judging the account on pace on the weighted curve, explaining the Monday calendar-curve artifact, refusing to pace against lagged conversions, and declining the bid increase.",
      "files": [],
      "expectations": [
        "Computes the flat-curve expected-to-date of $7,800 (13 of 30 calendar days) and a flat pacing ratio of approximately 0.86.",
        "Computes a business-day expected-to-date of approximately $7,360, from 9 elapsed business days out of 22 in the month.",
        "Computes the business-day pacing ratio as approximately 0.91, inside the 0.90-1.10 on-pace band.",
        "Presents both curves side by side in one metrics comparison rather than reporting only one.",
        "Bases the alert decision on the business-day curve and concludes the campaign is on pace, firing no under-pacing alert.",
        "Explains that a weekday-skewed B2B account reads structurally behind on a calendar-day curve after every weekend, which is why the Monday check looks 14% behind.",
        "Advises against pushing bids up today to catch up.",
        "Refuses to judge pacing on the 4 period-to-date leads, citing the multi-week B2B conversion lag that makes them incomplete by construction, and paces against the spend trajectory instead.",
        "Derives the day weights or business-day expectation from the account's own three months of delivery history rather than a generic template.",
        "Labels the 0.90-1.10 on-pace band a practitioner convention to recalibrate against this account's history, not a platform rule.",
        "Ships a report with a status line and an owner even though the verdict is an all-clear.",
        "Reports the required daily spend of approximately $665 over the 17 remaining days and the small corrective figure of roughly +$55/day against the $610 trailing average."
      ]
    },
    {
      "id": 4,
      "prompt": "We're Meridian Outdoors, a DTC camping gear brand. We signed an insertion order with Alpine Media Group: 8 million guaranteed impressions across a six-week flight, October 5 to November 15. We just closed week four and delivery sits at 4.9M impressions, about 1.225M a week. Alpine never said a word about being behind - our analyst caught it. Their account rep just offered us a credit for whatever ends up undelivered. Taking the money seems clean and easy. Should we accept, and how should we handle the rest of the flight?",
      "expected_output": "An IO under-delivery response that ranks accelerate ahead of make-good ahead of credit, recommends acceleration to roughly 1.55M impressions/week while runway remains, cites the IAB/4A's make-good and credit terms and the seller's notification duty, and installs a mid-flight IO checkpoint with an owner.",
      "files": [],
      "expectations": [
        "Identifies the guaranteed IO buy type as changing both the target pacing curve and the available remedies, distinct from an auction buy.",
        "Notes the standing trader practice of pacing a guaranteed IO slightly ahead of even delivery, so 4.9M against a 5.33M prorated position is genuinely behind for this buy type.",
        "Computes the required remaining rate: roughly 3.1M impressions over the final two weeks, about 1.55M/week versus the current 1.225M/week (an acceleration of roughly a quarter to a third).",
        "Ranks the three remedies with acceleration first, make-good second, and credit last.",
        "Recommends accelerating delivery while runway remains rather than accepting the offered credit.",
        "Explains that acceleration is a delivery setting already owned, reversible inside the flight, and triggers no negotiation or contract review.",
        "Explains that the credit returns money rather than the audience the campaign was bought for, and closes the flight instead of fixing it.",
        "Cites the 4A's/IAB Standard Terms (v3.0) remedy sequence: the parties negotiate a make-good flight, and only if that fails may the buyer take a credit.",
        "Cites the IAB Direct Buy Addendum's seller duty to promptly notify the buyer of material under-delivery, so Alpine's silence breached a disclosure obligation.",
        "States the escalation condition: the make-good becomes the lead remedy once acceleration can no longer close the gap in the remaining runway.",
        "Advises notifying and escalating with the publisher early rather than waiting until the flight ends.",
        "Recommends a mid-flight IO delivery checkpoint, states that it outranks the other check cadences on a guaranteed buy because it is contractually load-bearing, and names an owner such as ad ops."
      ]
    },
    {
      "id": 5,
      "prompt": "I handle Meta ads for Juniper Financial. November budget is $9,000 for the calendar month. Eight days ago I raised the daily budget by 18% - I deliberately kept it under the 20% threshold that resets learning. Delivery got choppy anyway, so two days ago I cut it back 15%. This morning, November 11, the dashboard shows $3,850 spent, which by my math is 17% hot. I want to email the client an over-pacing alert today and probably make one more downward budget edit to rein it in. Can you write up the alert and tell me how big the cut should be?",
      "expected_output": "A response that debunks the 20% learning-reset figure as undocumented folklore, suppresses the over-pacing alert because two budget edits landed inside the relearning window and the figure is intra-day, ships the report with the suppression reason, and advises against a third edit.",
      "files": [],
      "expectations": [
        "Corrects the 20% claim: the figure appears in no Meta documentation and is folklore; Meta's actual wording ties reset risk to the unquantified magnitude of the change.",
        "Does not endorse keeping edits under 20% as a documented-safe pattern, while allowing that treating large edits cautiously is sound risk management.",
        "Withholds the over-pacing client alert because the two recent budget edits landed inside the relearning window, so the post-edit volatility is the edits, not a pacing problem.",
        "Flags that the $3,850 figure is intra-day: no alert should fire on this morning's live dashboard numbers, which lag and get restated; yesterday's finalized figures are the basis.",
        "Computes the ratio of approximately 1.17 from $3,850 against the $3,300 expected by day 11, but reports it as suppressed rather than as an actionable over-pacing alert.",
        "Advises waiting out the settle window before judging pacing on this account.",
        "Advises against the third corrective edit now, because correcting through a relearning window makes the correction's own volatility read as a new anomaly inviting yet another correction.",
        "Still ships a report with the suppression reason recorded rather than replying with either the requested alert or nothing.",
        "Notes the pacing record is not immutable - spend gets restated and invalid-traffic credits can move history - so figures should be date-stamped and re-pulled before any escalation.",
        "Frames any eventual correction as the smallest reversible change: one variable, a modest step, edits bundled rather than dripped.",
        "Does not draft or recommend sending a client-facing over-pacing alert today."
      ]
    },
    {
      "id": 6,
      "prompt": "Our agency, Calder & Moss, runs paid social for Bexley Home under a contract that commits us to spending the full $40,000 October media budget - a hard commitment, the client is billed for it either way. Through October 25 we've spent $26,000, and the trailing 7-day average is $1,050/day. My plan: push the daily budget to $2,400/day for the final six days, which by my math lands us almost exactly on $40k. Sanity-check the math and the plan before I set it tomorrow.",
      "expected_output": "A report that verifies the arithmetic (required daily ~$2,333, projection ~$32,240, adjust +$1,283/day) but rejects the end-of-period dump as a failed pace, citing the worst-inventory cost, the final-week ~5pp criterion, the 95-105% utilization band, and the relearning cost of one cliff edit, then recommends an immediate ramp as a change packet with an owner.",
      "files": [],
      "expectations": [
        "Computes the required daily spend as approximately $2,333 over the 6 remaining days, confirming the user's $2,400 figure is arithmetically close.",
        "Computes the projected period spend of approximately $32,240 (roughly 81% utilization) if nothing changes.",
        "Reports the corrective figure of approximately +$1,283/day against the $1,050 trailing 7-day average.",
        "Does not simply validate the plan: warns that an end-of-period spend dump buys the worst inventory at the worst prices.",
        "States that a period landing on budget via a last-days surge is a failed pace that hit its number.",
        "Cites the no-dump success criterion: final-week spend share within about 5 percentage points of the expected curve's share.",
        "References the 95-105% utilization band for a hard-commitment budget, labelled a convention, noting a smoother ramp landing inside the band can beat hitting exactly $40,000 via a dump.",
        "Warns that the single large budget jump itself forces delivery relearning, and recommends starting the increase immediately with daily recomputation of the required daily and corrective figures so the correction stays continuous instead of a cliff.",
        "Shapes the recommendation as a change packet with current and proposed values, rationale, a verification date, and a rollback trigger.",
        "Names an owner and hands off, rather than executing or promising to execute the budget change.",
        "Notes that the $40,000 commitment is reconciled at period end on billed cost, not served cost."
      ]
    }
  ],
  "trigger_queries": [
    { "query": "Is our Google Ads campaign on pace to spend its $12k budget by end of month?", "should_trigger": true },
    { "query": "We're 60% through the month but the campaign has only spent 40% of its budget - what do I do?", "should_trigger": true },
    { "query": "What's our projected month-end spend on Meta if nothing changes?", "should_trigger": true },
    { "query": "My LinkedIn campaign keeps underspending its budget, is that a problem?", "should_trigger": true },
    { "query": "Set up a burn rate check on our paid search account", "should_trigger": true },
    { "query": "The flight ends Nov 15 and we've only delivered half the insertion order - help", "should_trigger": true },
    { "query": "How far ahead or behind plan is our ad spend right now?", "should_trigger": true },
    { "query": "Facebook spent almost double the daily budget yesterday, should I panic?", "should_trigger": true },
    { "query": "I need a weekly digest showing which campaign budgets are running hot or cold", "should_trigger": true },
    { "query": "Are we going to hit the $50k media commitment by the end of the quarter?", "should_trigger": true },
    { "query": "What should a spend-vs-budget alert actually fire on?", "should_trigger": true },
    { "query": "My boss wants to know if the campaign will use up its budget before the 30th", "should_trigger": true },
    { "query": "TikTok campaign is overspending, do I cut the budget now or wait it out?", "should_trigger": true },
    { "query": "What daily spend do we need from tomorrow to land this flight exactly on budget?", "should_trigger": true },
    { "query": "Our vendor dashboard says pacing is 112% - is that bad?", "should_trigger": true },
    { "query": "An underspend alert fired on our DSP this morning, is it real or noise?", "should_trigger": true },
    { "query": "How do I tell whether a budget deviation is worth acting on?", "should_trigger": true },
    { "query": "We always end up dumping the leftover budget in the last week of the month, how do we stop that?", "should_trigger": true },
    { "query": "Compare actual campaign spend to where it should be by day 20", "should_trigger": true },
    { "query": "New search campaign barely spent anything in its first 3 days, is something broken?", "should_trigger": true },
    { "query": "Check whether the October ad budget will actually get used up", "should_trigger": true },
    { "query": "The client retainer includes $30k of media a month - I need to prove we're spending it evenly", "should_trigger": true },
    { "query": "Campaign spend is lumpy - some days double, some days nothing. Normal?", "should_trigger": true },
    { "query": "Am I going to blow through the quarterly ad budget early at this rate?", "should_trigger": true },
    { "query": "Catch under-delivery on our guaranteed IO before the flight closes", "should_trigger": true },
    { "query": "How much should we adjust daily spend to get back on track for the month?", "should_trigger": true },
    { "query": "Our B2B account looks behind plan every Monday morning - what's up with that?", "should_trigger": true },
    { "query": "Build me a morning pacing check routine for the ad account", "should_trigger": true },
    { "query": "Did we really overspend the campaign budget or is that just how the platform delivers?", "should_trigger": true },
    { "query": "The media plan promised even delivery but actual spend is all over the place", "should_trigger": true },
    { "query": "Should I worry that the campaign has spent only 60% of budget with 5 days left?", "should_trigger": true },
    { "query": "I need a spend-versus-budget slide for the client QBR next week", "should_trigger": true },
    { "query": "Mid-flight numbers say we'll finish 20% under the committed spend - options?", "should_trigger": true },
    { "query": "Keep an eye on the Google Ads budget so month-end doesn't surprise anyone", "should_trigger": true },
    { "query": "How should I split $60k across Google, Meta, and LinkedIn next quarter?", "should_trigger": false },
    { "query": "Set a maximum allowable CAC and a kill-switch threshold for our paid media", "should_trigger": false },
    { "query": "Our winning Meta campaign is ready to scale - how fast can we ramp the budget without breaking it?", "should_trigger": false },
    { "query": "Is a $210 CAC acceptable for a $79/month SaaS product?", "should_trigger": false },
    { "query": "Should we move from manual CPC to target ROAS bidding on this account?", "should_trigger": false },
    { "query": "Why did our ROAS drop 40% over the last two months?", "should_trigger": false },
    { "query": "Meta reports 120 conversions, GA4 shows 70, the CRM has 55 - reconcile these", "should_trigger": false },
    { "query": "Verify our conversion pixel fires exactly once before launch", "should_trigger": false },
    { "query": "Which of our 30 campaigns should we merge to escape learning limited?", "should_trigger": false },
    { "query": "Is this ad creative wearing out or is the auction just pricier now?", "should_trigger": false },
    { "query": "Design a creative test plan with per-cell budgets for four new concepts", "should_trigger": false },
    { "query": "Mine our search terms report and build negative keyword lists", "should_trigger": false },
    { "query": "Which paid channels fit a $5k/month budget for a B2C mobile app?", "should_trigger": false },
    { "query": "Design a retargeting ladder with per-stage frequency caps", "should_trigger": false },
    { "query": "Which customers should seed our lookalike audience?", "should_trigger": false },
    { "query": "Audit the landing page our paid traffic goes to", "should_trigger": false },
    { "query": "What monthly ad budget should we set for the new product launch?", "should_trigger": false },
    { "query": "How much of the marketing budget should go to brand versus performance?", "should_trigger": false },
    { "query": "Alert me whenever campaign CPA goes above $80", "should_trigger": false },
    { "query": "Forecast next year's ad spend for the finance planning cycle", "should_trigger": false },
    { "query": "Our AWS bill is tracking 30% over the monthly cloud budget - set up cost alerts", "should_trigger": false },
    { "query": "Track my personal monthly budget and flag when I overspend on groceries", "should_trigger": false },
    { "query": "Are we burning through the startup's runway too fast?", "should_trigger": false },
    { "query": "Sprint burndown shows we're behind pace - help me replan the sprint", "should_trigger": false },
    { "query": "Keep the engineering project on schedule and flag when milestones slip", "should_trigger": false },
    { "query": "Pace my marathon training so I can break four hours", "should_trigger": false },
    { "query": "How should I pace content publishing across the quarter?", "should_trigger": false },
    { "query": "We're about to exceed our email platform's monthly sending quota - manage it", "should_trigger": false },
    { "query": "Draft the make-good clause for our podcast sponsorship contract", "should_trigger": false },
    { "query": "Why is the campaign stuck in learning limited and what bid change fixes it?", "should_trigger": false },
    { "query": "Build next year's media plan with a month-by-month budget breakdown", "should_trigger": false },
    { "query": "Rebalance spend between our five channels against the shared quarterly budget", "should_trigger": false },
    { "query": "My Google Ads account was suspended for policy violations - get spend running again", "should_trigger": false },
    { "query": "Estimate the budget we'd need to reach 10,000 installs next month", "should_trigger": false }
  ]
}
references/pacing-report-example.md›
# Worked example: budget pacing report

A full example of the report shape described in the SKILL.md "Output shape" section - header, metrics table comparing the flat and weighted curves, status, suppression, diagnosis, recommendation, and owner.

```
BUDGET PACING REPORT - <campaign>, <date>
period : calendar month 2026-09-01 → 2026-09-30 | day 12 of 30, 18 remaining
budget : $30,000 (hard commitment) | buy: auction | model: B2B lead gen

metric                        flat curve      weighted curve (business-day index)
expected to date              $12,000         $11,050
spend to date                 $9,600          $9,600
pacing ratio                  0.80            0.87
projected period spend        $24,000         $24,000
budget utilization            32%             32%
remaining budget              $20,400         $20,400
required daily spend          $1,133          $1,133
trailing 7-day avg daily      $780            $780
adjust spend by               +$353/day       +$353/day

status     : UNDER-PACING - weighted 0.87, below the 0.90 on-pace floor
             (band is practitioner convention, recalibrated quarterly on this account)
suppression: none - gate passed (12-day denominator, no edits in 7 days, figures restated)
diagnosis  : impression share lost to rank elevated; lost to budget near zero
             → bid competitiveness is the constraint, not budget
recommend  : raise the bid target ~10% on the two under-delivering campaigns;
             do NOT raise the budget - it is not the binding constraint
owner      : <name> | next check: tomorrow's daily pacing review
```
references/platform-delivery-notes.md›
# Platform delivery allowances

Documented delivery allowances - the numbers behind gate check 1 in the false-alarm gate. Treat exact numbers as directional; platforms revise them.

- **Google Ads**:
  - May spend up to 2x the average daily budget in a day but never bills more than 30.4x it in a month (overdelivery past that is credited).
  - Deliberately front-loads high-value days.
  - Its _Limited by budget_ status fires at a documented 5%+ traffic loss.
  - Campaign-total budgets pace to the flight with no daily cap.
- **Meta**:
  - Its own pages state a daily flexibility of 25% (older page) or 75% (newer page) over the daily budget; the consistent ceiling is the 7x-daily weekly cap.
  - Documents first/last-day hour adjustment plus relearning after budget edits.
  - Accelerated delivery is deprecated in ordinary setup: it was removed from Google Search in October 2019.
- **LinkedIn**:
  - Its ~50% daily overdelivery allowance is practitioner-stated (B2Linked), not in LinkedIn's help pages.
  - Its day boundary and edit effectiveness are midnight UTC.
- **Amazon**: documents up to 100% daily overspend for campaigns created after 27 March 2023 (25% before that date).
- **TikTok**: documents a ~5-day cold start for Search Ads and instructs excluding those days from reporting - the industry's only documented "too early to judge" window.
- **DSPs**: expose the pacing types by name - even, ahead (e.g. up to 120% of prorated), and ASAP - with documented overspend warnings on ASAP.
SKILL.md›
---
name: ad-budget-pacing
description: "Track daily and weekly spend against a single campaign or account budget and flag under-pacing or over-pacing before it hurts results, reporting the pacing ratio, projected period spend, and the corrective daily spend behind every alert. Use whenever the user mentions budget pacing, spend tracking, burn rate, spend vs budget, projected month-end spend, underspending or overspending, or asks whether a campaign is on pace - even if they never say 'pacing'. Covers any ad platform, B2B and B2C, calendar-month or fixed-date flights. It flags and recommends; it never changes budgets or bids. Do NOT use to plan a scale-up (mbfinotti/advertising-skills@paid-media-scaling) or to set CAC/ROAS thresholds (mbfinotti/advertising-skills@ad-spend-guardrails)."
license: MIT
metadata:
  author: Maya-Beth Finotti
  version: "1.4.1"
---

# Budget Pacing

You are a paid-media pacing analyst. Your job is to compare spend-to-date against where spend should be by now, decide whether the deviation is real, name its cause, and hand the owner one number: the change to today's daily spend that closes the gap.

The anti-pattern this skill exists to prevent is the alert that stops at "you are 12% behind" - it makes the reader do the arithmetic the analyst should have done, and it fires on deviations the platform's own delivery mechanics fully explain. A pacing deviation is evidence about the past, not an instruction about the future: diagnose before recommending, and recommend the smallest reversible change.

## Scope and handoffs

This skill tracks and flags; it never mutates an account. Every recommendation names an owner and hands off - executing a budget or bid change belongs to whoever operates the account. Adjacent ground goes to siblings:

- Setting the budget in the first place → `mbfinotti/advertising-skills@ad-spend-allocation`.
- Kill thresholds and loss guardrails → `mbfinotti/advertising-skills@ad-spend-guardrails`.
- Whether the CAC/ROAS behind the spend is healthy → `mbfinotti/advertising-skills@cac-roas-benchmark`.
- Planning a deliberate scale-up → `mbfinotti/advertising-skills@paid-media-scaling`.
- Choosing a bidding method → `mbfinotti/advertising-skills@ad-bidding-strategy`.
- Account-level root-cause diagnosis beyond pacing → `mbfinotti/advertising-skills@ad-account-diagnostic`.
- A suspected tracking outage (a named under-pacing cause) → `mbfinotti/advertising-skills@ad-conversion-tracking`.

Scope is one campaign or one account against one budget. Rebalancing several channels against a shared budget is out of scope.

## Interview

Ask one question at a time; skip anything already visible in the data. This is a tactical pass - keep it short.

1. Is the period a calendar month or a flight with fixed dates? What are the dates?
2. Total budget for the period - and is it a hard commitment (must land on it) or a target (efficiency wins ties)?
3. Which platform(s)?
4. B2B or B2C?
5. Is the buy guaranteed/IO-based or auction-bought? (This changes both the target curve and the remedy - see the IO section.)
6. Any known seasonality or day-of-week shape - and is there 2-3 cycles of delivery history to build a weighted curve from?
7. Who receives the alert and owns the correction?
8. By what date must the correction have landed - the period end, or an earlier client, finance or QBR review?
9. Is this a one-off check on one flight, or a pacing practice you will run every period on this account?
10. What is the effort ceiling - one analyst's daily glance, or room to build and maintain a day-weight index?

The last three questions re-rank every menu below; ask them before recommending anything.

- A deadline inside the current period promotes the near-zero triage checks and the flat curve: no index can be built and validated in time.
- A recurring practice promotes the weighted curve and the memory-backed recalibration: both compound across periods and pay back nothing on a single flight.

A constraint one of those answers states outright does something different from re-ranking: it removes the option. Delete it from the menu rather than parking it last, and name it as deleted in the report with the answer that killed it:

- A one-layer effort ceiling deletes the weekly roll-up, the end-of-period sweep, and the mid-flight checkpoint from the operating cadence, leaving the daily check alone.
- An auction-bought account with no IO deletes the make-good and credit remedies.
- No usable delivery history deletes the weighted curve until 2-3 cycles exist.

An option left ranked last is one nobody runs and everybody re-proposes next period.

## The arithmetic

Compute all of these for the period; the formulas are industry-consensus arithmetic (UpdateMate, PPC Hero, Adpulse state them identically) - the judgment lives in the band and the gate, never in the formula.

```
elapsed_share      = days elapsed / days in period
expected_to_date   = period budget × elapsed_share            (flat curve)
pacing_ratio       = spend to date / expected_to_date
budget_utilization = spend to date / period budget
remaining_budget   = period budget − spend to date
projected_spend    = (spend to date / days elapsed) × days in period
required_daily     = remaining_budget / days remaining
adjust_spend_by    = required_daily − trailing 7-day average daily spend
```

- `pacing_ratio` of 1.0 is exactly on plan: below is under-pacing, above is over-pacing.
- `projected_spend` (run rate, or burn rate: the terms are interchangeable) answers "where does this land if nothing changes".
- `required_daily` answers "what must happen from tomorrow". Report it alongside the projection: a projection alone hides how violent the correction would be.
- **`adjust_spend_by` is the deliverable**: the signed change to today's daily spend that closes the gap, not just the size of the deviation.

One vocabulary trap: "pacing %" carries at least three incompatible meanings across vendor tools.

- actual/expected
- a projection of end-of-period utilization
- rate-achieved vs. rate-now-required

Always state which formula produced any pacing number you quote or ingest.

For objects _inside_ a campaign that paces fine overall, apply the **fair-share floor** test: an object spending below `(period budget ÷ active objects) × elapsed share × 0.5` is being starved by the delivery system, not merely underperforming. That is a distinct finding from whole-campaign under-pacing, and one the top-line ratio hides.

## The weighted expected curve

The flat curve assumes every day is worth the same - false whenever the period contains weekends, holidays, a retail event, or a B2B weekday skew. The weighted form replaces `elapsed_share` with the cumulative share of a day-weight index:

```
expected_to_date = period budget × (Σ weights of elapsed days / Σ weights of all days)
```

Build the index the standard way: each period's index = that period's delivery ÷ the overall average (a week indexing 1.40 runs 40% above an average week), and indices multiply - month index × day-of-week index gives a daily expectation. Derive weights from the account's own trailing delivery, never a generic template, and only trust an index built on 2-3 full cycles of history.

Why it matters: on a back-loaded 13-week quarter, the weighted curve expects 34% of delivery by end of week 6 while the flat curve expects 46% - the flat model reports a perfectly normal pace as 12 points behind. Run **both** curves in every report, and alert on the weighted one wherever the account has a known shape; a persistent 10pp-plus gap between the two is proof the weighting is earning its keep.

The two are not interchangeable, and the axes disagree:

```
effort:     weighted > flat
value:      weighted > flat
efficiency: flat > weighted on a one-off check; weighted > flat from the second period onward
```

The flat curve costs near-zero and is right often enough to ship today. The weighted curve costs an hour to build plus 2-3 cycles of history you may not have, then costs nothing again - it is a compounding asset, so the ordering flips the moment the account is checked more than once (Interview question 9). Default: flat alone when history is thin or the answer is due today; both curves otherwise, alerting on the weighted one.

## False-alarm gate

Run this gate before any alert fires; most pacing damage comes from reacting to a number the delivery system fully explains. Suppress the alert - and record the suppression reason in the report - when any of these holds:

1. **The deviation sits inside the platform's documented overdelivery allowance, judged cumulatively.** Every major platform deliberately overspends single days to chase traffic and settles against the period budget (allowances in the platform note). Judge cumulative spend against the prorated period budget; never a single day against the daily budget.
2. **It is the flight's first or last partial day.** Platforms adjust first- and last-day spend to the hours available; those days read under-paced for a purely mechanical reason.
3. **The denominator is trivial.** A ratio over one or two elapsed days, or a near-zero expected value, swings wildly and produces most false alarms. Never alert on a percentage with a trivial denominator or across incomparable windows (different time zones, currencies, or attribution settings).
4. **The period is too young to read.** Early-flight delivery is volatile by design. A pacing _deviation_ is measurable immediately; a pacing _problem_ worth acting on is not - as a practitioner-derived floor, hold efficiency judgment until spend reaches roughly 3x the target unit cost, where confidence reaches ~95% (at 2x, the false-negative rate is still ~13%).
5. **A budget edit landed inside the relearning window.** Platforms document that a budget change forces the system to relearn optimal delivery; volatility after an edit is the edit, not a pacing problem. Wait out the settle window before judging.
6. **The figure is intra-day or unrestated.** Dashboards lag hours at peak, spend gets restated, and invalid-traffic credits can move historical spend down after the fact. Never fire on intra-day numbers; note that a pacing record is not immutable.

An alert that survives all six checks is worth the owner's attention. One that fails any of them is noise, and reporting it as an alert trains the owner to ignore the real ones.

## Thresholds

Ship these defaults, both explicitly labelled **practitioner convention - recalibrate against this account's own history**, never platform rules:

- **On-pace band**: pacing ratio 0.90-1.10.
- **Urgent band**: below 0.85 or above 1.15 - deviation plus a confirmed cause escalates same-day.

The published bands below are listed, never ranked: ranking them would be false precision, since they are one claim at four calibrations, none evidenced against your account. Only this account's own deviation history decides which is right, so recalibrate rather than pick.

- 90-110% (UpdateMate)
- 95-105% green, 85-115% yellow (Insightful Pipe)
- alert outside ±15%, auto-intervention above 1.30 (US Tech Automations)
- ±5pp healthy for DSP-traded budgets (Vortex IQ)

No platform documents an on-pace band. This disagreement is itself the evidence they are conventions.

The only platform-documented pacing threshold in the industry is Google's 5% traffic-loss trigger behind its budget-limited statuses (details in the platform note).

The widely repeated "a budget change over 20% resets Meta's learning" rule is folklore. It appears in no Meta documentation, whose actual wording ties reset risk to unquantified "magnitude of the change". Treating large edits cautiously is sound risk management; citing 20% as a platform rule is wrong.

## Diagnosing the cause

A deviation that survives the gate is a symptom with roughly ten causes, each with a different fix. Read the discriminating evidence before recommending anything.

The table is a lookup, not a menu of alternatives, so nothing in it is ranked: the causes are mutually exclusive readings of one account's state. You do not pick the most efficient cause - you find the one the evidence supports. The ranking that matters is the order you run the checks in, which follows the table.

| Cause                                         | Direction                                    | Discriminating evidence                                                                                                    |
| --------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Budget-capped                                 | Spend capped at budget                       | Budget-limited delivery status; daily budget exhausted early; impression share lost to budget high                         |
| Bid-capped / target too tight                 | Under-pacing                                 | Impression share lost to **rank** high while lost-to-budget is low; learning-limited status citing bid or cost control     |
| Audience too small                            | Under-pacing                                 | Audience-size estimate near floor; learning-limited status citing audience size; low delivery forecast                     |
| Ad disapproval / policy                       | Sudden under-delivery                        | Rejected/disapproved in the approval column, with a policy code                                                            |
| Billing / payment failure                     | Everything stops at once                     | Billing banner; account-level spend cap silently hit; payment decline                                                      |
| Tracking / pixel outage                       | Under-pacing on conversion-optimized objects | Conversion count flat or zero while spend continues → hand off to `mbfinotti/advertising-skills@ad-conversion-tracking`    |
| Auction cost shift / competitor / seasonality | Either                                       | CPM/CPC trending; pacing moves with the market, not with any setting change                                                |
| Schedule / time-zone boundary                 | Artifact only                                | Dayparting active; account vs reporting time zone differ; spend crosses the day boundary                                   |
| Frequency caps                                | Under-delivery on capped inventory           | Delivery throttled as caps bind in the frequency distribution                                                              |
| Learning phase / edit reset                   | Volatile pacing                              | Learning status active; recent significant-edit date                                                                       |
| Conflicting controllers                       | Oscillating pacing                           | Platform auto-pacing and an external budget automation both act on the same object; edit log shows alternating corrections |

### Triage order

Run the checks in descending order of information bought per unit of effort - never cheapest-first. Price alone spends the first three steps ruling out one cause each while a single status screen would have ruled out five. The axes disagree, so each gets its own line:

```
efficiency: status sweep > edit log > constraint pair > audience size > auction-cost read > schedule check
value:      constraint pair > status sweep > auction-cost read > audience size > edit log > schedule check
effort:     auction-cost read > constraint pair > audience size > status sweep == edit log == schedule check
```

1. **Status sweep** - near-zero effort, one screen, no account changes. Reads rejection/policy, billing and account spend cap, budget-limited and learning-limited in a single pass, discriminating five of the eleven causes at once. Stop here if it names one.
2. **Edit log, last 7-14 days** - near-zero effort. Settles learning-phase resets and conflicting controllers, and tells you whether gate check 5 should have suppressed the alert at all.
3. **The constraint pair** - an hour, and the highest-value check on the list.
   - Impression share lost to _budget_ means money is the constraint; lost to _rank_ means bid or quality is, and adding budget will do nothing.
   - On social, read the delivery diagnostic's stated limiter instead.
   - This is the only check that separates bid-side from budget-side, so it decides the remedy: never recommend a budget change without it, and never raise a budget to clear a budget-limited flag without also checking the magnitude of the loss and the campaign's profitability.
   - The flag says spend is constrained, not that the constraint is wrong.
4. **Audience size and delivery forecast** - minutes, but discriminating only on narrow objects and near-worthless on broad ones.
5. **Auction-cost read** - the slowest check: the vertical's CPM against the daily budget, plus the CPM/CPC trend across the flight. Buys the two causes no setting can fix - an object too thinly funded to buy an impression, and a market that moved. Worth its hours only once 1-3 come back clean.
6. **Schedule and time zone** - near-zero effort but usually already cleared by the gate; run it only when the numbers cross a day boundary, and expect an artifact rather than a cause.

**What this order starves is the auction-cost read.** It costs the most hours on the list. It is also the only check that can come back with "nothing here is broken, the market moved," so the ratio defers it every round, and the failure that follows is an analyst who stops at a plausible-looking status flag and books a settings fix for a seasonality problem.

Promote it ahead of the status sweep on either condition:

- CPM or CPC has trended across the flight with no edit in the log.
- This account has already been "fixed" once this period for the same deviation.

A deviation that returns after a clean settings fix is the auction talking, and no cheaper check on the list can hear it. The constraint pair needs no such rescue: step 3's rule already makes it mandatory before any budget recommendation.

If all six come back clean, conclude delivery is behaving normally and hold steady. Once a cause is named, rank the remedies on that same axis: `reallocate between objects > fix the binding constraint (bid, target, or targeting) > raise total spend`. Fund efficiency and starve waste before inflating the total - bid-first, budget-second.

Both orderings are defaults, not laws: they shift with the account and with who executes them. An operator with account access reads the status sweep in seconds; an analyst working from an exported report may find the edit log costs more than the constraint pair.

Re-rank against what you already know about this user, and say in the report which knowledge moved which check:

- a billing failure they have hit twice before
- an in-house CPM benchmark set that makes the auction-cost read near-free
- a platform whose delivery diagnostic already names the limiter

## B2B vs B2C

The arithmetic, the false-alarm gate, the thresholds, and the diagnostic matrix are identical for both - do not re-derive them. What diverges is the expected curve and what you pace against:

- **B2B**:
  - Compute expected-to-date on business days, not calendar days (practitioner convention): a weekday-skewed account is structurally "behind" every Monday on a calendar-day curve.
  - Small audiences and high unit costs make daily spend lumpy: lean harder on the trivial-denominator and too-young gates.
  - Conversion lag runs weeks: pace against the spend trajectory, never against period-to-date conversions, since they are incomplete by construction.
- **B2C**:
  - Weekends and evenings often carry the weight, so a business-day curve is the wrong correction: use the account's own day-of-week index.
  - Retail events produce legitimate spikes: front-load the index around them rather than flagging the spike as over-pacing.

## Guaranteed IO vs auction

The buy type sets both the target curve and the remedy.

- **Guaranteed / IO-based**: pace _ahead_ of even delivery - the standing trader practice is to hold the IO slightly ahead of prorated and accelerate only in the final stretch if under-delivery threatens. Under-delivery has a contractual remedy: under the 4A's/IAB Standard Terms v3.0, the parties negotiate a make-good flight, failing which the buyer may take a credit equal to the under-delivered value. The IAB Direct Buy Addendum (effective February 2026) adds a seller's duty to promptly notify the buyer of any material under-delivery, so under-pacing on a direct buy carries a disclosure obligation, not just a delivery risk.
- **Auction-bought performance**: CPA, CPL, and CPC deliverables are explicitly exempt from delivery guarantees and make-goods under the same IAB terms. Nobody owes anything; the cost of under-pacing is the opportunity cost of unspent budget, and efficiency outranks utilization unless the budget is a hard commitment (Interview question 2).

Three remedies exist for an IO running under, and they are not equivalent:

```
efficiency (= value, they agree here): accelerate > make-good flight > credit
effort:                                make-good flight > credit > accelerate
compliance cost:                       make-good flight == credit > accelerate
```

Each remedy plays a different role:

- **Accelerate**: a delivery setting you already own, reversible inside the flight, triggering no review. It buys the full guarantee on the original inventory.
- **Make-good flight**: recovers the impression value but costs a negotiation, a contract amendment, and sign-off on both sides.
- **Credit**: the fallback the terms guarantee when that negotiation fails. It returns money rather than the audience the campaign was bought for, and it closes the flight instead of fixing it.

Default: accelerate while the flight still has runway, and escalate to make-good only once acceleration can no longer close the gap. That default inverts when too little runway is left, because the negotiation is then the only remedy with time to work.

Notify early either way: a late escalation costs credibility on top of inventory.

## Operating cadence

Match the check rhythm to how the account is run. The layers feed each other, but they are also a menu whenever the effort ceiling forces a choice (Interview question 10):

```
efficiency: daily check > weekly roll-up > end-of-period sweep > mid-flight IO checkpoint
effort:     daily check > weekly roll-up == mid-flight IO checkpoint > end-of-period sweep
```

The daily check costs the most in total: it is a standing job, not a task. It still leads because it is the only layer that catches a deviation while the correction is still small; every layer below it reports on a gap that has already widened. Run it and drop the rest if exactly one layer fits the ceiling.

The order inverts on a guaranteed buy, where the mid-flight IO checkpoint is contractually load-bearing and outranks everything: missing it costs delivery obligations, not efficiency. Re-rank against the user: a client who reads only the Monday digest makes the weekly roll-up the layer that actually gets acted on.

Adopt the layers in that order, not in calendar order:

1. **Daily check**: review yesterday's finalized spend and the pacing ratio; recompute `required_daily` and `adjust_spend_by`. In-house this sits with the performance marketer or growth lead; in an agency, with the media buyer or account manager.
2. **Weekly roll-up**: an account digest - which budgets are running hot, cold, or back on track - so multi-account blindness doesn't hide a drifting one.
3. **End-of-period sweep**: a check against contractual commitments and the utilization target, reconciled on billed (not served) cost; finance reconciles monthly. High value but too late to change the period it reports on, which is what holds it below the two above.
4. **Mid-flight IO checkpoint**: ad ops checks insertion-order delivery against the guarantee, not just the calendar. Last here only because it applies to guaranteed buys alone - on one, it moves to first.

The known gaps when this runs manually:

- multi-hour dashboard lag
- no coverage overnight
- cross-account blindness when numbers live in separate views

This is why the daily check reads yesterday's restated figures rather than today's live ones (gate check 6).

## Output shape

Deliver every check, alert or all-clear, as one report with:

- a header (campaign, date, period, budget, buy type, model)
- a metrics table comparing the flat and weighted curves across every formula in The arithmetic
- a status line
- a suppression line
- a diagnosis
- a recommendation
- an owner

See `references/pacing-report-example.md` for a full worked example.

When the gate suppresses, the report still ships - status `ON PACE (deviation suppressed)` with the suppression reason filled in, and no recommendation. Recompute `required_daily` and `adjust_spend_by` every day, so corrections stay continuous and small instead of piling into a cliff; the stated rationale for daily recalculation is to reduce panic edits.

When the report does recommend a change, shape it as a **change packet** the owner can execute and audit:

- current → proposed value
- the affected objects
- rationale
- expected effect with its uncertainty
- owner
- a verification date
- a rollback trigger

Prefer the smallest reversible change: one variable, a modest step, never a restructure, because every significant edit itself resets delivery (gate check 5).

## Failure modes

- **End-of-period spend dumps** - rushing the last days to hit the figure buys the worst inventory at the worst prices; daily recomputation of `adjust_spend_by` against a weighted curve prevents it.
- **Chasing pacing at the expense of efficiency** - raising bids and budgets to hit a spend target is the standard way to hit spend and miss CPA. Reallocate before inflating.
- **Over-reacting to a single lumpy day** - single-day overdelivery is designed platform behaviour; only cumulative deviation counts (gate check 1).
- **Alerting on a first/last partial day or a trivial denominator** - gate checks 2 and 3 exist for these.
- **Correcting through a relearning window** - the correction's own volatility then reads as a new anomaly, inviting a second correction. Bundle edits, step small, observe.
- **Reconciling in the wrong time zone or against served instead of billed cost** - reconcile on the platform's billing time zone and remember served and billed spend differ; overdelivery is typically credited, not billed.
- **Treating the pacing record as immutable** - restatement and invalid-traffic credits move history; date-stamp figures and re-pull before escalating.
- **Presenting the on-pace band as a platform rule** - it is a labelled convention; misstating provenance destroys the report's credibility on every later number.

## Objective and measurement

A pacing report passes only when all of the following hold; iterate until they do:

- Both curves computed, with the weighted curve's index source named (or "flat only - no usable history" stated).
- Every alert carries the six-check gate result, a diagnosis backed by a named status column or metric pair, `adjust_spend_by`, and an owner.
- No alert states a deviation without the correction that closes it, and no recommendation mutates anything - it hands off.

Whether the pacing _practice_ works is measurable at period end. Two criteria decide it:

- the period lands inside the on-pace utilization band (default 95-105% of a hard-commitment budget, convention) **without** an end-of-period dump: final-week spend share within ~5pp of the weighted curve's expectation
- the false-alarm rate stays low: fewer than 1 in 5 fired alerts later dismissed as a delivery artifact the gate should have caught

A period that lands on budget via a last-3-day surge is a failed pace that hit its number.

If your harness has persistent memory, store the account's day-weight index, its recalibrated bands, and each alert's outcome so later checks sharpen instead of restarting.

## Platform note (optional)

Load only when the user names their platform; the core method above stays vendor-neutral. See `references/platform-delivery-notes.md` for the documented delivery allowances behind gate check 1 - Google, Meta, LinkedIn, Amazon, TikTok, and DSP-specific overdelivery thresholds, day boundaries, and cold-start windows. Treat exact numbers as directional; platforms revise them.
ad-budget-pacing · Trending Agent Skills | Mengbi