← Files Seal CopilotARCHIVED FILE
skills/cart-watchdog/SKILL.md
6.26 KB · Oct 5, 2026 · 18:29 UTC
--- name: cart-watchdog description: > Intraday watchdog for add-to-cart activity. Detects unusual silence or spikes vs the site's own learned hour-of-week baseline (not a fixed threshold) and rules out bots before alerting. Requires a baseline from the `calibrate-watchdog` skill. Trigger on: "is my cart alive", "check add to cart", "carrito parado", "cart watchdog", "no estamos vendiendo", "intraday alert", "checkout watchdog", or when run from a scheduled task. For hotels, substitutes `booking_start` for `add_to_cart`. disable-model-invocation: true short-description: 'Intraday check of add-to-cart against the learned baseline. Silent when healthy. Use for "check the cart", "is the cart working", "cómo va el carrito", or hourly runs.' --- # Cart Watchdog Before writing your answer, read `examples/output.md` in this skill directory and match its density, structure and tone. It is the reference for what a good run of this skill looks like. Catch live problems — broken AtC button, payment outage, tracking gap — before the daily report does. Budget: ≤6 tool calls. Designed for **scheduled execution**, hourly during business hours. ## Step 0 — Load the baseline Read `<state-dir>/<site_id>/watchdog-baseline.json`. - **No file** → do not improvise a threshold. Reply in one line: *"No baseline yet — run `calibrate-watchdog` once and I can watch this properly."* Stop. - **Expired** (`expires_at` in the past) → still run, but prefix the status with "baseline stale, recalibrate" and widen every threshold by half. - **Mode C** (daily-only baseline) → skip the hourly logic below and judge on the day-to-date total alone. Say that hour-level detail is unavailable. The file also carries `last_status` from the previous run. You need it: a 🔴 requires two consecutive bad checks, and this is the only way to know about the previous one. ## Step 1 — Today's volume so far (1 call) `get_microconversions(conversion_type=<event>, period=today)` This returns the day total, not an hourly series. Compare it against the baseline's `cumulative[day_of_week][current_hour]` — the expected count for the hours elapsed so far today, in the site's timezone. **Status from the ratio** `actual / expected_to_date`: - 🟢 **Healthy** — ratio ≥ 0.5 - ⚠️ **Watch** — ratio between 0.2 and 0.5 - 🔴 **Act** — ratio < 0.2 **and** `last_status` was already ⚠️ or 🔴 A single low reading is never 🔴 on its own. Two consecutive are. For spikes, mirror it: ratio ≥ 3 is 🔴 (likely bots), ≥ 2 is ⚠️. **Quiet cells are not incidents.** If the sum of medians for the elapsed hours is below 5 events, there is not enough signal — report 🟢 and say the window is too quiet to judge. ## Step 2 — Locate the silence (1–2 calls, only if not 🟢) `get_microconversions_raw(conversion_type=[<event>], period=today, limit=100)` Rows carry `hour` (local, 0–23) and `timestamp_local`. Use `hour` to bucket and `timestamp_local` for the most recent event. Page once more only if the first page does not contain the latest activity. Two extra signals from this: - **Time since last event** vs the current cell's `gap`: more than 2× gap supports ⚠️, more than 3× gap supports 🔴. - **When the drop started** — the last hour with normal-looking volume is the incident start time. Name it; it is what the user needs to match against their deploy log. ## Step 3 — Rule out bots (1 call, mandatory before any 🔴) `get_bot_stats(days=1)` - Drop coinciding with a bot spike → the drop is real but the metric was previously inflated. Say so and recommend recalibrating. - Spike that is bots → demote 🔴 to ⚠️ "bot inflation" and explain. - **Empty result** → agent analytics is off, not 0% bots. Keep the status but mark it "unvalidated for bots" (see `methodology.md`). ## Step 4 — Isolate the cause (≤2 calls, only if 🔴) One call is enough — `get_microconversion_details(conversion_type=<event>, period=today)` returns `by_device`, `by_source`, `by_country` and `by_landing_page` together, each with `count` and `percentage`. Compare the device and source splits against the baseline's usual mix. Mobile-only drop after a deploy → tracking probably broken on the mobile build. One-source drop with no other anomalies → that source paused or blocked. Uniform drop → payment or cart outage; tell the user to test manually now. ## Step 5 — Persist the status Write `last_status` and the check timestamp back into the baseline file so the next run can apply the two-consecutive-checks rule. If the file is not writable, say once that consecutive-check escalation is unavailable. ## Output format **One status line first:** `🟢 Healthy` / `⚠️ Watch — <reason>` / `🔴 Act now — <reason>`. If 🟢 and the run is scheduled: that single line is the entire response. Do not pad. Silence on a healthy run is correct. If ⚠️ or 🔴: add the evidence (today's count vs expected-to-date, time since last event), the incident start time, the suspected cause from Step 4, and one concrete action — e.g. "open a product page on mobile and try to add to cart now". ## Scheduling guidance Recommend hourly during business hours: *"Run cart-watchdog every hour from 8 am to midnight in [site timezone]."* The skill is silent when healthy, so it will not become noise. Offer the schedule once, after a successful run. ## What you do NOT do - Do not run without a baseline. Recommend `calibrate-watchdog` instead. - Do not alert on a single quiet hour. Two consecutive checks, or nothing. - Do not rebuild the baseline here — that is `calibrate-watchdog`'s job and it costs up to 40 calls. - Do not page the user during scheduled night hours unless they opted in. --- Log the run in `<state-dir>/<site_id>/runs.jsonl` with exactly these fields and no others: `ts` (ISO timestamp, UTC), `skill`, `calls` (the number of Sealmetrics calls you made, counted), `budget` (this skill's documented ceiling, a number — `6` here), `verdict` (one of `on_track`, `watch`, `act`, `kpis_only`, `refused`, `error`, or the score for an audit), `scheduled` (boolean), `notes` (one line). The first real audit wrote `calls_used` and a free-text verdict because this footer said "calls used" in prose; the field names are the contract. Skip silently if the path is not writable.
SHA-256: bb3703dc19360e3a8259cb9a07e49f94879eb288fa05d98ab7d2cda077159838