@canonry/canonry 4.146.0 → 4.147.0

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 (30) hide show
  1. package/assets/assets/{AuditHistoryPanel-IDsSUFI3.js → AuditHistoryPanel-DiQ0Ynw5.js} +1 -1
  2. package/assets/assets/{BacklinksPage-BswN-pyj.js → BacklinksPage-DLUQuPE_.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-CIe-R58_.js → ChartPrimitives-BoEy1qo7.js} +1 -1
  4. package/assets/assets/{HistoryPage-B18Jpq8c.js → HistoryPage-mYR2vk8n.js} +1 -1
  5. package/assets/assets/MeasurementPropertyPage-BocyGHJN.js +1 -0
  6. package/assets/assets/ProjectPage-Q5wQ7nSW.js +12 -0
  7. package/assets/assets/{RunRow-3ZwTR4Bv.js → RunRow-Ct-A6H9e.js} +1 -1
  8. package/assets/assets/{RunsPage-BCAJulR1.js → RunsPage-CsDtq0Qw.js} +1 -1
  9. package/assets/assets/{SettingsPage-BT2_l0Do.js → SettingsPage-BXwFGc1P.js} +1 -1
  10. package/assets/assets/{TrafficPage-Cux8rj5G.js → TrafficPage-B2omyoI8.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-DI1Ad8KS.js → TrafficSourceDetailPage-CoEqc6OJ.js} +1 -1
  12. package/assets/assets/{arrow-left-BMSx9HQB.js → arrow-left-Dh0vsQxe.js} +1 -1
  13. package/assets/assets/extract-error-message-DvWJ0xRn.js +1 -0
  14. package/assets/assets/{index-C6E5hp28.css → index-CXe6S1ey.css} +1 -1
  15. package/assets/assets/index-FE8JPHmT.js +213 -0
  16. package/assets/assets/{trash-2-CyoJtRAr.js → trash-2-D1_8ZseY.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-UQOTEIA6.js → chunk-4BL24FQA.js} +378 -3
  19. package/dist/{chunk-B5H55ZMA.js → chunk-BVOU4UJM.js} +3687 -3025
  20. package/dist/{chunk-ED7C5TWT.js → chunk-DRDNHYIF.js} +3757 -1424
  21. package/dist/{chunk-Z7B6BRPP.js → chunk-ZDYS24LW.js} +4 -4
  22. package/dist/cli.js +223 -15
  23. package/dist/index.js +4 -4
  24. package/dist/{intelligence-service-M5UNHF7X.js → intelligence-service-7CGZ537D.js} +2 -2
  25. package/dist/mcp.js +5 -5
  26. package/package.json +8 -7
  27. package/assets/assets/MeasurementPropertyPage-CvmQeoo7.js +0 -1
  28. package/assets/assets/ProjectPage-BE1MUAB5.js +0 -11
  29. package/assets/assets/extract-error-message-B-9FdQh8.js +0 -1
  30. package/assets/assets/index-kOXUzdqD.js +0 -213
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-UQOTEIA6.js";
13
+ } from "./chunk-4BL24FQA.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -126,7 +126,7 @@ import {
126
126
  siteAuditSnapshots,
127
127
  toAlertView,
128
128
  usageCounters
129
- } from "./chunk-ED7C5TWT.js";
129
+ } from "./chunk-DRDNHYIF.js";
130
130
  import {
131
131
  AGENT_MEMORY_VALUE_MAX_BYTES,
132
132
  AGENT_PROVIDER_IDS,
@@ -217,7 +217,7 @@ import {
217
217
  validationError,
218
218
  winnabilityClassLabel,
219
219
  withRetry
220
- } from "./chunk-B5H55ZMA.js";
220
+ } from "./chunk-BVOU4UJM.js";
221
221
 
222
222
  // src/telemetry.ts
223
223
  import crypto from "crypto";
@@ -7420,7 +7420,7 @@ function readStoredGroundingSources(rawResponse) {
7420
7420
  return result;
7421
7421
  }
7422
7422
  async function backfillInsightsCommand(project, opts) {
7423
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-M5UNHF7X.js");
7423
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-7CGZ537D.js");
7424
7424
  const config = loadConfig();
7425
7425
  const db = createClient(config.database);
7426
7426
  migrate(db);
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  showFirstRunNotice,
31
31
  trackCliCommandFinished,
32
32
  trackEvent
33
- } from "./chunk-Z7B6BRPP.js";
33
+ } from "./chunk-ZDYS24LW.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -46,8 +46,9 @@ import {
46
46
  printCliError,
47
47
  saveConfig,
48
48
  saveConfigPatch,
49
+ systemError,
49
50
  usageError
