@ainyc/canonry 4.82.0 → 4.84.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.
- package/assets/agent-workspace/skills/aero/SKILL.md +14 -10
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +7 -5
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +1 -1
- package/assets/agent-workspace/skills/aero/references/orchestration.md +22 -20
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +9 -9
- package/assets/agent-workspace/skills/aero/references/reporting.md +14 -9
- package/assets/agent-workspace/skills/aero/soul.md +5 -5
- package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +84 -36
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +25 -10
- package/assets/assets/{BacklinksPage-CHclt-pq.js → BacklinksPage-OrSg_iPA.js} +1 -1
- package/assets/assets/{ChartPrimitives-2Ub4vNWe.js → ChartPrimitives-DPBhAT_r.js} +1 -1
- package/assets/assets/{ProjectPage-UPmHfuxR.js → ProjectPage-CpMcEmtw.js} +1 -1
- package/assets/assets/{RunRow-rUL1UeA3.js → RunRow-2Rty0BAH.js} +1 -1
- package/assets/assets/{RunsPage-BQpHfUJf.js → RunsPage-B3ahqf8s.js} +1 -1
- package/assets/assets/{SettingsPage-DjTJlr_1.js → SettingsPage-BIjeI85q.js} +1 -1
- package/assets/assets/{TrafficPage-D7rv3BrH.js → TrafficPage-DjGoj691.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BysyuH2H.js → TrafficSourceDetailPage-BgKG-2q3.js} +1 -1
- package/assets/assets/{arrow-left-CR_FGlkE.js → arrow-left-Cf7wmru1.js} +1 -1
- package/assets/assets/{extract-error-message-BKkAbWNp.js → extract-error-message-CANxezte.js} +1 -1
- package/assets/assets/{index-DzzTt20n.js → index-CGlPx_cu.js} +3 -3
- package/assets/assets/{trash-2-uSttujvh.js → trash-2-6nHJZrvy.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-KPSFRSS7.js → chunk-BNF3HXBW.js} +5 -0
- package/dist/{chunk-NSZ3D3MM.js → chunk-M3IYKTSF.js} +17 -4
- package/dist/{chunk-IEUTAQUF.js → chunk-VJBO4VIK.js} +108 -5
- package/dist/{chunk-JLAD6CYH.js → chunk-Y3O3HBMN.js} +1 -1
- package/dist/cli.js +22 -16
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-2UUJ3YGI.js → intelligence-service-PDIAMP5I.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
|
@@ -16,25 +16,29 @@ Persist only *user-scoped* context (operator preferences, communication style) i
|
|
|
16
16
|
|
|
17
17
|
**Two signals, not one.** Every (query × provider) snapshot tracks **mentioned** (brand in answer text) and **cited** (domain in source links) independently. Lead with **Mention Coverage** when narrating health — it is the primary gauge — and report **Citation Coverage** as the secondary signal. Never compute one from the other, and never collapse them into a single "visibility" headline. The downloadable report (`cnry report`) and the dashboard hero both honor this split.
|
|
18
18
|
|
|
19
|
-
When a project has GA4 connected, traffic is a first-class signal alongside citations. Use `cnry ga traffic` / `cnry ga attribution --trend` for the current snapshot, `cnry ga ai-referral-history` and `cnry ga social-referral-history` for daily series. Reads query a local DB synced by `cnry ga sync` — confirm `cnry ga status` shows a recent `lastSyncedAt` before quoting numbers; if stale, re-sync first. When the project has a server-side traffic source attached (Cloud Run / WordPress / Vercel), `cnry traffic status` and `cnry traffic events` surface crawler + AI-referral evidence the GA4 layer can miss. Full command reference and return shapes live in the co-installed `canonry/references/canonry-cli.md`.
|
|
19
|
+
When a project has GA4 connected, traffic is a first-class signal alongside mentions and citations. Use `cnry ga traffic` / `cnry ga attribution --trend` for the current snapshot, `cnry ga ai-referral-history` and `cnry ga social-referral-history` for daily series. Reads query a local DB synced by `cnry ga sync` — confirm `cnry ga status` shows a recent `lastSyncedAt` before quoting numbers; if stale, re-sync first. When the project has a server-side traffic source attached (Cloud Run / WordPress / Vercel), `cnry traffic status` and `cnry traffic events` surface crawler + AI-referral evidence the GA4 layer can miss. Full command reference and return shapes live in the co-installed `canonry/references/canonry-cli.md`.
|
|
20
20
|
|
|
21
21
|
**Diagnosing a stuck Vercel/Cloud Run source:** if `cnry traffic status` shows `status=error` with a recent `lastError` of `refusing to advance` or `ExceedsBillingLimitError`, the source's `lastSyncedAt` has aged past the upstream retention boundary and every sync now throws. Recovery: `cnry traffic reset <project> --source <id> --advance-to-now`. This advances `lastSyncedAt` to NOW and resumes going-forward syncs — historical events in the gap are unrecoverable from the sync path; run `cnry traffic backfill --days N` separately if any of that history is needed (capped at retention).
|
|
22
22
|
|
|
23
23
|
## Judgment Rules
|
|
24
24
|
|
|
25
25
|
### What to Prioritize
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
|
|
27
|
+
Mention is the primary gauge (see "Two signals, not one" above); citation is the secondary signal on the same query. Rank work accordingly:
|
|
28
|
+
|
|
29
|
+
1. **Branded-term mention loss** — the engine no longer MENTIONING your brand by name is the most urgent regression. Losing the citation for your own name is the secondary signal on the same query: report it, but the mention is what moved share.
|
|
30
|
+
2. **Mention-share losses** — a competitor took mention share on a query where yours fell. Rank by share swing first, then by any lost citation on the same query.
|
|
31
|
+
3. **Neither mentioned nor cited** — new queries where you are absent on both signals (not mentioned and not cited). Mention gap leads; the missing citation is the trailing clause.
|
|
32
|
+
4. **Indexing issues** — pages not indexed can't be cited, and a weak/unindexed page also starves the engine of reasons to mention you. Keep this on the list; it feeds both signals.
|
|
33
|
+
5. **Content optimization** — improve mention rate first (give the answer a reason to name you), then cited rate on partially-covered queries.
|
|
31
34
|
|
|
32
35
|
### What NOT to Do
|
|
33
36
|
- Don't promise fixes will appear in the next sweep (AEO changes take weeks/months)
|
|
34
|
-
- Don't give generic SEO advice — always ground recommendations in citation data
|
|
37
|
+
- Don't give generic SEO advice — always ground recommendations in mention and citation data, leading with the mention signal
|
|
35
38
|
- Don't run sweeps without user confirmation (they consume API quota)
|
|
36
39
|
- Don't edit client's code without showing diffs and getting approval
|
|
37
|
-
- Don't conflate "not
|
|
40
|
+
- Don't conflate "not mentioned" with "page doesn't exist" — and don't conflate "not cited" with "not mentioned" either; check first. The two signals are independent (see "Two signals, not one") and are never computed from each other.
|
|
41
|
+
- Don't coerce `answerMentioned` null → false. Null means "not checked," not "not mentioned" — treat it as missing data, never as a negative.
|
|
38
42
|
|
|
39
43
|
### When to use `--probe` runs
|
|
40
44
|
When you need to **verify** something on your own initiative — "did the OpenAI provider migration land cleanly?", "is the regression still reproducible after the WP fix?", "does this query actually surface us when I think it should?" — use `cnry run <project> --probe --provider <p> --query "..."`. Probe runs:
|
|
@@ -49,7 +53,7 @@ A real (non-probe) sweep is appropriate when the user explicitly asks to refresh
|
|
|
49
53
|
|
|
50
54
|
### How to Communicate
|
|
51
55
|
- Data first: show the numbers before the interpretation
|
|
52
|
-
-
|
|
56
|
+
- Lead with the mention transition, keep citation as a trailing clause: "ChatGPT stopped mentioning you for 'roof repair phoenix' between Mar 28-Apr 2, and your mention share fell from 50% to 0% as a competitor took the slot" — then, second, note that you also lost the citation for that query. Not "your visibility decreased."
|
|
53
57
|
- Action-oriented: every observation ends with a recommended next step
|
|
54
58
|
|
|
55
59
|
## References
|
|
@@ -59,7 +63,7 @@ Detailed playbooks live alongside this file. Read them on demand when the task m
|
|
|
59
63
|
| File | Read when |
|
|
60
64
|
|---|---|
|
|
61
65
|
| `references/orchestration.md` | Planning a multi-step or recurring workflow (baseline, weekly review, content-gap analysis) |
|
|
62
|
-
| `references/regression-playbook.md` | A query lost
|
|
66
|
+
| `references/regression-playbook.md` | A query lost a mention (primary) or a citation (secondary) and you need to triage and respond |
|
|
63
67
|
| `references/aeo-discovery.md` | Expanding a tracked-query basket, auditing competitive surface, or responding to `aeo-discover-probe.completed` |
|
|
64
68
|
| `references/memory-patterns.md` | Deciding whether to remember a fact in agent memory or re-query canonry |
|
|
65
69
|
| `references/reporting.md` | Producing a client-facing weekly or monthly summary |
|
|
@@ -5,13 +5,15 @@ description: How to operate the tracked-basket discovery pipeline. Read when an
|
|
|
5
5
|
|
|
6
6
|
# AEO Discovery (Tracked-Basket Expansion)
|
|
7
7
|
|
|
8
|
-
Discovery turns a free-text ICP description into a deduped basket of representative queries, probes each against Gemini grounding, and classifies the results into three buckets:
|
|
8
|
+
Discovery turns a free-text ICP description into a deduped basket of representative queries, probes each against Gemini grounding, and classifies the results into three buckets. Read each bucket as **mention-or-citation** presence — the brand named in the answer text (`answerMentioned`, the primary signal) OR the domain in the grounding sources (`cited`, the secondary signal) — not citation alone:
|
|
9
9
|
|
|
10
|
-
- **cited** — the project
|
|
11
|
-
- **wasted-surface** — a tracked competitor
|
|
12
|
-
- **aspirational** — neither the project nor a tracked competitor
|
|
10
|
+
- **cited** — the project shows up for the query: its brand is mentioned in the answer text, or its canonical/owned domain appears in the grounding sources (mention-or-citation present)
|
|
11
|
+
- **wasted-surface** — a tracked competitor shows up (mentioned or cited) but the project does not
|
|
12
|
+
- **aspirational** — neither the project nor a tracked competitor shows up on either signal (greenfield)
|
|
13
13
|
|
|
14
|
-
Plus a competitor map: every non-canonical domain that shows up
|
|
14
|
+
Plus a competitor map: every non-canonical domain (and named competitor brand) that shows up across probes, ranked by hit count and classified by type, so the operator can spot recurring competitors that aren't yet on the watchlist. Read the headline competitor signal as mention-or-citation, not citation alone — a competitor the engine keeps NAMING is taking your share of voice even when no domain is cited.
|
|
15
|
+
|
|
16
|
+
> **Mention data on probes (engine PR #707, merged 2026-06-17).** Discovery probes now carry `answerMentioned` per probe, so mention-based bucketing and competitor reads are available. Sessions that pre-date #707 have `answerMentioned = null` on their probes — read null as "not checked," never as not-mentioned, and fall back to the cited signal for those older sessions.
|
|
15
17
|
|
|
16
18
|
After probing, one Gemini call classifies every recurring cited domain into a `competitorType`:
|
|
17
19
|
|
|
@@ -13,7 +13,7 @@ Aero ships with a built-in durable notes store — the `canonry_memory_set`, `ca
|
|
|
13
13
|
|
|
14
14
|
| Scope | Examples | Home |
|
|
15
15
|
|---|---|---|
|
|
16
|
-
| **Project state** | Baselines, historical regressions, citation rates per query/provider, recent insights, sweep history, audit trail | Canonry DB — query via CLI / API / read tools |
|
|
16
|
+
| **Project state** | Baselines (**mention rate + mention share** as the primary KPI, then cited rate), historical regressions, mention + citation rates per query/provider, recent insights, sweep history, audit trail | Canonry DB — query via CLI / API / read tools |
|
|
17
17
|
| **Operator facts** | Personal preferences, non-observable context ("content lead is Sarah", "migrating off Webflow next quarter"), tone/voice preferences the operator confirmed | Aero memory (`canonry_memory_set`) |
|
|
18
18
|
| **Session scratch** | "I just tried X and it failed", intermediate reasoning, turn-local state | Nowhere — let it die with the session |
|
|
19
19
|
|
|
@@ -5,32 +5,34 @@ description: Workflow recipes — baseline, regression response, weekly review,
|
|
|
5
5
|
|
|
6
6
|
# Orchestration Workflows
|
|
7
7
|
|
|
8
|
+
**Read the mention signal first in every workflow.** Compute and compare **mention rate + mention share** before cited rate. The fast mention read is `cnry overview <project> --format json` (returns `queryCounts.mentionRate`, `scores.mention`, `scores.mentionShare`) plus `cnry analytics <project> --feature gaps --format json` (returns `mentionedQueries[]`, `mentionGap[]`, `notMentioned[]` alongside the cited buckets). Use `cnry evidence <project>` for the per-query drilldown — it prints the two-glyph `[C/c][M/m]` cell per (query × provider) and a `Mentioned: X / Y` line next to `Cited: X / Y`. Mention and citation are independent — never derive one from the other. Treat `answerMentioned = null` as "not checked," never as not-mentioned.
|
|
9
|
+
|
|
8
10
|
## Workflow 1: New Client Baseline
|
|
9
11
|
|
|
10
12
|
Trigger: First sweep completes for a new project
|
|
11
13
|
|
|
12
14
|
Steps:
|
|
13
|
-
1. `cnry
|
|
14
|
-
2. Compute baseline:
|
|
15
|
+
1. `cnry overview <project> --format json` → mention read first: `queryCounts.mentionRate`, `scores.mention`, `scores.mentionShare`. Then `cnry analytics <project> --feature gaps --format json` for `mentionedQueries[]` / `mentionGap[]` / `notMentioned[]`, and `cnry evidence <project> --format json` for the per-query `[C/c][M/m]` drilldown and the secondary cited data.
|
|
16
|
+
2. Compute baseline in this order: **mention rate, mention share**, then cited rate; provider breakdown; top/bottom queries by mention.
|
|
15
17
|
3. `cnry technical-aeo run <project> --wait`, then `cnry technical-aeo score <project> --format json` → site readiness score across every page in the sitemap (auto-discovered; add `--limit <n>` to `run` to cap, default 500). Persists to the dashboard and is trendable via `cnry technical-aeo trend <project>`.
|
|
16
|
-
4. Identify top 3 gaps (
|
|
18
|
+
4. Identify top 3 gaps — lead with `mentionGap[]` / `notMentioned[]` (where competitors are named and you aren't), then the cited gaps with fixable site issues.
|
|
17
19
|
5. Generate onboarding report with baseline + action plan
|
|
18
|
-
6. Store baseline metrics in memory
|
|
20
|
+
6. Store baseline metrics in memory (include mention rate + mention share, not just cited rate)
|
|
19
21
|
|
|
20
22
|
## Workflow 2: Regression Response
|
|
21
23
|
|
|
22
24
|
Trigger: Comparison shows decline or webhook fires regression.detected
|
|
23
25
|
|
|
24
26
|
Steps:
|
|
25
|
-
1. `cnry
|
|
27
|
+
1. `cnry overview <project> --format json` → current state, mention first: did `scores.mention` / `scores.mentionShare` move? Then `cnry analytics <project> --feature gaps --format json` (`mentionGap[]` / `notMentioned[]`) and `cnry evidence <project> --format json` for the per-query `[C/c][M/m]` drilldown (which signal actually dropped on which provider).
|
|
26
28
|
2. `cnry history <project>` → trend for affected query
|
|
27
|
-
3. Check
|
|
28
|
-
4. Check
|
|
29
|
+
3. Check competitor mention share BEFORE cited displacement: did a competitor take the **mention** share you lost (`mentionGap[]`)? Only then ask whether a competitor gained the **citation** you lost.
|
|
30
|
+
4. Check indexing: `cnry google coverage <project>` → is the page still indexed? (a deindexed/thin page starves both signals)
|
|
29
31
|
5. Audit the page: `npx @ainyc/aeo-audit "<page-url>" --format json`
|
|
30
|
-
6. Diagnose cause: indexing issue / content issue / competitive displacement
|
|
31
|
-
7. Recommend fix with evidence
|
|
32
|
+
6. Diagnose cause: indexing issue / content issue / competitive displacement (mention-share loss first, citation loss second)
|
|
33
|
+
7. Recommend fix with evidence — lead with what restores the mention
|
|
32
34
|
8. If content fix: generate diff (schema, llms.txt, or content changes)
|
|
33
|
-
9. Update memory with regression event + diagnosis
|
|
35
|
+
9. Update memory with regression event + diagnosis (record which signal regressed: mention, citation, or both)
|
|
34
36
|
|
|
35
37
|
**Want to verify the regression is real / reproducible before reporting?** Use a probe run instead of a real sweep:
|
|
36
38
|
|
|
@@ -45,21 +47,21 @@ Then `cnry runs get <id>` to inspect the snapshot. The probe's snapshot won't di
|
|
|
45
47
|
Trigger: Scheduled (weekly, or on-demand)
|
|
46
48
|
|
|
47
49
|
Steps:
|
|
48
|
-
1. `cnry
|
|
49
|
-
2. Compare to baseline/prior week from memory
|
|
50
|
-
3. Compute deltas:
|
|
51
|
-
4. Flag any new regressions not yet addressed
|
|
52
|
-
5. Check competitor movement
|
|
50
|
+
1. `cnry overview <project> --format json` → current metrics, mention first (`queryCounts.mentionRate`, `scores.mention`, `scores.mentionShare`); `cnry analytics <project> --feature gaps --format json` for the mention gaps; `cnry evidence <project> --format json` for the per-query `[C/c][M/m]` drilldown
|
|
51
|
+
2. Compare to baseline/prior week from memory — mention rate + mention share first, cited rate second
|
|
52
|
+
3. Compute deltas: mentions gained/lost/stable (primary), then citations gained/lost/stable (secondary)
|
|
53
|
+
4. Flag any new regressions not yet addressed (lead with lost mentions)
|
|
54
|
+
5. Check competitor movement — mention share swing first, then cited-domain displacement
|
|
53
55
|
6. Generate summary with key changes + recommended next steps
|
|
54
56
|
|
|
55
57
|
## Workflow 4: Content Gap Analysis
|
|
56
58
|
|
|
57
|
-
Trigger: User asks "why aren't we cited for X?" or multiple uncited queries detected
|
|
59
|
+
Trigger: User asks "why aren't we mentioned/cited for X?" or multiple not-mentioned / uncited queries detected
|
|
58
60
|
|
|
59
61
|
Steps:
|
|
60
|
-
1. `cnry
|
|
62
|
+
1. `cnry overview <project> --format json` + `cnry analytics <project> --feature gaps --format json` → confirm the gap, mention first: is the query in `notMentioned[]` (not named at all) or `mentionGap[]` (a competitor is named, you aren't)? Then `cnry evidence <project>` for the per-query `[C/c][M/m]` cell to see whether you also lack the citation. Mention gap leads the diagnosis; the missing citation is the secondary lens.
|
|
61
63
|
2. Check if a relevant page exists on the domain
|
|
62
|
-
3. If no page: recommend content creation (topic, target queries)
|
|
63
|
-
4. If page exists: `npx @ainyc/aeo-audit "<page-url>"` → diagnose why
|
|
64
|
+
3. If no page: recommend content creation (topic, target queries) — give the engine a reason to name you
|
|
65
|
+
4. If page exists: `npx @ainyc/aeo-audit "<page-url>"` → diagnose why neither mentioned nor cited
|
|
64
66
|
5. Check schema completeness, llms.txt coverage, indexing status
|
|
65
|
-
6. Generate prioritized fix list
|
|
67
|
+
6. Generate prioritized fix list — fixes that earn the mention first, then the citation
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: regression-playbook
|
|
3
|
-
description: Detection → triage → diagnosis → response for lost citations. Read when investigating why a query lost
|
|
3
|
+
description: Detection → triage → diagnosis → response for lost mentions (primary) and lost citations (secondary). Read when investigating why a query lost a mention or a citation.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Regression Playbook
|
|
7
7
|
|
|
8
8
|
## Detection
|
|
9
9
|
|
|
10
|
-
A regression is
|
|
10
|
+
A regression is, primarily, a **lost mention**: a query+provider pair whose answer text named the brand (`answerMentioned = true`) in run N no longer does in run N+1. A **lost citation** (the domain dropped from the grounding sources between the same two runs) is the secondary regression on the same query. The two signals are independent — a query can lose its mention while keeping its citation, or vice versa — so detect and report them separately; never infer one from the other. Treat `answerMentioned = null` as "not checked," not as a lost mention.
|
|
11
11
|
|
|
12
12
|
## Triage
|
|
13
13
|
|
|
14
|
-
Classify the regression by severity
|
|
14
|
+
Classify the regression by severity. Mention loss leads; mention-share loss to a competitor is next; a citation loss is a lower, secondary tier on the same query.
|
|
15
15
|
|
|
16
16
|
| Severity | Criteria |
|
|
17
17
|
|---|---|
|
|
18
|
-
| **Critical** |
|
|
19
|
-
| **High** |
|
|
20
|
-
| **Medium** | Non-branded query lost on one provider |
|
|
21
|
-
| **Low** | Query lost
|
|
18
|
+
| **Critical** | Lost a branded-term MENTION on any provider (the engine stopped naming you for your own brand) |
|
|
19
|
+
| **High** | Mention-share loss — a competitor took mention share on a top query where yours fell; or a top-performing query lost its mention on the primary provider |
|
|
20
|
+
| **Medium** | Non-branded query lost its mention on one provider; or a top query lost its CITATION (secondary signal) while the mention held |
|
|
21
|
+
| **Low** | Query lost a mention or citation it only held marginally |
|
|
22
22
|
|
|
23
23
|
## Diagnosis
|
|
24
24
|
|
|
25
25
|
For each regression, check causes in order:
|
|
26
26
|
|
|
27
|
-
1. **Competitor displacement** —
|
|
28
|
-
2. **Indexing loss** — Is the page still indexed? Check Google Search Console integration or HTTP status.
|
|
27
|
+
1. **Competitor displacement** — Check mention share BEFORE cited-domain displacement. First: did a competitor brand take the mention share you lost? Compare `scores.mentionShare` (`cnry overview`) run-over-run and read `cnry analytics <project> --feature gaps` (`mentionGap[]` = competitor mentioned where you're not) to see who is being named instead of you. Only then check the citation side: did a competitor domain appear in the grounding sources for this query+provider? Check current run snapshots. For the whole cited picture, `cnry sources <project> --rank` (MCP: `canonry_analytics_sources`) ranks every cited domain and tags each with a surface class (own / direct-competitor / ota-aggregator / editorial-media / other), and `--by-provider` shows which engine grounds on whom — so you can tell a rival you must out-rank from an aggregator/editorial surface you should pitch for placement.
|
|
28
|
+
2. **Indexing loss** — Is the page still indexed? Check Google Search Console integration or HTTP status. An unindexed or thin page starves the engine of reasons to mention you as well as to cite you.
|
|
29
29
|
3. **Content change** — Did the page content change significantly? Compare content hashes if available.
|
|
30
30
|
4. **Provider behavior change** — Did the provider change its response pattern for this query type?
|
|
31
31
|
5. **Unknown** — No clear cause identified. Flag for manual investigation.
|
|
@@ -15,10 +15,11 @@ cnry report <project> --output dist/aeo.html # custom path
|
|
|
15
15
|
cnry report <project> --format json # raw payload, useful for narrating in chat
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
The HTML is self-contained (inline CSS + SVG charts, no network dependencies) and covers: executive summary, per-query × per-provider citation
|
|
18
|
+
The HTML is self-contained (inline CSS + SVG charts, no network dependencies) and leads visually with mention coverage (the primary gauge), then covers: executive summary, per-query × per-provider matrix (mention + citation), competitor landscape, AI citation sources, GSC + GA4 performance, social and AI referrals, indexing health, trend, prioritized insights, and recommended next steps. Same payload is available via `GET /api/v1/projects/<name>/report` and the `canonry_report` MCP tool — use `--format json` when you want to summarize specific numbers in a thread instead of attaching the file.
|
|
19
19
|
|
|
20
20
|
Behaviors worth knowing before narrating numbers from the report:
|
|
21
|
-
- `executiveSummary.
|
|
21
|
+
- **Mention is the primary metric; citation is secondary.** Narrate the mention figures first. `executiveSummary.mentionRate` is **per-query** — `mentionedQueryCount / totalQueryCount`, where a query counts as mentioned if any provider's answer text named the brand in the run. The report leads visually with mention coverage, but the machine field backing that headline is not confirmed in the CLI docs — [confirm field name against `cnry report --format json` / `ProjectReportDto`] before quoting it as the headline; `executiveSummary.mentionRate` / `mentionedQueryCount` are the confirmed per-query mention fields.
|
|
22
|
+
- `executiveSummary.citationRate` is the **secondary**, per-query citation signal — `citedQueryCount / totalQueryCount`, where a query counts as cited if any provider in the run cited it. The denominator is total tracked queries (not (query × provider) pairs), so the rate stays comparable when provider count varies between runs. Use `citedQueryCount` / `totalQueryCount` directly when narrating ratios. Mention and citation are independent — never compute one from the other.
|
|
22
23
|
- The same per-query definition powers every `citationsTrend[].citationRate` so trend deltas reflect real movement, not provider-mix variance.
|
|
23
24
|
- `citationsTrend` excludes partial runs. A project with only one completed run shows `trend: "unknown"` — never claim a comparison that isn't there.
|
|
24
25
|
- Project ownership and competitor tagging use subdomain-aware matching: `blog.example.com` counts as the project when `example.com` is the canonical domain or in `ownedDomains`; `blog.rival.com` is tagged `isCompetitor: true` when `rival.com` is tracked.
|
|
@@ -32,9 +33,11 @@ The hand-rolled templates below are still the right call when the user wants a f
|
|
|
32
33
|
# Weekly AEO Report: <project> (<date range>)
|
|
33
34
|
|
|
34
35
|
## Summary
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
36
|
+
- Mention rate: <X>% (Δ<+/-Y>% from last week) ← primary KPI
|
|
37
|
+
- Mention share: <X>% (Δ<+/-Y>% from last week) ← AI share-of-voice vs competitors
|
|
38
|
+
- Cited rate: <X>% (Δ<+/-Y>% from last week) ← secondary signal
|
|
39
|
+
- Regressions: <N> new, <N> resolved (lead with lost mentions; note lost citations second)
|
|
40
|
+
- Gains: <N> new mentions / <N> new citations
|
|
38
41
|
- Providers monitored: <N>
|
|
39
42
|
|
|
40
43
|
## Key Changes
|
|
@@ -72,14 +75,16 @@ The hand-rolled templates below are still the right call when the user wants a f
|
|
|
72
75
|
## Metrics
|
|
73
76
|
| Metric | Start of Month | End of Month | Change |
|
|
74
77
|
|--------|---------------|--------------|--------|
|
|
75
|
-
|
|
|
78
|
+
| Mention rate (primary) | <X>% | <Y>% | <Δ>% |
|
|
79
|
+
| Mention share (primary) | <X>% | <Y>% | <Δ>% |
|
|
80
|
+
| Cited rate (secondary) | <X>% | <Y>% | <Δ>% |
|
|
76
81
|
| Queries monitored | <N> | <N> | <Δ> |
|
|
77
82
|
| Active regressions | <N> | <N> | <Δ> |
|
|
78
83
|
|
|
79
84
|
## Provider Breakdown
|
|
80
|
-
| Provider | Cited Rate | Trend |
|
|
81
|
-
|
|
82
|
-
| <provider> | <X>% | ↑/↓/→ |
|
|
85
|
+
| Provider | Mention Rate | Mention Trend | Cited Rate | Cited Trend |
|
|
86
|
+
|----------|--------------|---------------|-----------|-------------|
|
|
87
|
+
| <provider> | <X>% | ↑/↓/→ | <X>% | ↑/↓/→ |
|
|
83
88
|
|
|
84
89
|
## Fixes Deployed
|
|
85
90
|
| Date | Fix | Status | Impact |
|
|
@@ -5,12 +5,12 @@ description: Aero's persona, values, and voice — context-agnostic identity tha
|
|
|
5
5
|
|
|
6
6
|
# Who You Are
|
|
7
7
|
|
|
8
|
-
You are **Aero** — an AEO analyst. You help operators understand
|
|
8
|
+
You are **Aero** — an AEO analyst. You help operators understand whether AI answer engines NAME their brand (mention) and, secondarily, whether they CITE their domain, and you act decisively on what the data shows. Mention is the primary gauge; citation is the secondary signal. The two are independent — never compute one from the other.
|
|
9
9
|
|
|
10
10
|
## Values
|
|
11
11
|
|
|
12
|
-
- **Evidence over opinion.** Numbers before interpretation. "
|
|
13
|
-
- **Proactive, not passive.** Regressions don't wait to be asked about. Surface them when you spot them. Flag
|
|
12
|
+
- **Evidence over opinion.** Numbers before interpretation. "ChatGPT stopped mentioning you for 'roof repair phoenix' between March 28 and April 2, and your mention share fell from 50% to 0%" beats "your visibility decreased" — then note the lost citation second.
|
|
13
|
+
- **Proactive, not passive.** Regressions don't wait to be asked about. Surface them when you spot them. Flag competitors the moment they take mention share in answers you used to own, and when they appear in citations you own.
|
|
14
14
|
- **Honest about uncertainty.** When the data is ambiguous, say so. Don't manufacture confidence. Don't promise fixes will appear in the next sweep — AEO changes take weeks.
|
|
15
15
|
- **Cautious with writes.** Sweeps cost quota. Schedules shape downstream notifications. Queries define what gets tracked. Confirm intent before mutating state the operator will notice. When *you* need to test something (verify a fix, reproduce a regression), use `cnry run --probe` — same wire call, no dashboard/analytics/notification pollution.
|
|
16
16
|
- **Canonry is the source of truth.** Read state back; never maintain a parallel copy in your head. Conclusions age, the data doesn't.
|
|
@@ -25,6 +25,6 @@ You have opinions. If a client's setup is actively hurting them, say so plainly.
|
|
|
25
25
|
|
|
26
26
|
## Boundaries
|
|
27
27
|
|
|
28
|
-
- Never fabricate citation data. If you haven't run a sweep, say so.
|
|
29
|
-
- Never speculate why an AI cited a competitor without evidence — stick to what canonry observed.
|
|
28
|
+
- Never fabricate mention or citation data. If you haven't run a sweep, say so. Never coerce `answerMentioned` null → false — null means "not checked," not "not mentioned."
|
|
29
|
+
- Never speculate why an AI mentioned or cited a competitor without evidence — stick to what canonry observed.
|
|
30
30
|
- Private client data stays private.
|
|
@@ -131,7 +131,7 @@ Aero also wakes unprompted after every `run.completed` so insights and regressio
|
|
|
131
131
|
|
|
132
132
|
- **Never touch live WordPress without explicit approval**
|
|
133
133
|
- **Back up `~/.canonry/config.yaml` before any config edit**
|
|
134
|
-
- **Never fabricate citation data** — if a sweep hasn't run, say so
|
|
134
|
+
- **Never fabricate mention or citation data** — if a sweep hasn't run, say so; never coerce `answerMentioned` null → false (null = "not checked")
|
|
135
135
|
- **Client data stays private** — canonry repo is public; no real domains in issues
|
|
136
136
|
- **Respect API rate limits** — batch operations, avoid tight loops
|
|
137
137
|
|
|
@@ -1,51 +1,87 @@
|
|
|
1
1
|
# AEO Analysis: Interpreting Canonry Results
|
|
2
2
|
|
|
3
|
+
Canonry tracks two independent signals per (query × provider): **mention** (the brand is named in the AI answer text, `answerMentioned`) and **citation** (the domain appears in the grounding sources, `cited`/`citedDomains`). **Mention is the primary read; citation is secondary.** Never compute one from the other, and never coerce `answerMentioned` null → false — null means "not checked," not "not mentioned."
|
|
4
|
+
|
|
5
|
+
## What Mention Means
|
|
6
|
+
|
|
7
|
+
A "mentioned" query means the client's brand was NAMED in the AI provider's answer text when that query was asked — the model said the brand out loud in its prose. This is the primary gauge of AI visibility: it is what the user actually reads. It does NOT mean:
|
|
8
|
+
- The AI recommended them positively (it may name them neutrally or unfavorably)
|
|
9
|
+
- The brand was the headline answer
|
|
10
|
+
- It will persist on the next sweep
|
|
11
|
+
|
|
12
|
+
A "not-mentioned" query means the answer text never named the client. `answerMentioned = null` is distinct: the mention was not checked for that snapshot — treat it as missing, not negative.
|
|
13
|
+
|
|
14
|
+
**Mention share** is the competitive read: of all brand names appearing across the answer set (the project plus tracked competitors), the fraction that were the project = AI share-of-voice. A competitor taking mention share on a query you used to own is the highest-signal regression.
|
|
15
|
+
|
|
16
|
+
### First diagnostic read (mention-first)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cnry get <project> scores.mentionCoverage.value # mention rate (primary)
|
|
20
|
+
cnry get <project> scores.mentionShare.value # mention share / AI share-of-voice (primary)
|
|
21
|
+
cnry analytics <project> --feature gaps # mentionGap[] / notMentioned[] (who's named instead of you)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Read citation as the secondary lens only after the mention read:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cnry get <project> scores.citationCoverage.value # cited rate (secondary)
|
|
28
|
+
```
|
|
29
|
+
|
|
3
30
|
## What Citation Means
|
|
4
31
|
|
|
5
|
-
A "cited" query means the client's domain appeared in an AI provider's
|
|
32
|
+
A "cited" query means the client's domain appeared in an AI provider's grounding sources when that query was asked — the structured source list, not the prose. It is the **secondary** signal. It does NOT mean:
|
|
6
33
|
- The AI recommended them positively
|
|
7
34
|
- The citation is prominent
|
|
8
35
|
- It will persist on the next sweep
|
|
36
|
+
- That the brand was also mentioned in the answer text (citation and mention are independent — a model can cite the domain without naming the brand, and vice versa)
|
|
9
37
|
|
|
10
|
-
A "not-cited" query means the AI answered without
|
|
38
|
+
A "not-cited" query means the AI answered without grounding on the client's domain.
|
|
11
39
|
|
|
12
40
|
## Reading Evidence Output
|
|
13
41
|
|
|
42
|
+
`cnry evidence` renders a two-glyph cell per (query × provider): `[C/c][M/m]` — uppercase = present, lowercase = absent, `–` = no snapshot. **C/c = cited** (secondary), **M/m = mentioned** (primary). Always print the legend before the table; never collapse the two signals into one cell. Lead your interpretation with the mention glyph.
|
|
43
|
+
|
|
14
44
|
```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
45
|
+
Legend: [C/c][M/m] C=cited c=not-cited M=mentioned m=not-mentioned –=no snapshot
|
|
46
|
+
|
|
47
|
+
[C][M] AEO Agency NYC ← mentioned AND cited: branded/direct match, fully visible
|
|
48
|
+
[c][M] best plumber brooklyn ← mentioned but NOT cited: named in the answer, domain not in sources (mention win, citation gap)
|
|
49
|
+
[C][m] ai seo tools ← cited but NOT mentioned: domain grounded, brand never named (citation without share of voice)
|
|
50
|
+
[c][m] how to fix a leaky faucet ← neither: informational gap, no page for this topic
|
|
51
|
+
[c][m] emergency plumber near me ← neither: competitive gap, others mentioned/cited instead
|
|
19
52
|
```
|
|
20
53
|
|
|
54
|
+
The summary line reports each signal independently: `Mentioned: X / Y` (primary) and `Cited: X / Y` (secondary) — a query can be one, both, or neither.
|
|
55
|
+
|
|
21
56
|
### Query Categories
|
|
22
57
|
|
|
23
58
|
**Branded/direct queries** (e.g., "[business name] [city]"):
|
|
24
|
-
- If
|
|
25
|
-
- If not
|
|
59
|
+
- If mentioned: good — the engine names you for your own core queries (and check the citation as the secondary confirmation)
|
|
60
|
+
- If not mentioned: urgent — the engine won't even say your name; something broken at a fundamental level (indexing, schema, llms.txt). Losing the citation for your own name is the secondary signal on the same query.
|
|
26
61
|
|
|
27
62
|
**Competitive queries** (e.g., "best [service] [city]"):
|
|
28
|
-
- If not
|
|
63
|
+
- If not mentioned: check who IS mentioned (mention share) — competitor analysis needed. Then check who is cited as the secondary lens.
|
|
29
64
|
- Harder wins; require established authority and trust signals
|
|
30
65
|
|
|
31
66
|
**Informational/how-to queries** (e.g., "how to [do X]"):
|
|
32
|
-
- If not cited: almost always a content gap — no page targeting this topic, or it's not indexed
|
|
33
|
-
- High-leverage — informational content positions a site as authoritative to AI models
|
|
67
|
+
- If not mentioned (and not cited): almost always a content gap — no page targeting this topic, or it's not indexed
|
|
68
|
+
- High-leverage — informational content positions a site as authoritative to AI models, earning the mention first and the citation second
|
|
34
69
|
|
|
35
70
|
## Using Analytics
|
|
36
71
|
|
|
37
|
-
### Citation Rate Trends (`--feature metrics`)
|
|
38
|
-
|
|
39
|
-
- Improving or declining
|
|
72
|
+
### Mention + Citation Rate Trends (`--feature metrics`)
|
|
73
|
+
`BrandMetricsDto` returns both `mentionTrend` (primary) and `trend` (the citation trend, secondary) over time across providers. Read mention first. Use to identify:
|
|
74
|
+
- Improving or declining mention trends (does the engine name you more or less often?), then citation trends
|
|
40
75
|
- Provider-specific performance differences
|
|
41
76
|
- Impact of content/indexing changes over time
|
|
42
77
|
|
|
43
|
-
**Query normalization:** When new queries are added to a project mid-history, canonry automatically normalizes each time bucket to only include queries that existed before that bucket started. This prevents newly-added (typically uncited) queries from creating a false drop in the
|
|
78
|
+
**Query normalization:** When new queries are added to a project mid-history, canonry automatically normalizes each time bucket to only include queries that existed before that bucket started. This prevents newly-added (typically not-yet-mentioned/uncited) queries from creating a false drop in the rate trend. The chart displays dashed vertical annotation lines at points where queries were added (e.g. "+3 q"), and each bucket's tooltip shows the query count ("q") used for that bucket's calculation.
|
|
44
79
|
|
|
45
80
|
### Gap Analysis (`--feature gaps`)
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
81
|
+
`GapAnalysisDto` returns mention buckets — `mentionedQueries[]`, `mentionGap[]` (a competitor is mentioned but you're not), `notMentioned[]` (nobody named) — alongside the cited buckets (`cited[]`, `gap[]`, `uncited[]`). Read the mention buckets first. Priorities:
|
|
82
|
+
- **`mentionGap[]` queries** are highest priority — competitors are taking mention share (AI share-of-voice) you're not winning
|
|
83
|
+
- **`notMentioned[]` queries** may need content or may be too broad
|
|
84
|
+
- The cited `gap[]` / `uncited[]` buckets are the secondary lens on the same queries
|
|
49
85
|
|
|
50
86
|
### Source Breakdown (`--feature sources`)
|
|
51
87
|
Shows which source categories AI models cite for your queries. Helps identify:
|
|
@@ -59,10 +95,15 @@ Every content target carries a deterministic `winnabilityClass`: **ownable** (wo
|
|
|
59
95
|
- `canonry content brief <project> <targetRef>` — synthesize a structured brief (angle, why-winnable, schema hookup) for an **ownable** target. Ceded targets are rejected — don't chase them.
|
|
60
96
|
Recommend briefs only for ownable targets; for ceded head terms, advise earning placement on the aggregator/editorial surface instead of writing a competing page.
|
|
61
97
|
|
|
62
|
-
## Diagnosing Citation Gaps
|
|
98
|
+
## Diagnosing Mention + Citation Gaps
|
|
99
|
+
|
|
100
|
+
### Step 0: Read the mention signal first
|
|
101
|
+
Before anything else, separate the two signals. `cnry analytics <project> --feature gaps` tells you whether the query is in `notMentioned[]` (the engine never names you), `mentionGap[]` (a competitor is named instead), or only in the cited `gap[]`/`uncited[]` (a citation gap while the mention may hold). The fix priority follows the mention: earn the name first, the source citation second. `answerMentioned = null` means the snapshot wasn't checked — re-run, don't read it as not-mentioned.
|
|
102
|
+
|
|
103
|
+
> **Known gap:** `cnry health` is citation-only today (no mention dimension). For the mention-first read, use `cnry overview` / `cnry get <project> scores.mentionCoverage.value` / `cnry get <project> scores.mentionShare.value` until health is extended.
|
|
63
104
|
|
|
64
|
-
### Step 1: Check indexing
|
|
65
|
-
Not cited ≠ bad content. Often the page isn't indexed yet.
|
|
105
|
+
### Step 1: Check indexing
|
|
106
|
+
Not mentioned / not cited ≠ bad content. Often the page isn't indexed yet, which starves both signals.
|
|
66
107
|
```bash
|
|
67
108
|
cnry google coverage <project>
|
|
68
109
|
```
|
|
@@ -72,7 +113,7 @@ If key pages are "unknown to Google," submit them before drawing conclusions.
|
|
|
72
113
|
Is there a page on the site targeting that query? If not, that's the gap — not a canonry or provider issue.
|
|
73
114
|
|
|
74
115
|
### Step 3: Check competitors
|
|
75
|
-
For competitive queries, if others are cited and the client isn't:
|
|
116
|
+
For competitive queries, if others are mentioned/cited and the client isn't (check mention share first, cited domains second):
|
|
76
117
|
- Do competitors have more specific, dedicated pages?
|
|
77
118
|
- Do they have stronger schema/structured data?
|
|
78
119
|
- Are they more established in the index?
|
|
@@ -89,7 +130,7 @@ cnry analytics <project> --feature gaps --window 30d
|
|
|
89
130
|
Look for patterns: are gaps growing or shrinking? Are new competitors appearing?
|
|
90
131
|
|
|
91
132
|
### Step 6: Check GA4 traffic for impact
|
|
92
|
-
A lost citation isn't always a lost user. Before declaring a regression real, confirm whether AI-referral traffic actually fell on the same window:
|
|
133
|
+
A lost mention (or lost citation) isn't always a lost user. Before declaring a regression real, confirm whether AI-referral traffic actually fell on the same window:
|
|
93
134
|
```bash
|
|
94
135
|
cnry ga status <project> # confirm lastSyncedAt is recent; re-sync if stale
|
|
95
136
|
cnry ga ai-referral-history <project> --format json
|
|
@@ -105,40 +146,47 @@ GA4 also covers the inverse case: a *gain* on `attribution --trend` for the AI c
|
|
|
105
146
|
|
|
106
147
|
## Trend Interpretation
|
|
107
148
|
|
|
108
|
-
|
|
149
|
+
Read transitions on the mention signal first (primary), then the citation signal (secondary). They move independently — a query can gain the mention while losing the citation.
|
|
109
150
|
|
|
110
|
-
**
|
|
151
|
+
**Stable mentioned** — the engine keeps naming you; monitor for regressions, no action needed. (Track the cited state as the secondary confirmation.)
|
|
111
152
|
|
|
112
|
-
**
|
|
153
|
+
**New mention** (was not-mentioned, now mentioned) — primary win. Correlate with what changed: new content, indexing, schema update. A **new citation** (domain newly in sources) is a secondary win on the same query.
|
|
154
|
+
|
|
155
|
+
**Regression** — investigate immediately, leading with a **lost mention** (was mentioned, now not). A lost citation while the mention holds is the secondary, lower-tier regression. Either way:
|
|
156
|
+
- Did a competitor take the mention share (`mentionGap[]`)?
|
|
113
157
|
- Did a competitor page launch?
|
|
114
158
|
- Did the page get deindexed or go down?
|
|
115
159
|
- Did the model update?
|
|
116
160
|
- Check `cnry google deindexed <project>` for index losses
|
|
117
161
|
|
|
118
|
-
**Fluctuation** (cited in some runs, not others) — normal for competitive queries. Track trend over 5+ runs before drawing conclusions. AI answers are non-deterministic.
|
|
162
|
+
**Fluctuation** (mentioned/cited in some runs, not others) — normal for competitive queries. Track the trend over 5+ runs before drawing conclusions. AI answers are non-deterministic.
|
|
119
163
|
|
|
120
164
|
## What to Recommend
|
|
121
165
|
|
|
122
|
-
### Low overall
|
|
123
|
-
|
|
166
|
+
### Low overall mention rate (< 50%)
|
|
167
|
+
Mention rate is the primary KPI — fix this before cited rate.
|
|
168
|
+
1. Audit indexing — `cnry google coverage <project>` (an unindexed page can't be named or cited)
|
|
124
169
|
2. Submit unindexed pages to Google Indexing API
|
|
125
170
|
3. Submit sitemap to Bing WMT + send IndexNow batch
|
|
126
|
-
4. Check core pages for schema (LocalBusiness / Organization / FAQPage)
|
|
127
|
-
5. Map
|
|
171
|
+
4. Check core pages for schema (LocalBusiness / Organization / FAQPage) so the brand name is unambiguous
|
|
172
|
+
5. Map `notMentioned[]` / `mentionGap[]` queries to pages — which have no corresponding page, and who is named instead?
|
|
173
|
+
|
|
174
|
+
A low cited rate while the mention rate holds is the secondary problem: the engine names you but grounds on other sources — pursue the citation (schema, llms.txt, indexing) after the mention is secured.
|
|
128
175
|
|
|
129
|
-
### Branded terms not
|
|
130
|
-
Red flag. Check:
|
|
176
|
+
### Branded terms not mentioned
|
|
177
|
+
Red flag — the engine won't even say your name. Check (the lost citation for your own name is the secondary signal here):
|
|
131
178
|
- Is the homepage indexed?
|
|
132
179
|
- Does `llms.txt` exist and list the business clearly?
|
|
133
180
|
- Does schema include the exact brand name in `name` field?
|
|
181
|
+
- Is a brand alias missing? (`spec.brandAliases` widens the `answerMentioned` detector for variants like "Acme Cloud" vs "AcmeCloud".)
|
|
134
182
|
|
|
135
|
-
### Informational terms not
|
|
183
|
+
### Informational terms not mentioned
|
|
136
184
|
Content strategy play:
|
|
137
|
-
- Does a page targeting this topic exist? If not, create it.
|
|
185
|
+
- Does a page targeting this topic exist? If not, create it — give the engine a reason to name you.
|
|
138
186
|
- Is it indexed? If not, submit it.
|
|
139
187
|
- Is it structured for AI extraction? (FAQ schema, clear H2s, definition-style answers)
|
|
140
188
|
|
|
141
|
-
### Provider variance (cited on one, not others)
|
|
189
|
+
### Provider variance (mentioned/cited on one, not others)
|
|
142
190
|
Expected — each provider has independent knowledge. Focus on the ones that matter most for the client's audience. Don't over-optimize for one provider at the expense of others.
|
|
143
191
|
|
|
144
192
|
## The AEO Timeline Reality
|
|
@@ -103,24 +103,35 @@ Use `--probe` whenever you're testing on your own initiative — verifying a fix
|
|
|
103
103
|
|
|
104
104
|
`snapshot` does not create a project or write to the DB. It generates category queries, runs providers, and produces a report for prospecting.
|
|
105
105
|
|
|
106
|
-
## Citation Data
|
|
106
|
+
## Mention + Citation Data
|
|
107
|
+
|
|
108
|
+
Two independent signals per (query × provider): **mention** (`answerMentioned` — brand named in the answer text; the **primary** read) and **citation** (`cited`/`citedDomains` — domain in the grounding sources; **secondary**). Read mention first. Never compute one from the other; never coerce `answerMentioned` null → false (null = "not checked").
|
|
107
109
|
|
|
108
110
|
```bash
|
|
109
|
-
cnry evidence <project> # per-query
|
|
111
|
+
cnry evidence <project> # per-query [C/c][M/m] cell + Mentioned: X / Y / Cited: X / Y
|
|
110
112
|
cnry evidence <project> --format json # JSON output
|
|
111
113
|
cnry history <project> # audit trail
|
|
112
114
|
cnry export <project> --include-results # export as YAML
|
|
113
|
-
cnry backfill answer-
|
|
114
|
-
cnry backfill answer-visibility --dry-run # preview which snapshots would change
|
|
115
|
-
cnry backfill answer-mentions # recompute answerMentioned from stored answers (honors brandAliases)
|
|
115
|
+
cnry backfill answer-mentions # recompute answerMentioned (primary) from stored answers (honors brandAliases)
|
|
116
116
|
cnry backfill answer-mentions --dry-run
|
|
117
|
+
cnry backfill answer-visibility # recompute citationState (secondary) from stored answers
|
|
118
|
+
cnry backfill answer-visibility --dry-run # preview which snapshots would change
|
|
117
119
|
cnry backfill insights <project> # recompute insights for completed runs
|
|
118
120
|
cnry backfill insights <project> --since 2026-04-01 --dry-run
|
|
119
121
|
```
|
|
120
122
|
|
|
121
|
-
Output uses a two-glyph cell per (query × provider): `[C/c][M/m]` — uppercase = present, lowercase = absent, `–` = no snapshot. Always print the legend before the table; never collapse the two signals into one cell.
|
|
123
|
+
Output uses a two-glyph cell per (query × provider): `[C/c][M/m]` — uppercase = present, lowercase = absent, `–` = no snapshot. **C/c = cited** (secondary), **M/m = mentioned** (primary). Always print the legend before the table; never collapse the two signals into one cell.
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
```
|
|
126
|
+
Legend: [C/c][M/m] C=cited c=not-cited M=mentioned m=not-mentioned –=no snapshot
|
|
127
|
+
|
|
128
|
+
[C][M] acme corp ny ← mentioned AND cited
|
|
129
|
+
[c][M] best crm for smb ← mentioned, not cited (mention win, citation gap)
|
|
130
|
+
[C][m] crm pricing ← cited, not mentioned (citation without share of voice)
|
|
131
|
+
[c][m] free crm tools ← neither
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Summary: `Mentioned: X / Y` (primary) and `Cited: X / Y` (secondary) are reported independently — a query can be one, both, or neither.
|
|
124
135
|
|
|
125
136
|
## Reports
|
|
126
137
|
|
|
@@ -144,8 +155,8 @@ Behavior to know when narrating numbers from the report:
|
|
|
144
155
|
|
|
145
156
|
```bash
|
|
146
157
|
cnry analytics <project> # default analytics view
|
|
147
|
-
cnry analytics <project> --feature metrics # citation rate trends
|
|
148
|
-
cnry analytics <project> --feature gaps # brand gap analysis (cited/gap/uncited)
|
|
158
|
+
cnry analytics <project> --feature metrics # mention + citation rate trends (BrandMetricsDto: mentionTrend primary, trend secondary)
|
|
159
|
+
cnry analytics <project> --feature gaps # brand gap analysis — mention buckets (mentionedQueries[]/mentionGap[]/notMentioned[]) primary, cited buckets (cited[]/gap[]/uncited[]) secondary
|
|
149
160
|
cnry analytics <project> --feature sources # source breakdown by category
|
|
150
161
|
cnry analytics <project> --window 7d # time window: 7d, 30d, 90d, all
|
|
151
162
|
```
|
|
@@ -190,7 +201,7 @@ cnry insights <project> # list active insights (regressio
|
|
|
190
201
|
cnry insights <project> --dismissed # include dismissed insights
|
|
191
202
|
cnry insights <project> --format json # JSON output
|
|
192
203
|
cnry insights dismiss <project> <id> # dismiss an insight
|
|
193
|
-
cnry health <project> # latest citation health snapshot
|
|
204
|
+
cnry health <project> # latest citation health snapshot (citation-only — see known gap below)
|
|
194
205
|
cnry health <project> --history # health trend over time
|
|
195
206
|
cnry health <project> --history --limit 10 # limit history entries
|
|
196
207
|
cnry health <project> --format json # JSON output
|
|
@@ -198,6 +209,8 @@ cnry backfill insights <project> # backfill insights for all comple
|
|
|
198
209
|
cnry backfill insights <project> --from-run <id> --to-run <id> # backfill a range
|
|
199
210
|
```
|
|
200
211
|
|
|
212
|
+
> **Known gap (mention-first read):** `cnry health` is **citation-only** today — it has no mention dimension. For the primary mention-first read, use `cnry overview` and `cnry get <project> scores.mentionCoverage.value` / `cnry get <project> scores.mentionShare.value` until health is extended.
|
|
213
|
+
|
|
201
214
|
## Queries & Competitors
|
|
202
215
|
|
|
203
216
|
```bash
|
|
@@ -237,6 +250,8 @@ Available events: `citation.lost`, `citation.gained`, `run.completed`, `run.fail
|
|
|
237
250
|
|
|
238
251
|
`insight.critical` and `insight.high` fire when the intelligence engine generates critical- or high-severity insights after a sweep completes.
|
|
239
252
|
|
|
253
|
+
> **No mention events yet.** Notification events cover the citation signal only — there are **no** `mention.lost` / `mention.gained` events today. For mention-first monitoring, read `scores.mentionCoverage` / `scores.mentionShare` via `cnry overview` (or the `insight.*` events, which can be driven by mention-side insights); do not wire automation to mention events that aren't emitted.
|
|
254
|
+
|
|
240
255
|
## Provider Settings & Quotas
|
|
241
256
|
|
|
242
257
|
```bash
|