@canonry/canonry 4.177.0 → 4.177.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Think PostHog, for AI search visibility. Canonry tracks what ChatGPT, Claude, Ge
18
18
  |---|---|
19
19
  | **Measure** | Track mentions and citations across Gemini, ChatGPT, Claude, Perplexity, and local models. Join them with GSC, GA4, Bing, server side traffic, Business Profile, and backlink data. |
20
20
  | **Diagnose** | Crawl the site, score Page Health, inspect evidence, compare competitors, and explain regressions. |
21
- | **Act** | Give your agent the context to make surgical on-site technical SEO changes and coordinate content, indexing, analytics, and paid media. |
21
+ | **Act** | Give your agent the context + skills to make surgical on-site technical SEO changes and coordinate content, indexing, analytics, and paid media. |
22
22
  | **Operate** | Create automation workflows, schedule checks, sync data, send webhooks, and generate client-ready reports. |
23
23
 
24
24
  ### Built-in integrations and workflows
@@ -160,6 +160,13 @@ schedule interval. Use `cnry traffic events`, `cnry traffic sources`, and
160
160
  `cnry traffic status` for every adapter. See
161
161
  `references/server-side-traffic.md` for setup and smoke tests.
162
162
 
163
+ **WordPress safety:** incremental pulls are fixed `[since, until)` windows; a
164
+ new or idle source begins at the plugin's 365-day maximum retention horizon.
165
+ Canonry rejects an endpoint that returns events outside that window. Keep
166
+ existing WordPress rollups intact: generic replace-mode backfill is unavailable
167
+ until a retention-aware repair can prove coverage and declare any unrecoverable
168
+ span.
169
+
163
170
  **Vercel gotcha:** a freshly connected Vercel source captures only going-forward traffic — `lastSyncedAt` is seeded to NOW to avoid the 30-day default window exceeding Vercel's ~14-day request-logs retention (which would otherwise throw on every first sync). Use `cnry traffic backfill <project> --source <id> --days N` for historical recovery. If an idle Vercel/Cloud Run source has been failing long enough that `lastSyncedAt` aged past retention, unstick it with `cnry traffic reset <project> --source <id> --advance-to-now`.
164
171
 
165
172
  ## Local AEO (Google Business Profile)
@@ -72,21 +72,17 @@ sync flow does NOT echo the private key back in any response.
72
72
  ## Connecting a WordPress source
73
73
 
74
74
  The WordPress adapter pulls events from the **Canonry Traffic Logger**
75
- WordPress plugin, which captures every non-admin GET page-load **that
76
- reaches PHP** and exposes a paginated REST endpoint protected by an
77
- Application Password.
78
-
79
- > **Cache blind spot.** The plugin is a PHP hook, so it only sees
80
- > requests that execute WordPress. A full-page cache (LiteSpeed, WP
81
- > Rocket, W3 Total Cache, WP Super Cache) or CDN serves cached pages
82
- > before PHP runs, so cache-served page views, including live AI
83
- > user-fetches (Claude-User, ChatGPT-User), are NOT logged. Bot crawls
84
- > of uncached endpoints (sitemap, feeds, assets, cache misses) still
85
- > come through, which can make capture look healthy while real page
86
- > views go uncounted. Exclude AI user-agents from the cache (and any
87
- > CDN), or capture from access/edge logs instead. The
88
- > `traffic.source.cache-blindspot` doctor check warns whenever a
89
- > WordPress source is connected.
75
+ WordPress plugin, which is PHP-only: it captures non-admin GET page-loads
76
+ **that reach PHP** and exposes a paginated REST endpoint protected by an
77
+ Application Password. It has no browser-side capture path.
78
+
79
+ > **Cache blind spot.** Cache-served requests never execute PHP, so they
80
+ > produce no plugin event. A full-page cache (LiteSpeed, WP Rocket, W3 Total
81
+ > Cache, WP Super Cache) or any CDN can therefore make the source look active
82
+ > while real page views, AI crawlers, and live AI user-fetches such as
83
+ > `Claude-User` and `ChatGPT-User` go uncounted. To use this source for
84
+ > AI-agent traffic, bypass **every** cache layer for the selected AI user
85
+ > agents, or capture from access/edge logs instead.
90
86
 
