opencode-skills-collection 3.0.34 → 3.0.36

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 (269) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +16 -1
  2. package/bundled-skills/accesslint-audit/SKILL.md +115 -0
  3. package/bundled-skills/accesslint-diff/SKILL.md +81 -0
  4. package/bundled-skills/accesslint-scan/SKILL.md +47 -0
  5. package/bundled-skills/composition-patterns/SKILL.md +87 -0
  6. package/bundled-skills/composition-patterns/rules/_sections.md +29 -0
  7. package/bundled-skills/composition-patterns/rules/_template.md +24 -0
  8. package/bundled-skills/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  9. package/bundled-skills/composition-patterns/rules/architecture-compound-components.md +112 -0
  10. package/bundled-skills/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  11. package/bundled-skills/composition-patterns/rules/patterns-explicit-variants.md +100 -0
  12. package/bundled-skills/composition-patterns/rules/react19-no-forwardref.md +42 -0
  13. package/bundled-skills/composition-patterns/rules/state-context-interface.md +191 -0
  14. package/bundled-skills/composition-patterns/rules/state-decouple-implementation.md +113 -0
  15. package/bundled-skills/composition-patterns/rules/state-lift-state.md +125 -0
  16. package/bundled-skills/debugging-toolkit/SKILL.md +35 -0
  17. package/bundled-skills/deploy-to-vercel/SKILL.md +304 -0
  18. package/bundled-skills/deploy-to-vercel/resources/deploy-codex.sh +301 -0
  19. package/bundled-skills/deploy-to-vercel/resources/deploy.sh +301 -0
  20. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  21. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  22. package/bundled-skills/docs/maintainers/backups/README-2026-06-02.md +687 -0
  23. package/bundled-skills/docs/maintainers/repo-growth-seo.md +4 -4
  24. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  25. package/bundled-skills/docs/users/bundles.md +245 -1
  26. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  27. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  28. package/bundled-skills/docs/users/getting-started.md +3 -3
  29. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  30. package/bundled-skills/docs/users/plugins.md +21 -13
  31. package/bundled-skills/docs/users/specialized-plugin-roadmap.md +95 -0
  32. package/bundled-skills/docs/users/usage.md +4 -4
  33. package/bundled-skills/docs/users/visual-guide.md +4 -4
  34. package/bundled-skills/mmx-cli/SKILL.md +5 -2
  35. package/bundled-skills/nextjs-seo-indexing/SKILL.md +3 -3
  36. package/bundled-skills/polis-protocol/SKILL.md +93 -0
  37. package/bundled-skills/python-development/SKILL.md +35 -0
  38. package/bundled-skills/radix-ui-design-system/SKILL.md +2 -2
  39. package/bundled-skills/react-native-skills/SKILL.md +120 -0
  40. package/bundled-skills/react-native-skills/rules/_sections.md +86 -0
  41. package/bundled-skills/react-native-skills/rules/_template.md +28 -0
  42. package/bundled-skills/react-native-skills/rules/animation-derived-value.md +53 -0
  43. package/bundled-skills/react-native-skills/rules/animation-gesture-detector-press.md +95 -0
  44. package/bundled-skills/react-native-skills/rules/animation-gpu-properties.md +65 -0
  45. package/bundled-skills/react-native-skills/rules/design-system-compound-components.md +66 -0
  46. package/bundled-skills/react-native-skills/rules/fonts-config-plugin.md +71 -0
  47. package/bundled-skills/react-native-skills/rules/imports-design-system-folder.md +68 -0
  48. package/bundled-skills/react-native-skills/rules/js-hoist-intl.md +61 -0
  49. package/bundled-skills/react-native-skills/rules/list-performance-callbacks.md +44 -0
  50. package/bundled-skills/react-native-skills/rules/list-performance-function-references.md +132 -0
  51. package/bundled-skills/react-native-skills/rules/list-performance-images.md +53 -0
  52. package/bundled-skills/react-native-skills/rules/list-performance-inline-objects.md +97 -0
  53. package/bundled-skills/react-native-skills/rules/list-performance-item-expensive.md +94 -0
  54. package/bundled-skills/react-native-skills/rules/list-performance-item-memo.md +82 -0
  55. package/bundled-skills/react-native-skills/rules/list-performance-item-types.md +104 -0
  56. package/bundled-skills/react-native-skills/rules/list-performance-virtualize.md +67 -0
  57. package/bundled-skills/react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
  58. package/bundled-skills/react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
  59. package/bundled-skills/react-native-skills/rules/navigation-native-navigators.md +188 -0
  60. package/bundled-skills/react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
  61. package/bundled-skills/react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
  62. package/bundled-skills/react-native-skills/rules/react-state-dispatcher.md +91 -0
  63. package/bundled-skills/react-native-skills/rules/react-state-fallback.md +56 -0
  64. package/bundled-skills/react-native-skills/rules/react-state-minimize.md +65 -0
  65. package/bundled-skills/react-native-skills/rules/rendering-no-falsy-and.md +74 -0
  66. package/bundled-skills/react-native-skills/rules/rendering-text-in-text-component.md +36 -0
  67. package/bundled-skills/react-native-skills/rules/scroll-position-no-state.md +82 -0
  68. package/bundled-skills/react-native-skills/rules/state-ground-truth.md +80 -0
  69. package/bundled-skills/react-native-skills/rules/ui-expo-image.md +66 -0
  70. package/bundled-skills/react-native-skills/rules/ui-image-gallery.md +104 -0
  71. package/bundled-skills/react-native-skills/rules/ui-measure-views.md +78 -0
  72. package/bundled-skills/react-native-skills/rules/ui-menus.md +174 -0
  73. package/bundled-skills/react-native-skills/rules/ui-native-modals.md +77 -0
  74. package/bundled-skills/react-native-skills/rules/ui-pressable.md +61 -0
  75. package/bundled-skills/react-native-skills/rules/ui-safe-area-scroll.md +65 -0
  76. package/bundled-skills/react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
  77. package/bundled-skills/react-native-skills/rules/ui-styling.md +87 -0
  78. package/bundled-skills/schema-markup-generator/SKILL.md +1 -1
  79. package/bundled-skills/skill-issue/SKILL.md +73 -0
  80. package/bundled-skills/social-metadata-hardening/SKILL.md +4 -3
  81. package/bundled-skills/social-post-writer-seo/SKILL.md +19 -0
  82. package/bundled-skills/tdd-workflows/SKILL.md +35 -0
  83. package/bundled-skills/user-thoughts/SKILL.md +236 -0
  84. package/bundled-skills/user-thoughts/assets/Runtime-Template/README.ai.md +13 -0
  85. package/bundled-skills/user-thoughts/assets/Runtime-Template/define.ini +3 -0
  86. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/README.ai.md +25 -0
  87. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/backlog.md +19 -0
  88. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/dev-stack.md +7 -0
  89. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/general.md +7 -0
  90. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/plans.md +7 -0
  91. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/rules.md +7 -0
  92. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/ui/details.md +7 -0
  93. package/bundled-skills/user-thoughts/assets/Runtime-Template/mdbase/details/ui/outline.md +7 -0
  94. package/bundled-skills/user-thoughts/references/commands.md +54 -0
  95. package/bundled-skills/user-thoughts/references/edge-cases.md +84 -0
  96. package/bundled-skills/user-thoughts/references/safety.md +65 -0
  97. package/bundled-skills/user-thoughts/references/sortin.md +76 -0
  98. package/bundled-skills/user-thoughts/scripts/common.py +62 -0
  99. package/bundled-skills/user-thoughts/scripts/ignore_ops.py +125 -0
  100. package/bundled-skills/user-thoughts/scripts/init.py +63 -0
  101. package/bundled-skills/user-thoughts/scripts/show_mdbase.py +93 -0
  102. package/bundled-skills/user-thoughts/scripts/show_raw.py +42 -0
  103. package/bundled-skills/user-thoughts/scripts/sortin.py +211 -0
  104. package/bundled-skills/user-thoughts/scripts/status.py +56 -0
  105. package/bundled-skills/user-thoughts/scripts/toggle.py +68 -0
  106. package/bundled-skills/user-thoughts/scripts/write_raw.py +106 -0
  107. package/bundled-skills/vercel-cli-with-tokens/SKILL.md +361 -0
  108. package/bundled-skills/vercel-optimize/CONTRIBUTING.md +41 -0
  109. package/bundled-skills/vercel-optimize/SKILL.md +331 -0
  110. package/bundled-skills/vercel-optimize/lib/auth-route.mjs +23 -0
  111. package/bundled-skills/vercel-optimize/lib/budget-summary.mjs +182 -0
  112. package/bundled-skills/vercel-optimize/lib/citations.mjs +139 -0
  113. package/bundled-skills/vercel-optimize/lib/cost-coverage.mjs +143 -0
  114. package/bundled-skills/vercel-optimize/lib/dedup-recs.mjs +325 -0
  115. package/bundled-skills/vercel-optimize/lib/deep-dive.mjs +350 -0
  116. package/bundled-skills/vercel-optimize/lib/display-labels.mjs +185 -0
  117. package/bundled-skills/vercel-optimize/lib/extract-claims.mjs +550 -0
  118. package/bundled-skills/vercel-optimize/lib/framework-support.mjs +67 -0
  119. package/bundled-skills/vercel-optimize/lib/gates/build-minutes-fanout.mjs +69 -0
  120. package/bundled-skills/vercel-optimize/lib/gates/cold-start.mjs +66 -0
  121. package/bundled-skills/vercel-optimize/lib/gates/contract.mjs +79 -0
  122. package/bundled-skills/vercel-optimize/lib/gates/cwv-poor.mjs +87 -0
  123. package/bundled-skills/vercel-optimize/lib/gates/external-api-slow.mjs +55 -0
  124. package/bundled-skills/vercel-optimize/lib/gates/hard-gates.mjs +73 -0
  125. package/bundled-skills/vercel-optimize/lib/gates/index.mjs +45 -0
  126. package/bundled-skills/vercel-optimize/lib/gates/isr-overrevalidation.mjs +62 -0
  127. package/bundled-skills/vercel-optimize/lib/gates/middleware-heavy.mjs +51 -0
  128. package/bundled-skills/vercel-optimize/lib/gates/observability-events-attribution.mjs +56 -0
  129. package/bundled-skills/vercel-optimize/lib/gates/platform-bot-protection.mjs +115 -0
  130. package/bundled-skills/vercel-optimize/lib/gates/platform-fluid-compute.mjs +83 -0
  131. package/bundled-skills/vercel-optimize/lib/gates/region-misconfig.mjs +64 -0
  132. package/bundled-skills/vercel-optimize/lib/gates/route-errors.mjs +80 -0
  133. package/bundled-skills/vercel-optimize/lib/gates/scanner-driven.mjs +122 -0
  134. package/bundled-skills/vercel-optimize/lib/gates/select-candidates.mjs +134 -0
  135. package/bundled-skills/vercel-optimize/lib/gates/slow-route.mjs +88 -0
  136. package/bundled-skills/vercel-optimize/lib/gates/types.d.ts +38 -0
  137. package/bundled-skills/vercel-optimize/lib/gates/uncached-route.mjs +93 -0
  138. package/bundled-skills/vercel-optimize/lib/gates/usage-spike-triage.mjs +121 -0
  139. package/bundled-skills/vercel-optimize/lib/grade-recommendation.mjs +155 -0
  140. package/bundled-skills/vercel-optimize/lib/impact-label.mjs +126 -0
  141. package/bundled-skills/vercel-optimize/lib/impact-magnitude.mjs +60 -0
  142. package/bundled-skills/vercel-optimize/lib/investigation-brief.mjs +610 -0
  143. package/bundled-skills/vercel-optimize/lib/observation-safety.mjs +174 -0
  144. package/bundled-skills/vercel-optimize/lib/project-facts.mjs +99 -0
  145. package/bundled-skills/vercel-optimize/lib/queries.mjs +315 -0
  146. package/bundled-skills/vercel-optimize/lib/reconcile-candidates.mjs +372 -0
  147. package/bundled-skills/vercel-optimize/lib/render-report.mjs +955 -0
  148. package/bundled-skills/vercel-optimize/lib/repo-root.mjs +86 -0
  149. package/bundled-skills/vercel-optimize/lib/route-normalize.mjs +220 -0
  150. package/bundled-skills/vercel-optimize/lib/sanitizers/bot-protection-certainty.mjs +38 -0
  151. package/bundled-skills/vercel-optimize/lib/sanitizers/cache-tag-invalidation-certainty.mjs +30 -0
  152. package/bundled-skills/vercel-optimize/lib/sanitizers/count-correct.mjs +52 -0
  153. package/bundled-skills/vercel-optimize/lib/sanitizers/function-duration-invocations.mjs +38 -0
  154. package/bundled-skills/vercel-optimize/lib/sanitizers/index.mjs +79 -0
  155. package/bundled-skills/vercel-optimize/lib/sanitizers/middleware-conflict.mjs +36 -0
  156. package/bundled-skills/vercel-optimize/lib/sanitizers/missing-citation.mjs +16 -0
  157. package/bundled-skills/vercel-optimize/lib/sanitizers/pre-release.mjs +74 -0
  158. package/bundled-skills/vercel-optimize/lib/sanitizers/rate-limit.mjs +67 -0
  159. package/bundled-skills/vercel-optimize/lib/sanitizers/rendering-mode-mislabel.mjs +38 -0
  160. package/bundled-skills/vercel-optimize/lib/sanitizers/undeclared-dep.mjs +78 -0
  161. package/bundled-skills/vercel-optimize/lib/sanitizers/vercel-directive-strip.mjs +37 -0
  162. package/bundled-skills/vercel-optimize/lib/sanitizers/window-units.mjs +32 -0
  163. package/bundled-skills/vercel-optimize/lib/scanners/cache-components-suspense-dedupe.mjs +109 -0
  164. package/bundled-skills/vercel-optimize/lib/scanners/edge-heavy-import.mjs +94 -0
  165. package/bundled-skills/vercel-optimize/lib/scanners/force-dynamic.mjs +42 -0
  166. package/bundled-skills/vercel-optimize/lib/scanners/headers-in-page.mjs +44 -0
  167. package/bundled-skills/vercel-optimize/lib/scanners/index.mjs +35 -0
  168. package/bundled-skills/vercel-optimize/lib/scanners/large-static-asset.mjs +92 -0
  169. package/bundled-skills/vercel-optimize/lib/scanners/max-age-without-s-maxage.mjs +42 -0
  170. package/bundled-skills/vercel-optimize/lib/scanners/middleware-broad-matcher.mjs +55 -0
  171. package/bundled-skills/vercel-optimize/lib/scanners/missing-cache-headers.mjs +90 -0
  172. package/bundled-skills/vercel-optimize/lib/scanners/prisma-include-tree.mjs +42 -0
  173. package/bundled-skills/vercel-optimize/lib/scanners/region-pin-in-config.mjs +88 -0
  174. package/bundled-skills/vercel-optimize/lib/scanners/source-maps-production.mjs +36 -0
  175. package/bundled-skills/vercel-optimize/lib/scanners/sveltekit-prerender-missing.mjs +43 -0
  176. package/bundled-skills/vercel-optimize/lib/scanners/turbo-force-bypass.mjs +129 -0
  177. package/bundled-skills/vercel-optimize/lib/scanners/unoptimized-image.mjs +113 -0
  178. package/bundled-skills/vercel-optimize/lib/scanners/use-cache-date-stamp.mjs +106 -0
  179. package/bundled-skills/vercel-optimize/lib/support-topics.mjs +355 -0
  180. package/bundled-skills/vercel-optimize/lib/throttle.mjs +273 -0
  181. package/bundled-skills/vercel-optimize/lib/util.mjs +17 -0
  182. package/bundled-skills/vercel-optimize/lib/vercel.mjs +784 -0
  183. package/bundled-skills/vercel-optimize/lib/verify-claim.mjs +1296 -0
  184. package/bundled-skills/vercel-optimize/lib/workspace-resolver.mjs +521 -0
  185. package/bundled-skills/vercel-optimize/references/candidates.md +176 -0
  186. package/bundled-skills/vercel-optimize/references/data-collection.md +218 -0
  187. package/bundled-skills/vercel-optimize/references/docs-library.json +683 -0
  188. package/bundled-skills/vercel-optimize/references/doctrine.md +105 -0
  189. package/bundled-skills/vercel-optimize/references/observability-plus.md +108 -0
  190. package/bundled-skills/vercel-optimize/references/playbooks/README.md +53 -0
  191. package/bundled-skills/vercel-optimize/references/playbooks/ai-application.md +32 -0
  192. package/bundled-skills/vercel-optimize/references/playbooks/api-service.md +30 -0
  193. package/bundled-skills/vercel-optimize/references/playbooks/content-site.md +30 -0
  194. package/bundled-skills/vercel-optimize/references/playbooks/ecommerce.md +30 -0
  195. package/bundled-skills/vercel-optimize/references/playbooks/marketing.md +30 -0
  196. package/bundled-skills/vercel-optimize/references/playbooks/saas.md +31 -0
  197. package/bundled-skills/vercel-optimize/references/playbooks/sveltekit.md +75 -0
  198. package/bundled-skills/vercel-optimize/references/recommendations.md +203 -0
  199. package/bundled-skills/vercel-optimize/references/scanner-patterns.md +251 -0
  200. package/bundled-skills/vercel-optimize/references/scoring.md +205 -0
  201. package/bundled-skills/vercel-optimize/references/support-topics/README.md +46 -0
  202. package/bundled-skills/vercel-optimize/references/support-topics/astro-edge-middleware-scope.md +22 -0
  203. package/bundled-skills/vercel-optimize/references/support-topics/astro-output-mode-and-isr.md +22 -0
  204. package/bundled-skills/vercel-optimize/references/support-topics/auth-preserving-parallelization.md +22 -0
  205. package/bundled-skills/vercel-optimize/references/support-topics/bot-protection-product-guardrails.md +22 -0
  206. package/bundled-skills/vercel-optimize/references/support-topics/build-minutes-monorepo-fanout.md +23 -0
  207. package/bundled-skills/vercel-optimize/references/support-topics/cache-components-static-shell-boundaries.md +22 -0
  208. package/bundled-skills/vercel-optimize/references/support-topics/cache-components-suspense-dedupe-pitfall.md +23 -0
  209. package/bundled-skills/vercel-optimize/references/support-topics/cdn-cache-auth-safety.md +22 -0
  210. package/bundled-skills/vercel-optimize/references/support-topics/cold-start-initialization-bundle.md +22 -0
  211. package/bundled-skills/vercel-optimize/references/support-topics/core-web-vitals-client-bottlenecks.md +22 -0
  212. package/bundled-skills/vercel-optimize/references/support-topics/database-egress-pooling-region.md +22 -0
  213. package/bundled-skills/vercel-optimize/references/support-topics/dynamic-rendering-traps.md +22 -0
  214. package/bundled-skills/vercel-optimize/references/support-topics/external-api-critical-path-platform.md +22 -0
  215. package/bundled-skills/vercel-optimize/references/support-topics/external-api-critical-path.md +22 -0
  216. package/bundled-skills/vercel-optimize/references/support-topics/fast-data-transfer-payloads.md +22 -0
  217. package/bundled-skills/vercel-optimize/references/support-topics/fluid-compute-caveats.md +22 -0
  218. package/bundled-skills/vercel-optimize/references/support-topics/function-duration-io-and-after.md +22 -0
  219. package/bundled-skills/vercel-optimize/references/support-topics/function-invocation-reduction.md +22 -0
  220. package/bundled-skills/vercel-optimize/references/support-topics/function-region-misconfiguration-ttfb.md +23 -0
  221. package/bundled-skills/vercel-optimize/references/support-topics/image-optimization-cost-control.md +22 -0
  222. package/bundled-skills/vercel-optimize/references/support-topics/isr-revalidation-static-generation.md +22 -0
  223. package/bundled-skills/vercel-optimize/references/support-topics/middleware-proxy-edge-cost.md +22 -0
  224. package/bundled-skills/vercel-optimize/references/support-topics/next-fetch-revalidate-floor.md +22 -0
  225. package/bundled-skills/vercel-optimize/references/support-topics/next-font-cls-self-hosting.md +23 -0
  226. package/bundled-skills/vercel-optimize/references/support-topics/next-heavy-ui-lazy-load-boundaries.md +23 -0
  227. package/bundled-skills/vercel-optimize/references/support-topics/next-image-lcp-preload-sizes.md +23 -0
  228. package/bundled-skills/vercel-optimize/references/support-topics/next-route-handler-get-cache-defaults.md +22 -0
  229. package/bundled-skills/vercel-optimize/references/support-topics/next-script-third-party-strategy.md +23 -0
  230. package/bundled-skills/vercel-optimize/references/support-topics/nextjs-version-cache-semantics.md +22 -0
  231. package/bundled-skills/vercel-optimize/references/support-topics/not-found-catchall-request-waste.md +23 -0
  232. package/bundled-skills/vercel-optimize/references/support-topics/nuxt-route-rules-cache-isr.md +22 -0
  233. package/bundled-skills/vercel-optimize/references/support-topics/observability-events-cost-attribution.md +22 -0
  234. package/bundled-skills/vercel-optimize/references/support-topics/post-response-work-waituntil.md +22 -0
  235. package/bundled-skills/vercel-optimize/references/support-topics/route-error-durable-offload.md +22 -0
  236. package/bundled-skills/vercel-optimize/references/support-topics/route-error-runtime-limits.md +22 -0
  237. package/bundled-skills/vercel-optimize/references/support-topics/runtime-cache-reusable-data.md +22 -0
  238. package/bundled-skills/vercel-optimize/references/support-topics/sveltekit-isr-prerender-safety.md +22 -0
  239. package/bundled-skills/vercel-optimize/references/support-topics/sveltekit-split-cold-start-tradeoff.md +22 -0
  240. package/bundled-skills/vercel-optimize/references/support-topics/usage-spike-triage.md +22 -0
  241. package/bundled-skills/vercel-optimize/references/support-topics/use-cache-date-stamp-isr-write-amplifier.md +23 -0
  242. package/bundled-skills/vercel-optimize/references/support-topics/use-cache-remote-shared-origin-data.md +22 -0
  243. package/bundled-skills/vercel-optimize/references/support-topics/workflow-resumable-stream-routes.md +23 -0
  244. package/bundled-skills/vercel-optimize/references/verification.md +102 -0
  245. package/bundled-skills/vercel-optimize/references/voice.md +76 -0
  246. package/bundled-skills/vercel-optimize/scripts/budget-summary.mjs +56 -0
  247. package/bundled-skills/vercel-optimize/scripts/build-docs.mjs +74 -0
  248. package/bundled-skills/vercel-optimize/scripts/check-citations.mjs +81 -0
  249. package/bundled-skills/vercel-optimize/scripts/check-docs-fresh.mjs +93 -0
  250. package/bundled-skills/vercel-optimize/scripts/collect-signals.mjs +576 -0
  251. package/bundled-skills/vercel-optimize/scripts/collect-sub-agent-outputs.mjs +296 -0
  252. package/bundled-skills/vercel-optimize/scripts/deep-dive.mjs +319 -0
  253. package/bundled-skills/vercel-optimize/scripts/gate-investigations.mjs +166 -0
  254. package/bundled-skills/vercel-optimize/scripts/merge-signals.mjs +192 -0
  255. package/bundled-skills/vercel-optimize/scripts/prepare-investigation-brief.mjs +231 -0
  256. package/bundled-skills/vercel-optimize/scripts/reconcile-candidates.mjs +62 -0
  257. package/bundled-skills/vercel-optimize/scripts/render-report.mjs +437 -0
  258. package/bundled-skills/vercel-optimize/scripts/scan-codebase.mjs +313 -0
  259. package/bundled-skills/vercel-optimize/scripts/verify-and-regen.mjs +346 -0
  260. package/bundled-skills/vercel-optimize/scripts/verify-finding.mjs +19 -0
  261. package/bundled-skills/vercel-react-view-transitions/SKILL.md +327 -0
  262. package/bundled-skills/vercel-react-view-transitions/references/css-recipes.md +242 -0
  263. package/bundled-skills/vercel-react-view-transitions/references/implementation.md +182 -0
  264. package/bundled-skills/vercel-react-view-transitions/references/nextjs.md +176 -0
  265. package/bundled-skills/vercel-react-view-transitions/references/patterns.md +262 -0
  266. package/bundled-skills/vibe-code-cleanup/SKILL.md +4 -4
  267. package/bundled-skills/vibecode-production-qa-validator/SKILL.md +3 -2
  268. package/package.json +1 -1
  269. package/skills_index.json +338 -4
