← All skills
Hygiene

meta-zombie-audit

Meta zombie audit

Finds objects your tracking sheet or database thinks are ACTIVE that Meta quietly stopped returning.

What it does

Most ads syncs are upsert-only: they write what the API returns and never touch what it doesn't. But when a campaign or ad set is archived or deleted on Meta, it simply stops appearing in default API listings. Nothing comes back to say this is gone, so the local row keeps its last status forever.

The result is a zombie: your database, spreadsheet, or dashboard says ACTIVE while Meta archived the thing weeks ago. In production we caught an ad set that read ACTIVE locally for 11 days after it was archived on Meta; every report and every automated decision built on that row was wrong for 11 days. This skill finds your zombies.

Quick start

Terminal
git clone https://github.com/PierreNicolasMarquez/pierce-skills.git
cp -r pierce-skills/skills/meta-zombie-audit ~/.claude/skills/

Then in Claude Code: "run the meta-zombie-audit skill against my campaigns table".

The full SKILL.md, with the exact API calls, lives in the pierce-skills repo. MIT-licensed, runs on your token, never phones home.

How it works

You bring your local list (a synced table, a tracking spreadsheet, a board) with object id, name and believed status, plus a Meta token with ads_read.

  1. 1

    Pull truth with archived objects included

    Default listings hide the dead, so the skill asks for everything explicitly with an effective_status filter covering ACTIVE, PAUSED, ARCHIVED, CAMPAIGN_PAUSED and WITH_ISSUES (plus ADSET_PAUSED for ad sets), paginating to the end. Notes from running this for real: DELETED is not accepted in the listing filter, the filter value is JSON and must be URL-encoded, and any error key in a response is a hard stop, never an empty result.

  2. 2

    Direct-fetch anything still missing

    Any id in the local list absent from step 1 gets an individual lookup. An error on that fetch (object missing or a permission error on a deleted object) means DELETED server-side.

  3. 3

    Diff every local row

    ZOMBIE: local says ACTIVE, Meta says ARCHIVED, DELETED, or not found. The dangerous class, reported first, with updated_time when available so you know how long the row has been lying. STATUS DRIFT: both objects exist but statuses differ, including an ACTIVE ad set under a paused campaign reading ADSET_PAUSED effective. ORPHAN: exists on Meta, absent locally. CLEAN: statuses agree.

  4. 4

    Report blast radius

    One table sorted zombies first: id, name, local status, Meta effective_status, last Meta update. Then one sentence per zombie on blast radius: what reports or automations read this row?

  5. 5

    Fix the class, not the instance

    Repairing the rows fixes today. The pattern fix is sync-side expiry (after each sync, any locally-ACTIVE row not present in the latest API response gets a missing_since flag and is demoted after a grace period) or a read-side staleness filter (every consumer of ACTIVE also requires recent spend or impressions before trusting the status). A synced database wants the first, a spreadsheet the second.

Caveats

  • Deleted objects are only caught by the direct fetch in step 2; the listing filter cannot return them.

  • An empty API response and an API error are different things. Treat any error key as a hard stop or the audit will certify a broken pipe as clean.

Related skills

The managed version

Pierce runs this every week on your accounts, and every action it takes is approved by you in Slack.