@ainyc/canonry 4.182.3 → 4.183.1

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.
Files changed (28) hide show
  1. package/README.md +139 -104
  2. package/assets/agent-workspace/skills/aero/references/orchestration.md +1 -1
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -1
  4. package/assets/assets/{AuditHistoryPanel-1_FHpzj-.js → AuditHistoryPanel-DM-2GC2i.js} +1 -1
  5. package/assets/assets/{BacklinksPage-045za10_.js → BacklinksPage-YJU9B2RQ.js} +1 -1
  6. package/assets/assets/{HistoryPage-36K_6asu.js → HistoryPage-DcFzvVRB.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-B4DJGoY6.js → MeasurementPropertyPage-OQ3X0KHU.js} +1 -1
  8. package/assets/assets/{ProjectPage-CshC68Ne.js → ProjectPage-CMZO1xb2.js} +8 -8
  9. package/assets/assets/{RunRow-U2CN755e.js → RunRow-6SFvSqhK.js} +1 -1
  10. package/assets/assets/{RunsPage-D0CtU4d-.js → RunsPage-Chk_-IOW.js} +1 -1
  11. package/assets/assets/{SettingsPage-zMWieTPK.js → SettingsPage-DSS1eunM.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-TpQPu_Uj.js → SiteHealthSection-CewNWjGo.js} +3 -3
  13. package/assets/assets/{TrafficPage-DfLUt-64.js → TrafficPage-DRZ1aqnG.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-DbjNNWSt.js → TrafficSourceDetailPage-vaBD4zHK.js} +1 -1
  15. package/assets/assets/{extract-error-message-CWqz1QPC.js → extract-error-message-DD4JJz8j.js} +1 -1
  16. package/assets/assets/{index-Brb7M_6G.js → index-BdR4Vlu6.js} +23 -23
  17. package/assets/assets/{react-sigma_core.esm.min-Drqprr9L.js → react-sigma_core.esm.min-B8Wmi5Ko.js} +1 -1
  18. package/assets/index.html +1 -1
  19. package/dist/{chunk-FVC7PGYQ.js → chunk-3SFCUICM.js} +3 -3
  20. package/dist/{chunk-K45YKXE4.js → chunk-7ATZMDG2.js} +158 -41
  21. package/dist/{chunk-BDJT7XZL.js → chunk-AZJOCWZ4.js} +42 -6
  22. package/dist/{chunk-DY5ZDKQW.js → chunk-DU5Q5ZOX.js} +4574 -4390
  23. package/dist/{chunk-I3KSOMJA.js → chunk-VXPM6O4R.js} +2 -2
  24. package/dist/cli.js +5 -5
  25. package/dist/index.js +4 -4
  26. package/dist/{intelligence-service-HGA553GT.js → intelligence-service-BQIIWWQJ.js} +2 -2
  27. package/dist/mcp.js +3 -3
  28. package/package.json +9 -9
