@ainyc/canonry 3.6.4 → 4.1.3

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.
@@ -1,8 +1,9 @@
1
1
  import {
2
+ CitationStates,
2
3
  ContentActions,
3
4
  RunKinds,
4
5
  __export
5
- } from "./chunk-O7EVT3AF.js";
6
+ } from "./chunk-O5JZQUPX.js";
6
7
 
7
8
  // src/intelligence-service.ts
8
9
  import { eq, desc, asc, and, or, inArray } from "drizzle-orm";
@@ -40,10 +41,10 @@ __export(schema_exports, {
40
41
  gscUrlInspections: () => gscUrlInspections,
41
42
  healthSnapshots: () => healthSnapshots,
42
43
  insights: () => insights,
43
- keywords: () => keywords,
44
44
  migrationsTable: () => migrationsTable,
45
45
  notifications: () => notifications,
46
46
  projects: () => projects,
47
+ queries: () => queries,
47
48
  querySnapshots: () => querySnapshots,
48
49
  runs: () => runs,
49
50
  schedules: () => schedules,
@@ -69,14 +70,14 @@ var projects = sqliteTable("projects", {
69
70
  createdAt: text("created_at").notNull(),
70
71
  updatedAt: text("updated_at").notNull()
71
72
  });
72
- var keywords = sqliteTable("keywords", {
73
+ var queries = sqliteTable("queries", {
73
74
  id: text("id").primaryKey(),
74
75
  projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
75
- keyword: text("keyword").notNull(),
76
+ query: text("query").notNull(),
76
77
  createdAt: text("created_at").notNull()
77
78
  }, (table) => [
78
- index("idx_keywords_project").on(table.projectId),
79
- uniqueIndex("idx_keywords_project_keyword").on(table.projectId, table.keyword)
79
+ index("idx_queries_project").on(table.projectId),
80
+ uniqueIndex("idx_queries_project_query").on(table.projectId, table.query)
80
81
  ]);
81
82
  var competitors = sqliteTable("competitors", {
82
83
  id: text("id").primaryKey(),
@@ -105,7 +106,7 @@ var runs = sqliteTable("runs", {
105
106
  var querySnapshots = sqliteTable("query_snapshots", {
106
107
  id: text("id").primaryKey(),
107
108
  runId: text("run_id").notNull().references(() => runs.id, { onDelete: "cascade" }),
108
- keywordId: text("keyword_id").notNull().references(() => keywords.id, { onDelete: "cascade" }),
109
+ queryId: text("query_id").notNull().references(() => queries.id, { onDelete: "cascade" }),
109
110
  provider: text("provider").notNull().default("gemini"),
110
111
  model: text("model"),
111
112
  citationState: text("citation_state").notNull(),
@@ -120,7 +121,7 @@ var querySnapshots = sqliteTable("query_snapshots", {
120
121
  createdAt: text("created_at").notNull()
121
122
  }, (table) => [
122
123
  index("idx_snapshots_run").on(table.runId),
123
- index("idx_snapshots_keyword").on(table.keywordId),
124
+ index("idx_snapshots_query").on(table.queryId),
124
125
  index("idx_snapshots_citation_state").on(table.citationState),
125
126
  index("idx_snapshots_provider_model").on(table.provider, table.model),
126
127
  index("idx_snapshots_location").on(table.location),
@@ -428,7 +429,7 @@ var insights = sqliteTable("insights", {
428
429
  type: text("type").notNull(),
429
430
  severity: text("severity").notNull(),
430
431
  title: text("title").notNull(),
431
- keyword: text("keyword").notNull(),
432
+ query: text("query").notNull(),
432
433
  provider: text("provider").notNull(),
433
434
  recommendation: text("recommendation"),
434
435
  cause: text("cause"),
@@ -438,7 +439,7 @@ var insights = sqliteTable("insights", {
438
439
  index("idx_insights_project").on(table.projectId),
439
440
  index("idx_insights_run").on(table.runId),
440
441
  index("idx_insights_created").on(table.createdAt),
441
- index("idx_insights_keyword_provider").on(table.keyword, table.provider)
442
+ index("idx_insights_query_provider").on(table.query, table.provider)
442
443
  ]);
443
444
  var healthSnapshots = sqliteTable("health_snapshots", {
444
445
  id: text("id").primaryKey(),
@@ -580,12 +581,12 @@ CREATE TABLE IF NOT EXISTS projects (
580
581
  updated_at TEXT NOT NULL
581
582
  );
582
583
 
583
- CREATE TABLE IF NOT EXISTS keywords (
584
+ CREATE TABLE IF NOT EXISTS queries (
584
585
  id TEXT PRIMARY KEY,
585
586
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
586
- keyword TEXT NOT NULL,
587
+ query TEXT NOT NULL,
587
588
  created_at TEXT NOT NULL,
588
- UNIQUE(project_id, keyword)
589
+ UNIQUE(project_id, query)
589
590
  );
590
591
 
591
592
  CREATE TABLE IF NOT EXISTS competitors (
@@ -611,7 +612,7 @@ CREATE TABLE IF NOT EXISTS runs (
611
612
  CREATE TABLE IF NOT EXISTS query_snapshots (
612
613
  id TEXT PRIMARY KEY,
613
614
  run_id TEXT NOT NULL REFERENCES runs(id) ON DELETE CASCADE,
614
- keyword_id TEXT NOT NULL REFERENCES keywords(id) ON DELETE CASCADE,
615
+ query_id TEXT NOT NULL REFERENCES queries(id) ON DELETE CASCADE,
615
616
  provider TEXT NOT NULL DEFAULT 'gemini',
616
617
  citation_state TEXT NOT NULL,
617
618
  answer_text TEXT,
@@ -653,12 +654,12 @@ CREATE TABLE IF NOT EXISTS usage_counters (
653
654
  UNIQUE(scope, period, metric)
654
655
  );
655
656
 
656
- CREATE INDEX IF NOT EXISTS idx_keywords_project ON keywords(project_id);
657
+ CREATE INDEX IF NOT EXISTS idx_queries_project ON queries(project_id);
657
658
  CREATE INDEX IF NOT EXISTS idx_competitors_project ON competitors(project_id);
658
659
  CREATE INDEX IF NOT EXISTS idx_runs_project ON runs(project_id);
659
660
  CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(status);
660
661
  CREATE INDEX IF NOT EXISTS idx_snapshots_run ON query_snapshots(run_id);
661
- CREATE INDEX IF NOT EXISTS idx_snapshots_keyword ON query_snapshots(keyword_id);
662
+ CREATE INDEX IF NOT EXISTS idx_snapshots_query ON query_snapshots(query_id);
662
663
  CREATE INDEX IF NOT EXISTS idx_audit_log_project ON audit_log(project_id);
663
664
  CREATE INDEX IF NOT EXISTS idx_audit_log_created ON audit_log(created_at);
664
665
  CREATE TABLE IF NOT EXISTS schedules (
@@ -975,7 +976,7 @@ var MIGRATION_VERSIONS = [
975
976
  version: 19,
976
977
  name: "named-unique-indexes",
977
978
  statements: [
978
- `CREATE UNIQUE INDEX IF NOT EXISTS idx_keywords_project_keyword ON keywords(project_id, keyword)`,
979
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_queries_project_query ON queries(project_id, query)`,
979
980
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_competitors_project_domain ON competitors(project_id, domain)`,
980
981
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_schedules_project ON schedules(project_id)`,
981
982
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_usage_scope_period_metric ON usage_counters(scope, period, metric)`,
@@ -1020,7 +1021,7 @@ var MIGRATION_VERSIONS = [
1020
1021
  type TEXT NOT NULL,
1021
1022
  severity TEXT NOT NULL,
1022
1023
  title TEXT NOT NULL,
1023
- keyword TEXT NOT NULL,
1024
+ query TEXT NOT NULL,
1024
1025
  provider TEXT NOT NULL,
1025
1026
  recommendation TEXT,
1026
1027
  cause TEXT,
@@ -1029,7 +1030,7 @@ var MIGRATION_VERSIONS = [
1029
1030
  )`,
1030
1031
  `CREATE INDEX IF NOT EXISTS idx_insights_project ON insights(project_id)`,
1031
1032
  `CREATE INDEX IF NOT EXISTS idx_insights_created ON insights(created_at)`,
1032
- `CREATE INDEX IF NOT EXISTS idx_insights_keyword_provider ON insights(keyword, provider)`
1033
+ `CREATE INDEX IF NOT EXISTS idx_insights_query_provider ON insights(query, provider)`
1033
1034
  ]
1034
1035
  },
1035
1036
  {
@@ -1373,6 +1374,26 @@ var MIGRATION_VERSIONS = [
1373
1374
  `CREATE INDEX IF NOT EXISTS idx_ga_window_summary_run
1374
1375
  ON ga_traffic_window_summaries(sync_run_id)`
1375
1376
  ]
1377
+ },
1378
+ {
1379
+ version: 48,
1380
+ name: "rename-keywords-to-queries",
1381
+ // The actual legacy rename runs before bootstrap SQL so existing DBs never
1382
+ // see new-name indexes before their old columns have been renamed. This
1383
+ // version records the schema cutover and lands the final index names.
1384
+ statements: [
1385
+ `DROP INDEX IF EXISTS idx_keywords_project`,
1386
+ `DROP INDEX IF EXISTS idx_keywords_project_keyword`,
1387
+ `DROP INDEX IF EXISTS idx_snapshots_keyword`,
1388
+ `DROP INDEX IF EXISTS idx_insights_keyword_provider`,
1389
+ `CREATE INDEX IF NOT EXISTS idx_queries_project ON queries(project_id)`,
1390
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_queries_project_query ON queries(project_id, query)`,
1391
+ `CREATE INDEX IF NOT EXISTS idx_snapshots_query ON query_snapshots(query_id)`,
1392
+ `CREATE INDEX IF NOT EXISTS idx_insights_query_provider ON insights(query, provider)`
1393
+ ],
1394
+ run: (tx) => {
1395
+ normalizeLegacyQuerySchema(tx);
1396
+ }
1376
1397
  }
1377
1398
  ];
1378
1399
  function isDuplicateColumnError(err) {
@@ -1387,6 +1408,44 @@ function columnExists(db, table, column) {
1387
1408
  ));
1388
1409
  return (rows[0]?.c ?? 0) > 0;
1389
1410
  }
1411
+ function tableExists(db, table) {
1412
+ const rows = db.all(sql.raw(
1413
+ `SELECT COUNT(*) as c FROM sqlite_master WHERE type = 'table' AND name = '${table}'`
1414
+ ));
1415
+ return (rows[0]?.c ?? 0) > 0;
1416
+ }
1417
+ function tableIsEmpty(db, table) {
1418
+ const rows = db.all(sql.raw(`SELECT COUNT(*) as c FROM ${table}`));
1419
+ return (rows[0]?.c ?? 0) === 0;
1420
+ }
1421
+ function hasLegacyQuerySchema(db) {
1422
+ return tableExists(db, "keywords") || columnExists(db, "query_snapshots", "keyword_id") || columnExists(db, "insights", "keyword");
1423
+ }
1424
+ function normalizeLegacyQuerySchema(db) {
1425
+ if (!hasLegacyQuerySchema(db)) return;
1426
+ if (tableExists(db, "keywords") && tableExists(db, "queries")) {
1427
+ if (!tableIsEmpty(db, "queries")) {
1428
+ throw new Error("Cannot migrate keywords to queries because both tables contain data");
1429
+ }
1430
+ db.run(sql.raw(`DROP TABLE queries`));
1431
+ }
1432
+ db.run(sql.raw(`DROP INDEX IF EXISTS idx_keywords_project`));
1433
+ db.run(sql.raw(`DROP INDEX IF EXISTS idx_keywords_project_keyword`));
1434
+ db.run(sql.raw(`DROP INDEX IF EXISTS idx_snapshots_keyword`));
1435
+ db.run(sql.raw(`DROP INDEX IF EXISTS idx_insights_keyword_provider`));
1436
+ if (tableExists(db, "keywords")) {
1437
+ db.run(sql.raw(`ALTER TABLE keywords RENAME TO queries`));
1438
+ }
1439
+ if (columnExists(db, "queries", "keyword")) {
1440
+ db.run(sql.raw(`ALTER TABLE queries RENAME COLUMN keyword TO query`));
1441
+ }
1442
+ if (columnExists(db, "query_snapshots", "keyword_id")) {
1443
+ db.run(sql.raw(`ALTER TABLE query_snapshots RENAME COLUMN keyword_id TO query_id`));
1444
+ }
1445
+ if (columnExists(db, "insights", "keyword")) {
1446
+ db.run(sql.raw(`ALTER TABLE insights RENAME COLUMN keyword TO query`));
1447
+ }
1448
+ }
1390
1449
  function dropColumnIfExists(db, table, column) {
1391
1450
  try {
1392
1451
  db.run(sql.raw(`ALTER TABLE ${table} DROP COLUMN ${column}`));
@@ -1466,6 +1525,9 @@ function recordMigration(db, version, name) {
1466
1525
  db.run(sql`INSERT OR IGNORE INTO _migrations (version, name) VALUES (${version}, ${name})`);
1467
1526
  }
1468
1527
  function migrate(db) {
1528
+ db.transaction((tx) => {
1529
+ normalizeLegacyQuerySchema(tx);
1530
+ });
1469
1531
  const statements = MIGRATION_SQL.split(";").map((s) => s.trim()).filter((s) => s.length > 0);
1470
1532
  for (const statement of statements) {
1471
1533
  db.run(sql.raw(statement));
@@ -1482,6 +1544,7 @@ function migrate(db) {
1482
1544
  throw err;
1483
1545
  }
1484
1546
  }
1547
+ mv.run?.(tx);
1485
1548
  recordMigration(tx, mv.version, mv.name);
1486
1549
  });
1487
1550
  }
@@ -1493,18 +1556,18 @@ function detectRegressions(currentRun, previousRun) {
1493
1556
  const previousCited = /* @__PURE__ */ new Map();
1494
1557
  for (const snap of previousRun.snapshots) {
1495
1558
  if (snap.cited) {
1496
- previousCited.set(`${snap.keyword}:${snap.provider}`, {
1559
+ previousCited.set(`${snap.query}:${snap.provider}`, {
1497
1560
  citationUrl: snap.citationUrl,
1498
1561
  position: snap.position
1499
1562
  });
1500
1563
  }
1501
1564
  }
1502
1565
  for (const snap of currentRun.snapshots) {
1503
- const key = `${snap.keyword}:${snap.provider}`;
1566
+ const key = `${snap.query}:${snap.provider}`;
1504
1567
  if (!snap.cited && previousCited.has(key)) {
1505
1568
  const prev = previousCited.get(key);
1506
1569
  regressions.push({
1507
- keyword: snap.keyword,
1570
+ query: snap.query,
1508
1571
  provider: snap.provider,
1509
1572
  previousCitationUrl: prev.citationUrl,
1510
1573
  previousPosition: prev.position,
@@ -1522,14 +1585,14 @@ function detectGains(currentRun, previousRun) {
1522
1585
  const previousCited = /* @__PURE__ */ new Set();
1523
1586
  for (const snap of previousRun.snapshots) {
1524
1587
  if (snap.cited) {
1525
- previousCited.add(`${snap.keyword}:${snap.provider}`);
1588
+ previousCited.add(`${snap.query}:${snap.provider}`);
1526
1589
  }
1527
1590
  }
1528
1591
  for (const snap of currentRun.snapshots) {
1529
- const key = `${snap.keyword}:${snap.provider}`;
1592
+ const key = `${snap.query}:${snap.provider}`;
1530
1593
  if (snap.cited && !previousCited.has(key)) {
1531
1594
  gains.push({
1532
- keyword: snap.keyword,
1595
+ query: snap.query,
1533
1596
  provider: snap.provider,
1534
1597
  citationUrl: snap.citationUrl,
1535
1598
  position: snap.position,
@@ -1588,18 +1651,18 @@ function computeHealthTrend(runs2) {
1588
1651
  // ../intelligence/src/causes.ts
1589
1652
  function analyzeCause(regression, currentSnapshots) {
1590
1653
  const currentSnap = currentSnapshots.find(
1591
- (s) => s.keyword === regression.keyword && s.provider === regression.provider && !s.cited && s.competitorDomain
1654
+ (s) => s.query === regression.query && s.provider === regression.provider && !s.cited && s.competitorDomain
1592
1655
  );
1593
1656
  if (currentSnap) {
1594
1657
  return {
1595
1658
  cause: "competitor_gain",
1596
1659
  competitorDomain: currentSnap.competitorDomain,
1597
- details: `Competitor ${currentSnap.competitorDomain} now cited for "${regression.keyword}" on ${regression.provider}`
1660
+ details: `Competitor ${currentSnap.competitorDomain} now cited for "${regression.query}" on ${regression.provider}`
1598
1661
  };
1599
1662
  }
1600
1663
  return {
1601
1664
  cause: "unknown",
1602
- details: `No specific cause identified for loss of "${regression.keyword}" on ${regression.provider}`
1665
+ details: `No specific cause identified for loss of "${regression.query}" on ${regression.provider}`
1603
1666
  };
1604
1667
  }
1605
1668
 
@@ -1609,14 +1672,14 @@ function generateInsights(regressions, gains, health, causes) {
1609
1672
  const insights2 = [];
1610
1673
  const now = (/* @__PURE__ */ new Date()).toISOString();
1611
1674
  for (const reg of regressions) {
1612
- const key = `${reg.keyword}:${reg.provider}`;
1675
+ const key = `${reg.query}:${reg.provider}`;
1613
1676
  const cause = causes.get(key);
1614
1677
  insights2.push({
1615
1678
  id: `ins_${randomUUID().slice(0, 8)}`,
1616
1679
  type: "regression",
1617
1680
  severity: "high",
1618
- title: `Lost ${reg.provider} citation for "${reg.keyword}"`,
1619
- keyword: reg.keyword,
1681
+ title: `Lost ${reg.provider} citation for "${reg.query}"`,
1682
+ query: reg.query,
1620
1683
  provider: reg.provider,
1621
1684
  recommendation: {
1622
1685
  action: "audit",
@@ -1632,8 +1695,8 @@ function generateInsights(regressions, gains, health, causes) {
1632
1695
  id: `ins_${randomUUID().slice(0, 8)}`,
1633
1696
  type: "gain",
1634
1697
  severity: "low",
1635
- title: `New ${gain.provider} citation for "${gain.keyword}"`,
1636
- keyword: gain.keyword,
1698
+ title: `New ${gain.provider} citation for "${gain.query}"`,
1699
+ query: gain.query,
1637
1700
  provider: gain.provider,
1638
1701
  recommendation: {
1639
1702
  action: "monitor",
@@ -1655,7 +1718,7 @@ function analyzeRuns(currentRun, previousRun, allRuns) {
1655
1718
  const causes = /* @__PURE__ */ new Map();
1656
1719
  for (const reg of regressions) {
1657
1720
  const cause = analyzeCause(reg, currentRun.snapshots);
1658
- causes.set(`${reg.keyword}:${reg.provider}`, cause);
1721
+ causes.set(`${reg.query}:${reg.provider}`, cause);
1659
1722
  }
1660
1723
  const insights2 = generateInsights(regressions, gains, health, causes);
1661
1724
  return {
@@ -2027,7 +2090,7 @@ function classifyRegressionSeverity(signals) {
2027
2090
  }
2028
2091
 
2029
2092
  // ../intelligence/src/insight-grouping.ts
2030
- function groupInsights(insights2, keyFn = (i) => `${i.keyword} ${i.provider} ${i.type}`) {
2093
+ function groupInsights(insights2, keyFn = (i) => `${i.query} ${i.provider} ${i.type}`) {
2031
2094
  const order = [];
2032
2095
  const buckets = /* @__PURE__ */ new Map();
2033
2096
  for (const i of insights2) {
@@ -2254,10 +2317,10 @@ var IntelligenceService = class {
2254
2317
  }
2255
2318
  persistResult(result, runId, projectId) {
2256
2319
  const previouslyDismissed = /* @__PURE__ */ new Set();
2257
- const existingInsights = this.db.select({ keyword: insights.keyword, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(eq(insights.runId, runId)).all();
2320
+ const existingInsights = this.db.select({ query: insights.query, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(eq(insights.runId, runId)).all();
2258
2321
  for (const row of existingInsights) {
2259
2322
  if (row.dismissed) {
2260
- previouslyDismissed.add(`${row.keyword}:${row.provider}:${row.type}`);
2323
+ previouslyDismissed.add(`${row.query}:${row.provider}:${row.type}`);
2261
2324
  }
2262
2325
  }
2263
2326
  this.db.transaction((tx) => {
@@ -2265,7 +2328,7 @@ var IntelligenceService = class {
2265
2328
  tx.delete(healthSnapshots).where(eq(healthSnapshots.runId, runId)).run();
2266
2329
  const now = (/* @__PURE__ */ new Date()).toISOString();
2267
2330
  for (const insight of result.insights) {
2268
- const wasDismissed = previouslyDismissed.has(`${insight.keyword}:${insight.provider}:${insight.type}`);
2331
+ const wasDismissed = previouslyDismissed.has(`${insight.query}:${insight.provider}:${insight.type}`);
2269
2332
  tx.insert(insights).values({
2270
2333
  id: insight.id,
2271
2334
  projectId,
@@ -2273,7 +2336,7 @@ var IntelligenceService = class {
2273
2336
  type: insight.type,
2274
2337
  severity: insight.severity,
2275
2338
  title: insight.title,
2276
- keyword: insight.keyword,
2339
+ query: insight.query,
2277
2340
  provider: insight.provider,
2278
2341
  recommendation: insight.recommendation ? JSON.stringify(insight.recommendation) : null,
2279
2342
  cause: insight.cause ? JSON.stringify(insight.cause) : null,
@@ -2315,10 +2378,10 @@ var IntelligenceService = class {
2315
2378
  if (regressions.length === 0) return rawInsights;
2316
2379
  const gscRows = this.db.select({ query: gscSearchData.query, impressions: gscSearchData.impressions }).from(gscSearchData).where(eq(gscSearchData.projectId, projectId)).all();
2317
2380
  const gscConnected = gscRows.length > 0;
2318
- const gscImpressionsByKeyword = /* @__PURE__ */ new Map();
2381
+ const gscImpressionsByQuery = /* @__PURE__ */ new Map();
2319
2382
  for (const row of gscRows) {
2320
2383
  const key = row.query.toLowerCase();
2321
- gscImpressionsByKeyword.set(key, (gscImpressionsByKeyword.get(key) ?? 0) + row.impressions);
2384
+ gscImpressionsByQuery.set(key, (gscImpressionsByQuery.get(key) ?? 0) + row.impressions);
2322
2385
  }
2323
2386
  const recentRunIds = this.db.select({ id: runs.id }).from(runs).where(
2324
2387
  and(
@@ -2330,16 +2393,16 @@ var IntelligenceService = class {
2330
2393
  const haveHistory = recentRunIds.length > 0;
2331
2394
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
2332
2395
  if (haveHistory) {
2333
- const priorRows = this.db.select({ keyword: insights.keyword, provider: insights.provider }).from(insights).where(and(eq(insights.type, "regression"), inArray(insights.runId, recentRunIds))).all();
2396
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider }).from(insights).where(and(eq(insights.type, "regression"), inArray(insights.runId, recentRunIds))).all();
2334
2397
  for (const row of priorRows) {
2335
- const key = `${row.keyword}:${row.provider}`;
2398
+ const key = `${row.query}:${row.provider}`;
2336
2399
  priorRegressionsByPair.set(key, (priorRegressionsByPair.get(key) ?? 0) + 1);
2337
2400
  }
2338
2401
  }
2339
2402
  return rawInsights.map((insight) => {
2340
2403
  if (insight.type !== "regression") return insight;
2341
- const gscImpressions = gscConnected ? gscImpressionsByKeyword.get(insight.keyword.toLowerCase()) ?? 0 : void 0;
2342
- const recurrenceCount = haveHistory ? priorRegressionsByPair.get(`${insight.keyword}:${insight.provider}`) ?? 0 : void 0;
2404
+ const gscImpressions = gscConnected ? gscImpressionsByQuery.get(insight.query.toLowerCase()) ?? 0 : void 0;
2405
+ const recurrenceCount = haveHistory ? priorRegressionsByPair.get(`${insight.query}:${insight.provider}`) ?? 0 : void 0;
2343
2406
  const severity = classifyRegressionSeverity({
2344
2407
  gscImpressions,
2345
2408
  recurrenceCount
@@ -2349,19 +2412,19 @@ var IntelligenceService = class {
2349
2412
  }
2350
2413
  buildRunData(runId, projectId, completedAt) {
2351
2414
  const rows = this.db.select({
2352
- keyword: keywords.keyword,
2415
+ query: queries.query,
2353
2416
  provider: querySnapshots.provider,
2354
2417
  citationState: querySnapshots.citationState,
2355
2418
  citedDomains: querySnapshots.citedDomains,
2356
2419
  competitorOverlap: querySnapshots.competitorOverlap
2357
- }).from(querySnapshots).leftJoin(keywords, eq(querySnapshots.keywordId, keywords.id)).where(eq(querySnapshots.runId, runId)).all();
2420
+ }).from(querySnapshots).leftJoin(queries, eq(querySnapshots.queryId, queries.id)).where(eq(querySnapshots.runId, runId)).all();
2358
2421
  const snapshots = rows.map((r) => {
2359
2422
  const domains = parseJsonColumn(r.citedDomains, []);
2360
2423
  const competitors2 = parseJsonColumn(r.competitorOverlap, []);
2361
2424
  return {
2362
- keyword: r.keyword ?? "",
2425
+ query: r.query ?? "",
2363
2426
  provider: r.provider,
2364
- cited: r.citationState === "cited",
2427
+ cited: r.citationState === CitationStates.cited,
2365
2428
  citationUrl: domains[0] ?? void 0,
2366
2429
  competitorDomain: competitors2[0] ?? void 0
2367
2430
  };
@@ -2372,7 +2435,7 @@ var IntelligenceService = class {
2372
2435
 
2373
2436
  export {
2374
2437
  projects,
2375
- keywords,
2438
+ queries,
2376
2439
  competitors,
2377
2440
  runs,
2378
2441
  querySnapshots,