@@ -0,0 +1,174 @@
1
+ export function splitCustomerSafeObservations(observations, abstentions = [], signals = {}) {
2
+ const safe = [];
3
+ const heldBack = [];
4
+ for (const observation of Array.isArray(observations) ? observations : []) {
5
+ const unsafeReason = unsupportedObservationReason(observation, abstentions, signals);
6
+ if (unsafeReason) {
7
+ heldBack.push({
8
+ candidateRef: observation?.candidateRef ?? null,
9
+ reason: unsafeReason,
10
+ needsEvidence: true,
11
+ });
12
+ } else {
13
+ safe.push(observation);
14
+ }
15
+ }
16
+ return { observations: safe, heldBackObservations: heldBack };
17
+ }
18
+
19
+ function unsupportedObservationReason(observation, abstentions = [], signals = {}) {
20
+ if (contradictsNoChangeReason(observation, abstentions)) {
21
+ return 'This observation repeated an action that another investigation rejected. Re-run with a single scoped candidate before applying it.';
22
+ }
23
+ if (hasUnsupportedWafBotCategoryClaim(observation)) {
24
+ return 'This observation described an Observability bot category as a WAF-rule condition without supported rule evidence. Re-run with documented WAF condition evidence before applying it.';
25
+ }
26
+ if (hasUnsafeBotProtectionObservation(observation)) {
27
+ return 'This observation recommended Bot Protection or WAF changes without a staged safe-rollout plan and allowlist review. Promote it to a verified platform recommendation before applying it.';
28
+ }
29
+ if (hasStaleNextCacheApiObservation(observation, signals)) {
30
+ return 'This observation used a cache API that does not match the detected framework-version evidence. Re-run with the current Next.js cache evidence before applying it.';
31
+ }
32
+ if (hasUnsupportedFrameworkCausalClaim(observation)) {
33
+ return 'This observation made a framework-specific cause claim that verification could not support. Re-run with runtime logs or official framework evidence before applying it.';
34
+ }
35
+ if (hasUnsupportedStaticGenerationClaim(observation)) {
36
+ return 'This observation made a static-generation behavior claim that verification could not support. Re-run with route-manifest or runtime evidence before applying it.';
37
+ }
38
+ if (hasUnsupportedSourceAbsenceClaim(observation)) {
39
+ return 'This observation made a source-file absence claim that verification could not support. Re-run with a file-existence check or runtime logs before applying it.';
40
+ }
41
+ if (hasUnsupportedCacheLifeCdnClaim(observation)) {
42
+ return 'This observation depended on an unsupported cacheLife-to-CDN claim. Re-run with production header evidence before applying it.';
43
+ }
44
+ if (hasUnsupportedRuntimeRootCauseClaim(observation)) {
45
+ return 'This observation made a runtime root-cause claim that needs log, stack, or upstream response evidence before it can ship.';
46
+ }
47
+ if (hasImplementationGradeObservationAction(observation)) {
48
+ return 'This observation described an implementation change that needs the ready-to-apply recommendation evidence bar before it can ship.';
49
+ }
50
+ return null;
51
+ }
52
+
53
+ function observationText(observation) {
54
+ return [
55
+ observation?.summary,
56
+ observation?.evidence,
57
+ observation?.suggestedAction,
58
+ ].filter(Boolean).join(' ');
59
+ }
60
+
61
+ function evidenceText(observation) {
62
+ return [
63
+ observation?.summary,
64
+ observation?.evidence,
65
+ ].filter(Boolean).join(' ');
66
+ }
67
+
68
+ function hasUnsupportedWafBotCategoryClaim(observation) {
69
+ const text = observationText(observation);
70
+ if (!/\bWAF\b/i.test(text)) return false;
71
+ return /\bbot_category\s*=/i.test(text) ||
72
+ /\btarget(?:ing)?\s+(?:browser_impersonation|automated_browser|ecommerce|monitor)\b/i.test(text);
73
+ }
74
+
75
+ function hasUnsafeBotProtectionObservation(observation) {
76
+ const text = observationText(observation);
77
+ if (!/\b(?:Bot Protection|BotID|bot_filter|WAF|managed bot rules?)\b/i.test(text)) return false;
78
+ const recommendsAction = /\b(?:enable|add|create|configure|challenge|deny|block|rate-limit|target)\b/i.test(String(observation?.suggestedAction ?? ''));
79
+ if (!recommendsAction) return false;
80
+ const hasSafeRollout = /\b(?:staged|log mode|log action|dry run)\b/i.test(text);
81
+ const hasAllowlist = /\ballowlist|exclusions?\b/i.test(text);
82
+ return !(hasSafeRollout && hasAllowlist);
83
+ }
84
+
85
+ function hasStaleNextCacheApiObservation(observation, signals = {}) {
86
+ const text = observationText(observation);
87
+ if (!/\bunstable_cache\b/.test(text)) return false;
88
+ if (signals?.stack?.framework !== 'next') return false;
89
+ const major = parseInt(String(signals?.stack?.frameworkVersion ?? '').match(/\d+/)?.[0] ?? '', 10);
90
+ return Number.isFinite(major) && major >= 16;
91
+ }
92
+
93
+ function hasImplementationGradeObservationAction(observation) {
94
+ const action = String(observation?.suggestedAction ?? '');
95
+ if (action.trim() === '') return false;
96
+ if (/\b(?:use cache:\s*remote|unstable_cache|Cache-Control|s-maxage|cacheLife|export const revalidate|checkBotId|BotID)\b/i.test(action)) return true;
97
+ return /\b(?:enable|add|wrap|apply|move|parallelize|set|create|configure|deny|challenge|block|fix|replace|refactor|rewrite|upgrade|downgrade)\b/i.test(action) ||
98
+ /\bcache\s+(?:the|this|that|shared|public|origin|response|route|data|lookup|fetch|helper)\b/i.test(action) ||
99
+ /\bturn\s+(?:on|off)\b/i.test(action) ||
100
+ /\bswitch\s+(?:to|from|the|this)\b/i.test(action) ||
101
+ /\buse\s+Promise\.all\b/i.test(action) ||
102
+ /\b(?:raise|lower|increase|decrease)\s+(?:the\s+)?(?:TTL|timeout|memory|CPU|cache|cache lifetime|duration)\b/i.test(action);
103
+ }
104
+
105
+ function contradictsNoChangeReason(observation, abstentions) {
106
+ const target = candidateTarget(observation?.candidateRef);
107
+ if (!target) return false;
108
+ const lowerObservationText = observationText(observation).toLowerCase();
109
+ const relevantReasons = abstentions
110
+ .filter((a) => candidateTarget(a?.candidateRef) === target)
111
+ .map((a) => String(a?.reason ?? '').toLowerCase());
112
+ if (relevantReasons.length === 0) return false;
113
+
114
+ if (/\bparalleliz(?:e|ing)\b/.test(lowerObservationText) &&
115
+ /\bgetsession\b/.test(lowerObservationText) &&
116
+ relevantReasons.some((reason) => /\bgetsession\b/.test(reason) && /\b(?:gates?|redirect|auth-preserving|blocked)\b/.test(reason))) {
117
+ return true;
118
+ }
119
+ return false;
120
+ }
121
+
122
+ function candidateTarget(ref) {
123
+ if (typeof ref !== 'string') return null;
124
+ const idx = ref.indexOf(':');
125
+ if (idx === -1) return null;
126
+ return ref.slice(idx + 1);
127
+ }
128
+
129
+ function hasUnsupportedFrameworkCausalClaim(observation) {
130
+ const text = observationText(observation).toLowerCase();
131
+ if (!text.includes('notfound') || !text.includes('use cache')) return false;
132
+ return (
133
+ /known next\.js cache components edge case/.test(text) ||
134
+ /next\.js\s+\d+(?:\.\d+)?[^.]{0,120}treats[^.]{0,120}dynamic api/.test(text) ||
135
+ /can surface as 5xx/.test(text) ||
136
+ /surface as 500/.test(text) ||
137
+ /instead of throwing inside (?:the )?cache/.test(text) ||
138
+ /cache boundary/.test(text)
139
+ );
140
+ }
141
+
142
+ function hasUnsupportedStaticGenerationClaim(observation) {
143
+ const text = observationText(observation).toLowerCase();
144
+ if (!/\bgeneratestaticparams\b/.test(text)) return false;
145
+ return /\b(?:returns?\s*(?:an\s+)?empty|\[\])\b[^.\n]{0,240}\b(?:every request|on[- ]demand|no params? (?:are )?prebuilt|populate generatestaticparams|served from (?:the )?cdn|hit bucket|cachebreakdown)\b/i.test(text) ||
146
+ /\b(?:every request|on[- ]demand|no params? (?:are )?prebuilt|populate generatestaticparams|served from (?:the )?cdn|hit bucket|cachebreakdown)\b[^.\n]{0,240}\b(?:returns?\s*(?:an\s+)?empty|\[\])\b/i.test(text) ||
147
+ /\bdynamic\s*=\s*['"`]error['"`]\b[^.\n]{0,240}\b(?:generatestaticparams|dynamicparams|every request|on[- ]demand)\b/i.test(text);
148
+ }
149
+
150
+ function hasUnsupportedSourceAbsenceClaim(observation) {
151
+ const ref = String(observation?.candidateRef ?? '');
152
+ if (!ref.startsWith('route_errors:')) return false;
153
+ const text = observationText(observation).toLowerCase();
154
+ return /\b(?:enoent|no\s+(?:matching|corresponding)\s+(?:mdx|file|post)|missing\s+(?:mdx|file|post)|does\s+not\s+exist|not\s+found\s+on\s+disk)\b/.test(text);
155
+ }
156
+
157
+ function hasUnsupportedCacheLifeCdnClaim(observation) {
158
+ return hasUnsupportedCacheLifeCdnText(observationText(observation));
159
+ }
160
+
161
+ export function hasUnsupportedCacheLifeCdnText(text) {
162
+ if (typeof text !== 'string' || !/\bcacheLife\b/i.test(text)) return false;
163
+ if (/\btoLaunch-\d+\b/i.test(text)) return true;
164
+ return /\bcacheLife\b[^.\n]{0,240}\b(?:Cache-Control|s-maxage|CDN|edge cache|cache breakdown|x-vercel-cache|HIT|MISS|function (?:still )?runs per request|every request invokes the function|canonical|toLaunch-\d+)\b/i.test(text) ||
165
+ /\b(?:Cache-Control|s-maxage|CDN|edge cache|cache breakdown|x-vercel-cache|HIT|MISS|function (?:still )?runs per request|every request invokes the function|canonical|toLaunch-\d+)\b[^.\n]{0,240}\bcacheLife\b/i.test(text) ||
166
+ /\b(?:no|never|without|missing)\s+cacheLife\b[^.\n]{0,240}\b(?:no|not|never|0%|every|per request|function)\b[^.\n]{0,120}\b(?:cache|cached|hit|runs?|invoke)/i.test(text);
167
+ }
168
+
169
+ function hasUnsupportedRuntimeRootCauseClaim(observation) {
170
+ const text = observationText(observation);
171
+ if (!/\b(?:caused by|root cause|responsible for failures|would produce)\b/i.test(text)) return false;
172
+ if (!/\b(?:5xx|500|error|failures?)\b/i.test(text)) return false;
173
+ return !/\b(?:logs?\s+(?:show|confirm|include|contain)|stack\s+(?:shows|trace|evidence)|trace\s+(?:shows|confirms)|exception\s+(?:shows|confirms)|response body\s+(?:shows|confirms)|runtime evidence)\b/i.test(evidenceText(observation));
174
+ }
@@ -0,0 +1,99 @@
1
+ // Single source for "already on" project facts. Feeds report Strengths, sub-agent brief, and verifier contradiction check.
2
+ // contradictPhrases must lowercase exactly — verifier does case-insensitive substring match.
3
+
4
+ // Stable order = byte-identical brief output. Empty result when project config didn't load — don't pretend.
5
+ export function deriveProjectFacts(signals) {
6
+ const out = [];
7
+ const cfg = signals?.project?.defaultResourceConfig;
8
+ const projectErr = signals?.project?.error;
9
+ if (!cfg || projectErr) return out;
10
+
11
+ if (cfg.fluid === true) {
12
+ out.push({
13
+ id: 'fluid_compute',
14
+ strength: 'Fluid Compute is enabled (`defaultResourceConfig.fluid=true`) — instance reuse + reduced cold starts active.',
15
+ briefLine: 'Fluid Compute is ENABLED on this project (`defaultResourceConfig.fluid=true`). Do not recommend toggling it on.',
16
+ contradictPhrases: [
17
+ 'enable fluid compute',
18
+ 'enable fluid',
19
+ 'turn on fluid compute',
20
+ 'switch to fluid compute',
21
+ 'migrate to fluid compute',
22
+ 'opt in to fluid compute',
23
+ ],
24
+ });
25
+ }
26
+ if (cfg.elasticConcurrencyEnabled === true) {
27
+ out.push({
28
+ id: 'in_function_concurrency',
29
+ strength: 'In-function concurrency is enabled — multiple invocations share a single function instance, lowering active CPU costs on I/O-bound work.',
30
+ briefLine: 'In-function concurrency is ENABLED. Do not recommend toggling it on.',
31
+ contradictPhrases: [
32
+ 'enable in-function concurrency',
33
+ 'enable elastic concurrency',
34
+ 'turn on in-function concurrency',
35
+ 'enable concurrent invocations',
36
+ ],
37
+ });
38
+ }
39
+ if (cfg.functionDefaultMemoryType === 'standard') {
40
+ out.push({
41
+ id: 'memory_standard',
42
+ strength: 'Function memory tier: Standard (2GB) — the cost-efficient default; upgrade to Performance (4GB) only with memory, CPU-bound, or latency-sensitive route evidence.',
43
+ briefLine: 'Function memory tier is Standard (2GB), the cost-efficient default. Recommending an upgrade to Performance (4GB) requires memory, CPU-bound, or latency-sensitive route evidence.',
44
+ contradictPhrases: [],
45
+ });
46
+ } else if (cfg.functionDefaultMemoryType === 'performance') {
47
+ out.push({
48
+ id: 'memory_performance',
49
+ strength: 'Function memory tier: **Performance (4GB)** — verify this is intentional; Performance costs ~2x Standard. If your routes don\'t saturate Standard\'s memory headroom, downgrade.',
50
+ briefLine: 'Function memory tier is Performance (4GB). Do not recommend upgrading further — the next valid tier change is downgrading to Standard.',
51
+ contradictPhrases: [
52
+ 'upgrade memory to performance',
53
+ 'upgrade to performance memory',
54
+ 'switch to performance memory',
55
+ 'enable performance memory',
56
+ ],
57
+ });
58
+ }
59
+ if (Array.isArray(cfg.functionDefaultRegions) && cfg.functionDefaultRegions.length > 0) {
60
+ const r = cfg.functionDefaultRegions;
61
+ out.push({
62
+ id: 'function_regions',
63
+ strength: `Function regions: \`${r.join(', ')}\` (${r.length === 1 ? 'single region' : 'multi-region'}).`,
64
+ briefLine: `Function regions configured: ${r.join(', ')}. If your rec hinges on region placement, it must accept this configuration as the starting point.`,
65
+ contradictPhrases: [],
66
+ });
67
+ }
68
+ if (cfg.functionZeroConfigFailover === true) {
69
+ out.push({
70
+ id: 'zero_config_failover',
71
+ strength: 'Function failover is enabled in project config.',
72
+ briefLine: 'Function failover is ENABLED in project config. Do not recommend enabling it.',
73
+ contradictPhrases: [
74
+ 'enable zero-config failover',
75
+ 'enable multi-region failover',
76
+ 'turn on zero-config failover',
77
+ ],
78
+ });
79
+ }
80
+ return out;
81
+ }
82
+
83
+ // `why` excluded — citing a fact as evidence ("fluid is on, so …") is legitimate, not contradiction.
84
+ export function findRecContradictions(rec, facts) {
85
+ if (!rec || typeof rec !== 'object') return [];
86
+ if (!Array.isArray(facts) || facts.length === 0) return [];
87
+ const haystack = [
88
+ rec.what,
89
+ rec.fix,
90
+ rec.desiredBehavior,
91
+ rec.currentBehavior,
92
+ ]
93
+ .map((s) => (typeof s === 'string' ? s.toLowerCase() : ''))
94
+ .join('\n');
95
+ if (!haystack) return [];
96
+ return facts.filter((f) =>
97
+ (f.contradictPhrases ?? []).some((p) => haystack.includes(p.toLowerCase()))
98
+ );
99
+ }
@@ -0,0 +1,315 @@
1
+ // Declarative metric-query registry. Single source for every `vercel metrics ...` call.
2
+ //
3
+ // CLI default --since is 1h. Mixing 1h with 14d windows silently produces incompatible rollups — every query MUST pass since: TIME_WINDOW. test/time-window.test.mjs enforces this.
4
+ // 14d: long enough for weekly cycles, short enough to surface recent regressions before stale data dilutes them.
5
+
6
+ import { normalizeSummary } from './vercel.mjs';
7
+
8
+ export const TIME_WINDOW = '14d';
9
+
10
+ // CLI default cardinality cap is 10 — too small for a typical app.
11
+ const ROUTE_LIMIT = 200;
12
+ const HOST_LIMIT = 50;
13
+ const DIM_LIMIT = 50;
14
+
15
+ // CLI emits value under `<metric_id_with_underscores>_<aggregation>` (e.g. `vercel_request_count_sum`).
16
+ function defaultNormalize(metricId, aggregation, groupBy) {
17
+ return (resp) => ({ rows: normalizeSummary(resp, metricId, aggregation, groupBy) });
18
+ }
19
+
20
+ // Collapse (route × function_start_type) rows into one row per route. Observed values: "cold", "hot", "prewarmed".
21
+ function normalizeColdStart(metricId, aggregation) {
22
+ return (resp) => {
23
+ const rows = normalizeSummary(resp, metricId, aggregation, ['route', 'function_start_type']);
24
+ const byRoute = new Map();
25
+ for (const r of rows) {
26
+ if (!r.route) continue;
27
+ const prior = byRoute.get(r.route) ?? { route: r.route, total: 0, coldCount: 0, warmCount: 0, prewarmedCount: 0 };
28
+ const v = r.value ?? 0;
29
+ prior.total += v;
30
+ if (r.function_start_type === 'cold') prior.coldCount += v;
31
+ else if (r.function_start_type === 'hot') prior.warmCount += v;
32
+ else if (r.function_start_type === 'prewarmed') prior.prewarmedCount += v;
33
+ byRoute.set(r.route, prior);
34
+ }
35
+ return {
36
+ rows: [...byRoute.values()].map((r) => ({
37
+ ...r,
38
+ coldPct: r.total > 0 ? r.coldCount / r.total : 0,
39
+ })),
40
+ };
41
+ };
42
+ }
43
+
44
+ export const QUERIES = [
45
+ {
46
+ id: 'requestsByRouteCache',
47
+ metricId: 'vercel.request.count',
48
+ aggregation: 'sum',
49
+ groupBy: ['route', 'cache_result'],
50
+ limit: ROUTE_LIMIT,
51
+ description: 'Request count per route × cache_result. Source of cache hit rate; total invocations folds across cache_result.',
52
+ },
53
+ {
54
+ id: 'fnDurationP95ByRoute',
55
+ metricId: 'vercel.function_invocation.function_duration_ms',
56
+ aggregation: 'p95',
57
+ groupBy: ['route'],
58
+ limit: ROUTE_LIMIT,
59
+ description: 'p95 wall-clock function duration per route. Canonical slow-route signal.',
60
+ },
61
+ {
62
+ id: 'requestsByRouteStatus',
63
+ metricId: 'vercel.request.count',
64
+ aggregation: 'sum',
65
+ groupBy: ['route', 'http_status'],
66
+ limit: ROUTE_LIMIT,
67
+ description: 'Request count per route × http_status. Compatibility fallback for older route_errors fixtures.',
68
+ },
69
+ {
70
+ id: 'fnStatusByRoute',
71
+ metricId: 'vercel.function_invocation.count',
72
+ aggregation: 'sum',
73
+ groupBy: ['route', 'http_status'],
74
+ limit: ROUTE_LIMIT,
75
+ description: 'Function invocation count per route × http_status. Canonical 5xx source for slow_route disqualification and route_errors.',
76
+ },
77
+ {
78
+ id: 'requestsByRouteMethod',
79
+ metricId: 'vercel.request.count',
80
+ aggregation: 'sum',
81
+ groupBy: ['route', 'request_method'],
82
+ limit: ROUTE_LIMIT,
83
+ description: 'Request count per route × request_method. Uncached_route gate uses this to skip mostly-POST routes (Server Actions, mutations) where 0% cache is correct behavior.',
84
+ },
85
+ {
86
+ id: 'externalApiP75',
87
+ metricId: 'vercel.external_api_request.request_duration_ms',
88
+ aggregation: 'p75',
89
+ groupBy: ['origin_hostname'],
90
+ limit: HOST_LIMIT,
91
+ description: 'p75 external API duration per origin hostname.',
92
+ },
93
+
94
+ {
95
+ id: 'fnStartTypeByRoute',
96
+ metricId: 'vercel.function_invocation.count',
97
+ aggregation: 'sum',
98
+ groupBy: ['route', 'function_start_type'],
99
+ limit: ROUTE_LIMIT,
100
+ description: 'Function invocation count split by cold | hot | prewarmed. Feeds cold_start gate.',
101
+ normalizer: normalizeColdStart('vercel.function_invocation.count', 'sum'),
102
+ },
103
+ {
104
+ id: 'fnGbHrByRoute',
105
+ metricId: 'vercel.function_invocation.function_duration_gbhr',
106
+ aggregation: 'sum',
107
+ groupBy: ['route'],
108
+ limit: ROUTE_LIMIT,
109
+ description: 'Billed GB-hours per route (function duration in Fluid billing).',
110
+ },
111
+ {
112
+ id: 'fnCpuMsByRoute',
113
+ metricId: 'vercel.function_invocation.function_cpu_time_ms',
114
+ aggregation: 'sum',
115
+ groupBy: ['route'],
116
+ limit: ROUTE_LIMIT,
117
+ description: 'Active CPU time per route. Fluid Compute bills on this; high CPU = expensive route.',
118
+ },
119
+ {
120
+ id: 'fnPeakMemoryByRoute',
121
+ metricId: 'vercel.function_invocation.peak_memory_mb',
122
+ aggregation: 'max',
123
+ groupBy: ['route'],
124
+ limit: ROUTE_LIMIT,
125
+ description: 'Peak memory observed per route. Compared against provisioned to right-size.',
126
+ },
127
+ {
128
+ id: 'fnProvisionedMemoryByRoute',
129
+ metricId: 'vercel.function_invocation.provisioned_memory_mb',
130
+ aggregation: 'max',
131
+ groupBy: ['route'],
132
+ limit: ROUTE_LIMIT,
133
+ description: 'Provisioned memory per route. Feeds oversized_memory gate.',
134
+ },
135
+ {
136
+ id: 'fnTtfbP95ByRoute',
137
+ metricId: 'vercel.function_invocation.ttfb_ms',
138
+ aggregation: 'p95',
139
+ groupBy: ['route'],
140
+ limit: ROUTE_LIMIT,
141
+ description: 'Server-measured time-to-first-byte per route. Complements function_duration_ms p95.',
142
+ },
143
+
144
+ {
145
+ id: 'fdtByRoute',
146
+ metricId: 'vercel.request.fdt_total_bytes',
147
+ aggregation: 'sum',
148
+ groupBy: ['route'],
149
+ limit: ROUTE_LIMIT,
150
+ description: 'Fast Data Transfer bytes per route. Bandwidth cost driver.',
151
+ },
152
+ {
153
+ id: 'fdtByBot',
154
+ metricId: 'vercel.request.fdt_total_bytes',
155
+ aggregation: 'sum',
156
+ groupBy: ['bot_category'],
157
+ limit: DIM_LIMIT,
158
+ description: 'FDT bytes by bot category. Empty `bot_category` = human traffic; non-empty = bots.',
159
+ },
160
+ {
161
+ id: 'fdtByCache',
162
+ metricId: 'vercel.request.fdt_total_bytes',
163
+ aggregation: 'sum',
164
+ groupBy: ['cache_result'],
165
+ limit: DIM_LIMIT,
166
+ description: 'FDT bytes by cache_result. Uncached vs cached bandwidth.',
167
+ },
168
+
169
+ {
170
+ id: 'middlewareCount',
171
+ metricId: 'vercel.middleware_invocation.count',
172
+ aggregation: 'sum',
173
+ groupBy: ['request_path'],
174
+ limit: ROUTE_LIMIT,
175
+ description: 'Middleware invocations per request_path. Heavy middleware traffic = missing matcher.',
176
+ },
177
+ {
178
+ id: 'middlewareDurationP95',
179
+ metricId: 'vercel.middleware_invocation.duration_ms',
180
+ aggregation: 'p95',
181
+ groupBy: ['request_path'],
182
+ limit: ROUTE_LIMIT,
183
+ description: 'p95 middleware duration per request_path.',
184
+ },
185
+
186
+ {
187
+ id: 'isrReadsByRoute',
188
+ metricId: 'vercel.isr_operation.read_units',
189
+ aggregation: 'sum',
190
+ groupBy: ['route'],
191
+ limit: ROUTE_LIMIT,
192
+ description: 'ISR read units per route. Healthy when high relative to writes.',
193
+ },
194
+ {
195
+ id: 'isrWritesByRoute',
196
+ metricId: 'vercel.isr_operation.write_units',
197
+ aggregation: 'sum',
198
+ groupBy: ['route'],
199
+ limit: ROUTE_LIMIT,
200
+ description: 'ISR write units per route. High writes/reads = over-aggressive revalidate.',
201
+ },
202
+
203
+ {
204
+ id: 'imageCount',
205
+ metricId: 'vercel.image_transformation.count',
206
+ aggregation: 'sum',
207
+ groupBy: [],
208
+ limit: 1,
209
+ description: 'Total image transformations performed.',
210
+ },
211
+ {
212
+ id: 'imageByHost',
213
+ metricId: 'vercel.image_transformation.count',
214
+ aggregation: 'sum',
215
+ groupBy: ['source_image_hostname'],
216
+ limit: HOST_LIMIT,
217
+ description: 'Image transformations per source hostname. Identify which hosts dominate the bill.',
218
+ },
219
+ {
220
+ id: 'imageSourceBytes',
221
+ metricId: 'vercel.image_transformation.source_size_bytes',
222
+ aggregation: 'sum',
223
+ groupBy: [],
224
+ limit: 1,
225
+ description: 'Bytes of source images optimized. High = ingress bandwidth cost.',
226
+ },
227
+
228
+ {
229
+ id: 'cwvLcpByRoute',
230
+ metricId: 'vercel.speed_insights_metric.lcp',
231
+ aggregation: 'p75',
232
+ groupBy: ['route'],
233
+ limit: ROUTE_LIMIT,
234
+ description: 'p75 Largest Contentful Paint per route. > 2500ms = poor.',
235
+ },
236
+ {
237
+ id: 'cwvInpByRoute',
238
+ metricId: 'vercel.speed_insights_metric.inp',
239
+ aggregation: 'p75',
240
+ groupBy: ['route'],
241
+ limit: ROUTE_LIMIT,
242
+ description: 'p75 Interaction to Next Paint per route. > 200ms = poor.',
243
+ },
244
+ {
245
+ id: 'cwvClsByRoute',
246
+ metricId: 'vercel.speed_insights_metric.cls',
247
+ aggregation: 'p75',
248
+ groupBy: ['route'],
249
+ limit: ROUTE_LIMIT,
250
+ description: 'p75 Cumulative Layout Shift per route. > 0.1 = poor.',
251
+ },
252
+ {
253
+ id: 'cwvTtfbByRoute',
254
+ metricId: 'vercel.speed_insights_metric.ttfb_ms',
255
+ aggregation: 'p75',
256
+ groupBy: ['route'],
257
+ limit: ROUTE_LIMIT,
258
+ description: 'p75 client-measured TTFB per route.',
259
+ },
260
+ {
261
+ id: 'cwvCount',
262
+ metricId: 'vercel.speed_insights_metric.count',
263
+ aggregation: 'sum',
264
+ groupBy: [],
265
+ limit: 1,
266
+ description: 'Total Speed Insights measurements. Use to decide whether CWV gates have enough signal.',
267
+ },
268
+ {
269
+ id: 'cwvCountByRoute',
270
+ metricId: 'vercel.speed_insights_metric.count',
271
+ aggregation: 'sum',
272
+ groupBy: ['route'],
273
+ limit: ROUTE_LIMIT,
274
+ description: 'Speed Insights measurements per route. CWV route gates require at least 50 samples on the specific route.',
275
+ },
276
+
277
+ {
278
+ id: 'firewallByAction',
279
+ metricId: 'vercel.firewall_action.count',
280
+ aggregation: 'sum',
281
+ groupBy: ['waf_action'],
282
+ limit: DIM_LIMIT,
283
+ description: 'Firewall action count per waf_action (allow | challenge | block | log).',
284
+ },
285
+ {
286
+ id: 'botIdChecks',
287
+ metricId: 'vercel.bot_id_check.count',
288
+ aggregation: 'sum',
289
+ groupBy: [],
290
+ limit: 1,
291
+ description: 'Total BotID checks. > 0 confirms BotID is wired up; = 0 confirms it is not.',
292
+ },
293
+
294
+ {
295
+ id: 'externalApiCount',
296
+ metricId: 'vercel.external_api_request.count',
297
+ aggregation: 'sum',
298
+ groupBy: ['origin_hostname'],
299
+ limit: HOST_LIMIT,
300
+ description: 'External API call count per origin hostname.',
301
+ },
302
+ {
303
+ id: 'externalApiBytes',
304
+ metricId: 'vercel.external_api_request.transfer_bytes',
305
+ aggregation: 'sum',
306
+ groupBy: ['origin_hostname'],
307
+ limit: HOST_LIMIT,
308
+ description: 'Outbound bytes per external API hostname.',
309
+ },
310
+ ];
311
+
312
+ export function normalizerFor(entry) {
313
+ if (entry.normalizer) return entry.normalizer;
314
+ return defaultNormalize(entry.metricId, entry.aggregation, entry.groupBy);
315
+ }