{"id":16267,"plugin_id":"plugin_asdk_app_6aa5672de100819198bb079e9546ee0e","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:13:07.274Z","digest":"280bcc3c9645d57747e46c052f79fc1c6ba0f1c9cb0d85d353b03aba95481286","against":null,"payload":{"description":"One-off calibration run that learns a site's natural add-to-cart (or booking-start) rhythm and stores it as the baseline the hourly watchdog compares against. Run once per site before scheduling `cart-watchdog`, and again after any tracking change or a major shift in traffic volume. Trigger on: \"calibrate the watchdog\", \"set up cart monitoring\", \"learn my cart baseline\", \"calibrar el vigilante\", \"prepare the watchdog\", or when `cart-watchdog` reports that no baseline exists.\n","included_files":[{"relative_path":"examples/output.md","size_in_bytes":977}],"name":"calibrate-watchdog","skill_md_contents":"---\nname: calibrate-watchdog\ndescription: >\n  One-off calibration run that learns a site's natural add-to-cart (or\n  booking-start) rhythm and stores it as the baseline the hourly watchdog\n  compares against. Run once per site before scheduling `cart-watchdog`, and\n  again after any tracking change or a major shift in traffic volume. Trigger\n  on: \"calibrate the watchdog\", \"set up cart monitoring\", \"learn my cart\n  baseline\", \"calibrar el vigilante\", \"prepare the watchdog\", or when\n  `cart-watchdog` reports that no baseline exists.\ndisable-model-invocation: true\nshort-description: 'Learn a site''s hourly add-to-cart rhythm so the watchdog has a baseline. Run once before cart-watchdog. Use for \"calibrate watchdog\", \"calibrar\", \"set up monitoring\".'\n---\n\n# Calibrate Watchdog\n\nBefore writing your answer, read `examples/output.md` in this skill directory\nand match its density, structure and tone. It is the reference for what a good\nrun of this skill looks like.\n\nBuild the hour-of-week baseline that makes intraday monitoring meaningful,\nand store it so the hourly watchdog never has to rebuild it. Budget: ≤40 tool\ncalls — high because it runs once and every later watchdog run costs ≤6.\n\nThis is a **manual, explicit** skill. Never run it from a casual question and\nnever run it on a schedule.\n\n## Why this is a separate skill\n\nThe MCP has no hourly time series on the aggregated tools. Hourly counts come\nonly from `get_microconversions_raw`, which is capped at a 31-day range and\n100 rows per page. Rebuilding a 4-week baseline on every hourly check would\ncost hundreds of calls, so the baseline is built once, here, and cached.\n\n## Step 1 — Identify the watched event and the volume\n\n1. `list_microconversion_types` — pick the add-to-cart equivalent for stores\n   (`add_to_cart`, `add_to_basket`, `atc`, `cart_add`) or `booking_start` and\n   equivalents for hotels. State which event you chose.\n2. `get_microconversions(conversion_type=<event>, period=30d)` — the 30-day\n   total. This decides the calibration mode and costs one call.\n\n| 30d volume | Mode | What you build |\n|---|---|---|\n| ≤ 4,000 events | **A — full** | 168 cells (day-of-week × hour) from 28 days |\n| 4,001 – 30,000 | **B — sampled** | 168 cells from the most recent complete week |\n| > 30,000 | **C — daily** | 7 day-of-week daily medians, no hourly detail |\n\nSay which mode you used and why. The mode goes in the stored baseline.\n\n## Step 2 — Pull the events\n\n**Mode A.** Four windows of 7 days, walking back 28 days. For each window:\n\n```\nget_microconversions_raw(conversion_type=[<event>], start_date=YYYY-MM-DD,\n  end_date=YYYY-MM-DD, limit=100, page=1…)\n```\n\nPage until a page returns fewer than 100 rows, or until 9 pages in that\nwindow — whichever comes first. Hard cap 36 pages across all four windows.\n\n**Mode B.** The most recent complete Monday–Sunday week only, same call,\npaging up to 30 pages. A single week is a real shape but a noisier one: store\n`weeks: 1` so the watchdog widens its tolerance.\n\n**Mode C.** Skip the raw tool entirely. Make 7 calls, one per day of the last\ncomplete week:\n\n```\nget_microconversions(conversion_type=<event>, start_date=D, end_date=D)\n```\n\nThat gives a daily total per day of week. At this volume an outage is visible\nwithin an hour at day level, so hourly cells are not worth 300 calls.\n\nIf any window returns zero rows, say the event has no data in that period and\nstop — a baseline built on nothing is worse than none.\n\n## Step 3 — Build the baseline\n\nEvery row carries `date`, `hour` (local, 0–23) and `timestamp_local`. Bucket\nby `date` and `hour` directly — do not parse the timestamp, and never use\n`timestamp_utc`, since the site's own day boundaries are what matter.\n\n**Modes A and B.** Bucket events into day-of-week × hour-of-day. For each of\nthe 168 cells store:\n\n- `median` — median event count for that cell across the weeks you have\n  (in mode B, the single week's count is the median)\n- `gap` — typical minutes between events in that cell: `60 / median` when\n  `median ≥ 1`, otherwise `60`\n\n**Mode C.** For each day of week store the daily total as `median`, plus an\n`hourly_share` curve assumed flat. Say explicitly that hour-level judgments\nare not available in this mode.\n\nAlso compute and store the **cumulative expectation** per day of week: for\neach hour h, the sum of medians for hours 0…h. The watchdog compares a\nrunning day-to-date total against this, because the aggregate tool it uses\nreturns a day total, not an hourly series.\n\n## Step 4 — Store it\n\nWrite `<state-dir>/<site_id>/watchdog-baseline.json`:\n\n```json\n{\n  \"site_id\": \"...\",\n  \"event\": \"add_to_cart\",\n  \"mode\": \"A\",\n  \"weeks\": 4,\n  \"calibrated_at\": \"2026-09-07\",\n  \"expires_at\": \"2026-10-07\",\n  \"cells\": { \"mon\": { \"0\": {\"median\": 2, \"gap\": 30}, \"1\": {...} }, \"tue\": {...} },\n  \"cumulative\": { \"mon\": [0, 2, 3, 5, ...] },\n  \"daily_median\": { \"mon\": 140, \"tue\": 155, ... },\n  \"last_status\": null\n}\n```\n\nCreate the directory if it does not exist. If the filesystem is not writable\n(some sandboxed environments), say so plainly and print the baseline as a\nJSON block for the user to save themselves — the watchdog can be pasted the\nbaseline instead of reading it.\n\n## Step 5 — Report and hand off\n\nOutput, in under 15 lines:\n\n1. **Event watched** and the mode chosen, with the 30-day volume that decided it.\n2. **Rhythm summary:** busiest hour-of-week and quietest, with their medians.\n   This is the sanity check — if the busiest hour looks wrong to the user,\n   the event mapping is probably wrong.\n3. **Confidence line:** weeks of data used, and any cell with a median below\n   5, which the watchdog will treat as too quiet to judge.\n4. **Expiry:** the baseline goes stale in 30 days or after any tracking change.\n5. **Next step:** offer to schedule `cart-watchdog` hourly during business\n   hours, and give the exact command.\n\n## What you do NOT do\n\n- Do not run on a schedule, and do not run because someone asked a general\n  question about carts.\n- Do not build a baseline from fewer than 7 days of data. Say the site needs\n  more history and stop.\n- Do not exceed the page caps to get a \"better\" baseline — a sampled baseline\n  that exists beats a perfect one that costs 300 calls.\n- Do not overwrite an existing baseline without saying what changed\n  (event, mode, or median volume) versus the previous one.\n\n---\n\nLog the run in `<state-dir>/<site_id>/runs.jsonl` with exactly these fields\nand no others: `ts` (ISO timestamp, UTC), `skill`, `calls` (the number of\nSealmetrics calls you made, counted), `budget` (this skill's documented\nceiling, a number — `40` here), `verdict` (one of `on_track`, `watch`, `act`,\n`kpis_only`, `refused`, `error`, or the score for an audit), `scheduled`\n(boolean), `notes` (one line). The first real audit wrote `calls_used` and a\nfree-text verdict because this footer said \"calls used\" in prose; the field\nnames are the contract. Skip silently if the path is not writable.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}