Research & Analysis๐Ÿค–claude๐ŸŒuniversal

programme-anomaly-watch

skills/programme-anomaly-watch/SKILL.md

Use this skill to spot week-over-week anomalies across an agency's portfolio of brands and networks โ€” revenue drops, reversal spikes, dead links, publishers that fell out of the top 10. Designed to run on a schedule via Claude's own scheduling so the agency learns about problems before clients do. Trigger on: "Are there any problems with the affiliate programmes this week?", "Anomaly check", "Anything weird in the affiliate data?".

Quick Start

Install this SKILL.md

npx skills add https://github.com/bobberrisford/affiliatemcp/tree/main/skills/programme-anomaly-watch
---
name: programme-anomaly-watch
description: |
  Use this skill to spot week-over-week anomalies across an agency's portfolio of brands and networks โ€” revenue drops, reversal spikes, dead links, publishers that fell out of the top 10. Designed to run on a schedule via Claude's own scheduling so the agency learns about problems before clients do.
  Trigger on: "Are there any problems with the affiliate programmes this week?", "Anomaly check", "Anything weird in the affiliate data?".
---

# Operating instructions

You are checking the book for week-over-week anomalies. Output is a short, ranked list โ€” nothing more.

## Step 1 โ€” enumerate the book

Call `affiliate_resolve_brand` with no arguments. The response is an array of `{ brand, network, networkBrandId }` bindings.

If the array is empty, say "No brands registered โ€” nothing to watch" and stop. Do not pad.

## Step 1b - load recorded plans

Call `affiliate_list_client_strategies` once to see which registered brands have a plan recorded (`hasStrategy` / `hasKpi`) and whether any strategy directories are orphaned. For each registered brand in the book with either `hasStrategy` or `hasKpi`, call `affiliate_get_client_strategy({ brand })` to load its `strategy` prose and `kpi.targets`. Skip registered brands with no plan; most of the book may have none, and that is fine.

This is **advisory** context that reshapes severity (Step 4); it never changes what the data says. Report any `kpi.parseErrors` verbatim and ignore those targets. If orphan strategy directories exist, report them under `Failures`/notes and do not invent network data for them.

## Step 2 โ€” pick the windows

Default period: the last 7 days, ending today. Comparison window: the 7 days immediately prior. Express all dates as ISO `YYYY-MM-DD`. Honour explicit user overrides ("this month vs last month", named dates).

## Step 2b โ€” use the snapshot for the current-window health signal

Before fanning out, you may call `affiliate_build_brand_snapshot({ brand })` per brand for the current window (the 7-day default is `last7d`). Its value here is the count-honest `byNetwork` health: a network whose pull `failed` must not be read as "no anomalies". Treat a `failed` network exactly like a Step 3 binding failure โ€” report it under `Failures` and say its absence of anomalies is not safe to assume.