91
87
  **Which user-agents to exclude from the cache** (one per line in
92
88
  LiteSpeed's "Do Not Cache User Agents", WP Rocket's
@@ -94,23 +90,61 @@ LiteSpeed's "Do Not Cache User Agents", WP Rocket's
94
90
  Agents"):
95
91
 
96
92
  ```
97
- Claude-User
98
- ClaudeBot
99
- ChatGPT-User
100
- OAI-SearchBot
101
93
  GPTBot
94
+ OAI-SearchBot
95
+ OAI-AdsBot
96
+ ChatGPT-User
97
+ openai-mcp
98
+ ClaudeBot
99
+ Claude-
100
+ anthropic-ai
102
101
  PerplexityBot
103
102
  Perplexity-User
103
+ ShapBot
104
+ Shap-User
105
+ Google-Agent
106
+ Google-GeminiNotebook
107
+ Google-NotebookLM
108
+ Google-CloudVertexBot
109
+ Bytespider
110
+ Applebot
111
+ meta-externalagent
112
+ CCBot
113
+ cohere-ai
114
+ Diffbot
115
+ MistralAI-User
116
+ MistralAI-Index
117
+ MistralAI-Training
118
+ MistralBot
119
+ DeepSeekBot
120
+ xAI-Bot
121
+ Grok-Bot
122
+ GrokBot
123
+ YouBot
124
+ DuckAssistBot
125
+ Amazonbot
126
+ Amzn-SearchBot
127
+ Amzn-User
104
128
  ```
105
129
 
106
- These are the answer-engine fetchers in both live-user-fetch (`*-User`)
107
- and crawler forms. Do NOT add `Googlebot` or `Bingbot`: caching helps
108
- search crawlers (page speed is a ranking signal, and cached pages let
109
- them crawl more per visit, which matters most on crawl-budget-starved
110
- sites), and their crawl stats are already authoritative in GSC and Bing
111
- Webmaster Tools. Rule of thumb: bypass cache only for agents you cannot
112
- measure elsewhere and that gain nothing from being cached. Answer-engine
113
- fetchers fit both; search crawlers fit neither.
130
+ This list mirrors Canonry's current classifier: answer-engine user-fetch,
131
+ crawl, search, and training agents for which WordPress has no cache-independent
132
+ measurement surface. `ClaudeBot` covers Anthropic's unhyphenated core crawler;
133
+ `Claude-` is a separate family rule so newly named `Claude-*Bot` variants
134
+ inherit the bypass. Do NOT add traditional search agents
135
+ `Googlebot`, `bingbot`, `DuckDuckBot`, `YandexBot`, or `Baiduspider`: caching
136
+ helps them crawl efficiently, and the important Google/Bing crawl evidence is
137
+ available through their webmaster tools.
138
+
139
+ > **1.1.0 -> 1.1.1 measurement boundary.** Plugin 1.1.0 briefly added a
140
+ > JavaScript beacon to recover browser/referral page views served from cache.
141
+ > Plugin 1.1.1 removes it and returns to PHP-only capture. This intentionally
142
+ > means cache-served browser referrals can again be absent even when GA4
143
+ > reports sessions; neither version made cache-served crawler requests visible
144
+ > to PHP. Annotate the upgrade time, do not interpret a trend spanning it as
145
+ > like-for-like traffic, and purge HTML from both the WordPress cache and every
146
+ > outer CDN. A temporary `/wp-json/canonry/v1/pv` compatibility route returns
147
+ > `204` for scripts stranded in old cached HTML, but never records an event.
114
148
 
115
149
  ```bash
116
150
  # 1. Install the plugin. Download the latest release zip from the
@@ -151,6 +185,38 @@ The plugin auto-prunes events older than the retention window (default
151
185
  90 days) once per day via WP-Cron. Operators who want a different
152
186
  window change it in `Settings → Canonry Traffic Logger`.
153
187
 
188
+ ### WordPress incremental-window safety
189
+
190
+ Each incremental WordPress sync uses one fixed half-open `[since, until)`
191
+ window. A fresh source, or an idle source without an explicit
192
+ `--since-minutes`, starts with a 365-day horizon, matching the plugin's
193
+ maximum configurable retention. A site configured for less retention simply
194
+ returns its available tail. If the window needs more than one capped drain,
195
+ Canonry persists both its lower and upper bounds with the continuation cursor
196
+ and retries that exact interval until the plugin reports it is terminal. It
197
+ then advances the normal watermark. Every returned event is validated against
198
+ the requested interval; an older or custom extension that ignores `since` or
199
+ `until` fails closed before any rollup is written. Update that extension to a
200
+ bounded-window-capable Canonry traffic logger before syncing again.
201
+
202
+ Do not run generic replace-mode backfill for a WordPress source. The plugin
203
+ prunes retained events and cannot prove that it covers every bucket a replace
204
+ transaction would delete, even when no continuation is pending. Canonry
205
+ rejects that generic path universally. Keep existing rollups intact, use a
206
+ retention-aware repair, and explicitly declare any unrecoverable portion before
207
+ reporting a historical trend.
208
+
209
+ After upgrading from the former unbounded WordPress sync, a source with an old
210
+ continuation cursor is intentionally rejected rather than guessed at. Keep its
211
+ schedule paused, record the ambiguous historical span, then use the explicit
212
+ reset below to start fresh. Reset stops future replay; it does not repair past
213
+ rollups. Generic WordPress replace-mode backfill remains unavailable until a
214
+ retention-aware repair can establish coverage.
215
+
216
+ Reconnecting with a different WordPress `baseUrl` archives the old source and
217
+ creates a fresh one. Its existing rollups and any unrecovered marker remain
218
+ with the old lineage rather than mixing with the new endpoint's traffic.
219
+
154
220
  ## Connecting a Vercel source
155
221
 
156
222
  The Vercel adapter pulls per-request logs from the Vercel API for a
@@ -869,15 +935,14 @@ cnry traffic reset <project> --source <id> --advance-to-now
869
935
 
870
936
  `--advance-to-now` is required — there is no implicit reset.
871
937
 
872
- `reset` accepts any **non-archived** source type. The `lastSyncedAt`
873
- advance is meaningful for time-windowed sources (Vercel, Cloud Run)
874
- where it determines the next sync window. Cursor-based sources
875
- (WordPress) keep their `last_cursor` intact, so the `lastSyncedAt`
876
- advance is informational the next WordPress drain still resumes
877
- from the cursor. The primary use case is the retention-trap recovery
878
- above; clearing `lastError` for a transient WordPress failure also
879
- works. Archived sources are rejected — re-connect them with
880
- `cnry traffic connect ...` instead.
938
+ `reset` accepts any **non-archived** source type. A WordPress reset clears
939
+ its `last_cursor` and pending-window marker as well as advancing
940
+ `lastSyncedAt`, so the next bounded drain begins at the reset watermark
941
+ instead of combining it with an old cursor. The primary use case is the
942
+ retention-trap recovery above; clearing `lastError` for a transient WordPress
943
+ failure also works. Reset deliberately abandons any ambiguous pending history;
944
+ it is not a historical repair. Archived sources are rejected — re-connect them
945
+ with `cnry traffic connect ...` instead.
881
946
 
882
947
  Time-window and cursor adapters use the `last_event_ids` overlap ring. Queue
883
948
  pull uses durable event receipts sized to Queue retention. Both paths make a
@@ -947,7 +1012,7 @@ The doctor checks are adapter-agnostic. When they fail or warn:
947
1012
  | `traffic.source.queue-backlog` | `traffic.queue-backlog.within-drain-budget` | 1–1,000 Queue messages remain. If no new messages arrive, the next scheduled sync can drain them. Run a manual sync to accelerate. |
948
1013
  | `traffic.source.queue-backlog` | `traffic.queue-backlog.remaining` | More than 1,000 Queue messages remain. Run a manual sync. If the backlog persists, shorten the traffic-sync schedule. |
949
1014
  | `traffic.source.credentials` | `traffic.credentials.resolve-failed` | Reconnect from the host that owns the source credentials. Queue pull requires a non-empty Account Queues Edit token paired by source ID. |
950
- | `traffic.source.cache-blindspot` | `traffic.cache-blindspot.wordpress-plugin` | A WordPress source is connected, so the plugin cannot see cache-served page views. Exclude AI user-agents from the page cache and any CDN, or switch to a log/edge source. Warns only, not a failure. |
1015
+ | `traffic.source.cache-blindspot` | `traffic.cache-blindspot.wordpress-plugin` | Cache-served requests never execute PHP and produce no event, so a source can look active while real page views go uncounted. Exclude selected AI user agents from every page-cache and CDN layer, or switch to a log/edge source. Warns only, not a failure. |
951
1016
  | `traffic.source.worker-version` | `traffic.worker-version.waiting-for-first-event` | Send a smoke-test request through the Worker. For Queue delivery, run a sync to ingest it. Then run the doctor again. |
952
1017
  | `traffic.source.worker-version` | `traffic.worker-version.stale` | Regenerate and redeploy the Worker from the credential-owning host with the source's existing delivery mode, then verify the route or Queue binding. |
953
1018
 
@@ -1012,21 +1077,18 @@ domains, or PII are surfaced.
1012
1077
 
1013
1078
  ## Limits & caveats
1014
1079
 
1015
- - **The WordPress plugin is blind to cache-served traffic.** The
1016
- `wordpress` adapter logs only requests that reach PHP. A full-page
1017
- cache or CDN serves cached pages from the edge, so cache-served page
1018
- views, including live AI user-fetches (Claude-User, ChatGPT-User),
1019
- never reach the plugin and go uncounted, even though bot crawls of
1020
- uncached endpoints (sitemap, assets) still appear. On a cached
1021
- WordPress site, treat the plugin's page-view counts as a floor, not a
1022
- total. Either exclude AI user-agents from the cache + CDN, or capture
1023
- cache-independent via a `cloud-run` / `vercel` / edge-log source. The
1024
- `traffic.source.cache-blindspot` doctor check surfaces this. Adapter
1025
- coverage differs: `vercel` ingests edge request-logs so cache hits are
1026
- captured (it records the `cache` HIT/MISS label), and `cloud-run` logs
1027
- every request that reaches the service, missing only what a CDN placed
1028
- in front of Cloud Run serves from its own edge cache. Only the
1029
- hook-based `wordpress` adapter has the always-present blind spot.
1080
+ - **The WordPress plugin is PHP-only.** The `wordpress` adapter records only
1081
+ requests that reach PHP. Cache-served page requests, including AI crawlers
1082
+ and live AI user-fetches, go uncounted even while crawls of uncached
1083
+ sitemaps, assets, or cache misses appear. On a cached WordPress site, treat
1084
+ this source as a floor unless the selected AI user agents bypass every
1085
+ page-cache and CDN layer. The static doctor warning surfaces this limitation
1086
+ without requesting the origin. Otherwise, use a cache-independent
1087
+ `cloud-run`, `vercel`, or edge-log source. Adapter coverage
1088
+ differs: `vercel` ingests edge request logs so cache hits are captured (it
1089
+ records the `cache` HIT/MISS label), and `cloud-run` logs every request that
1090
+ reaches the service, missing only what a CDN ahead of Cloud Run serves at its
1091
+ own edge.
1030
1092
  - **Path-level citation cross-reference is not implemented yet.** The
1031
1093
  citation store is domain-grain (`query_snapshots.cited_domains`). A
1032
1094
  future iteration that lands URL-grain citation evidence will extend
@@ -1047,17 +1109,21 @@ domains, or PII are surfaced.
1047
1109
  `traffic_sources.source_type` and a `TrafficSourceValidator`
1048
1110
  registration.
1049
1111
 
1050
- ### Page caches and the beacon lane
1051
-
1052
- A page cache (LiteSpeed, WP Rocket, Super Cache, any `advanced-cache.php`
1053
- drop-in) serves visitors before WordPress PHP boots, so the plugin's request
1054
- hook never sees those page views: on a cached site the PHP lane records only
1055
- redirects, errors, and crawlers on uncached URLs, and landed AI referrals read
1056
- as zero while GA4 shows sessions. Plugin 1.1.0 adds a beacon lane — a
1057
- first-party inline ping to the plugin's own REST route (never page-cached) —
1058
- that records real browser views, cached or not. It auto-enables when a page
1059
- cache is detected (`Settings Canonry Traffic Logger` can force on/off).
1060
- Bots and non-200s stay in the PHP lane; browser 200s belong to the beacon, so
1061
- uncached views are not double-counted. On sites running plugin ≤ 1.0.x behind
1062
- a cache, treat GA4 as the landed-visit signal and the server source as the
1063
- bot/crawler signal only.
1112
+ ### Page caches and PHP-only coverage
1113
+
1114
+ A page cache (LiteSpeed, WP Rocket, Super Cache, or any
1115
+ `advanced-cache.php` drop-in) can serve a request before WordPress boots. The
1116
+ plugin therefore has one capture lane only: PHP. It cannot recover a
1117
+ cache-served crawler, user fetch, referral, or browser page view after the
1118
+ fact.
1119
+
1120
+ For the AI agents measured by this source, configure cache bypasses at every
1121
+ layer that can answer the public request: the WordPress cache, a host/CDN cache,
1122
+ and any edge cache. A LiteSpeed exclusion alone is insufficient when an outer
1123
+ CDN can return a cached response first.
1124
+
1125
+ Cache exclusions for the selected AI agents can recover crawler and user-fetch
1126
+ coverage, but they do not recover ordinary browser referrals served from cache.
1127
+ Use GA4 for landed browser visits or edge/access logs for cache-independent
1128
+ request coverage. The `traffic.source.cache-blindspot` doctor check is a static
1129
+ warning; it does not request or impersonate traffic against the public origin.
@@ -91,7 +91,7 @@ import {
91
91
  trafficConnectWordpressRequestSchema,
92
92
  trafficEventKindSchema,
93
93
  trafficSeriesGranularitySchema
94
- } from "./chunk-UXXXKDW4.js";
94
+ } from "./chunk-PQT3ECM3.js";
95
95
 
96
96
  // src/config.ts
97
97
  import fs from "fs";
@@ -9487,17 +9487,17 @@ var trafficConnectVercelInputSchema = z3.object({
9487
9487
  var trafficSyncInputSchema = z3.object({
9488
9488
  project: projectNameSchema,
9489
9489
  sourceId: z3.string().min(1).describe("Traffic source ID returned by canonry_traffic_connect_cloud_run or canonry_traffic_sources_list."),
9490
- sinceMinutes: z3.number().int().positive().max(7 * 24 * 60).optional().describe("Lookback window in minutes. Defaults to the source's configured window (60 min) when omitted; clamped forward to lastSyncedAt to avoid double-counting.")
9490
+ sinceMinutes: z3.number().int().positive().max(365 * 24 * 60).optional().describe("Optional lookback in minutes. Defaults are adapter-specific and clamp forward to lastSyncedAt; a new or idle WordPress source uses 365d to cover the plugin\u2019s maximum configurable retention.")
9491
9491
  });
9492
9492
  var trafficBackfillInputSchema = z3.object({
9493
9493
  project: projectNameSchema,
9494
9494
  sourceId: z3.string().min(1).describe("Traffic source ID returned by canonry_traffic_sources_list."),
9495
- days: z3.number().int().positive().max(30).optional().describe("Lookback window in days. Default 30, capped server-side at the upstream log retention ceiling (Cloud Logging _Default = 30d).")
9495
+ days: z3.number().int().positive().max(90).optional().describe("Lookback window in days. Default 30, capped by the adapter at 90d. Generic WordPress replace backfill is unavailable because retained coverage is unproven.")
9496
9496
  });
9497
9497
  var trafficResetInputSchema = z3.object({
9498
9498
  project: projectNameSchema,
9499
9499
  sourceId: z3.string().min(1).describe("Traffic source ID returned by canonry_traffic_sources_list."),
9500
- advanceToNow: z3.literal(true).describe("Must be `true`. Explicit gate against accidental resets. Advances lastSyncedAt to NOW and clears the source's error state.")
9500
+ advanceToNow: z3.literal(true).describe("Must be `true`. Explicit gate against accidental resets. Advances lastSyncedAt to NOW and clears the source's error state; WordPress also clears its continuation state and records an unrecovered span that needs retention-aware repair.")
9501
9501
  });
9502
9502
  var trafficEventsInputSchema = z3.object({
9503
9503
  project: projectNameSchema,
@@ -10650,7 +10650,7 @@ var canonryMcpTools = [
10650
10650
  defineTool({
10651
10651
  name: "canonry_traffic_connect_wordpress",
10652
10652
  title: "Connect WordPress traffic-logger source",
10653
- description: "Connect a WordPress site (running the canonry traffic-logger plugin) as a server-side traffic source. Probes the plugin endpoint with the supplied Application Password before persisting \u2014 a bad credential or unreachable host surfaces as a 502 error. Reconnecting updates the existing active WordPress source in place. The Application Password is stored in ~/.canonry/config.yaml (not the DB) and never echoed back.",
10653
+ description: "Connect a WordPress site (running the canonry traffic-logger plugin) as a server-side traffic source. Probes the plugin endpoint with the supplied Application Password before persisting; a bad credential or unreachable host surfaces as a 502 error. Reconnecting the same endpoint updates the active source in place. Changing baseUrl archives the old lineage and creates a fresh source so rollups cannot mix across endpoints. The Application Password is stored in ~/.canonry/config.yaml (not the DB) and never echoed back.",
10654
10654
  access: "write",
10655
10655
  tier: "traffic",
10656
10656
  inputSchema: trafficConnectWordpressInputSchema,
@@ -10671,8 +10671,8 @@ var canonryMcpTools = [
10671
10671
  }),
10672
10672
  defineTool({
10673
10673
  name: "canonry_traffic_sync",
10674
- title: "Sync Cloud Run traffic source",
10675
- description: "Pull the most recent Cloud Logging entries for a Cloud Run traffic source, classify them as crawler / AI-referral / unknown, and upsert hourly rollups + raw samples. Returns totals, bucket counts, and the run id. The window auto-clamps forward to lastSyncedAt to avoid double-counting on back-to-back calls.",
10674
+ title: "Sync traffic source",
10675
+ description: "Pull a Cloud Run, WordPress, Vercel, or Cloudflare Queue traffic source, classify crawler / AI-referral / unknown traffic, and upsert hourly rollups plus raw samples. Time-window pulls clamp forward to lastSyncedAt. WordPress uses a fixed bounded window, defaults a new or idle source to 365d, validates the returned events remain inside that window, and serializes syncs with a source lease.",
10676
10676
  access: "write",
10677
10677
  tier: "traffic",
10678
10678
  inputSchema: trafficSyncInputSchema,
@@ -10682,8 +10682,8 @@ var canonryMcpTools = [
10682
10682
  }),
10683
10683
  defineTool({
10684
10684
  name: "canonry_traffic_backfill",
10685
- title: "Backfill Cloud Run traffic source",
10686
- description: 'Async one-shot reclassification of historical Cloud Run logs. Pulls the last `days` of request logs (capped at the 30d Cloud Logging retention ceiling), classifies them with current rules, and replaces the hourly rollup buckets + sample slice in the window. Returns immediately with `{ runId, status: "running" }`; poll canonry_run_get for completion. lastSyncedAt only advances forward \u2014 a backfill never undoes incremental sync progress that ran ahead of it.',
10685
+ title: "Backfill traffic source",
10686
+ description: 'Async one-shot reclassification for Cloud Run or Vercel traffic. It replaces the selected window\u2019s rollups with a fresh bounded pull and current classifier output. WordPress generic replace backfill is unavailable because the endpoint cannot prove retained coverage; use a retention-aware repair that explicitly declares any unrecoverable span. Returns `{ runId, status: "running" }`; poll canonry_run_get for completion.',
10687
10687
  access: "write",
10688
10688
  tier: "traffic",
10689
10689
  inputSchema: trafficBackfillInputSchema,
@@ -10694,7 +10694,7 @@ var canonryMcpTools = [
10694
10694
  defineTool({
10695
10695
  name: "canonry_traffic_reset",
10696
10696
  title: "Advance traffic source lastSyncedAt to NOW",
10697
- description: "Operator recovery for a stuck traffic source. Advances `lastSyncedAt` to NOW, sets `status` back to `connected`, and clears `last_error`. Accepts any non-archived source: the `lastSyncedAt` advance determines the next sync window for time-windowed sources (Vercel, Cloud Run); cursor-based sources (WordPress) keep their `last_cursor` so the advance is informational. Common trigger: an idle Vercel/Cloud Run source whose `lastSyncedAt` aged past the upstream retention boundary and every sync now throws a retention error. Historical events in the gap are unrecoverable from the sync path; run canonry_traffic_backfill separately if any of them are needed. Archived sources are rejected \u2014 re-connect via the appropriate canonry_traffic_connect_* tool instead.",
10697
+ description: "Operator recovery for a stuck traffic source. Advances `lastSyncedAt` to NOW, sets `status` back to `connected`, and clears `last_error`. A WordPress reset also clears its continuation state and records an unrecovered span so its next bounded drain cannot combine an old cursor with a new window. That stops replay but is not historical repair. Generic WordPress replace-mode backfill is unavailable because retained coverage is unproven; use a retention-aware repair that explicitly declares any unrecoverable span. Archived sources are rejected; reconnect them with the appropriate canonry_traffic_connect_* tool.",
10698
10698
  access: "write",
10699
10699
  tier: "traffic",
10700
10700
  inputSchema: trafficResetInputSchema,