50
- } from "./chunk-UQOTEIA6.js";
51
+ } from "./chunk-4BL24FQA.js";
51
52
  import {
52
53
  apiKeys,
53
54
  createClient,
@@ -55,7 +56,7 @@ import {
55
56
  projects,
56
57
  queries,
57
58
  renderReportHtml
58
- } from "./chunk-ED7C5TWT.js";
59
+ } from "./chunk-DRDNHYIF.js";
59
60
  import {
60
61
  AdsDeliverySnapshotStatuses,
61
62
  AdsHistoricalCampaignRollupStatuses,
@@ -68,6 +69,7 @@ import {
68
69
  CheckScopes,
69
70
  CheckStatuses,
70
71
  CitationStates,
72
+ MeasurementEvidenceShapes,
71
73
  READ_ONLY_SCOPE,
72
74
  REPORT_PERIOD_OPTIONS,
73
75
  ResearchRunStatuses,
@@ -106,7 +108,7 @@ import {
106
108
  providerQuotaPolicySchema,
107
109
  resolveProviderInput,
108
110
  winnabilityClassSchema
109
- } from "./chunk-B5H55ZMA.js";
111
+ } from "./chunk-BVOU4UJM.js";
110
112
 
111
113
  // src/cli.ts
112
114
  import { pathToFileURL } from "url";
@@ -15714,6 +15716,7 @@ Usage: ${usage}`, {
15714
15716
  ];
15715
15717
 
15716
15718
  // src/commands/measurement-plan.ts
15719
+ import crypto3 from "crypto";
15717
15720
  import fs16 from "fs";
15718
15721
  import { parse } from "yaml";
15719
15722
  function readPlan(source) {
@@ -15745,6 +15748,76 @@ async function publishMeasurementPlan(project, source) {
15745
15748
  async function retireMeasurementPlanSegment(project, stableKey) {
15746
15749
  console.log(JSON.stringify(await createApiClient().retireMeasurementPlanSegment(project, stableKey), null, 2));
15747
15750
  }
15751
+ async function measurementAssignmentRequest(project, opts) {
15752
+ const client = createApiClient();
15753
+ const current = await client.getMeasurementPlanDraft(project);
15754
+ if (!current.draft || !current.etag) {
15755
+ throw new Error(`Project "${project}" has no Advanced Measurement draft. Start setup in the dashboard or create a draft first.`);
15756
+ }
15757
+ const targetKeys = opts.allProperties ? current.draft.authoring.targets.filter((target) => target.status === "included").map((target) => target.stableKey) : opts.targetKeys;
15758
+ return {
15759
+ client,
15760
+ request: {
15761
+ ...targetKeys?.length ? { targetKeys } : {},
15762
+ ...opts.groupKeys?.length ? { groupKeys: opts.groupKeys } : {},
15763
+ queryIds: opts.queryIds
15764
+ }
15765
+ };
15766
+ }
15767
+ async function previewMeasurementPlanAssignments(project, opts) {
15768
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15769
+ console.log(JSON.stringify(await client.previewMeasurementDraftAssignments(project, request), null, 2));
15770
+ }
15771
+ async function applyMeasurementPlanAssignments(project, opts) {
15772
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15773
+ const preview = await client.previewMeasurementDraftAssignments(project, request);
15774
+ const result = await client.applyMeasurementDraftAssignments(
15775
+ project,
15776
+ request,
15777
+ crypto3.randomUUID(),
15778
+ preview.draftEtag
15779
+ );
15780
+ console.log(JSON.stringify({ preview, result }, null, 2));
15781
+ }
15782
+ async function replaceMeasurementPlanAssignments(project, opts) {
15783
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15784
+ const preview = await client.previewMeasurementDraftAssignments(project, request);
15785
+ const result = await client.replaceMeasurementDraftAssignments(
15786
+ project,
15787
+ request,
15788
+ crypto3.randomUUID(),
15789
+ preview.draftEtag
15790
+ );
15791
+ console.log(JSON.stringify({ preview, result }, null, 2));
15792
+ }
15793
+ function readGroupMembershipCsv(source) {
15794
+ return source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15795
+ }
15796
+ async function previewMeasurementPlanGroups(project, source) {
15797
+ const preview = await createApiClient().previewMeasurementDraftGroupMembership(project, {
15798
+ csv: readGroupMembershipCsv(source)
15799
+ });
15800
+ console.log(JSON.stringify(preview, null, 2));
15801
+ }
15802
+ async function applyMeasurementPlanGroups(project, source, opts) {
15803
+ const client = createApiClient();
15804
+ const csv = readGroupMembershipCsv(source);
15805
+ const preview = await client.previewMeasurementDraftGroupMembership(project, { csv });
15806
+ if (preview.counts.needsAttention > 0 && !opts.acknowledgeSkipped) {
15807
+ throw new Error(
15808
+ `${preview.counts.needsAttention} CSV rows need attention. Correct them or add --acknowledge-skipped to apply only the selected matched rows.`
15809
+ );
15810
+ }
15811
+ const acceptedRows = opts.acceptAllMatched ? preview.rows.filter((row) => row.status === "matched").map((row) => row.dataRow) : opts.acceptedRows ?? [];
15812
+ if (acceptedRows.length === 0) throw new Error("No matched CSV rows were selected for apply.");
15813
+ const result = await client.applyMeasurementDraftGroupMembership(project, {
15814
+ csv,
15815
+ sourceChecksum: preview.sourceChecksum,
15816
+ previewChecksum: preview.previewChecksum,
15817
+ acceptedRows
15818
+ }, crypto3.randomUUID(), preview.draftEtag);
15819
+ console.log(JSON.stringify({ preview, result }, null, 2));
15820
+ }
15748
15821
  async function discoverMeasurementTargets(project, sitemapUrl, ruleSource, maxUrls) {
15749
15822
  const request = measurementDiscoveryRequestSchema.parse({
15750
15823
  sitemapUrl,
@@ -15801,6 +15874,11 @@ function printMeasurementProperty(response) {
15801
15874
  }
15802
15875
  console.log(lines.join("\n"));
15803
15876
  }
15877
+ function shapedPage(response) {
15878
+ if (response.answers !== void 0) return { shape: MeasurementEvidenceShapes.answers, ...response.answers };
15879
+ if (response.evidence !== void 0) return { shape: MeasurementEvidenceShapes.sources, ...response.evidence };
15880
+ throw systemError("The measurement property evidence response carried neither an evidence nor an answers page.");
15881
+ }
15804
15882
  async function showMeasurementPropertyEvidence(project, opts) {
15805
15883
  const response = await createApiClient().getMeasurementPropertyEvidence(project, {
15806
15884
  targetKey: opts.targetKey,
@@ -15808,19 +15886,22 @@ async function showMeasurementPropertyEvidence(project, opts) {
15808
15886
  ...opts.provider === void 0 ? {} : { provider: opts.provider },
15809
15887
  ...opts.location === void 0 ? {} : { location: opts.location },
15810
15888
  ...opts.runId === void 0 ? {} : { runId: opts.runId },
15889
+ ...opts.shape === void 0 ? {} : { shape: opts.shape },
15811
15890
  ...opts.cursor === void 0 ? {} : { cursor: opts.cursor },
15812
15891
  ...opts.limit === void 0 ? {} : { limit: opts.limit }
15813
15892
  });
15814
15893
  if (opts.format === "jsonl") {
15894
+ const page = shapedPage(response);
15815
15895
  emitJsonl([{
15816
15896
  kind: "measurement-property-evidence-header",
15897
+ shape: page.shape,
15817
15898
  property: response.property,
15818
15899
  queryClass: response.queryClass,
15819
15900
  measurement: response.measurement,
15820
- totalEstimate: response.evidence.totalEstimate ?? null,
15821
- nextCursor: response.evidence.nextCursor ?? null
15901
+ totalEstimate: page.totalEstimate ?? null,
15902
+ nextCursor: page.nextCursor ?? null
15822
15903
  }]);
15823
- emitJsonl(response.evidence.items);
15904
+ emitJsonl(page.items);
15824
15905
  return;
15825
15906
  }
15826
15907
  if (opts.format === "json") {
@@ -15829,6 +15910,10 @@ async function showMeasurementPropertyEvidence(project, opts) {
15829
15910
  }
15830
15911
  printMeasurementPropertyEvidence(response);
15831
15912
  }
15913
+ function signalText(signal) {
15914
+ if (signal === null) return "not measured";
15915
+ return signal ? "yes" : "no";
15916
+ }
15832
15917
  function printMeasurementPropertyEvidence(response) {
15833
15918
  const lines = [];
15834
15919
  lines.push(`${response.property.label} \u2014 ${response.queryClass} questions`);
@@ -15837,18 +15922,28 @@ function printMeasurementPropertyEvidence(response) {
15837
15922
  console.log(lines.join("\n"));
15838
15923
  return;
15839
15924
  }
15840
- const page = response.evidence;
15925
+ const page = shapedPage(response);
15926
+ const answerShape = page.shape === MeasurementEvidenceShapes.answers;
15841
15927
  lines.push(`Measurement: ${response.measurement.state}${response.measurement.displayedRunId ? ` \xB7 run ${response.measurement.displayedRunId}` : ""}`);
15842
15928
  if (page.items.length === 0) {
15843
- lines.push("No source evidence matched this Property in the displayed run.");
15929
+ lines.push(answerShape ? "No answers matched this Property in the displayed run." : "No source evidence matched this Property in the displayed run.");
15844
15930
  console.log(lines.join("\n"));
15845
15931
  return;
15846
15932
  }
15847
- lines.push(`${page.items.length} of ${page.totalEstimate ?? page.items.length} evidence rows`);
15933
+ lines.push(`${page.items.length} of ${page.totalEstimate ?? page.items.length} ${answerShape ? "answers" : "evidence rows"}`);
15848
15934
  lines.push("");
15849
- lines.push(`${"Match".padEnd(14)}${"Engine".padEnd(12)}${"Question".padEnd(40)}URL`);
15850
- for (const item of page.items) {
15851
- lines.push(`${item.classification.padEnd(14)}${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${item.sourceUrl}`);
15935
+ if (page.shape === MeasurementEvidenceShapes.answers) {
15936
+ lines.push(`${"Engine".padEnd(12)}${"Question".padEnd(40)}${"Mentioned".padEnd(15)}${"Cited".padEnd(8)}Sources`);
15937
+ for (const item of page.items) {
15938
+ lines.push(
15939
+ `${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${signalText(item.mentioned).padEnd(15)}${signalText(item.cited).padEnd(8)}${item.sources.length}`
15940
+ );
15941
+ }
15942
+ } else {
15943
+ lines.push(`${"Match".padEnd(14)}${"Engine".padEnd(12)}${"Question".padEnd(40)}URL`);
15944
+ for (const item of page.items) {
15945
+ lines.push(`${item.classification.padEnd(14)}${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${item.sourceUrl}`);
15946
+ }
15852
15947
  }
15853
15948
  if (page.nextCursor) lines.push(`
15854
15949
  More rows: --cursor ${page.nextCursor}`);
@@ -15857,6 +15952,7 @@ More rows: --cursor ${page.nextCursor}`);
15857
15952
 
15858
15953
  // src/cli-commands/measurement-plan.ts
15859
15954
  var QUERY_CLASSES = ["all", "branded", "non-brand"];
15955
+ var EVIDENCE_SHAPES = ["sources", "answers"];
15860
15956
  function queryClassOption(input) {
15861
15957
  const value = getString(input.values, "query-class");
15862
15958
  if (value === void 0) return void 0;
@@ -15864,6 +15960,13 @@ function queryClassOption(input) {
15864
15960
  if (!match) throw usageError(`--query-class must be one of ${QUERY_CLASSES.join(", ")}`);
15865
15961
  return match;
15866
15962
  }
15963
+ function shapeOption(input) {
15964
+ const value = getString(input.values, "shape");
15965
+ if (value === void 0) return void 0;
15966
+ const match = EVIDENCE_SHAPES.find((candidate) => candidate === value);
15967
+ if (!match) throw usageError(`--shape must be one of ${EVIDENCE_SHAPES.join(", ")}`);
15968
+ return match;
15969
+ }
15867
15970
  function propertyScope(input, command, usage) {
15868
15971
  return {
15869
15972
  targetKey: requireStringOption(input, "target-key", { command, usage, message: "--target-key is required" }),
@@ -15881,6 +15984,30 @@ var PROPERTY_SCOPE_OPTIONS = {
15881
15984
  location: stringOption(),
15882
15985
  "run-id": stringOption()
15883
15986
  };
15987
+ var ASSIGNMENT_AUDIENCE_OPTIONS = {
15988
+ group: multiStringOption(),
15989
+ "target-key": multiStringOption(),
15990
+ "all-properties": { type: "boolean" },
15991
+ "query-id": multiStringOption()
15992
+ };
15993
+ function assignmentAudience(input, command, usage) {
15994
+ const project = requireProject(input, command, usage);
15995
+ const groupKeys = getStringArray(input.values, "group")?.map((value) => value.trim()).filter(Boolean);
15996
+ const targetKeys = getStringArray(input.values, "target-key")?.map((value) => value.trim()).filter(Boolean);
15997
+ const queryIds = getStringArray(input.values, "query-id")?.map((value) => value.trim()).filter(Boolean) ?? [];
15998
+ const allProperties = getBoolean(input.values, "all-properties");
15999
+ if (queryIds.length === 0) throw usageError(`Error: at least one --query-id is required
16000
+ Usage: ${usage}`);
16001
+ if (allProperties && ((groupKeys?.length ?? 0) > 0 || (targetKeys?.length ?? 0) > 0)) {
16002
+ throw usageError(`Error: --all-properties cannot be combined with --group or --target-key
16003
+ Usage: ${usage}`);
16004
+ }
16005
+ if (!allProperties && (groupKeys?.length ?? 0) === 0 && (targetKeys?.length ?? 0) === 0) {
16006
+ throw usageError(`Error: select at least one --group, --target-key, or --all-properties
16007
+ Usage: ${usage}`);
16008
+ }
16009
+ return { project, options: { groupKeys, targetKeys, queryIds, allProperties } };
16010
+ }
15884
16011
  var MEASUREMENT_PLAN_CLI_COMMANDS = [
15885
16012
  { path: ["measurement-plan", "show"], usage: "canonry measurement-plan show <project> [--revision N] [--format json]", options: { revision: stringOption() }, run: async (input) => {
15886
16013
  const value = getString(input.values, "revision");
@@ -15901,6 +16028,85 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15901
16028
  if (!stableKey) throw usageError("stable segment key is required");
15902
16029
  return retireMeasurementPlanSegment(project, stableKey);
15903
16030
  } },
16031
+ {
16032
+ path: ["measurement-plan", "assignments", "preview"],
16033
+ usage: "canonry measurement-plan assignments preview <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] [--format json]",
16034
+ options: ASSIGNMENT_AUDIENCE_OPTIONS,
16035
+ run: (input) => {
16036
+ const usage = "canonry measurement-plan assignments preview <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...]";
16037
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.preview", usage);
16038
+ return previewMeasurementPlanAssignments(project, options);
16039
+ }
16040
+ },
16041
+ {
16042
+ path: ["measurement-plan", "assignments", "apply"],
16043
+ usage: "canonry measurement-plan assignments apply <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] [--format json]",
16044
+ options: ASSIGNMENT_AUDIENCE_OPTIONS,
16045
+ run: (input) => {
16046
+ const usage = "canonry measurement-plan assignments apply <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...]";
16047
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.apply", usage);
16048
+ return applyMeasurementPlanAssignments(project, options);
16049
+ }
16050
+ },
16051
+ {
16052
+ path: ["measurement-plan", "assignments", "replace"],
16053
+ usage: "canonry measurement-plan assignments replace <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] --confirm [--format json]",
16054
+ options: { ...ASSIGNMENT_AUDIENCE_OPTIONS, confirm: { type: "boolean" } },
16055
+ run: (input) => {
16056
+ const usage = "canonry measurement-plan assignments replace <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] --confirm";
16057
+ if (!getBoolean(input.values, "confirm")) throw usageError(`Error: --confirm is required
16058
+ Usage: ${usage}`);
16059
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.replace", usage);
16060
+ return replaceMeasurementPlanAssignments(project, options);
16061
+ }
16062
+ },
16063
+ {
16064
+ path: ["measurement-plan", "groups", "preview"],
16065
+ usage: "canonry measurement-plan groups preview <project> <csv|-> [--format json]",
16066
+ run: (input) => {
16067
+ const usage = "canonry measurement-plan groups preview <project> <csv|->";
16068
+ const project = requireProject(input, "measurement-plan.groups.preview", usage);
16069
+ const source = input.positionals[1];
16070
+ if (!source) throw usageError(`Error: CSV file path or - is required
16071
+ Usage: ${usage}`);
16072
+ return previewMeasurementPlanGroups(project, source);
16073
+ }
16074
+ },
16075
+ {
16076
+ path: ["measurement-plan", "groups", "apply"],
16077
+ usage: "canonry measurement-plan groups apply <project> <csv|-> --confirm [--accept-row N ... | --accept-all-matched] [--acknowledge-skipped] [--format json]",
16078
+ options: {
16079
+ confirm: { type: "boolean" },
16080
+ "accept-row": multiStringOption(),
16081
+ "accept-all-matched": { type: "boolean" },
16082
+ "acknowledge-skipped": { type: "boolean" }
16083
+ },
16084
+ run: (input) => {
16085
+ const usage = "canonry measurement-plan groups apply <project> <csv|-> --confirm [--accept-row N ... | --accept-all-matched] [--acknowledge-skipped]";
16086
+ const project = requireProject(input, "measurement-plan.groups.apply", usage);
16087
+ const source = input.positionals[1];
16088
+ if (!source) throw usageError(`Error: CSV file path or - is required
16089
+ Usage: ${usage}`);
16090
+ if (!getBoolean(input.values, "confirm")) throw usageError(`Error: --confirm is required
16091
+ Usage: ${usage}`);
16092
+ const acceptAllMatched = getBoolean(input.values, "accept-all-matched");
16093
+ const rowValues = getStringArray(input.values, "accept-row") ?? [];
16094
+ if (acceptAllMatched === rowValues.length > 0) {
16095
+ throw usageError(`Error: choose exactly one of --accept-row or --accept-all-matched
16096
+ Usage: ${usage}`);
16097
+ }
16098
+ const acceptedRows = rowValues.map((value) => Number(value));
16099
+ if (acceptedRows.some((row) => !Number.isSafeInteger(row) || row < 1)) {
16100
+ throw usageError(`Error: --accept-row must be a positive integer
16101
+ Usage: ${usage}`);
16102
+ }
16103
+ return applyMeasurementPlanGroups(project, source, {
16104
+ acceptedRows,
16105
+ acceptAllMatched,
16106
+ acknowledgeSkipped: getBoolean(input.values, "acknowledge-skipped")
16107
+ });
16108
+ }
16109
+ },
15904
16110
  {
15905
16111
  path: ["measurement-plan", "discover"],
15906
16112
  usage: "canonry measurement-plan discover <project> --sitemap-url <url> --rule <yaml|json|-> [--max-urls N] [--format json]",
@@ -15952,8 +16158,8 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15952
16158
  },
15953
16159
  {
15954
16160
  path: ["measurement-plan", "property-evidence"],
15955
- usage: "canonry measurement-plan property-evidence <project> --target-key <key> [--query-class all|branded|non-brand] [--provider <p>] [--location <l>] [--run-id <id>] [--cursor <c>] [--limit N] [--format json|jsonl]",
15956
- options: { ...PROPERTY_SCOPE_OPTIONS, cursor: stringOption(), limit: stringOption() },
16161
+ usage: "canonry measurement-plan property-evidence <project> --target-key <key> [--query-class all|branded|non-brand] [--provider <p>] [--location <l>] [--run-id <id>] [--shape sources|answers] [--cursor <c>] [--limit N] [--format json|jsonl]",
16162
+ options: { ...PROPERTY_SCOPE_OPTIONS, shape: stringOption(), cursor: stringOption(), limit: stringOption() },
15957
16163
  run: (input) => {
15958
16164
  const usage = "canonry measurement-plan property-evidence <project> --target-key <key>";
15959
16165
  const project = requireProject(input, "measurement-plan.property-evidence", usage);
@@ -15962,8 +16168,10 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15962
16168
  if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1 || limit > 100)) {
15963
16169
  throw usageError("--limit must be an integer from 1 to 100");
15964
16170
  }
16171
+ const shape = shapeOption(input);
15965
16172
  return showMeasurementPropertyEvidence(project, {
15966
16173
  ...propertyScope(input, "measurement-plan.property-evidence", usage),
16174
+ ...shape === void 0 ? {} : { shape },
15967
16175
  cursor: getString(input.values, "cursor"),
15968
16176
  ...limit === void 0 ? {} : { limit }
15969
16177
  });
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-Z7B6BRPP.js";
3
+ } from "./chunk-ZDYS24LW.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-UQOTEIA6.js";
7
- import "./chunk-ED7C5TWT.js";
8
- import "./chunk-B5H55ZMA.js";
6
+ } from "./chunk-4BL24FQA.js";
7
+ import "./chunk-DRDNHYIF.js";
8
+ import "./chunk-BVOU4UJM.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-ED7C5TWT.js";
4
- import "./chunk-B5H55ZMA.js";
3
+ } from "./chunk-DRDNHYIF.js";
4
+ import "./chunk-BVOU4UJM.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-UQOTEIA6.js";
6
+ } from "./chunk-4BL24FQA.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-B5H55ZMA.js";
9
+ } from "./chunk-BVOU4UJM.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -110,9 +110,9 @@ var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "gbp", "ads
110
110
  var CANONRY_MCP_TOOLKITS = [
111
111
  {
112
112
  name: "monitoring",
113
- title: "Runs, snapshots, insights, health",
114
- description: "Inspect run history, query snapshots, intelligence insights, and health timelines.",
115
- whenToLoad: "Load when investigating regressions, comparing runs, or reviewing insights and health history."
113
+ title: "Measurement, runs, insights, health",
114
+ description: "Inspect portfolio and Property measurement, question results, run history, intelligence insights, and health timelines.",
115
+ whenToLoad: "Load when finding weak Properties, reviewing answers and competitors, checking data quality, comparing runs, or investigating regressions."
116
116
  },
117
117
  {
118
118
  name: "setup",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "4.146.0",
3
+ "version": "4.147.0",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -41,6 +41,7 @@
41
41
  "dependencies": {
42
42
  "@ainyc/aeo-audit": "4.0.1",
43
43
  "@anthropic-ai/sdk": "^0.91.1",
44
+ "@fastify/rate-limit": "^11.2.0",
44
45
  "@fastify/static": "^9.1.1",
45
46
  "@google/genai": "^1.46.0",
46
47
  "@mariozechner/pi-agent-core": "0.67.6",
@@ -66,23 +67,23 @@
66
67
  "tsup": "^8.5.1",
67
68
  "tsx": "^4.19.0",
68
69
  "@ainyc/canonry-api-client": "0.0.0",
70
+ "@ainyc/canonry-config": "0.0.0",
69
71
  "@ainyc/canonry-api-routes": "0.0.0",
70
- "@ainyc/canonry-contracts": "0.0.0",
71
72
  "@ainyc/canonry-db": "0.0.0",
72
- "@ainyc/canonry-config": "0.0.0",
73
+ "@ainyc/canonry-contracts": "0.0.0",
73
74
  "@ainyc/canonry-integration-bing": "0.0.0",
74
75
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
75
76
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
77
+ "@ainyc/canonry-integration-google": "0.0.0",
76
78
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
77
79
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
78
- "@ainyc/canonry-integration-google": "0.0.0",
80
+ "@ainyc/canonry-integration-google-places": "0.0.0",
79
81
  "@ainyc/canonry-integration-traffic": "0.0.0",
80
82
  "@ainyc/canonry-integration-wordpress": "0.0.0",
81
- "@ainyc/canonry-integration-google-places": "0.0.0",
82
83
  "@ainyc/canonry-intelligence": "0.0.0",
83
- "@ainyc/canonry-provider-gemini": "0.0.0",
84
- "@ainyc/canonry-provider-claude": "0.0.0",
85
84
  "@ainyc/canonry-provider-cdp": "0.0.0",
85
+ "@ainyc/canonry-provider-claude": "0.0.0",
86
+ "@ainyc/canonry-provider-gemini": "0.0.0",
86
87
  "@ainyc/canonry-provider-local": "0.0.0",
87
88
  "@ainyc/canonry-provider-openai": "0.0.0",
88
89
  "@ainyc/canonry-provider-perplexity": "0.0.0"
@@ -1 +0,0 @@
1
- import{C as J,r as P,u as A,D as X,j as e,L as B}from"./vendor-tanstack-BjS7iY3g.js";import{bH as Y,bO as ee,c_ as se,bU as te,bI as ae,B as v,T as E,I as C,c$ as ne,m as U}from"./index-kOXUzdqD.js";import{m as re}from"./v2-overview-adapter-owDeFdUc.js";import{A as ie}from"./arrow-left-BMSx9HQB.js";import"./vendor-radix-DnzzbllM.js";import"./vendor-recharts-33ACLxsD.js";import"./vendor-markdown-CpDJch4G.js";const _=50,o={branded:{headline:"When they know your name",technical:"Branded questions"},"non-brand":{headline:"When they don't",technical:"Non-brand questions"}},oe={plan_v1:"Setup update required",no_completed_run:"No completed measurement yet",no_population:"No questions of this type are assigned",evidence_incomplete:"Source evidence is incomplete",not_applicable:"Not applicable for this Property"},Q={complete:{label:"Measured",tone:"positive"},partial:{label:"Partly measured",tone:"caution"},running:{label:"Measuring now",tone:"neutral"},queued:{label:"Measurement queued",tone:"neutral"},failed:{label:"Measurement failed",tone:"negative"},not_measured:{label:"Not measured",tone:"neutral"}},$={assigned:{label:"Matches this Property",tone:"positive"},sibling:{label:"Matches another Property",tone:"caution"},ownedUnmapped:{label:"Site URL not in a Property",tone:"caution"},external:{label:"External URL",tone:"neutral"},ambiguous:{label:"Matches multiple Properties",tone:"caution"},invalid:{label:"Invalid URL",tone:"negative"}};function F(s){return oe[s.reason]??"Not measured"}function L({metric:s,emphasis:n=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:n?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:F(s)})]});const a=`${Math.round(s.value*100)}%`,d=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`;return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:n?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:a}),d?e.jsx("span",{className:"text-xs text-muted",children:d}):null]})}function V(s,n,a){return ne({client:U,path:{name:s},query:{scope:"property",targetKey:n,queryClass:a}})}function O(s){return s?.properties.items.at(0)}function le({branded:s,nonBrand:n,brandedError:a,nonBrandError:d,onRetry:l}){const c=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:n,isError:d}];return e.jsxs("section",{"aria-labelledby":"property-brand-contrast",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"The gap"}),e.jsxs("h2",{id:"property-brand-contrast",className:"text-base font-semibold text-heading",children:["Named versus not named",e.jsx(C,{text:"Branded questions already contain your name, so an answer engine has an easy path back to you. Non-brand questions describe the need instead, and that is the demand you have to earn. Each row is measured only over the questions assigned to this Property in that class; a class with no assigned question reads Not measured rather than 0%."})]})]})}),e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[560px]",children:[e.jsx("caption",{className:"sr-only",children:"Mention and citation coverage for this Property, split by question class"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Question type"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"})]})}),e.jsx("tbody",{children:c.map(({queryClass:r,row:x,isError:h})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:o[r].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:o[r].technical}),x&&h?e.jsxs("span",{className:"mt-2 flex flex-wrap items-center gap-2 text-sm text-caution",children:[e.jsx("span",{role:"status",children:"Refresh failed."}),e.jsxs(v,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>l(r),children:["Retry ",o[r].technical.toLocaleLowerCase()]})]}):null]}),x?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(L,{metric:x.mentionCoverage,emphasis:!0})}),e.jsx("td",{children:e.jsx(L,{metric:x.citationCoverage,emphasis:!0})})]}):h?e.jsx("td",{colSpan:2,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{role:"alert",children:["Could not load ",o[r].technical.toLocaleLowerCase(),"."]}),e.jsxs(v,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>l(r),children:["Retry ",o[r].technical.toLocaleLowerCase()]})]})}):e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})}),e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})})]})]},r))})]})})]})}function de({row:s,queryClass:n,isError:a}){return e.jsxs("section",{"aria-labelledby":"property-providers",className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"By answer engine"}),e.jsxs("h2",{id:"property-providers",className:"text-base font-semibold text-heading",children:["Which engines answer for this Property",e.jsx(C,{text:"Each row is measured over the questions that engine actually answered for this Property, so the rows are a split of the same population rather than parts that add up to the Property total. An engine that answered nothing for this Property is absent instead of shown at 0%."})]})]})}),s===void 0&&a?e.jsxs("p",{className:"text-sm text-secondary",children:["Details for ",o[n].technical.toLocaleLowerCase()," are unavailable. Retry that question type above."]}):s===void 0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading…"}):s.providers.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No answer engine has measured ",o[n].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${F(s.mentionCoverage)}.`:""]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[520px]",children:[e.jsx("caption",{className:"sr-only",children:"Per-engine mention and citation coverage"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Engine"}),e.jsx("th",{children:"Mentioned"}),e.jsx("th",{children:"Cited"})]})}),e.jsx("tbody",{children:s.providers.map(d=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:d.provider}),e.jsx("td",{children:e.jsx(L,{metric:d.mentionCoverage})}),e.jsx("td",{children:e.jsx(L,{metric:d.citationCoverage})})]},d.provider))})]})})]})}function ce({questions:s,queryClass:n}){return e.jsxs("section",{"aria-labelledby":"property-questions",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Questions"}),e.jsxs("h2",{id:"property-questions",className:"text-base font-semibold text-heading",children:[o[n].technical," assigned to this Property"]})]}),e.jsxs("p",{className:"supporting-copy",children:[s.length," assigned"]})]}),s.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No ",o[n].technical.toLocaleLowerCase()," are assigned. Add one in advanced measurement setup to measure this class."]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Questions assigned to this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"Question"})})}),e.jsx("tbody",{children:s.map(a=>e.jsx("tr",{children:e.jsx("td",{className:"text-secondary",children:a})},a))})]})})]})}function he({urls:s}){return e.jsxs("section",{"aria-labelledby":"property-urls",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Pages"}),e.jsxs("h2",{id:"property-urls",className:"text-base font-semibold text-heading",children:["URLs that count as this Property",e.jsx(C,{text:"A cited source URL is credited to this Property when it matches one of these. The most specific matcher wins, so a URL covered by two Properties at the same specificity is flagged for review instead of being credited to either."})]})]}),e.jsxs("p",{className:"supporting-copy",children:[s.length," configured"]})]}),s.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No URLs are configured for this Property."}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"URL matchers configured for this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"URL"})})}),e.jsx("tbody",{children:s.map(n=>e.jsx("tr",{children:e.jsx("td",{className:"break-all text-secondary",children:n})},n))})]})})]})}function ge(){const{projectName:s,targetKey:n}=J({strict:!1}),[a,d]=P.useState("non-brand"),l=s??"",c=n??"",r=!!l&&!!c,{canWrite:x}=Y(),h=A({...ee({client:U,path:{name:l}}),enabled:r}),p=A({...V(l,c,"branded"),enabled:r}),u=A({...V(l,c,"non-brand"),enabled:r}),S=O(p.data),k=O(u.data),j=a==="branded"?p.data:u.data,g=a==="branded"?S:k,q=(a==="branded"?p.isError:u.isError)&&g===void 0,I=j?.measurement.displayedRunId,f={client:U,path:{name:l},query:{targetKey:c,queryClass:a,limit:_,...I?{runId:I}:{}}},i=X({...se(f),enabled:r&&j!==void 0,initialPageParam:f,getNextPageParam:t=>t.evidence.nextCursor?{path:f.path,query:{...f.query,cursor:t.evidence.nextCursor}}:void 0}),R=h.data?.active??null,y=R?.plan.schemaVersion===2?R.plan:null,z=R!==null&&y===null,N=y?.targets.find(t=>t.stableKey===c)??null,D=P.useMemo(()=>{if(!y)return[];const t=new Map(y.querySnapshots.map(m=>[m.queryId,m.queryText]));return[...new Set(y.assignments.filter(m=>m.targetKey===c&&m.queryClass===a).flatMap(m=>{const w=t.get(m.queryId);return w===void 0?[]:[w]}))].sort((m,w)=>m.localeCompare(w))},[y,c,a]),K=P.useMemo(()=>N?.urlMatchers.map(re)??[],[N]),b=P.useMemo(()=>(i.data?.pages??[]).flatMap(t=>t.evidence.items),[i.data]),T=i.data?.pages[0]?.evidence.totalEstimate??b.length,W=i.data?.pages[0]?.measurement.state,M=e.jsxs(B,{to:"/projects/$projectName",params:{projectName:l},className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(ie,{className:"size-3.5","aria-hidden":"true"}),"Back to measurement overview"]});if(!r)return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Missing project name or Property key in URL."})});if(!te("portfolio",ae()?.projectTabs))return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"This view is not available here."})});if(h.isPending&&!h.isError)return e.jsx("div",{className:"page-container",children:e.jsxs("div",{role:"status","aria-live":"polite",children:[e.jsx("span",{className:"sr-only",children:"Loading Property"}),e.jsx("div",{className:"h-32 animate-pulse rounded-md bg-surface-subtle","aria-hidden":"true"})]})});const G=h.isError&&h.data===void 0,H=p.isError&&p.data===void 0,Z=u.isError&&u.data===void 0;return G||H&&Z?e.jsxs("div",{className:"page-container space-y-3",children:[M,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(v,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{h.refetch(),p.refetch(),u.refetch()},children:"Try again"})]}):!y||!N?e.jsxs("div",{className:"page-container space-y-3",children:[M,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:y?"This Property is not in the published setup. It may have been renamed or removed.":"A Property page needs a published advanced measurement setup. Republish setup from the project Portfolio tab."}),e.jsx(v,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(B,{to:"/projects/$projectName/portfolio",params:{projectName:l},children:x?z?"Republish setup":"Open measurement setup":"View measurement setup"})})]}):e.jsxs("div",{className:"page-container space-y-8",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[M,e.jsx("h1",{className:"page-title mt-2",children:N.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",l]})]}),e.jsxs("div",{className:"page-header-right",children:[j?e.jsx(E,{tone:Q[j.measurement.state].tone,children:Q[j.measurement.state].label}):null,g&&g.flags>0?e.jsxs(E,{tone:"caution",children:[g.flags," flagged"]}):null]})]}),e.jsx(le,{branded:S,nonBrand:k,brandedError:p.isError,nonBrandError:u.isError,onRetry:t=>{t==="branded"?p.refetch():u.refetch()}}),j&&(j.measurement.state==="not_measured"||j.nextAction.kind==="run_measurement")?e.jsxs("section",{className:"flex flex-wrap items-center justify-between gap-3 border-y border-default py-4","aria-label":"Measurement next step",children:[e.jsx("p",{className:"text-sm text-secondary",children:x?"Run a measurement from the project overview to collect this Property’s coverage and source evidence.":"This Property needs a new measurement before coverage and source evidence are available."}),e.jsx(v,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(B,{to:"/projects/$projectName",params:{projectName:l},children:x?"Go to measurement overview":"View measurement overview"})})]}):null,e.jsxs("div",{className:"flex flex-wrap items-end gap-4 border-y border-default py-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{htmlFor:"property-query-class",className:"block text-sm font-medium text-heading",children:"Question type"}),e.jsxs("select",{id:"property-query-class",value:a,onChange:t=>d(t.target.value==="branded"?"branded":"non-brand"),className:"h-11 rounded-md border border-default bg-surface px-3 text-sm text-primary focus:outline-none focus:ring-2 focus:ring-mono-400",children:[e.jsx("option",{value:"non-brand",children:o["non-brand"].technical}),e.jsx("option",{value:"branded",children:o.branded.technical})]})]}),e.jsxs("p",{className:"supporting-copy",children:["Everything below is measured over ",o[a].technical.toLocaleLowerCase()," only."]})]}),e.jsx(de,{row:g,queryClass:a,isError:q}),e.jsx(ce,{questions:D,queryClass:a}),e.jsx(he,{urls:K}),e.jsxs("section",{"aria-labelledby":"property-evidence",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Evidence"}),e.jsxs("h2",{id:"property-evidence",className:"text-base font-semibold text-heading",children:["Source URLs the engines used",e.jsx(C,{text:"Every source URL an answer engine returned for the questions assigned to this Property in the displayed measurement. A row matching this Property is what a citation is counted from; the other classifications are shown so a miss can be explained rather than guessed at."})]})]}),b.length>0?e.jsxs("p",{className:"supporting-copy",children:[b.length," of ",T]}):null]}),q?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",o[a].technical.toLocaleLowerCase()," is unavailable. Retry that question type above."]}):i.isPending&&b.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):i.isError&&b.length===0?e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsx("span",{role:"alert",children:"Evidence could not be loaded."}),e.jsx(v,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{i.refetch()},children:"Retry evidence"})]}):W==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:"Not measured yet. Run a measurement to collect source evidence for this Property."}):b.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No source evidence matched this Property in the displayed measurement."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[720px]",children:[e.jsx("caption",{className:"sr-only",children:"Source evidence for this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Match"}),e.jsx("th",{children:"Question"}),e.jsx("th",{children:"URL"})]})}),e.jsx("tbody",{children:b.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsxs("span",{className:"flex flex-wrap items-center gap-1",children:[e.jsx(E,{tone:$[t.classification].tone,children:$[t.classification].label}),t.historical||t.bridged?e.jsx(E,{tone:"caution",children:"Historical"}):null]})}),e.jsxs("td",{className:"text-secondary",children:[e.jsx("span",{className:"block",children:t.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[t.provider,t.location].filter(Boolean).join(" · ")})]}),e.jsx("td",{className:"break-all text-secondary",children:t.sourceUrl})]},`${t.expectedSlotId}:${t.usageEdgeId}:${t.sourceUrl}`))})]})}),i.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",b.length," of ",T]}),i.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(v,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:i.isFetchingNextPage,onClick:()=>{i.fetchNextPage()},children:i.isFetchingNextPage?"Loading…":i.isFetchNextPageError?"Retry more evidence":`Show ${_} more`})]}):null]})]})]})}export{ge as MeasurementPropertyPage};