The anomaly detection itself stays on `get_programme_performance` below: the week-over-week checks need the **comparison window** (a custom prior range the snapshot does not carry), and the top-10-dropout and silenced-publisher checks need the **per-publisher** rows (the snapshot's breakdown is per-programme). So the snapshot informs health, not the anomaly maths.

## Step 3 โ€” fan out per binding

For each `(brand, network)` binding, call the network's performance tool twice โ€” current window and comparison window. Tool names follow `affiliate_<network>_get_programme_performance`:

- Impact advertiser: `affiliate_impact-advertiser_get_programme_performance({ brand, from, to })`

Issue in parallel. Each call returns `ProgrammePerformanceRow[]` with `publisherId`, `publisherName`, `clicks`, `conversions`, `grossSale`, `commission`, `currency`, `status`.

If a binding fails, capture the verbatim error and report it under a `Failures` line at the end. Do not treat a failure as an anomaly.

## Step 4 โ€” compute anomalies

Walk each `(brand, network)` binding and emit an anomaly for any of:

- **Revenue drop**: current-period `grossSale` is down more than 25% vs. the comparison window. Quote both figures and the percent drop.
- **Reversal spike**: the share of rows with `status: 'reversed'` (weighted by `grossSale`) is more than 2x the comparison-window baseline. Quote both ratios.
- **Top-10 dropout**: a publisher that was in the top 10 by `grossSale` in the comparison window is absent from the top 10 in the current window. Name the publisher and quote both ranks.
- **Publisher silenced**: a publisher with non-zero `conversions` in the comparison window has zero `conversions` in the current window (a 100% drop). Name the publisher.
- **Dead programme**: the binding produced zero `clicks` in the current window. Likely a tracking break or a dead link.

Also emit an anomaly for a **KPI threshold breach** where a brand has a compatible target: `reversal_rate` over a `<=` or `<` limit, or `approval_rate` under a `>=` or `>` floor, this window. Quote the actual rate and the target. For unsupported comparators or unavailable metrics, say the target is unsupported for this anomaly scan and exclude it rather than guessing.

Compute severity as the absolute current-period revenue at risk: for a revenue drop, the lost gross sale; for a silenced publisher, their comparison-period gross sale; for a dead programme, the comparison-period gross sale of the whole binding. Use the per-row `currency` โ€” do not normalise.

**Reshape severity by the recorded plan** (when one exists for the brand):

- A drop in a partner type the brand's `Strategy.md` **deprioritised** can be lower concern only when the row data or publisher name makes that partner type evident. Down-rank it, keep the anomaly visible, and say why ("down 30%, but coupon is a deprioritised channel for this brand"). If partner type is not evident, do not guess.
- A drop in a **preferred / priority** partner type, or anything that crosses a recorded **escalation threshold** ("flag any drop over 20%"), is urgent. Up-rank it within the anomaly list while still quoting the underlying current and comparison figures.
- A KPI threshold breach is ranked by the recorded limit, not a generic baseline.

With no plan recorded for a brand, rank it exactly as today on raw revenue at risk. Absence of a plan is never itself an anomaly.

## Step 5 โ€” present the report

Output a single compact list, ordered by severity desc. Each line: `<brand> ยท <network> ยท <anomaly type> ยท <magnitude> ยท <publisher(s)>`. One line per anomaly. No tables, no preamble.

If there are no anomalies, say "No anomalies this week" in one line and stop. Do not pad with "good news" commentary.

At the end, list any per-binding failures verbatim under a `Failures` heading so the user can retry. If a binding failed, the absence of anomalies for that binding is not safe to assume โ€” say so.

## Scheduling

This skill is designed to be useful when run on a schedule. When invoked by Claude's scheduler, the output should be short enough to read on a phone โ€” keep the anomaly list under ~12 lines if possible. If the book genuinely has more than 12 anomalies, group by brand and emit one line per brand summarising the count and the top reason.

## Constraints

- Never call something an anomaly without quoting both the current and comparison figures.
- Currency: respect the per-row `currency`. If a brand spans currencies, compute anomalies per currency.
- Do not invent thresholds. The thresholds in step 4 are the contract; if the user wants different ones, ask. A recorded KPI target adds a brand-specific threshold; it never loosens the step-4 ones.
- Recorded strategy and KPIs are advisory: they reshape severity and add KPI-breach checks, but never authorise an action and never change the underlying figures.
- A KPI target on a metric a bound network cannot supply is reported as unsupported for that network and excluded from anomaly ranking; never zero-fill it.
- Pair with `programme-performance-report` when the user wants the full per-publisher detail behind an anomaly.
Repository
7stars
1forks
View on GitHub
Details
DiscoveredOct 14, 2026
Last UpdatedSep 21, 2026
Quality Score
40/100

Related Skills

More research & analysis skills you might like

pr-improver
Research & Analysis
Runs an autonomous review-and-fix improvement loop over the current branch's changes until a PR review comes back clean, scoped mechanically to the directories the branch touched. Reviews are performed by an installed PR-review skill (default: pr-review-toolkit's review-pr). Use to fix review findings on a branch before opening or updating a pull request ('clean up this branch', 'fix this PR until review passes', 'run review-and-fix on my changes'). NOT for a one-time review โ€” run the PR-review skill directly.
๐Ÿค–claude๐ŸŒuniversal
7.5k
643
View
code-improver
Research & Analysis
Runs an autonomous review-and-fix improvement loop over any code target โ€” a skill, plugin, module, or directory โ€” using a reviewer the user names: any installed skill or agent. Keeps a cross-round findings ledger, escalates when fixes stop converging, and guards scope mechanically. Use when asked to 'improve this code until review passes', 'run an improvement loop with <reviewer>', or to iterate review-and-fix with a specific reviewer. For skills prefer the skill-improver entry; for a branch prefer pr-improver.
๐Ÿค–claude๐ŸŒuniversal
7.5k
643
View
skill-improver
Research & Analysis
Runs an autonomous review-and-fix improvement loop over a Claude Code skill until a review comes back clean, with a cross-round findings ledger, escalation when fixes stop converging, and a mechanical scope guard. Reviews are performed by the plugin-dev skill-reviewer agent. Use to fix skill quality issues, iteratively refine a skill, or resume a loop after an escalation ('fix my skill', 'improve this skill until it passes review', 'skill improvement loop'). NOT for a one-time review โ€” use the plugin-dev skill-reviewer agent directly.
๐Ÿค–claude๐ŸŒuniversal
7.5k
643
View
audit-augmentation
Research & Analysis
Augments Trailmark code graphs with external audit findings from SARIF static analysis results, weAudit annotation files, and version-gated Trailmark 0.4.x binary-analysis graph exports. Maps findings to graph nodes by file and line overlap, creates severity-based subgraphs, and enables cross-referencing findings with pre-analysis data (blast radius, taint, etc.). Use when projecting SARIF results onto a code graph, overlaying weAudit annotations, importing binary graph findings, cross-referencing Semgrep, CodeQL, or binary-analysis findings with call graph data, or visualizing audit findings in the context of code structure.
๐ŸŒuniversal
7.5k
643
View