@@ -1,4 +1,4 @@
1
- import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-TpQPu_Uj.js";import"./index-Brb7M_6G.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-XjCNFK0x.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DLEICrrL.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
1
+ import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-CewNWjGo.js";import"./index-BdR4Vlu6.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-XjCNFK0x.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DLEICrrL.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
2
2
  In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function ee(r,n){return qt(r)||Yt(r,n)||Tt(r,n)||Xt()}var pe={black:"#000000",silver:"#C0C0C0",gray:"#808080",grey:"#808080",white:"#FFFFFF",maroon:"#800000",red:"#FF0000",purple:"#800080",fuchsia:"#FF00FF",green:"#008000",lime:"#00FF00",olive:"#808000",yellow:"#FFFF00",navy:"#000080",blue:"#0000FF",teal:"#008080",aqua:"#00FFFF",darkblue:"#00008B",mediumblue:"#0000CD",darkgreen:"#006400",darkcyan:"#008B8B",deepskyblue:"#00BFFF",darkturquoise:"#00CED1",mediumspringgreen:"#00FA9A",springgreen:"#00FF7F",cyan:"#00FFFF",midnightblue:"#191970",dodgerblue:"#1E90FF",lightseagreen:"#20B2AA",forestgreen:"#228B22",seagreen:"#2E8B57",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",limegreen:"#32CD32",mediumseagreen:"#3CB371",turquoise:"#40E0D0",royalblue:"#4169E1",steelblue:"#4682B4",darkslateblue:"#483D8B",mediumturquoise:"#48D1CC",indigo:"#4B0082",darkolivegreen:"#556B2F",cadetblue:"#5F9EA0",cornflowerblue:"#6495ED",rebeccapurple:"#663399",mediumaquamarine:"#66CDAA",dimgray:"#696969",dimgrey:"#696969",slateblue:"#6A5ACD",olivedrab:"#6B8E23",slategray:"#708090",slategrey:"#708090",lightslategray:"#778899",lightslategrey:"#778899",mediumslateblue:"#7B68EE",lawngreen:"#7CFC00",chartreuse:"#7FFF00",aquamarine:"#7FFFD4",skyblue:"#87CEEB",lightskyblue:"#87CEFA",blueviolet:"#8A2BE2",darkred:"#8B0000",darkmagenta:"#8B008B",saddlebrown:"#8B4513",darkseagreen:"#8FBC8F",lightgreen:"#90EE90",mediumpurple:"#9370DB",darkviolet:"#9400D3",palegreen:"#98FB98",darkorchid:"#9932CC",yellowgreen:"#9ACD32",sienna:"#A0522D",brown:"#A52A2A",darkgray:"#A9A9A9",darkgrey:"#A9A9A9",lightblue:"#ADD8E6",greenyellow:"#ADFF2F",paleturquoise:"#AFEEEE",lightsteelblue:"#B0C4DE",powderblue:"#B0E0E6",firebrick:"#B22222",darkgoldenrod:"#B8860B",mediumorchid:"#BA55D3",rosybrown:"#BC8F8F",darkkhaki:"#BDB76B",mediumvioletred:"#C71585",indianred:"#CD5C5C",peru:"#CD853F",chocolate:"#D2691E",tan:"#D2B48C",lightgray:"#D3D3D3",lightgrey:"#D3D3D3",thistle:"#D8BFD8",orchid:"#DA70D6",goldenrod:"#DAA520",palevioletred:"#DB7093",crimson:"#DC143C",gainsboro:"#DCDCDC",plum:"#DDA0DD",burlywood:"#DEB887",lightcyan:"#E0FFFF",lavender:"#E6E6FA",darksalmon:"#E9967A",violet:"#EE82EE",palegoldenrod:"#EEE8AA",lightcoral:"#F08080",khaki:"#F0E68C",aliceblue:"#F0F8FF",honeydew:"#F0FFF0",azure:"#F0FFFF",sandybrown:"#F4A460",wheat:"#F5DEB3",beige:"#F5F5DC",whitesmoke:"#F5F5F5",mintcream:"#F5FFFA",ghostwhite:"#F8F8FF",salmon:"#FA8072",antiquewhite:"#FAEBD7",linen:"#FAF0E6",lightgoldenrodyellow:"#FAFAD2",oldlace:"#FDF5E6",magenta:"#FF00FF",deeppink:"#FF1493",orangered:"#FF4500",tomato:"#FF6347",hotpink:"#FF69B4",coral:"#FF7F50",darkorange:"#FF8C00",lightsalmon:"#FFA07A",orange:"#FFA500",lightpink:"#FFB6C1",pink:"#FFC0CB",gold:"#FFD700",peachpuff:"#FFDAB9",navajowhite:"#FFDEAD",moccasin:"#FFE4B5",bisque:"#FFE4C4",mistyrose:"#FFE4E1",blanchedalmond:"#FFEBCD",papayawhip:"#FFEFD5",lavenderblush:"#FFF0F5",seashell:"#FFF5EE",cornsilk:"#FFF8DC",lemonchiffon:"#FFFACD",floralwhite:"#FFFAF0",snow:"#FFFAFA",lightyellow:"#FFFFE0",ivory:"#FFFFF0"},Ct=new Int8Array(4),be=new Int32Array(Ct.buffer,0,1),$t=new Float32Array(Ct.buffer,0,1),Kt=/^\s*rgba?\s*\(/,Jt=/^\s*rgba?\s*\(\s*([0-9]*)\s*,\s*([0-9]*)\s*,\s*([0-9]*)(?:\s*,\s*(.*)?)?\)\s*$/;function Qt(r){var n=0,i=0,e=0,t=1;if(r[0]==="#")r.length===4?(n=parseInt(r.charAt(1)+r.charAt(1),16),i=parseInt(r.charAt(2)+r.charAt(2),16),e=parseInt(r.charAt(3)+r.charAt(3),16)):(n=parseInt(r.charAt(1)+r.charAt(2),16),i=parseInt(r.charAt(3)+r.charAt(4),16),e=parseInt(r.charAt(5)+r.charAt(6),16)),r.length===9&&(t=parseInt(r.charAt(7)+r.charAt(8),16)/255);else if(Kt.test(r)){var a=r.match(Jt);a&&(n=+a[1],i=+a[2],e=+a[3],a[4]&&(t=+a[4]))}return{r:n,g:i,b:e,a:t}}var J={};for(var le in pe)J[le]=oe(pe[le]),J[pe[le]]=J[le];function Rt(r,n,i,e,t){return be[0]=e<<24|i<<16|n<<8|r,be[0]=be[0]&4278190079,$t[0]}function oe(r){if(r=r.toLowerCase(),typeof J[r]<"u")return J[r];var n=Qt(r),i=n.r,e=n.g,t=n.b,a=n.a;a=a*255|0;var o=Rt(i,e,t,a);return J[r]=o,o}var Ee={};function _t(r){if(typeof Ee[r]<"u")return Ee[r];var n=(r&16711680)>>>16,i=(r&65280)>>>8,e=r&255,t=255,a=Rt(n,i,e,t);return Ee[r]=a,a}function We(r,n,i,e){return i+(n<<8)+(r<<16)}function Ve(r,n,i,e,t,a){var o=Math.floor(i/a*t),s=Math.floor(r.drawingBufferHeight/a-e/a*t),l=new Uint8Array(4);r.bindFramebuffer(r.FRAMEBUFFER,n),r.readPixels(o,s,1,1,r.RGBA,r.UNSIGNED_BYTE,l);var h=ee(l,4),u=h[0],d=h[1],f=h[2],g=h[3];return[u,d,f,g]}function c(r,n,i){return(n=ae(n))in r?Object.defineProperty(r,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):r[n]=i,r}function je(r,n){var i=Object.keys(r);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(r);n&&(e=e.filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable})),i.push.apply(i,e)}return i}function b(r){for(var n=1;n<arguments.length;n++){var i=arguments[n]!=null?arguments[n]:{};n%2?je(Object(i),!0).forEach(function(e){c(r,e,i[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):je(Object(i)).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))})}return r}function ei(r,n){for(;!{}.hasOwnProperty.call(r,n)&&(r=Q(r))!==null;);return r}function Ae(){return Ae=typeof Reflect<"u"&&Reflect.get?Reflect.get.bind():function(r,n,i){var e=ei(r,n);if(e){var t=Object.getOwnPropertyDescriptor(e,n);return t.get?t.get.call(arguments.length<3?r:i):t.value}},Ae.apply(null,arguments)}function wt(r,n,i,e){var t=Ae(Q(r.prototype),n,i);return typeof t=="function"?function(a){return t.apply(i,a)}:t}function ti(r){return r.normalized?1:r.size}function ye(r){var n=0;return r.forEach(function(i){return n+=ti(i)}),n}function xt(r,n,i){var e=r==="VERTEX"?n.VERTEX_SHADER:n.FRAGMENT_SHADER,t=n.createShader(e);if(t===null)throw new Error("loadShader: error while creating the shader");n.shaderSource(t,i),n.compileShader(t);var a=n.getShaderParameter(t,n.COMPILE_STATUS);if(!a){var o=n.getShaderInfoLog(t);throw n.deleteShader(t),new Error(`loadShader: error while compiling the shader:
3
3
  `.concat(o,`
4
4
  `).concat(i))}return t}function ii(r,n){return xt("VERTEX",r,n)}function ri(r,n){return xt("FRAGMENT",r,n)}function ni(r,n){var i=r.createProgram();if(i===null)throw new Error("loadProgram: error while creating the program.");var e,t;for(e=0,t=n.length;e<t;e++)r.attachShader(i,n[e]);r.linkProgram(i);var a=r.getProgramParameter(i,r.LINK_STATUS);if(!a){var o=r.getProgramInfoLog(i);throw r.deleteProgram(i),new Error("loadProgram: error while linking the program: ".concat(o))}return i}function Ze(r){var n=r.gl,i=r.buffer,e=r.program,t=r.vertexShader,a=r.fragmentShader;n.deleteShader(t),n.deleteShader(a),n.deleteProgram(e),n.deleteBuffer(i)}var qe=`#define PICKING_MODE
package/assets/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-Brb7M_6G.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-BdR4Vlu6.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-CYBjbqVr.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-BpmvLvpp.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-FA0uySU7.js">
@@ -93,7 +93,7 @@ import {
93
93
  trafficConnectWordpressRequestSchema,
94
94
  trafficEventKindSchema,
95
95
  trafficSeriesGranularitySchema
96
- } from "./chunk-DY5ZDKQW.js";
96
+ } from "./chunk-DU5Q5ZOX.js";
97
97
 
