# MGID Source Auditor

Audits selective bidding entities and recommends blocks or QF changes. **All rules,
thresholds, and impact formulas live in this skill** (and reference.md).

Tools: [../_shared/ads-mcp-tools.md](../_shared/ads-mcp-tools.md)  
Assumptions: [../_shared/assumptions.md](../_shared/assumptions.md)

Prerequisite: tracking gate pass.

---

## Required inputs

| Input | Required | Default |
|---|---|---|
| Campaign ID(s) | Yes | simulator scope list, user ids, or all active when run standalone |
| Date range | Yes | last 7 days (max 90) |
| Target CPA | Yes | `get_campaign` → `bidding.price` if strategy=cpa, else **ask user** |

---

## MCP tools

| Tool | Purpose |
|---|---|
| `get_campaign` | `sourcesOptimization`, `bidding.strategy`, `bidding.price`, type (push?) |
| `get_selective_bidding_statistics` | Performance by entity |
| `get_quality_factors` | Current QF for proposed from/to values |
| `get_source_filters` | Existing blocks (avoid duplicate recs) |

### Campaign type gate (before anything else)

```
type in (content, product) → audit normally
type == push               → audit with entity: providers
type in (search_feed, newsletter) → SKIP, report as unsupported
```

`search_feed` and `newsletter` campaigns have no source/widget entities, so
selective-bidding rules are meaningless there. List them in the output as
skipped with the reason — never silently drop or silently audit them. See the
campaign-type table in [../_shared/ads-mcp-tools.md](../_shared/ads-mcp-tools.md).

### Entity selection

```
sourcesOptimization == true  → entity: sources
sourcesOptimization == false → entity: widgets
campaign type push           → entity: providers
```

Never fetch sources and widgets for the same campaign in one audit pass unless
comparing explicitly.

---

## Bidding strategy → action

| `bidding.strategy` | Poor performer action |
|---|---|
| `cpc` | **ASSUMPTION:** QF −15% (max −25%) when CPA > 1.5× target |
| `cpa` (CPA Tune) | **ASSUMPTION:** block when CPA > 2× target — **unless learning phase** |
| `maxConversion` | **ASSUMPTION:** block if CPA > 3× target; else QF −10% |

### CPA Tune learning phase

Before recommending blocks on `cpa` campaigns, check
[assumptions.md](../_shared/assumptions.md). If learning → suppress with
`cpa_tune_learning`; emit monitor alert instead.

---

## Minimum data (**ASSUMPTION**)

- Clicks ≥ 50 OR conversionsBuy ≥ 5
- Spend ≥ $10 for block actions

---

## Poor performer triggers (**ASSUMPTION**)

| Condition | Action |
|---|---|
| CPA > 2× target (CPA Tune, post-learning) | block |
| CPA > 1.5× target (manual CPC) | adjust_qf |
| Spend ≥ $50, conversionsBuy = 0, tracking OK | block or QF |
| Top-3 converter by volume + CPA ≤ target | skip block |

Full decision tree: [reference.md](reference.md)

---

## Impact estimation

Formulas in [reference.md](reference.md) — all **ASSUMPTION**.

---

## Output

**Chat:** entity counts + top N actions table.

**Return:** `Recommendation[]` (`block_source`, `block_widget`, `block_provider`, `adjust_qf`).

---

## Apply

| Action | Tool |
|---|---|
| QF change | `update_quality_factors` |
| Block/unblock | `update_source_filters` |

Write scope required. No batch-* tools.


---

# Source Auditor — Reference

Assumptions registry: [../_shared/assumptions.md](../_shared/assumptions.md)

All thresholds below are **ASSUMPTION** until backtested.

---

## Decision tree

```
tracking gate pass?
  no → suppress
min clicks/spend met?
  no → suppress (insufficient_data)
cpa strategy + learning phase?
  yes → suppress block (cpa_tune_learning); alert only
bidding.strategy == cpc?
  CPA > 1.5× target → adjust_qf −15%
bidding.strategy == cpa? (post-learning)
  CPA > 2.0× target → block
maxConversion?
  CPA > 3.0× target → block; else CPA > 1.5× → adjust_qf −10%
```

---

## Top converter downgrade

Sort entities by `conversionsBuy` desc within campaign.

- Top 3 AND CPA ≤ target → skip block
- Top 3 AND CPA > target but &lt; 3× target → adjust_qf −10% instead of block

---

## Field mapping (`get_selective_bidding_statistics`)

| Metric | Fields |
|---|---|
| ID | `sourceId` / widget uid in response |
| Name | `sourceName` |
| Spend | `spent.amount` |
| Clicks | `clicks` |
| Conversions | `conversionsBuy` |
| CPA | `conversionsCostBuy.amount` |
| ROAS | `roas` |

---

## Impact formulas (**ASSUMPTION**)

**Block:**

```
wasted_share = clamp(1 - target_cpa / actual_cpa, 0, 0.95)
daily_savings = (entity_spend_7d / 7) × wasted_share
range = [daily_savings × 0.85, daily_savings]
```

**QF −N%:**

```
spend_delta ≈ -(entity_daily_spend × N / 100)
```

---

## Confidence matrix (**ASSUMPTION**)

| Case | Confidence | Risk |
|---|---|---|
| Block, clicks ≥ 100, CPA > 2× | High | Low |
| Block, clicks 50–99 | Medium | Low |
| QF −15% | Medium | Low |
| Block during CPA Tune learning | — | **Suppressed** |
