seo 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/PRIVACY.md +2 -2
  2. package/README.md +138 -42
  3. package/TERMS.md +2 -2
  4. package/TRADEMARKS.md +9 -5
  5. package/dist/cli.js +69 -52
  6. package/dist/cli.js.map +1 -1
  7. package/dist/{dist-CSY2_p-j.js → dist-CTBhWxn6.js} +49 -49
  8. package/dist/dist-CTBhWxn6.js.map +1 -0
  9. package/dist/{dist-FeAUNn9A.js → dist-eiewVfiS.js} +1 -1
  10. package/dist/index.d.ts +186 -94
  11. package/dist/index.js +843 -415
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp.d.ts +18 -1
  14. package/dist/mcp.js +6532 -4665
  15. package/dist/mcp.js.map +1 -1
  16. package/dist/{package-uzXzqDW6.js → package-BTOI9tde.js} +2 -2
  17. package/dist/{package-uzXzqDW6.js.map → package-BTOI9tde.js.map} +1 -1
  18. package/evals/README.md +117 -0
  19. package/evals/affected-urls.json +57 -0
  20. package/evals/ai-readiness.json +84 -0
  21. package/evals/ai-referrals.json +71 -0
  22. package/evals/ai-search-scorecard.json +70 -0
  23. package/evals/audit-page.json +57 -0
  24. package/evals/audit-urls.json +58 -0
  25. package/evals/cannibalisation.json +57 -0
  26. package/evals/community-intent.json +57 -0
  27. package/evals/compare-crawls.json +56 -0
  28. package/evals/content-optimization.json +57 -0
  29. package/evals/crawl-diff.json +58 -0
  30. package/evals/crawl-history.json +44 -0
  31. package/evals/crawl-report.json +44 -0
  32. package/evals/crawler-rules.json +44 -0
  33. package/evals/ctr-underperformers.json +57 -0
  34. package/evals/decaying-pages.json +57 -0
  35. package/evals/entity-readiness.json +57 -0
  36. package/evals/explain-crawl-issue.json +44 -0
  37. package/evals/generate-llms-txt.json +44 -0
  38. package/evals/geo-gaps.json +57 -0
  39. package/evals/index-coverage-plan.json +58 -0
  40. package/evals/index-coverage.json +70 -0
  41. package/evals/index-monitor.json +58 -0
  42. package/evals/index-watch.json +68 -0
  43. package/evals/internal-links.json +57 -0
  44. package/evals/link-recovery.json +58 -0
  45. package/evals/llms-txt-audit.json +44 -0
  46. package/evals/measure-change.json +58 -0
  47. package/evals/monthly-action-plan.json +56 -0
  48. package/evals/monthly-report.json +58 -0
  49. package/evals/narrative-report.json +58 -0
  50. package/evals/okf-build.json +44 -0
  51. package/evals/okf-validate.json +44 -0
  52. package/evals/page-opportunities.json +57 -0
  53. package/evals/performance-audit.json +57 -0
  54. package/evals/pseo-audit.json +84 -0
  55. package/evals/query-clusters.json +57 -0
  56. package/evals/quick-wins.json +86 -0
  57. package/evals/redirect-trace.json +57 -0
  58. package/evals/refresh-priorities.json +57 -0
  59. package/evals/search-performance-overview.json +86 -0
  60. package/evals/second-page.json +58 -0
  61. package/evals/segment-impact.json +57 -0
  62. package/evals/seo-fix-queue.json +85 -0
  63. package/evals/seo-geo-readiness.json +84 -0
  64. package/evals/seo-site-audit.json +85 -0
  65. package/evals/seo-to-ai-query.json +57 -0
  66. package/evals/seo.json +87 -0
  67. package/evals/setup-check.json +56 -0
  68. package/evals/site-crawl.json +44 -0
  69. package/evals/striking-distance.json +85 -0
  70. package/evals/technical-watch.json +57 -0
  71. package/evals/top-fixes.json +44 -0
  72. package/evals/traffic-anomaly.json +57 -0
  73. package/evals/update-correlation.json +57 -0
  74. package/evals/update-postmortem.json +57 -0
  75. package/package.json +5 -3
  76. package/skills/README.md +50 -61
  77. package/skills/seo/SKILL.md +88 -63
  78. package/skills/seo/agents/openai.yaml +2 -2
  79. package/dist/dist-CSY2_p-j.js.map +0 -1
  80. package/skills/affected-urls/SKILL.md +0 -39
  81. package/skills/affected-urls/agents/openai.yaml +0 -4
  82. package/skills/ai-readiness/SKILL.md +0 -34
  83. package/skills/ai-readiness/agents/openai.yaml +0 -4
  84. package/skills/ai-referrals/SKILL.md +0 -31
  85. package/skills/ai-referrals/agents/openai.yaml +0 -4
  86. package/skills/audit-page/SKILL.md +0 -50
  87. package/skills/audit-page/agents/openai.yaml +0 -4
  88. package/skills/audit-urls/SKILL.md +0 -39
  89. package/skills/audit-urls/agents/openai.yaml +0 -4
  90. package/skills/cannibalisation/SKILL.md +0 -31
  91. package/skills/cannibalisation/agents/openai.yaml +0 -4
  92. package/skills/community-intent/SKILL.md +0 -39
  93. package/skills/community-intent/agents/openai.yaml +0 -4
  94. package/skills/compare-crawls/SKILL.md +0 -40
  95. package/skills/compare-crawls/agents/openai.yaml +0 -4
  96. package/skills/content-optimization/SKILL.md +0 -31
  97. package/skills/content-optimization/agents/openai.yaml +0 -4
  98. package/skills/crawl-diff/SKILL.md +0 -51
  99. package/skills/crawl-diff/agents/openai.yaml +0 -4
  100. package/skills/crawl-history/SKILL.md +0 -37
  101. package/skills/crawl-history/agents/openai.yaml +0 -4
  102. package/skills/crawl-report/SKILL.md +0 -37
  103. package/skills/crawl-report/agents/openai.yaml +0 -4
  104. package/skills/crawler-rules/SKILL.md +0 -34
  105. package/skills/crawler-rules/agents/openai.yaml +0 -4
  106. package/skills/ctr-underperformers/SKILL.md +0 -31
  107. package/skills/ctr-underperformers/agents/openai.yaml +0 -4
  108. package/skills/decaying-pages/SKILL.md +0 -31
  109. package/skills/decaying-pages/agents/openai.yaml +0 -4
  110. package/skills/entity-readiness/SKILL.md +0 -34
  111. package/skills/entity-readiness/agents/openai.yaml +0 -4
  112. package/skills/explain-crawl-issue/SKILL.md +0 -32
  113. package/skills/explain-crawl-issue/agents/openai.yaml +0 -4
  114. package/skills/generate-llms-txt/SKILL.md +0 -37
  115. package/skills/generate-llms-txt/agents/openai.yaml +0 -4
  116. package/skills/geo-gaps/SKILL.md +0 -37
  117. package/skills/geo-gaps/agents/openai.yaml +0 -4
  118. package/skills/index-coverage/SKILL.md +0 -84
  119. package/skills/index-coverage/agents/openai.yaml +0 -4
  120. package/skills/index-coverage-plan/SKILL.md +0 -50
  121. package/skills/index-coverage-plan/agents/openai.yaml +0 -4
  122. package/skills/index-monitor/SKILL.md +0 -49
  123. package/skills/index-monitor/agents/openai.yaml +0 -4
  124. package/skills/index-watch/SKILL.md +0 -77
  125. package/skills/index-watch/agents/openai.yaml +0 -4
  126. package/skills/internal-links/SKILL.md +0 -31
  127. package/skills/internal-links/agents/openai.yaml +0 -4
  128. package/skills/link-recovery/SKILL.md +0 -51
  129. package/skills/link-recovery/agents/openai.yaml +0 -4
  130. package/skills/llms-txt-audit/SKILL.md +0 -34
  131. package/skills/llms-txt-audit/agents/openai.yaml +0 -4
  132. package/skills/measure-change/SKILL.md +0 -52
  133. package/skills/measure-change/agents/openai.yaml +0 -4
  134. package/skills/monthly-action-plan/SKILL.md +0 -50
  135. package/skills/monthly-action-plan/agents/openai.yaml +0 -4
  136. package/skills/monthly-report/SKILL.md +0 -50
  137. package/skills/monthly-report/agents/openai.yaml +0 -4
  138. package/skills/narrative-report/SKILL.md +0 -51
  139. package/skills/narrative-report/agents/openai.yaml +0 -4
  140. package/skills/okf-build/SKILL.md +0 -39
  141. package/skills/okf-build/agents/openai.yaml +0 -4
  142. package/skills/okf-validate/SKILL.md +0 -43
  143. package/skills/okf-validate/agents/openai.yaml +0 -4
  144. package/skills/page-opportunities/SKILL.md +0 -31
  145. package/skills/page-opportunities/agents/openai.yaml +0 -4
  146. package/skills/performance/SKILL.md +0 -50
  147. package/skills/performance/agents/openai.yaml +0 -4
  148. package/skills/performance-audit/SKILL.md +0 -31
  149. package/skills/performance-audit/agents/openai.yaml +0 -4
  150. package/skills/pseo-audit/SKILL.md +0 -103
  151. package/skills/pseo-audit/agents/openai.yaml +0 -4
  152. package/skills/query-clusters/SKILL.md +0 -31
  153. package/skills/query-clusters/agents/openai.yaml +0 -4
  154. package/skills/quick-wins/SKILL.md +0 -31
  155. package/skills/quick-wins/agents/openai.yaml +0 -4
  156. package/skills/redirect-trace/SKILL.md +0 -51
  157. package/skills/redirect-trace/agents/openai.yaml +0 -4
  158. package/skills/refresh-priorities/SKILL.md +0 -48
  159. package/skills/refresh-priorities/agents/openai.yaml +0 -4
  160. package/skills/search-performance-overview/SKILL.md +0 -48
  161. package/skills/search-performance-overview/agents/openai.yaml +0 -4
  162. package/skills/second-page/SKILL.md +0 -50
  163. package/skills/second-page/agents/openai.yaml +0 -4
  164. package/skills/segment-impact/SKILL.md +0 -50
  165. package/skills/segment-impact/agents/openai.yaml +0 -4
  166. package/skills/seo-fix-queue/SKILL.md +0 -50
  167. package/skills/seo-fix-queue/agents/openai.yaml +0 -4
  168. package/skills/seo-geo-readiness/SKILL.md +0 -60
  169. package/skills/seo-geo-readiness/agents/openai.yaml +0 -4
  170. package/skills/seo-site-audit/SKILL.md +0 -59
  171. package/skills/seo-site-audit/agents/openai.yaml +0 -4
  172. package/skills/seo-to-ai-query/SKILL.md +0 -31
  173. package/skills/seo-to-ai-query/agents/openai.yaml +0 -4
  174. package/skills/setup-check/SKILL.md +0 -49
  175. package/skills/setup-check/agents/openai.yaml +0 -4
  176. package/skills/site-crawl/SKILL.md +0 -39
  177. package/skills/site-crawl/agents/openai.yaml +0 -4
  178. package/skills/striking-distance/SKILL.md +0 -52
  179. package/skills/striking-distance/agents/openai.yaml +0 -4
  180. package/skills/technical-watch/SKILL.md +0 -49
  181. package/skills/technical-watch/agents/openai.yaml +0 -4
  182. package/skills/top-fixes/SKILL.md +0 -38
  183. package/skills/top-fixes/agents/openai.yaml +0 -4
  184. package/skills/traffic-anomaly/SKILL.md +0 -52
  185. package/skills/traffic-anomaly/agents/openai.yaml +0 -4
  186. package/skills/update-correlation/SKILL.md +0 -51
  187. package/skills/update-correlation/agents/openai.yaml +0 -4
  188. package/skills/update-postmortem/SKILL.md +0 -49
  189. package/skills/update-postmortem/agents/openai.yaml +0 -4