98
98
  // src/config.ts
99
99
  import fs from "fs";
@@ -9387,7 +9387,7 @@ var technicalAeoRunInputSchema = z3.object({
9387
9387
  sitemapUrl: z3.string().url().optional().describe("Override the sitemap URL. Defaults to https://<canonicalDomain>/sitemap.xml."),
9388
9388
  limit: z3.number().int().positive().max(2e3).optional().describe("Deprecated compatibility alias for maxPages."),
9389
9389
  maxPages: z3.number().int().positive().max(5e4).optional().describe("Maximum pages crawled and audited. Defaults to 1,000; hard maximum 50,000."),
9390
- maxEdges: z3.number().int().positive().max(1e6).optional().describe("Maximum link observations retained for this crawl. Defaults to 100,000; hard maximum 1,000,000."),
9390
+ maxEdges: z3.number().int().positive().max(1e6).optional().describe("Maximum link observations retained for this crawl. When omitted the crawl engine derives the budget from the page count; hard maximum 1,000,000."),
9391
9391
  maxDepth: z3.number().int().min(0).max(100).optional().describe("Maximum internal-link depth from the root page."),
9392
9392
  checkDeadLinks: z3.boolean().optional().describe("Opt in to internal dead-link checks. Omitted and false both disable checks.")
9393
9393
  });
