---
name: maintain-catalog-feed-hygiene
description: >-
  Keeps a live catalog clean and matched once ads are running: works the Commerce Manager
  diagnostics queue (errors before warnings), verifies availability, price/currency, image
  quality, GTIN, and brand on a sample of items, screens for policy disapprovals, and sets a
  refresh cadence. Its core job is the pixel↔catalog matching contract, pixel/CAPI event
  content_ids must equal the catalog's retailer_id exactly, content_type must be correct (product
  vs product_group), and value + currency must be present on every commerce event, because a
  mismatch is what produces "products not matching" and silent zero-delivery catalog ads.
  Corrections go back through mads_upsert_catalog_products, idempotent on retailer_id. Reach for it
  on a routine cadence, whenever catalog ads under-deliver, or after any bulk feed update. It ends
  at a clean, matched feed, it does not build the initial catalog (set-up-product-catalog) or the
  event instrumentation itself (set-up-pixel-and-standard-events).
---
# Maintain Catalog Feed Hygiene and Pixel Matching

## Purpose
Catalog ads live or die on two things: whether the feed data is actually correct, and whether
pixel events describe products the same way the catalog does. This skill is the recurring
maintenance loop, diagnostics triage, field spot-checks, policy screening, and above all the
content_id/content_type/value+currency contract between pixel and catalog, that keeps
`launch-advantage-plus-catalog-ads` and `build-collection-ads-and-product-sets` actually serving.

## When to run
- Routine cadence check (weekly, or immediately after any scheduled feed refresh).
- Catalog ads report "products not matching," near-zero delivery, or a sudden impression drop
  despite a healthy budget.
- Disapproval rate spikes or a new policy rejection appears.
- After any bulk catalog update, to confirm the upsert landed clean.

## When NOT to run
- No catalog exists yet → `set-up-product-catalog`.
- The feed is healthy and the task is building new ads on top of it →
  `launch-advantage-plus-catalog-ads`, `build-collection-ads-and-product-sets`.
- The pixel itself isn't instrumented yet (no base code, no CAPI) →
  `set-up-pixel-and-standard-events`.

## Prerequisites
- An existing catalog with items, `mads_list_catalogs`.
- A pixel already connected to the catalog (from `set-up-product-catalog`), `mads_list_pixels`.
- Commerce Manager diagnostics access for the UI-only error/warning queue (HUMAN STEP) alongside
  the API-level checks VigilDog runs directly.

## Procedure
1. **Pull the current snapshot.** `mads_list_catalogs` for item count and last-update time, a
   count that hasn't moved since the last check may mean the feed refresh silently stopped.
2. **HUMAN STEP: work the Commerce Manager diagnostics queue.** Errors (blocking disapprovals)
   first, warnings next, opportunities as backlog.
3. **Spot-check required fields on a sample.** id (retailer_id), title, description, availability,
   condition, price with currency, link, image_link, brand, GTIN, flag any row missing one.
4. **Verify price and currency against the live site.** HUMAN STEP: spot-check a handful of
   product URLs. A mismatch here is a common, easy-to-miss disapproval cause.
5. **Check image-quality flags** (resolution, background, watermark or promo text) surfaced in
   diagnostics and queue fixes.
6. **Screen for policy disapprovals.** Restricted categories, tobacco, weapons, supplements,
   IP-infringing goods, get rejected at the catalog level; confirm they belong in the catalog at
   all before spending a cycle "fixing" them.
7. **Verify the matching contract.** Sample pixel events via `mads_list_pixels` and compare against
   catalog retailer_ids: content_ids must match exactly (case and whitespace included),
   content_type must be product or product_group correctly, and value + currency must be present.
8. **Isolate a "products not matching" report.** `mads_send_conversion_event` a controlled test
   event with a known retailer_id as content_id, correct content_type, and value + currency, to
   tell whether the break is event-side (wrong ids being sent) or catalog-side (item missing or
   unindexed).
9. **Correct errors through the catalog, not around it.** Stage fixed rows (pull from
   `sheets_get_values` if corrections are tracked in a spreadsheet), preview the diff, get user
   approval, then `mads_upsert_catalog_products`, idempotent on retailer_id, so it overwrites
   cleanly rather than duplicating.
10. **Re-verify after propagation.** Catalog changes can take minutes to a day to index, re-pull
    `mads_list_catalogs` / diagnostics before declaring an error fixed.
11. **Confirm or reset the refresh cadence** with the user (see Decision rules) and log an owner.
12. **Confirm delivery recovered.** `mads_run_insights` / `mads_get_insights` on the
    affected ad sets to confirm impressions and matches came back after the fix.

## Decision rules
- **Error-queue health bands:** under ~5% of items in error → healthy, keep monitoring; 5-15% →
  triage this week; over 15% → treat the catalog as broken and pause new ad builds on it until
  fixed.
- **Matching-break triage order (cheapest fix first):** content_id parity, then content_type
  correctness, then propagation delay, then product-set eligibility/exclusion.
- **Refresh cadence:** stable catalog → daily minimum; price/stock that moves intraday → hourly or
  real-time API upsert; flash sales or limited-time pricing → real-time.
- **Non-negotiables on every commerce event:** content_ids equal retailer_id exactly, content_type
  correct, value + currency present, any one missing breaks matching or reporting silently.
- **Done means:** error queue inside the healthy band, sampled fields complete, price/currency
  verified against the site, the matching contract spot-checked clean, and a refresh cadence +
  owner logged.

## Common failure modes
- **Silent retailer_id drift** after a platform re-export or re-migration, breaks matching
  catalog-wide, not just for the changed items.
- **Blaming Meta for "products not matching"** when it's almost always a content_id or
  content_type mismatch on the event side.
- **Fixing the feed but never re-verifying**, a stale diagnostics error keeps getting reported as
  live.
- **Re-uploading before the first upsert has propagated,** creating confusing duplicate-looking
  diagnostics.
- **Missing value/currency on events** breaking ROAS optimization and reporting with no obvious
  error message.
- **Leaving restricted-category items in "just in case"** and eating recurring policy disapprovals
  for it.

## Related skills
- Run after: `set-up-product-catalog` (the initial build this skill maintains).
- Run alongside: `launch-advantage-plus-catalog-ads` (where matching symptoms surface),
  `build-collection-ads-and-product-sets` (product-set eligibility overlaps with hygiene),
  `set-up-pixel-and-standard-events` (measurement) for event-parameter depth.