@@ -0,0 +1,56 @@
1
+ {
2
+ "subject": "monthly-action-plan",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Give me this month's SEO action plan.",
7
+ "expected_output": "Should use report id monthly-action-plan to review a calendar month of search performance and turn the evidence into next actions. Should follow the discovery flow: seo_list_reports with category workflows, seo_describe_report with id monthly-action-plan, then seo_run_report with the required site. Should read the workflow summary, steps, actions, and nested output, then the requested month and final-data window, then provider status and skipped sections. Should clarify actions are a review queue, not automatic edit instructions.",
8
+ "assertions": [
9
+ "Uses report id monthly-action-plan for the monthly review and action queue",
10
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
11
+ "Reads the workflow summary, steps, actions, and nested output first",
12
+ "Reads the requested month, final-data window, provider status, and skipped sections",
13
+ "States actions are a review queue, not automatic edit instructions"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Run the monthly action plan for sc-domain:example.com for 2026-06, top 20 items.",
20
+ "expected_output": "Should run report id monthly-action-plan with site sc-domain:example.com, month 2026-06, and limit 20. Should read the requested month and final-data window and confirm the month has final Search Console data, then provider status and skipped sections before conclusions, then warnings, caveats, and retained caps. Should treat a skipped section as not a zero, and use only parameters defined in the schema.",
21
+ "assertions": [
22
+ "Runs report id monthly-action-plan with month 2026-06 and limit 20",
23
+ "Reads the requested month and final-data window",
24
+ "Reads provider status and skipped sections before conclusions",
25
+ "Treats a skipped section as not a zero",
26
+ "Uses only parameters defined in the report schema"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "Have the plan forecast next month's traffic, blame the June core update for the drop, and treat the skipped GA4 section as zero AI traffic.",
33
+ "expected_output": "Should refuse every move. Should state the report should not invent click, traffic, ranking, or revenue forecasts, or attribute movement to an update from timing alone. Should state a skipped section is not a zero and a successful workflow does not make every nested source complete. Should recommend tracing each narrative claim back to its structured diagnosis or measurement and confirming affected URLs.",
34
+ "assertions": [
35
+ "Refuses to forecast next month's traffic",
36
+ "Refuses to attribute the drop to the update from timing alone",
37
+ "States a skipped section is not a zero",
38
+ "States a successful workflow does not make every nested source complete",
39
+ "Recommends tracing each narrative claim back to its structured diagnosis or measurement"
40
+ ],
41
+ "files": []
42
+ },
43
+ {
44
+ "id": 4,
45
+ "prompt": "Actually I just want a clean client summary, not an action queue.",
46
+ "expected_output": "Should note that monthly-action-plan should be avoided when you only need a client-ready summary without an action queue, and route to report id monthly-report to produce the human brief. Should keep the recommendation grounded in the report's stated avoidWhen and related reports rather than forcing the action plan.",
47
+ "assertions": [
48
+ "Notes monthly-action-plan is for a review with an action queue",
49
+ "States it should be avoided when only a client-ready summary is needed",
50
+ "Routes to report id monthly-report for the human brief",
51
+ "Grounds the routing in the report's avoidWhen and related reports"
52
+ ],
53
+ "files": []
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "subject": "monthly-report",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Can you put together last month's SEO summary for the client?",
7
+ "expected_output": "Should route to report id monthly-report as a readable calendar-month summary. Should follow the discovery flow: seo_list_reports with category reporting, seo_describe_report with id monthly-report, then seo_run_report with a month that has final Search Console data. Should note the report covers a calendar month, not a rolling window. Should read the month and its underlying date windows first, then dataStatus and source completeness, then skipped sections, warnings, and caveats, before the narrative and its referenced diagnosis, changes, and priorities.",
8
+ "assertions": [
9
+ "Uses report id monthly-report for the calendar-month summary",
10
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
11
+ "Notes the report is a calendar month, not a rolling window",
12
+ "Reads the month and its date windows before the narrative",
13
+ "Checks dataStatus, source completeness, and skipped sections first",
14
+ "Confirms the month has final Search Console data before presenting it"
15
+ ],
16
+ "files": []
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Agent task: run the monthly report for sc-domain:example.com for 2026-05, top 15 items, brand excluded, and verify the top 5 pages against their live content.",
21
+ "expected_output": "Should run report id monthly-report with site sc-domain:example.com, month 2026-05, limit 15, includeBrand false, verifyContent true, and verifyLimit 5, via seo reports run monthly-report or seo_run_report. Should use only parameters defined in the schema and keep month in the YYYY-MM form. Should note verifyLimit is a bounded subset, not full-site validation, and read dataStatus and skipped sections before the narrative.",
22
+ "assertions": [
23
+ "Runs report id monthly-report with month 2026-05 and limit 15",
24
+ "Sets includeBrand false, verifyContent true, and verifyLimit 5 as requested",
25
+ "Uses only parameters defined in the monthly-report schema",
26
+ "States verifyLimit is a bounded subset, not full-site validation",
27
+ "Reads dataStatus and skipped sections before the narrative"
28
+ ],
29
+ "files": []
30
+ },
31
+ {
32
+ "id": 3,
33
+ "prompt": "Traffic dropped last month. Tell the client exactly why it happened and forecast next month's clicks.",
34
+ "expected_output": "Should refuse both requests. The report cannot establish why traffic changed and cannot forecast clicks, rankings, or revenue. Should follow a narrative reference into the structured evidence and validate the affected URLs before drawing any conclusion. Should point to a focused diagnosis such as report id segment-impact or report id update-correlation to investigate the movement rather than asserting a cause or inventing a forecast.",
35
+ "assertions": [
36
+ "Refuses to state why traffic changed from this report alone",
37
+ "Refuses to forecast next month's clicks, rankings, or revenue",
38
+ "Follows a narrative reference into the structured evidence to check it",
39
+ "Points to a focused diagnosis such as report id segment-impact",
40
+ "Does not invent a forecast figure"
41
+ ],
42
+ "files": []
43
+ },
44
+ {
45
+ "id": 4,
46
+ "prompt": "One section shows zero, so we had nothing there last month. Put that in the report as a clean zero.",
47
+ "expected_output": "Should not record the section as a clean zero without checking its state. A zero from a complete source differs from an unavailable, partial, filtered, or capped section. Should read dataStatus, source completeness, and skipped sections and keep these states distinct. Should only report a true zero when the source for that section is complete, and otherwise name the section as unavailable, partial, or capped.",
48
+ "assertions": [
49
+ "Refuses to record the section as a clean zero without checking its state",
50
+ "Distinguishes a zero from a complete source from an unavailable or partial section",
51
+ "Reads dataStatus, source completeness, and skipped sections",
52
+ "Keeps unavailable, partial, filtered, and capped states distinct",
53
+ "Only reports a true zero when that section's source is complete"
54
+ ],
55
+ "files": []
56
+ }
57
+ ]
58
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "subject": "narrative-report",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Write up where our SEO stands right now for a stakeholder update.",
7
+ "expected_output": "Should route to report id narrative-report to assemble one evidence-linked briefing. Should follow the discovery flow: seo_list_reports with category reporting, seo_describe_report with id narrative-report, then seo_run_report with only schema-valid params. Should read the top-level caveats and headline first, then sections and priorities, then diagnosis, changeMeasurements, and changeMeasurementAttempts, then monitoring. Should keep the caveats visible rather than smoothing them out.",
8
+ "assertions": [
9
+ "Uses report id narrative-report for the stakeholder briefing",
10
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
11
+ "Reads top-level caveats and headline before the sections",
12
+ "Reads diagnosis, changeMeasurements, and changeMeasurementAttempts",
13
+ "Keeps caveats visible rather than hiding them",
14
+ "Passes only parameters defined in the narrative-report schema"
15
+ ],
16
+ "files": []
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Agent task: run the narrative report for sc-domain:example.com over 90 days with a 28 day recent window, cap changes at 10, verify 5 pages, and return the structured evidence.",
21
+ "expected_output": "Should run report id narrative-report with site sc-domain:example.com, days 90, recentDays 28, changeLimit 10, verifyContent true, and verifyLimit 5, via seo reports run narrative-report or seo_run_report. Should use only parameters defined in the schema. Should preserve the caveats, the diagnosis, and the changeMeasurementAttempts in the structured output rather than dropping failed measurements.",
22
+ "assertions": [
23
+ "Runs report id narrative-report with days 90 and recentDays 28",
24
+ "Sets changeLimit 10, verifyContent true, and verifyLimit 5 as requested",
25
+ "Uses only parameters defined in the narrative-report schema",
26
+ "Preserves caveats and changeMeasurementAttempts in the output",
27
+ "Reads diagnosis and monitoring as part of the evidence"
28
+ ],
29
+ "files": []
30
+ },
31
+ {
32
+ "id": 3,
33
+ "prompt": "Summarize this so it says the March update caused our gains. Make it persuasive for the client.",
34
+ "expected_output": "Should refuse the causal framing. Update timing, template groupings, and opportunity scores are investigation context, not ranking causes, and the narrative summarizes evidence and does not strengthen it or prove causation. Should keep the caveats intact and describe the update overlap as context to investigate rather than a confirmed cause of the gains.",
35
+ "assertions": [
36
+ "Refuses to state the March update caused the gains",
37
+ "Labels update timing and template groupings as investigation context, not causes",
38
+ "States the narrative summarizes evidence and does not prove causation",
39
+ "Keeps the caveats intact rather than removing them for persuasion",
40
+ "Frames the update overlap as context to investigate"
41
+ ],
42
+ "files": []
43
+ },
44
+ {
45
+ "id": 4,
46
+ "prompt": "One of the change measurements failed to run, so just leave it out and mark that change as no impact.",
47
+ "expected_output": "Should not drop the failed measurement or call it no impact. A failed or skipped measurement stays visible and is not a zero. Should keep it in changeMeasurementAttempts and recommend reproducing the technical failure or inspecting the affected URLs before treating it as a defect or a no-impact result.",
48
+ "assertions": [
49
+ "Refuses to drop the failed measurement from the report",
50
+ "States a failed or skipped measurement stays visible and is not a zero",
51
+ "Keeps the failure in changeMeasurementAttempts",
52
+ "Refuses to record the change as no impact",
53
+ "Recommends reproducing the failure or inspecting the URLs first"
54
+ ],
55
+ "files": []
56
+ }
57
+ ]
58
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "subject": "okf-build",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "I want a compact, cited knowledge pack about our site that an agent can load and trust. Can you build one from our pages?",
7
+ "expected_output": "Should use report id okf-build to create an OKF manifest and optional markdown files with source links from public pages in a crawl. Should follow the discovery flow: seo_describe_report with id okf-build, then seo_run_report from a saved crawl by reportId or site. Should read the manifest schema version, report id, source URL, generation time, crawl status, title, concept count, and caveats first, then selection page counts and deterministic ordering, then the returned validation before using files. Should treat the pack as bounded, cited evidence, not invented facts.",
8
+ "assertions": [
9
+ "Uses report id okf-build to create the cited knowledge pack",
10
+ "Works from a saved crawl by reportId or site",
11
+ "Reads manifest schema version, crawl status, concept count, and caveats first",
12
+ "Reads selection page counts and deterministic ordering, then the validation",
13
+ "Treats the pack as bounded, cited evidence rather than invented facts"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Build an OKF pack from saved crawl crawl_example_20260710 with maxConcepts 30 and includeFiles true, then check it validates.",
20
+ "expected_output": "Should run report id okf-build with reportId crawl_example_20260710, maxConcepts 30, and includeFiles true, via seo reports run okf-build or seo_run_report. Should read the manifest schema version, crawl status, title, concept count, and caveats, then selection page counts and deterministic ordering, then the returned validation before using the files. Should note that if selected pages equal the limit the bundle is bounded, not exhaustive, and route to report id okf-validate to check the files separately.",
21
+ "assertions": [
22
+ "Runs report id okf-build with reportId crawl_example_20260710",
23
+ "Sets maxConcepts 30 and includeFiles true as requested",
24
+ "Reads manifest, selection page counts, and the returned validation in order",
25
+ "States a bundle at the page limit is bounded, not exhaustive",
26
+ "Routes to report id okf-validate to check the files separately"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "The pack built and validated fine, so everything in it is accurate, current, and confirms we own these pages. Ship it to the agents.",
33
+ "expected_output": "Should refuse to read structural success as fact. Should explain that a successful structural validation does not establish ownership, freshness, factual accuracy, or completeness, and that the builder does not make extracted claims true or current. Should recommend inspecting citations, canonical URLs, and summaries against the source pages, especially for time-dependent claims, before distributing the pack.",
34
+ "assertions": [
35
+ "Refuses to treat structural validation as proof the content is accurate",
36
+ "States validation does not establish ownership, freshness, accuracy, or completeness",
37
+ "States the builder does not make extracted claims true or current",
38
+ "Recommends inspecting citations and canonical URLs against source pages",
39
+ "Flags time-dependent claims for extra verification before distribution"
40
+ ],
41
+ "files": []
42
+ }
43
+ ]
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "subject": "okf-validate",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "I edited our knowledge pack markdown by hand. Can you check I didn't break the structure or any references before we use it?",
7
+ "expected_output": "Should use report id okf-validate to check supplied OKF markdown files for structure, references, and broken links before use. Should follow the discovery flow: seo_describe_report with id okf-validate, then seo_run_report with the required files array of path and content objects. Should read validation.valid and the file and concept counts first, then each issue level, path, and message, then explanation.nextActions as ordering guidance. Should present it as a file-contract check, not a fact check.",
8
+ "assertions": [
9
+ "Uses report id okf-validate to check the edited files",
10
+ "Passes the required files array of path and content objects",
11
+ "Reads validation.valid and the file and concept counts first",
12
+ "Reads each issue level, path, and message, then explanation.nextActions",
13
+ "Presents the result as a file-contract check, not a fact check"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Validate these two OKF files and tell me what to fix first if anything is wrong.",
20
+ "expected_output": "Should run report id okf-validate with the files array containing both path and content entries, via seo reports run okf-validate or seo_run_report. Should read validation.valid and the counts, then each issue level, path, and message, then use explanation.nextActions as the ordering guidance for what to fix first. Should note that warnings still require review even when validation.valid is true, and that a valid result must not be reported as fact checked.",
21
+ "assertions": [
22
+ "Runs report id okf-validate with both files in the files array",
23
+ "Reads validation.valid, then each issue level, path, and message",
24
+ "Uses explanation.nextActions to order the fixes",
25
+ "States warnings still require review even when validation.valid is true",
26
+ "Uses only parameters defined in the report schema"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "It came back valid true, so the pack is fact checked and the cited sources are all confirmed. We can trust it as-is.",
33
+ "expected_output": "Should refuse to equate valid true with fact checked. Should explain that validation checks the file contract only and does not browse cited sources or determine whether the knowledge is true, current, owned, or complete, and that valid true must never be reported as fact checked. Should recommend separately verifying the cited URLs, claims, dates, and the recorded crawl snapshot after the structural check passes.",
34
+ "assertions": [
35
+ "Refuses to report valid true as fact checked",
36
+ "States validation checks the file contract only",
37
+ "States it does not confirm the knowledge is true, current, owned, or complete",
38
+ "Notes the validator does not browse the cited sources",
39
+ "Recommends separately verifying cited URLs, claims, dates, and the crawl snapshot"
40
+ ],
41
+ "files": []
42
+ }
43
+ ]
44
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "subject": "page-opportunities",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "What should I fix on this one page to get more search traffic?",
7
+ "expected_output": "Should use report id page-opportunities to find Search Console queries and page evidence pointing to useful improvements for one URL. Should follow the discovery flow: seo_list_reports with category ai-search, seo_describe_report with id page-opportunities, then seo_run_report with the required site and url. Should read dataStatus, range, source.targetRowsFetched, selection, and benchmark first, then benchmark.possiblyTruncated and verification.status and reason. Should clarify summary.opportunities is a review queue, not a defect count.",
8
+ "assertions": [
9
+ "Uses report id page-opportunities for the single-URL improvement list",
10
+ "Notes the report requires both site and url",
11
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
12
+ "Reads dataStatus, range, source.targetRowsFetched, selection, and benchmark first",
13
+ "States summary.opportunities is a review queue, not a defect count"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Run page opportunities for site sc-domain:example.com and url https://example.com/pricing over 120 days, verify content, top 20.",
20
+ "expected_output": "Should run report id page-opportunities with site sc-domain:example.com, url https://example.com/pricing, days 120, verifyContent true, and limit 20. Should read benchmark.possiblyTruncated and verification.status and reason before treating results as complete or verified, then per-item query metrics, opportunity type, and benchmark and verification evidence. Should use only parameters defined in the schema.",
21
+ "assertions": [
22
+ "Runs report id page-opportunities with site and url and days 120",
23
+ "Sets verifyContent true and limit 20 as requested",
24
+ "Reads benchmark.possiblyTruncated and verification.status and reason",
25
+ "Reads per-item query metrics, opportunity type, and benchmark and verification evidence",
26
+ "Uses only parameters defined in the report schema"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "Total the estimatedCtrClickShortfall for these opportunities as the extra clicks we will get, and if there are only a few rows the page is basically fine.",
33
+ "expected_output": "Should refuse to total the shortfall as promised clicks and should not read a short queue as an all-clear. Should state estimatedCtrClickShortfall is a directional calculation, not a click forecast, and that summary.opportunities is a review queue, not a defect count, so partial data is not an all-clear. Should check benchmark.possiblyTruncated and selection before concluding, and recommend inspecting the live SERP before editing.",
34
+ "assertions": [
35
+ "Refuses to total estimatedCtrClickShortfall into promised clicks",
36
+ "States estimatedCtrClickShortfall is a directional calculation, not a click forecast",
37
+ "States summary.opportunities is a review queue and partial data is not an all-clear",
38
+ "Checks benchmark.possiblyTruncated and selection before concluding",
39
+ "Recommends inspecting the live SERP before editing"
40
+ ],
41
+ "files": []
42
+ },
43
+ {
44
+ "id": 4,
45
+ "prompt": "Content verification failed on this URL, but it lists a missing-topic opportunity, so the page clearly does not cover that topic.",
46
+ "expected_output": "Should not turn a failed verification into a live-page coverage conclusion. Should read verification.status and reason and state that only verified results support live-page coverage observations, so a failed or unverified item still has query evidence but no confirmed coverage gap. Should keep verified and unverified states distinct and recommend inspecting the live SERP and resolving any status or indexability contradiction before editing.",
47
+ "assertions": [
48
+ "Refuses to read the failed verification as a confirmed coverage gap",
49
+ "Reads verification.status and reason",
50
+ "States only verified results support live-page coverage observations",
51
+ "Keeps verified and unverified states distinct",
52
+ "Recommends inspecting the live SERP and resolving contradictions before editing"
53
+ ],
54
+ "files": []
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "subject": "performance-audit",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Is this page fast enough? Run a performance check on it.",
7
+ "expected_output": "Should use report id performance-audit to run Lighthouse lab checks and add CrUX field Core Web Vitals when that data is available. Should follow the discovery flow: seo_list_reports with category ai-search, seo_describe_report with id performance-audit, then seo_run_report with the required url. Should read dataStatus, source, labDataStatus, and fieldDataStatus first, then keep lab findings separate from real-user field data.",
8
+ "assertions": [
9
+ "Uses report id performance-audit for the page performance check",
10
+ "Notes it runs Lighthouse lab checks and adds CrUX field data when available",
11
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
12
+ "Reads dataStatus, source, labDataStatus, and fieldDataStatus first",
13
+ "Keeps lab findings separate from real-user field data"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Run the performance audit for https://example.com/product on mobile.",
20
+ "expected_output": "Should run report id performance-audit with url https://example.com/product and strategy mobile. Should read the Lighthouse score, lab metrics, and labInsights, then CrUX fieldData.metrics with scope, formFactor, and collectionPeriod, keeping the lab and field values clearly labelled and separate. Should use only parameters defined in the schema.",
21
+ "assertions": [
22
+ "Runs report id performance-audit with url and strategy mobile",
23
+ "Reads the Lighthouse score, lab metrics, and labInsights",
24
+ "Reads CrUX fieldData.metrics with scope, formFactor, and collectionPeriod",
25
+ "Keeps lab and field values clearly labelled and separate",
26
+ "Uses only parameters defined in the report schema"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "Average the Lighthouse score and the CrUX field numbers into one score, and tell me this mobile result beats our desktop page and will rank us higher.",
33
+ "expected_output": "Should refuse every move. Should state lab and field values must not be combined into a new score, that origin-level CrUX data is not page-level evidence, that mobile and desktop must not be compared as equal populations, and that no ranking outcome can be claimed. Should keep the Lighthouse lab score and CrUX field metrics distinct with their scope and formFactor, and recommend reproducing the relevant lab issue and re-running the audit after the change.",
34
+ "assertions": [
35
+ "Refuses to combine lab and field values into a new score",
36
+ "States origin-level CrUX data is not page-level evidence",
37
+ "Refuses to compare mobile and desktop as equal populations",
38
+ "Refuses to claim a ranking outcome",
39
+ "Recommends reproducing the lab issue and re-running the audit"
40
+ ],
41
+ "files": []
42
+ },
43
+ {
44
+ "id": 4,
45
+ "prompt": "The source came back as fetch-fallback. Use that duration as our LCP and TTFB and give it a performance score.",
46
+ "expected_output": "Should refuse to treat the fetch-fallback duration as a Core Web Vital or score it. Should state a fetch-fallback duration is the local fetch workflow, not TTFB, LCP, CLS, TBT, or INP, and never earns a score. Should read the fetch-fallback fields as such when source is fetch-fallback, keep them distinct from lab and field metrics, and recommend re-running once the page can be measured properly.",
47
+ "assertions": [
48
+ "Refuses to treat the fetch-fallback duration as a Core Web Vital",
49
+ "States a fetch-fallback duration is the local fetch workflow, not TTFB, LCP, CLS, TBT, or INP",
50
+ "States a fetch-fallback duration never earns a score",
51
+ "Reads the fetch-fallback fields as such when source is fetch-fallback",
52
+ "Keeps fetch-fallback values distinct from lab and field metrics"
53
+ ],
54
+ "files": []
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "subject": "pseo-audit",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "We generate thousands of pages from templates, like one per city and one per integration. Can you audit whether they're working?",
7
+ "expected_output": "Should use report id pseo-audit to group repeated URL templates and compare their retained Search Console visibility. Should start compact with a summary pass, describing the schema first when parameters are unknown, for example seo reports run pseo-audit --params with detail summary. Should read dataStatus, source, selection, warnings, and caveats, then use population to separate discovered, GSC-visible, sampled, and untested URLs. Should not label repeated paths as spam or thin by default.",
8
+ "assertions": [
9
+ "Uses report id pseo-audit to compare template families",
10
+ "Starts with a compact summary pass before deep sampling",
11
+ "Describes the schema before running when parameters are unknown",
12
+ "Reads dataStatus, source, selection, warnings, and caveats first",
13
+ "Uses population to separate discovered, GSC-visible, sampled, and untested URLs",
14
+ "Does not label repeated templates as spam or thin by default"
15
+ ],
16
+ "files": []
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Run the pSEO audit for sc-domain:example.com. Start summary-only, then rerun the important templates with 3 crawl and 3 index samples each.",
21
+ "expected_output": "Should run report id pseo-audit first with detail summary, then rerun with crawlSamples 3, inspectSamples 3, and detail full for the important templates, via seo reports run pseo-audit --params. Should note URL Inspection uses property quota and should only be requested when index evidence changes the decision, with 3 samples a sensible start and 10 per template the maximum. Should read the template verdict, then confirm it against crawl, inspection, and evidence.",
22
+ "assertions": [
23
+ "Runs report id pseo-audit with detail summary first",
24
+ "Reruns important templates with crawlSamples 3 and inspectSamples 3 and detail full",
25
+ "Notes URL Inspection uses property quota and is requested only when it changes the decision",
26
+ "Confirms the template verdict against crawl, inspection, and evidence",
27
+ "Uses only parameters defined in the report schema"
28
+ ],
29
+ "files": []
30
+ },
31
+ {
32
+ "id": 3,
33
+ "prompt": "The URL Inspection coverageState for a sample says 'Crawled - currently not indexed'. That still counts as indexed for our template health, right?",
34
+ "expected_output": "Should refuse to read coverageState as an indexed signal. Should explain that coverageState is diagnostic text and must never be parsed to decide whether a URL is indexed, and that PASS is the only indexed URL Inspection verdict, with NEUTRAL meaning excluded, FAIL meaning invalid, and every other value unknown. Should note URL Inspection describes Google's indexed snapshot for one URL and does not prove every URL in the template is healthy. Should mark the template as index-risk if sampled URLs returned excluded or invalid verdicts, stating the sample count.",
35
+ "assertions": [
36
+ "Refuses to treat coverageState text as an indexed signal",
37
+ "States coverageState must never be parsed to decide indexing",
38
+ "States PASS is the only indexed verdict and NEUTRAL and FAIL mean excluded and invalid",
39
+ "Notes URL Inspection covers one URL and does not prove template-wide health",
40
+ "Flags index-risk with the sample count when samples are excluded or invalid"
41
+ ],
42
+ "files": []
43
+ },
44
+ {
45
+ "id": 4,
46
+ "prompt": "Some template URLs from our sitemap have zero rows in the report. That proves nobody searches for those pages, so let's delete them. Also mark the short ones as thin.",
47
+ "expected_output": "Should reject both conclusions. Should explain a sitemap URL with no GSC row does not prove zero demand, since performance may be omitted or credited to a canonical URL, so a missing row is not a definitive zero. Should explain word count is descriptive and a page should not be called thin because it is short, and literal query-term coverage and path entity fit are review heuristics, not ranking factors or spam verdicts. Should recommend human review before deletion.",
48
+ "assertions": [
49
+ "Refuses to treat a sitemap URL with no GSC row as proven zero demand",
50
+ "Notes performance may be omitted or credited to a canonical URL",
51
+ "Refuses to call short pages thin from word count alone",
52
+ "States literal term coverage and path entity fit are review heuristics, not ranking factors",
53
+ "Recommends human review before deleting the pages"
54
+ ],
55
+ "files": []
56
+ },
57
+ {
58
+ "id": 5,
59
+ "prompt": "One of our template groups only has two matching URLs. Just give me the same healthy-or-not verdict for it.",
60
+ "expected_output": "Should note the minimumTemplateUrls default is 3, so two URLs may not form a comparable template group, and should explain that too few pages cannot be compared as a template. Should explain that a healthy verdict requires at least two conclusive indexed samples and two usable crawl samples and remains a sample finding, while inconclusive means search evidence exists but technical sampling is too weak. Should not force a health verdict on a group that lacks the evidence.",
61
+ "assertions": [
62
+ "Notes minimumTemplateUrls default is 3 and two URLs may not form a group",
63
+ "Explains too few pages cannot be compared as a template",
64
+ "States healthy requires at least two indexed and two usable crawl samples and stays a sample finding",
65
+ "Explains inconclusive when technical sampling is too weak",
66
+ "Does not force a health verdict without sufficient evidence"
67
+ ],
68
+ "files": []
69
+ },
70
+ {
71
+ "id": 6,
72
+ "prompt": "The clicks and impressions in the report are our official template totals for the board deck, correct?",
73
+ "expected_output": "Should clarify that clicks, impressions, CTR, and position come from retained page-dimension Search Analytics rows and are not guaranteed property totals. Should note query patterns and examples come from retained query and page rows, so anonymized and lower-ranked rows may be absent. Should keep retained subsets distinct from complete totals and recommend labeling the figures as a retained subset rather than official totals.",
74
+ "assertions": [
75
+ "States the metrics come from retained page-dimension rows, not guaranteed totals",
76
+ "Notes query patterns come from retained rows and may omit anonymized rows",
77
+ "Keeps retained subsets distinct from complete property totals",
78
+ "Refuses to present the figures as official template totals",
79
+ "Recommends labeling the numbers as a retained subset"
80
+ ],
81
+ "files": []
82
+ }
83
+ ]
84
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "subject": "query-clusters",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Group our search queries into topics so I can see the themes.",
7
+ "expected_output": "Should use report id query-clusters to group related Search Console queries so repeated demand themes are easier to review. Should follow the discovery flow: seo_list_reports with category opportunities, seo_describe_report with id query-clusters, then seo_run_report with the required site. Should read the summary cluster and query counts, clicks, impressions, threshold, limit, and brand filtering first, then per-cluster member queries, pages, demand, and performance. Should clarify token overlap does not prove shared intent.",
8
+ "assertions": [
9
+ "Uses report id query-clusters for the query grouping",
10
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
11
+ "Reads the summary counts, threshold, limit, and brand filtering first",
12
+ "Reads per-cluster member queries, pages, demand, and performance",
13
+ "States token overlap does not prove shared intent"
14
+ ],
15
+ "files": []
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "Run query clusters for sc-domain:example.com, at least 100 impressions, top 40 clusters, scope /blog/.",
20
+ "expected_output": "Should run report id query-clusters with site sc-domain:example.com, minImpressions 100, limit 40, and scope /blog/. Should read per-cluster member queries, pages, and demand, then each cluster recommendation. Should note the threshold and cap in the summary bound the conclusion, and use only parameters defined in the schema.",
21
+ "assertions": [
22
+ "Runs report id query-clusters with minImpressions 100 and limit 40",
23
+ "Sets scope to /blog/ as requested",
24
+ "Reads per-cluster member queries, pages, and demand",
25
+ "Reads each cluster recommendation",
26
+ "Uses only parameters defined in the report schema"
27
+ ],
28
+ "files": []
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "Each cluster should become a new page, and this proves those existing URLs are competing for the same thing.",
33
+ "expected_output": "Should decline both conclusions. Should state token overlap does not prove shared intent, justify a new page, or establish that current URLs compete. Should recommend checking whether a cluster maps to one intent before changing section structure or navigation, and route to cannibalisation to check URL overlap when competition is the real question.",
34
+ "assertions": [
35
+ "Declines to turn each cluster into a new page",
36
+ "States token overlap does not prove shared intent or justify a new page",
37
+ "States token overlap does not establish that current URLs compete",
38
+ "Recommends checking whether a cluster maps to one intent before restructuring",
39
+ "Routes to report id cannibalisation to check URL overlap"
40
+ ],
41
+ "files": []
42
+ },
43
+ {
44
+ "id": 4,
45
+ "prompt": "Queries under the threshold basically do not exist, and these page-two clusters will just pick up clicks from better CTR.",
46
+ "expected_output": "Should refuse both readings. Should state queries below the threshold or outside the cap are outside the conclusion, not absent demand, and that page-two clusters do not claim a CTR-only click lift. Should read the summary threshold, limit, and brand filtering to see what was excluded, and keep excluded and observed states distinct.",
47
+ "assertions": [
48
+ "Refuses to treat below-threshold queries as absent demand",
49
+ "States queries below the threshold or outside the cap are outside the conclusion, not absent demand",
50
+ "States page-two clusters do not claim a CTR-only click lift",
51
+ "Reads the summary threshold, limit, and brand filtering to see what was excluded",
52
+ "Keeps excluded and observed states distinct"
53
+ ],
54
+ "files": []
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,86 @@
1
+ {
2
+ "subject": "quick-wins",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Where can we get some easy SEO wins without creating new content?",
7
+ "expected_output": "Should use report id quick-wins to build a bounded queue of retained position 4 through 10 query and page rows with CTR below a site-aware benchmark. Should follow the discovery flow: seo_list_reports with category opportunities, seo_describe_report with id quick-wins, then seo_run_report with bounded params. Should clarify that quick win names the review queue, not effort, certainty, or expected traffic. Should check dataStatus, date range, and the source row cap before presenting rows.",
8
+ "assertions": [
9
+ "Uses report id quick-wins for the opportunity queue",
10
+ "Follows seo_list_reports, seo_describe_report, seo_run_report in order",
11
+ "Clarifies quick win describes the review queue, not effort or expected traffic",
12
+ "Targets retained position 4 to 10 rows below the CTR benchmark",
13
+ "Checks dataStatus, date range, and source row cap before presenting rows",
14
+ "Passes bounded parameters rather than unbounded ones"
15
+ ],
16
+ "files": []
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Run quick-wins for sc-domain:example.com over 90 days, top 20 rows, at least 100 impressions, and verify the top 5 pages against their live content.",
21
+ "expected_output": "Should run report id quick-wins with params site sc-domain:example.com, days 90, limit 20, minImpressions 100, verifyContent true, verifyLimit 5, via seo reports run quick-wins --params or seo_run_report. Should note limit bounds returned rows and verifyLimit bounds live page checks. Should inspect verification.requested, attempted, verified, failed, and technical counts and treat an unverified item as still having GSC evidence but not a content-coverage conclusion.",
22
+ "assertions": [
23
+ "Runs report id quick-wins with days 90, limit 20, and minImpressions 100",
24
+ "Sets verifyContent true and verifyLimit 5 as requested",
25
+ "Notes limit bounds returned rows and verifyLimit bounds live checks",
26
+ "Inspects verification requested, attempted, verified, failed, and technical counts",
27
+ "Treats an unverified item as having GSC evidence but no content-coverage conclusion",
28
+ "Uses only parameters defined in the report schema"
29
+ ],
30
+ "files": []
31
+ },
32
+ {
33
+ "id": 3,
34
+ "prompt": "So if we rewrite the titles for the top quick-wins rows, this guarantees more clicks, right? Give me the total extra clicks.",
35
+ "expected_output": "Should refuse to guarantee clicks or total the shortfall as lift. Should explain that estimatedCtrClickShortfall and the priority score are heuristics and explicitly not estimated lift. Should note average position is not a stable rank and that CTR is influenced by intent and SERP features, so a title change does not promise clicks. Should recommend recording the change and comparing a later complete window instead of forcing query wording into copy.",
36
+ "assertions": [
37
+ "Refuses to guarantee more clicks from title rewrites",
38
+ "States estimatedCtrClickShortfall and priority score are heuristics, not lift",
39
+ "Does not total the shortfall into a promised click gain",
40
+ "Notes average position is not a stable rank",
41
+ "Recommends comparing a later complete window to measure the effect",
42
+ "Warns against forcing query wording into copy"
43
+ ],
44
+ "files": []
45
+ },
46
+ {
47
+ "id": 4,
48
+ "prompt": "The run shows possiblyTruncated true and some invalidRows. There are no rows for our pricing section, so pricing has no opportunities. Agreed?",
49
+ "expected_output": "Should not read the empty pricing result as a definitive zero. Should explain that source.possiblyTruncated and selection.invalidRows mean the evidence is capped or partial, so filtered or capped evidence cannot be called an all-clear or a true zero. Should keep filtered, invalid, capped, and complete states distinct. Should recommend widening the window or thresholds, or checking the source cap, before concluding pricing has no opportunities.",
50
+ "assertions": [
51
+ "Refuses to treat the empty pricing result as a definitive zero",
52
+ "Cites possiblyTruncated and invalidRows as capped or partial evidence",
53
+ "States filtered or capped evidence cannot be an all-clear",
54
+ "Keeps filtered, invalid, capped, and complete states distinct",
55
+ "Recommends widening the window or checking the cap before concluding"
56
+ ],
57
+ "files": []
58
+ },
59
+ {
60
+ "id": 5,
61
+ "prompt": "A row sits at average position 6 for a query that isn't in the page copy. Just drop the exact query phrase into the title and H1 to lock in position 6.",
62
+ "expected_output": "Should decline to force the exact query wording into the copy and should not treat average position 6 as a locked rank. Should explain average position is averaged and varies by search, device, country, and day. Should recommend inspecting the live SERP and testing clearer snippet framing, and only improving coverage if the page genuinely misses the answer, rather than keyword-stuffing the title and H1. Should keep the action structural.",
63
+ "assertions": [
64
+ "Declines to force the exact query phrase into the title and H1",
65
+ "States average position 6 is not a locked or stable rank",
66
+ "Notes average position varies by search, device, country, and day",
67
+ "Recommends inspecting the live SERP and testing snippet framing",
68
+ "Only suggests coverage changes if the answer is genuinely missing"
69
+ ],
70
+ "files": []
71
+ },
72
+ {
73
+ "id": 6,
74
+ "prompt": "Content verification failed to fetch several of the pages. Treat those as thin pages that need a rewrite.",
75
+ "expected_output": "Should not turn a failed fetch into a thin-content verdict. Should read verification.failed and technical counts and keep a failed or unverified page at lower confidence, noting it still has GSC evidence but cannot support a content-coverage conclusion. Should recommend retrying the fetch or inspecting the page directly before recommending a rewrite. Should keep failed and verified states distinct.",
76
+ "assertions": [
77
+ "Refuses to label failed-fetch pages as thin content",
78
+ "Reads verification.failed and technical counts",
79
+ "Keeps failed or unverified pages at lower confidence",
80
+ "States the page still has GSC evidence but no content-coverage conclusion",
81
+ "Recommends retrying the fetch or inspecting the page before a rewrite"
82
+ ],
83
+ "files": []
84
+ }
85
+ ]
86
+ }