@@ -11445,7 +11445,7 @@ var canonryMcpTools = [
11445
11445
  defineTool({
11446
11446
  name: "canonry_technical_aeo_run",
11447
11447
  title: "Run Technical AEO site audit",
11448
- description: "Start a site-audit run. The run discovers root, sitemap, and linked pages. Its unattended default is 1,000 pages and 100,000 link observations; callers may explicitly raise either to its hard maximum. It returns {runId, status} and continues in the background. If an active run has identical effective options, this tool returns it; different options are refused. Poll canonry_run_get, then read the crawl and score tools.",
11448
+ description: "Start a site-audit run. The run discovers root, sitemap, and linked pages. It defaults to 1,000 pages, and the engine derives the link-observation budget from that page count with a 100,000 floor, so raising maxPages raises it too. An explicit maxEdges is a ceiling that replaces the derivation and can sit below it. It returns {runId, status} and continues in the background. If an active run has identical effective options, this tool returns it; different options are refused. Poll canonry_run_get, then read the crawl and score tools.",
11449
11449
  access: "write",
11450
11450
  tier: "monitoring",
11451
11451
  inputSchema: technicalAeoRunInputSchema,
@@ -209,6 +209,7 @@ import {
209
209
  canonicalMeasurementPlanJson,
210
210
  canonicalMeasurementPlanV2,
211
211
  canonicalMeasurementPlanV2Json,
212
+ canonicalSimpleMeasurementDefinitionJson,
212
213
  canonicalizeAdsActivationManifest,
213
214
  canonicalizeGoogleAdsCustomerSelection,
214
215
  canonicalizeGtmAccountId,
@@ -573,6 +574,7 @@ import {
573
574
  serializeRunError,
574
575
  settingsDtoSchema,
575
576
  shiftIsoCalendarDate,
577
+ simpleMeasurementDefinitionSchema,
576
578
  siteAuditLivePageHealthSchema,
577
579
  siteAuditPageFactorSchema,
578
580
  siteAuditPagesResponseSchema,
@@ -652,10 +654,10 @@ import {
652
654
  wordpressSchemaDeployResultDtoSchema,
653
655
  wordpressSchemaStatusResultDtoSchema,
654
656
  wordpressStatusDtoSchema
655
- } from "./chunk-DY5ZDKQW.js";
657
+ } from "./chunk-DU5Q5ZOX.js";
656
658
 
657
659
  // src/intelligence-service.ts
658
- import { eq as eq63, desc as desc27, asc as asc12, and as and52, ne as ne8, or as or14, inArray as inArray23, gte as gte16, lte as lte13, isNull as isNull9, sql as sql25, exists } from "drizzle-orm";
660
+ import { eq as eq64, desc as desc27, asc as asc12, and as and53, ne as ne8, or as or14, inArray as inArray23, gte as gte16, lte as lte13, isNull as isNull9, sql as sql25, exists } from "drizzle-orm";
659
661
 
660
662
  // ../db/src/client.ts
661
663
  import { mkdirSync } from "fs";
@@ -756,6 +758,7 @@ __export(schema_exports, {
756
758
  researchRuns: () => researchRuns,
757
759
  runs: () => runs,
758
760
  schedules: () => schedules,
761
+ simpleMeasurementDefinitions: () => simpleMeasurementDefinitions,
759
762
  siteAuditPages: () => siteAuditPages,
760
763
  siteAuditSnapshots: () => siteAuditSnapshots,
761
764
  siteCrawlAttempts: () => siteCrawlAttempts,
@@ -1016,6 +1019,20 @@ var runs = sqliteTable("runs", {
1016
1019
  foreignColumns: [measurementPlanVersions.projectId, measurementPlanVersions.id]
1017
1020
  })
1018
1021
  ]);
1022
+ var simpleMeasurementDefinitions = sqliteTable("simple_measurement_definitions", {
1023
+ runId: text("run_id").notNull().primaryKey(),
1024
+ projectId: text("project_id").notNull(),
1025
+ definition: text("definition", { mode: "json" }).$type().notNull(),
1026
+ checksum: text("checksum").notNull(),
1027
+ capturedAt: text("captured_at").notNull()
1028
+ }, (table) => [
1029
+ index("idx_simple_measurement_definitions_project").on(table.projectId),
1030
+ foreignKey({
1031
+ name: "simple_measurement_definitions_project_run_fk",
1032
+ columns: [table.projectId, table.runId],
1033
+ foreignColumns: [runs.projectId, runs.id]
1034
+ }).onDelete("cascade")
1035
+ ]);
1019
1036
  var queryBasketVersions = sqliteTable("query_basket_versions", {
1020
1037
  projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
1021
1038
  revision: integer("revision").notNull(),
@@ -7080,6 +7097,36 @@ var MIGRATION_VERSIONS = [
7080
7097
  statements: [
7081
7098
  `ALTER TABLE measurement_plan_versions ADD COLUMN comparable_to_version_id TEXT`
7082
7099
  ]
7100
+ },
7101
+ {
7102
+ // A simple (planless) run resolves its live inputs at dispatch, not queue
7103
+ // time. The sidecar freezes only new captures; historic runs intentionally
7104
+ // remain absent because no truthful definition can be reconstructed for
7105
+ // them. It is deliberately separate from the advanced-plan manifest and
7106
+ // checksum/continuity chain.
7107
+ version: 150,
7108
+ name: "simple-measurement-definitions",
7109
+ statements: [
7110
+ `CREATE TABLE IF NOT EXISTS simple_measurement_definitions (
7111
+ run_id TEXT PRIMARY KEY NOT NULL,
7112
+ project_id TEXT NOT NULL,
7113
+ definition TEXT NOT NULL,
7114
+ checksum TEXT NOT NULL,
7115
+ captured_at TEXT NOT NULL,
7116
+ FOREIGN KEY (project_id, run_id)
7117
+ REFERENCES runs(project_id, id) ON DELETE CASCADE
7118
+ )`,
7119
+ `CREATE INDEX IF NOT EXISTS idx_simple_measurement_definitions_project
7120
+ ON simple_measurement_definitions(project_id)`,
7121
+ // Frozen input cannot be corrected in place: a retry must either reuse
7122
+ // this exact definition or start a distinct run, never reinterpret a
7123
+ // stored answer through newly-current project settings.
7124
+ `CREATE TRIGGER IF NOT EXISTS simple_measurement_definitions_no_update
7125
+ BEFORE UPDATE ON simple_measurement_definitions
7126
+ BEGIN
7127
+ SELECT RAISE(ABORT, 'simple measurement definition is immutable');
7128
+ END`
7129
+ ]
7083
7130
  }
7084
7131
  ];
7085
7132
  function addRunsMeasurementPlanVersionForeignKey(tx) {
@@ -38203,7 +38250,7 @@ var routeCatalog = [
38203
38250
  sitemapUrl: { ...stringSchema, description: "Deprecated compatibility alias for the sitemap override." },
38204
38251
  limit: { ...integerSchema, minimum: 1, maximum: 2e3, description: "Deprecated compatibility alias for maxPages. Max 2000." },
38205
38252
  maxPages: { ...integerSchema, minimum: 1, maximum: 5e4, description: "Crawl page budget. Defaults to 1000; max 50000." },
38206
- maxEdges: { ...integerSchema, minimum: 1, maximum: 1e6, description: "Internal-link observation budget. Defaults to 100000; max 1000000." },
38253
+ maxEdges: { ...integerSchema, minimum: 1, maximum: 1e6, description: "Internal-link observation budget. When omitted the crawl engine derives it from the page count; max 1000000." },
38207
38254
  maxDepth: { ...integerSchema, minimum: 0, maximum: 100, description: "Maximum crawl depth from the root. Max 100." },
38208
38255
  checkDeadLinks: { ...booleanSchema, default: false, description: "Enable dead-link checking. Defaults to false." }
38209
38256
  }
@@ -79595,7 +79642,9 @@ async function technicalAeoRoutes(app, opts) {
79595
79642
  sitemapUrl: effectiveRequest.sitemapUrl ?? void 0,
79596
79643
  limit: parsed.data.limit,
79597
79644
  maxPages: effectiveRequest.maxPages,
79598
- maxEdges: effectiveRequest.maxEdges,
79645
+ // Stays undefined when unset so the engine derives the edge budget
79646
+ // from the page count instead of inheriting a flat ceiling here.
79647
+ maxEdges: effectiveRequest.maxEdges ?? void 0,
79599
79648
  maxDepth: effectiveRequest.maxDepth ?? void 0,
79600
79649
  checkDeadLinks: effectiveRequest.checkDeadLinks
79601
79650
  });
@@ -79678,6 +79727,73 @@ function serializeQuery(row) {
79678
79727
  return { id: row.id, position: row.position, query: row.queryText, status: row.status, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, servedModel: row.servedModel, answerText: row.answerText, groundingSources: row.groundingSources, citedDomains: row.citedDomains, searchQueries: row.searchQueries, namedCompetitors: row.namedCompetitors, citedCompetitorDomains: row.citedCompetitorDomains, answerMentioned: row.answerMentioned, citationState: row.citationState, error: row.error, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
79679
79728
  }
79680
79729
 
79730
+ // ../api-routes/src/simple-measurement-definitions.ts
79731
+ import crypto49 from "crypto";
79732
+ import { and as and52, eq as eq63 } from "drizzle-orm";
79733
+ function captureSimpleMeasurementDefinition(db, input) {
79734
+ return db.transaction((tx) => {
79735
+ const run = tx.select({
79736
+ kind: runs.kind,
79737
+ trigger: runs.trigger,
79738
+ status: runs.status,
79739
+ measurementPlanVersionId: runs.measurementPlanVersionId
79740
+ }).from(runs).where(and52(eq63(runs.projectId, input.projectId), eq63(runs.id, input.runId))).get();
79741
+ if (!run) throw notFound("Run", input.runId);
79742
+ if (run.kind !== RunKinds["answer-visibility"] || run.trigger === RunTriggers.probe || run.measurementPlanVersionId !== null) {
79743
+ return null;
79744
+ }
79745
+ const definition = simpleMeasurementDefinitionSchema.parse(input.definition);
79746
+ const classifier = compileQueryClassifier(effectiveBrandNames(definition.identity));
79747
+ if (definition.queries.some((query) => query.queryClass !== (classifier?.classify(query.queryText) ?? null))) {
79748
+ throw validationError("Query classes must match the captured identity and text.");
79749
+ }
79750
+ const existing = tx.select().from(simpleMeasurementDefinitions).where(and52(eq63(simpleMeasurementDefinitions.projectId, input.projectId), eq63(simpleMeasurementDefinitions.runId, input.runId))).get();
79751
+ if (existing) {
79752
+ const frozen = simpleMeasurementDefinitionSchema.parse(existing.definition);
79753
+ const replayDefinition = {
79754
+ ...definition,
79755
+ capturedAt: frozen.capturedAt
79756
+ };
79757
+ const replayChecksum = crypto49.createHash("sha256").update(canonicalSimpleMeasurementDefinitionJson(replayDefinition)).digest("hex");
79758
+ if (existing.checksum !== replayChecksum) {
79759
+ if (frozen.competitors === void 0) {
79760
+ const { competitors: _currentCompetitors, ...legacyReplayDefinition } = replayDefinition;
79761
+ const legacyReplayChecksum = crypto49.createHash("sha256").update(canonicalSimpleMeasurementDefinitionJson(legacyReplayDefinition)).digest("hex");
79762
+ if (existing.checksum === legacyReplayChecksum) return frozen;
79763
+ }
79764
+ throw validationError("This run already has a captured measurement definition. Start a new run for changed inputs.");
79765
+ }
79766
+ return frozen;
79767
+ }
79768
+ if (run.status !== RunStatuses.running) {
79769
+ throw validationError("Only a running run can capture a new measurement definition.");
79770
+ }
79771
+ if (tx.select({ id: querySnapshots.id }).from(querySnapshots).where(eq63(querySnapshots.runId, input.runId)).limit(1).get()) {
79772
+ throw validationError("This run already has stored answers. Its measurement definition cannot be inferred afterward.");
79773
+ }
79774
+ const projectQueryIds = new Set(tx.select({ id: queries.id }).from(queries).where(eq63(queries.projectId, input.projectId)).all().map((query) => query.id));
79775
+ if (definition.queries.some((query) => !projectQueryIds.has(query.queryId))) {
79776
+ throw validationError("Every captured query must belong to the run project.");
79777
+ }
79778
+ if (definition.competitors !== void 0) {
79779
+ const liveCompetitorDomains = new Set(tx.select({ domain: competitors.domain }).from(competitors).where(eq63(competitors.projectId, input.projectId)).all().map((competitor) => competitor.domain));
79780
+ const capturedDomains = new Set(definition.competitors.map((competitor) => competitor.domain));
79781
+ if (liveCompetitorDomains.size !== capturedDomains.size || [...liveCompetitorDomains].some((domain) => !capturedDomains.has(domain))) {
79782
+ throw validationError("Captured competitors must exactly match the project competitors dispatched for this run.");
79783
+ }
79784
+ }
79785
+ const checksum = crypto49.createHash("sha256").update(canonicalSimpleMeasurementDefinitionJson(definition)).digest("hex");
79786
+ tx.insert(simpleMeasurementDefinitions).values({
79787
+ projectId: input.projectId,
79788
+ runId: input.runId,
79789
+ definition,
79790
+ checksum,
79791
+ capturedAt: definition.capturedAt
79792
+ }).run();
79793
+ return definition;
79794
+ });
79795
+ }
79796
+
79681
79797
  // ../api-routes/src/index.ts
79682
79798
  async function apiRoutes(app, opts) {
79683
79799
  app.decorate("db", opts.db);
@@ -80183,7 +80299,7 @@ function buildTrafficSourceValidators(opts) {
80183
80299
  }
80184
80300
 
80185
80301
  // src/intelligence-service.ts
80186
- import crypto49 from "crypto";
80302
+ import crypto50 from "crypto";
80187
80303
 
80188
80304
  // src/logger.ts
80189
80305
  var IS_TTY = process.stdout.isTTY === true;
@@ -80371,10 +80487,10 @@ var log = createLogger("IntelligenceService");
80371
80487
  var runChronologyKey = sql25`coalesce(${runs.finishedAt}, ${runs.createdAt})`;
80372
80488
  function analyzableRunPredicates(projectId) {
80373
80489
  return [
80374
- eq63(runs.projectId, projectId),
80490
+ eq64(runs.projectId, projectId),
80375
80491
  // Only this kind writes query_snapshots.
80376
- eq63(runs.kind, RunKinds["answer-visibility"]),
80377
- or14(eq63(runs.status, RunStatuses.completed), eq63(runs.status, RunStatuses.partial)),
80492
+ eq64(runs.kind, RunKinds["answer-visibility"]),
80493
+ or14(eq64(runs.status, RunStatuses.completed), eq64(runs.status, RunStatuses.partial)),
80378
80494
  // Defensive: RunCoordinator already skips probes before analyzeAndPersist
80379
80495
  // is called, but a future call site invoking it directly for a probe must
80380
80496
  // still not pollute the intelligence window.
@@ -80419,16 +80535,16 @@ var IntelligenceService = class {
80419
80535
  * Returns the analysis result for the coordinator to inspect (e.g. for webhook dispatch).
80420
80536
  */
80421
80537
  analyzeAndPersist(runId, projectId) {
80422
- const currentRunRecord = this.db.select().from(runs).where(and52(eq63(runs.id, runId), ...analyzableRunPredicates(projectId))).get();
80538
+ const currentRunRecord = this.db.select().from(runs).where(and53(eq64(runs.id, runId), ...analyzableRunPredicates(projectId))).get();
80423
80539
  if (!currentRunRecord) {
80424
80540
  log.info("intelligence.skip", { runId, reason: "run not eligible for analysis" });
80425
80541
  return null;
80426
80542
  }
80427
80543
  const currentLocation = currentRunRecord.location ?? null;
80428
80544
  const recentRuns = this.db.select().from(runs).where(
80429
- and52(
80545
+ and53(
80430
80546
  ...analyzableRunPredicates(projectId),
80431
- currentLocation === null ? isNull9(runs.location) : eq63(runs.location, currentLocation),
80547
+ currentLocation === null ? isNull9(runs.location) : eq64(runs.location, currentLocation),
80432
80548
  // Never look forward. The window is this run's own past, so
80433
80549
  // re-analyzing a historical run compares it against its true
80434
80550
  // predecessor rather than against sweeps that came after it.
@@ -80436,7 +80552,7 @@ var IntelligenceService = class {
80436
80552
  // MEASUREMENT: only runs that actually wrote snapshots — see above.
80437
80553
  // Index seek on idx_snapshots_run, short-circuited on the first row.
80438
80554
  exists(
80439
- this.db.select({ one: sql25`1` }).from(querySnapshots).where(eq63(querySnapshots.runId, runs.id))
80555
+ this.db.select({ one: sql25`1` }).from(querySnapshots).where(eq64(querySnapshots.runId, runs.id))
80440
80556
  )
80441
80557
  )
80442
80558
  ).orderBy(desc27(runs.finishedAt), desc27(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
@@ -80511,7 +80627,7 @@ var IntelligenceService = class {
80511
80627
  * Returns the persisted insights so the coordinator can count critical/high.
80512
80628
  */
80513
80629
  analyzeAndPersistGbp(runId, projectId) {
80514
- const runRow = this.db.select({ createdAt: runs.createdAt, startedAt: runs.startedAt, finishedAt: runs.finishedAt }).from(runs).where(eq63(runs.id, runId)).get();
80630
+ const runRow = this.db.select({ createdAt: runs.createdAt, startedAt: runs.startedAt, finishedAt: runs.finishedAt }).from(runs).where(eq64(runs.id, runId)).get();
80515
80631
  if (!runRow) {
80516
80632
  log.info("gbp-intelligence.skip", { runId, reason: "run not found" });
80517
80633
  this.persistGbpInsights(runId, projectId, [], []);
@@ -80519,9 +80635,9 @@ var IntelligenceService = class {
80519
80635
  }
80520
80636
  const windowStart = runRow.startedAt ?? runRow.createdAt;
80521
80637
  const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
80522
- const selected = this.db.select().from(gbpLocations).where(and52(
80523
- eq63(gbpLocations.projectId, projectId),
80524
- eq63(gbpLocations.selected, true),
80638
+ const selected = this.db.select().from(gbpLocations).where(and53(
80639
+ eq64(gbpLocations.projectId, projectId),
80640
+ eq64(gbpLocations.selected, true),
80525
80641
  gte16(gbpLocations.syncedAt, windowStart),
80526
80642
  lte13(gbpLocations.syncedAt, windowEnd)
80527
80643
  )).all();
@@ -80556,12 +80672,12 @@ var IntelligenceService = class {
80556
80672
  }
80557
80673
  /** Build the per-location signal bundle the GBP analyzer consumes. */
80558
80674
  buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
80559
- const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and52(eq63(gbpDailyMetrics.projectId, projectId), eq63(gbpDailyMetrics.locationName, locationName))).all();
80560
- const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and52(eq63(gbpPlaceActions.projectId, projectId), eq63(gbpPlaceActions.locationName, locationName))).all();
80561
- const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and52(eq63(gbpLodgingSnapshots.projectId, projectId), eq63(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).limit(1).get();
80562
- const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and52(eq63(gbpLocations.projectId, projectId), eq63(gbpLocations.locationName, locationName))).get();
80675
+ const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and53(eq64(gbpDailyMetrics.projectId, projectId), eq64(gbpDailyMetrics.locationName, locationName))).all();
80676
+ const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and53(eq64(gbpPlaceActions.projectId, projectId), eq64(gbpPlaceActions.locationName, locationName))).all();
80677
+ const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and53(eq64(gbpLodgingSnapshots.projectId, projectId), eq64(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).limit(1).get();
80678
+ const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and53(eq64(gbpLocations.projectId, projectId), eq64(gbpLocations.locationName, locationName))).get();
80563
80679
  const descriptionMissing = !(ownerRow?.description ?? "").trim();
80564
- const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and52(eq63(gbpPlaceDetails.projectId, projectId), eq63(gbpPlaceDetails.locationName, locationName))).orderBy(desc27(gbpPlaceDetails.syncedAt)).limit(1).get();
80680
+ const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and53(eq64(gbpPlaceDetails.projectId, projectId), eq64(gbpPlaceDetails.locationName, locationName))).orderBy(desc27(gbpPlaceDetails.syncedAt)).limit(1).get();
80565
80681
  const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
80566
80682
  const summary = buildGbpSummary({
80567
80683
  locationName,
@@ -80597,7 +80713,7 @@ var IntelligenceService = class {
80597
80713
  /** Build the month-over-month keyword series for a location from the
80598
80714
  * accumulating gbp_keyword_monthly table (latest complete month vs prior). */
80599
80715
  buildGbpKeywordTrend(projectId, locationName) {
80600
- const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and52(eq63(gbpKeywordMonthly.projectId, projectId), eq63(gbpKeywordMonthly.locationName, locationName))).all();
80716
+ const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and53(eq64(gbpKeywordMonthly.projectId, projectId), eq64(gbpKeywordMonthly.locationName, locationName))).all();
80601
80717
  if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
80602
80718
  const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
80603
80719
  const recentMonth = months[0] ?? null;
@@ -80628,7 +80744,7 @@ var IntelligenceService = class {
80628
80744
  */
80629
80745
  persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
80630
80746
  const covered = new Set(coveredLocationNames);
80631
- const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and52(eq63(insights.projectId, projectId), eq63(insights.provider, GBP_INSIGHT_PROVIDER))).all();
80747
+ const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and53(eq64(insights.projectId, projectId), eq64(insights.provider, GBP_INSIGHT_PROVIDER))).all();
80632
80748
  const staleIds = [];
80633
80749
  const dismissedSlots = /* @__PURE__ */ new Set();
80634
80750
  for (const row of existing) {
@@ -80639,7 +80755,7 @@ var IntelligenceService = class {
80639
80755
  }
80640
80756
  this.db.transaction((tx) => {
80641
80757
  for (const id of staleIds) {
80642
- tx.delete(insights).where(eq63(insights.id, id)).run();
80758
+ tx.delete(insights).where(eq64(insights.id, id)).run();
80643
80759
  }
80644
80760
  for (const insight of gbpInsights) {
80645
80761
  const parsed = parseGbpInsightId(insight.id);
@@ -80725,7 +80841,7 @@ var IntelligenceService = class {
80725
80841
  * create per run + aggregate). DB is left untouched.
80726
80842
  */
80727
80843
  backfill(projectName, opts, onProgress) {
80728
- const project = this.db.select().from(projects).where(eq63(projects.name, projectName)).get();
80844
+ const project = this.db.select().from(projects).where(eq64(projects.name, projectName)).get();
80729
80845
  if (!project) {
80730
80846
  throw new Error(`Project "${projectName}" not found`);
80731
80847
  }
@@ -80737,7 +80853,7 @@ var IntelligenceService = class {
80737
80853
  }
80738
80854
  sinceTimestamp = parsed;
80739
80855
  }
80740
- const allRuns = this.db.select().from(runs).where(and52(...analyzableRunPredicates(project.id))).orderBy(asc12(runs.finishedAt)).all();
80856
+ const allRuns = this.db.select().from(runs).where(and53(...analyzableRunPredicates(project.id))).orderBy(asc12(runs.finishedAt)).all();
80741
80857
  const measuredRunIds = this.runIdsWithSnapshots(allRuns.map((r) => r.id));
80742
80858
  const measuredRuns = allRuns.filter((r) => measuredRunIds.has(r.id));
80743
80859
  let startIdx = 0;
@@ -80814,7 +80930,7 @@ var IntelligenceService = class {
80814
80930
  return { processed, skipped, totalInsights };
80815
80931
  }
80816
80932
  loadTrackedCompetitors(projectId) {
80817
- return this.db.select({ domain: competitors.domain }).from(competitors).where(eq63(competitors.projectId, projectId)).all().map((r) => r.domain);
80933
+ return this.db.select({ domain: competitors.domain }).from(competitors).where(eq64(competitors.projectId, projectId)).all().map((r) => r.domain);
80818
80934
  }
80819
80935
  /**
80820
80936
  * Which of `runIds` actually wrote query snapshots. One grouped read, so
@@ -80845,15 +80961,15 @@ var IntelligenceService = class {
80845
80961
  }
80846
80962
  persistResult(result, runId, projectId) {
80847
80963
  const previouslyDismissed = /* @__PURE__ */ new Set();
80848
- const existingInsights = this.db.select({ query: insights.query, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(eq63(insights.runId, runId)).all();
80964
+ const existingInsights = this.db.select({ query: insights.query, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(eq64(insights.runId, runId)).all();
80849
80965
  for (const row of existingInsights) {
80850
80966
  if (row.dismissed) {
80851
80967
  previouslyDismissed.add(`${row.query}:${row.provider}:${row.type}`);
80852
80968
  }
80853
80969
  }
80854
80970
  this.db.transaction((tx) => {
80855
- tx.delete(insights).where(eq63(insights.runId, runId)).run();
80856
- tx.delete(healthSnapshots).where(eq63(healthSnapshots.runId, runId)).run();
80971
+ tx.delete(insights).where(eq64(insights.runId, runId)).run();
80972
+ tx.delete(healthSnapshots).where(eq64(healthSnapshots.runId, runId)).run();
80857
80973
  const now = (/* @__PURE__ */ new Date()).toISOString();
80858
80974
  for (const insight of result.insights) {
80859
80975
  const wasDismissed = previouslyDismissed.has(`${insight.query}:${insight.provider}:${insight.type}`);
@@ -80873,7 +80989,7 @@ var IntelligenceService = class {
80873
80989
  }).run();
80874
80990
  }
80875
80991
  tx.insert(healthSnapshots).values({
80876
- id: crypto49.randomUUID(),
80992
+ id: crypto50.randomUUID(),
80877
80993
  projectId,
80878
80994
  runId,
80879
80995
  overallCitedRate: String(result.health.overallCitedRate),
@@ -80900,8 +81016,8 @@ var IntelligenceService = class {
80900
81016
  clicks: gscSearchData.clicks,
80901
81017
  impressions: gscSearchData.impressions,
80902
81018
  position: gscSearchData.position
80903
- }).from(gscSearchData).where(and52(
80904
- eq63(gscSearchData.projectId, projectId),
81019
+ }).from(gscSearchData).where(and53(
81020
+ eq64(gscSearchData.projectId, projectId),
80905
81021
  gte16(gscSearchData.date, window.startDate),
80906
81022
  lte13(gscSearchData.date, window.endDate)
80907
81023
  )).all();
@@ -80954,17 +81070,17 @@ var IntelligenceService = class {
80954
81070
  const key = row.query.toLowerCase();
80955
81071
  gscImpressionsByQuery.set(key, (gscImpressionsByQuery.get(key) ?? 0) + row.impressions);
80956
81072
  }
80957
- const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(eq63(projects.id, projectId)).get();
81073
+ const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(eq64(projects.id, projectId)).get();
80958
81074
  const locationCount = Math.max(
80959
81075
  1,
80960
81076
  (projectRow?.locations ?? []).length
80961
81077
  );
80962
81078
  const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
80963
81079
  const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
80964
- and52(
80965
- eq63(runs.projectId, projectId),
80966
- eq63(runs.kind, RunKinds["answer-visibility"]),
80967
- or14(eq63(runs.status, "completed"), eq63(runs.status, "partial")),
81080
+ and53(
81081
+ eq64(runs.projectId, projectId),
81082
+ eq64(runs.kind, RunKinds["answer-visibility"]),
81083
+ or14(eq64(runs.status, "completed"), eq64(runs.status, "partial")),
80968
81084
  // Defensive — see top of file.
80969
81085
  ne8(runs.trigger, RunTriggers.probe)
80970
81086
  )
@@ -80984,7 +81100,7 @@ var IntelligenceService = class {
80984
81100
  const haveHistory = recentRunIds.length > 0;
80985
81101
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
80986
81102
  if (haveHistory) {
80987
- const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and52(eq63(insights.type, "regression"), inArray23(insights.runId, recentRunIds))).all();
81103
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and53(eq64(insights.type, "regression"), inArray23(insights.runId, recentRunIds))).all();
80988
81104
  const regressionGroups = /* @__PURE__ */ new Map();
80989
81105
  for (const row of priorRows) {
80990
81106
  if (!row.runId) continue;
@@ -81013,7 +81129,7 @@ var IntelligenceService = class {
81013
81129
  });
81014
81130
  }
81015
81131
  buildRunData(runId, projectId, completedAt, location = null, trackedCompetitors = []) {
81016
- const projectDomainRow = this.db.select({ canonicalDomain: projects.canonicalDomain, ownedDomains: projects.ownedDomains }).from(projects).where(eq63(projects.id, projectId)).get();
81132
+ const projectDomainRow = this.db.select({ canonicalDomain: projects.canonicalDomain, ownedDomains: projects.ownedDomains }).from(projects).where(eq64(projects.id, projectId)).get();
81017
81133
  const projectDomains = projectDomainRow ? effectiveDomains({
81018
81134
  canonicalDomain: projectDomainRow.canonicalDomain,
81019
81135
  ownedDomains: projectDomainRow.ownedDomains
@@ -81031,7 +81147,7 @@ var IntelligenceService = class {
81031
81147
  citedDomains: querySnapshots.citedDomains,
81032
81148
  rawResponse: querySnapshots.rawResponse,
81033
81149
  snapshotLocation: querySnapshots.location
81034
- }).from(querySnapshots).leftJoin(queries, eq63(querySnapshots.queryId, queries.id)).where(eq63(querySnapshots.runId, runId)).all();
81150
+ }).from(querySnapshots).leftJoin(queries, eq64(querySnapshots.queryId, queries.id)).where(eq64(querySnapshots.runId, runId)).all();
81035
81151
  const snapshots = [];
81036
81152
  let orphanCount = 0;
81037
81153
  for (const r of rows) {
@@ -81225,6 +81341,7 @@ export {
81225
81341
  generateWranglerToml,
81226
81342
  executeDiscovery,
81227
81343
  markSessionFailed,
81344
+ captureSimpleMeasurementDefinition,
81228
81345
  apiRoutes,
81229
81346
  createLogger,
81230
81347
  IntelligenceService
@@ -11,7 +11,7 @@ import {
11
11
  loadConfig,
12
12
  loadConfigRaw,
13
13
  saveConfigPatch
14
- } from "./chunk-FVC7PGYQ.js";
14
+ } from "./chunk-3SFCUICM.js";
15
15
  import {
16
16
  CC_CACHE_DIR,
17
17
  DUCKDB_SPEC,
@@ -40,6 +40,7 @@ import {
40
40
  bingCoverageSnapshots,
41
41
  bingUrlInspections,
42
42
  buildLocationProfileFields,
43
+ captureSimpleMeasurementDefinition,
43
44
  ccReleasePaths,
44
45
  ccReleaseSyncs,
45
46
  classifyAiUserFetch,
@@ -157,7 +158,7 @@ import {
157
158
  siteCrawlSnapshots,
158
159
  toAlertView,
159
160
  usageCounters
160
- } from "./chunk-K45YKXE4.js";
161
+ } from "./chunk-7ATZMDG2.js";
161
162
  import {
162
163
  AGENT_MEMORY_VALUE_MAX_BYTES,
163
164
  AGENT_PROVIDER_IDS,
@@ -214,8 +215,10 @@ import {
214
215
  agentMemoryUpsertRequestSchema,
215
216
  authInvalid,
216
217
  authRequired,
218
+ brandLabelFromDomain,
217
219
  bucketOnboardingCount,
218
220
  buildRunErrorFromMessages,
221
+ buildSimpleMeasurementDefinition,
219
222
  canonicalizeGtmAccountId,
220
223
  canonicalizeGtmContainerId,
221
224
  canonicalizeGtmResourceSelection,
@@ -296,7 +299,7 @@ import {
296
299
  validationError,
297
300
  winnabilityClassLabel,
298
301
  withRetry
299
- } from "./chunk-DY5ZDKQW.js";
302
+ } from "./chunk-DU5Q5ZOX.js";
300
303
 
301
304
  // src/telemetry.ts
302
305
  import crypto from "crypto";
@@ -6860,6 +6863,37 @@ var JobRunner = class {
6860
6863
  }
6861
6864
  }
6862
6865
  };
6866
+ if (existingRun.kind === RunKinds["answer-visibility"] && existingRun.trigger !== RunTriggers.probe && existingRun.measurementPlanVersionId === null) {
6867
+ const definition = buildSimpleMeasurementDefinition({
6868
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
6869
+ identity: {
6870
+ displayName: project.displayName,
6871
+ aliases: project.aliases,
6872
+ canonicalDomain: project.canonicalDomain,
6873
+ ownedDomains: project.ownedDomains
6874
+ },
6875
+ country: project.country,
6876
+ language: project.language,
6877
+ location: runLocation ?? null,
6878
+ engines: activeProviders.map(({ adapter, config }) => ({
6879
+ provider: adapter.name,
6880
+ requestedModel: config.model ?? null
6881
+ })),
6882
+ // The legacy competitors table has domains only. Freeze the exact
6883
+ // identity we actually dispatched with so later reporting never
6884
+ // borrows renamed or newly added competitors from live project state.
6885
+ competitors: projectCompetitors.map((competitor) => {
6886
+ const label = brandLabelFromDomain(competitor.domain) || competitor.domain;
6887
+ return { domain: competitor.domain, label, aliases: [label] };
6888
+ }),
6889
+ queries: projectQueries.map((query) => ({
6890
+ queryId: query.id,
6891
+ queryText: query.query,
6892
+ provenance: query.provenance ?? null
6893
+ }))
6894
+ });
6895
+ captureSimpleMeasurementDefinition(this.db, { projectId, runId, definition });
6896
+ }
6863
6897
  providerCallStart = Date.now();
6864
6898
  if (planExecution) {
6865
6899
  const plan = planExecution;
@@ -11304,15 +11338,17 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
11304
11338
  indexabilityVersion: crawlSummary.indexabilityRulesetVersion,
11305
11339
  linkScoreVersion: crawlSummary.linkScoreAlgorithmVersion,
11306
11340
  effectiveOptions: {
11341
+ // Null, never absent: a reader must be able to tell "the operator set
11342
+ // no edge budget and the engine derived one" from a missing field.
11307
11343
  mode: "summary",
11308
11344
  sitemapUrl: opts.sitemapUrl ?? null,
11309
11345
  maxPages,
11310
- maxEdges,
11346
+ maxEdges: maxEdges ?? null,
11311
11347
  maxDepth: opts.maxDepth ?? null,
11312
11348
  checkDeadLinks: opts.checkDeadLinks ?? false
11313
11349
  },
11314
11350
  pageBudget: maxPages,
11315
- edgeBudget: maxEdges,
11351
+ edgeBudget: maxEdges ?? null,
11316
11352
  maxDepth: opts.maxDepth ?? null,
11317
11353
  checkDeadLinks: opts.checkDeadLinks ?? false,
11318
11354
  complete: crawlSummary.complete,
@@ -11867,7 +11903,7 @@ function readStoredGroundingSources(rawResponse) {
11867
11903
  return result;
11868
11904
  }
11869
11905
  async function backfillInsightsCommand(project, opts) {
11870
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-HGA553GT.js");
11906
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-BQIIWWQJ.js");
11871
11907
  const config = loadConfig();
11872
11908
  const db = createClient(config.database);
11873
11909
  migrate(db);