📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-06-03 16:02:56 +00:00
parent ac7fffe532
commit 5cb67428bd
803 changed files with 78437 additions and 401 deletions
@@ -0,0 +1,69 @@
// Build Minutes climb on monorepos when Turborepo cache is bypassed or every project rebuilds on every commit.
// Threshold: Build Minutes line > 15% of total bill OR scanner emits any turbo-force-bypass finding (even at lower share).
// Account-scoped because the lever is project-settings (Ignored Build Step, Elastic Build Machines), not code.
export const metadata = {
id: 'build_minutes_fanout',
threshold: 'Build Minutes share > 0.15 OR turbo-force-bypass finding present',
billingDimension: 'build',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Build Minutes line dominates the bill or Turborepo cache is bypassed. On monorepos, unchanged work should be skipped through Vercel skip-unaffected behavior, a verified Ignored Build Step, and a complete Turbo cache contract.',
};
const BUILD_RE = /^Build (CPU )?Minutes$/i;
const SCANNER_PATTERN = 'turbo-force-bypass';
const SHARE_FLOOR = 0.15;
export function gate(signals) {
const services = signals?.usage?.services;
const total = Array.isArray(services)
? services.reduce((acc, s) => acc + Number(s.billedCost ?? s.cost ?? 0), 0)
: 0;
const buildBilled = Array.isArray(services)
? services
.filter((s) => BUILD_RE.test(String(s?.name ?? '')))
.reduce((acc, s) => acc + Number(s.billedCost ?? s.cost ?? 0), 0)
: 0;
const buildShare = total > 0 ? buildBilled / total : 0;
const findings = (signals?.codebase?.findings ?? []).filter((f) => f.pattern === SCANNER_PATTERN);
if (buildShare <= SHARE_FLOOR && findings.length === 0) return [];
const subtypes = unique(findings.map((f) => f.subtype).filter(Boolean));
const sampleFiles = unique(findings.map((f) => f.file).filter(Boolean)).slice(0, 4);
const reason = findings.length > 0
? (buildShare > SHARE_FLOOR
? 'Build Minutes share is high and Turborepo cache bypass detected in repo'
: 'Turborepo cache bypass detected in repo')
: 'Build Minutes line exceeds 15% of total billed cost';
return [{
kind: metadata.id,
scope: 'account',
files: sampleFiles,
priority: findings.length > 0 ? 65 : 50,
confidence: findings.length > 0 ? 0.86 : 0.74,
o11ySignal: `build_minutes_share=${(buildShare * 100).toFixed(0)}% scanner_findings=${findings.length}`,
reason,
question: findings.length > 0
? `Turborepo cache bypass detected (${subtypes.join(', ')}). Which build pipeline forces a rebuild on every commit, and can Ignored Build Step + cache re-enable cut the project fan-out?`
: 'Build Minutes exceed 15% of the bill. Is Ignored Build Step configured? Is Turborepo cache active across builds? Would Elastic Build Machines reduce duration on hot builds?',
evidence: {
metric: 'usage.services',
buildBilled,
totalBilled: total,
buildShare,
scannerFindings: findings.length,
scannerSubtypes: subtypes,
sampleFiles,
},
}];
}
function unique(values) {
return [...new Set(values)];
}
@@ -0,0 +1,66 @@
// Signal: `function_start_type` dimension on `vercel.function_invocation.count` (cold|hot|prewarmed).
// Threshold WHY: 40%+ cold is fixable via Fluid keep-warm; 30% is the noise floor for serverless without keep-warm.
// total>=1000/14d (~3/hr) keeps Poisson CI on cold rate at ~±5% near the 40% threshold.
export const metadata = {
id: 'cold_start',
threshold: 'coldPct > 0.4 AND total >= 1000',
billingDimension: 'function-duration',
scope: 'route',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Routes where > 40% of invocations are cold-start, at meaningful traffic (>=1,000 total invocations in window). Cold starts add 200-800ms per request and break the perceived latency budget on cache-miss paths. The 40% threshold is where cold-rate becomes a real signal vs Poisson noise on serverless. Sourced from vercel.function_invocation.count grouped by function_start_type.',
};
export function gate(signals) {
const cs = extractColdStarts(signals);
return cs
.filter((r) => r.coldPct > 0.4 && r.total >= 1000)
.map((r) => ({
kind: metadata.id,
scope: 'route',
route: r.route,
files: [],
priority: Math.round(r.total * r.coldPct),
confidence: 0.92,
o11ySignal: `cold=${(r.coldPct * 100).toFixed(0)}%,inv=${r.total}`,
reason: 'high cold-start rate on hot route',
question: `What initialization or bundle overhead makes ${r.route} cold-start ${(r.coldPct * 100).toFixed(0)}% of ${r.total} invocations?`,
evidence: { metric: 'fnStartTypeByRoute', route: r.route, coldPct: r.coldPct, total: r.total, coldCount: r.coldCount ?? null },
}));
}
function extractColdStarts(signals) {
const live = signals.metrics?.fnStartTypeByRoute;
if (Array.isArray(live?.rows) && live.rows.some((r) => 'coldCount' in r || 'coldPct' in r)) {
return live.rows
.filter((r) => r.route)
.map((r) => ({
route: r.route,
total: r.total ?? 0,
coldCount: r.coldCount ?? 0,
coldPct: r.coldPct ?? 0,
}));
}
// Legacy fixture: pre-derived coldStartByRoute rows.
const direct = signals.metrics?.coldStartByRoute;
if (Array.isArray(direct?.rows)) {
return direct.rows
.filter((r) => r.route)
.map((r) => ({ route: r.route, coldPct: r.coldPct ?? 0, total: r.total ?? 0 }));
}
// Older legacy fixture: series + summary shape.
const legacy = signals.metrics?.coldStarts;
if (Array.isArray(legacy?.series)) {
return legacy.series
.map((s) => {
const total = s.summary?.count ?? 0;
const coldCount = s.summary?.coldCount ?? s.summary?.sum ?? 0;
return { route: s.groupValues?.route, total, coldPct: total > 0 ? coldCount / total : 0 };
})
.filter((r) => r.route);
}
return [];
}
@@ -0,0 +1,79 @@
const VALID_SCOPES = new Set(['route', 'file', 'account']);
export class CandidateContractError extends Error {
constructor(errors) {
super(`gate candidate contract failed:\n${errors.map((e) => `- ${e}`).join('\n')}`);
this.name = 'CandidateContractError';
this.errors = errors;
}
}
export function validateCandidates(candidates, ctx = {}) {
if (!Array.isArray(candidates)) {
throw new CandidateContractError([`${ctx.source ?? 'gate'}: expected candidate array`]);
}
const errors = [];
for (let i = 0; i < candidates.length; i++) {
errors.push(...validateCandidate(candidates[i], { ...ctx, index: i }).errors);
}
if (errors.length > 0) throw new CandidateContractError(errors);
return candidates;
}
export function validateCandidate(candidate, ctx = {}) {
const label = candidateLabel(candidate, ctx);
const errors = [];
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
return { ok: false, errors: [`${label}: candidate must be an object`] };
}
if (!nonEmptyString(candidate.kind)) errors.push(`${label}: kind must be a non-empty string`);
if (!VALID_SCOPES.has(candidate.scope)) {
errors.push(`${label}: scope must be one of route, file, account`);
}
if (!Number.isFinite(candidate.priority)) errors.push(`${label}: priority must be a finite number`);
if (!Number.isFinite(candidate.confidence)) errors.push(`${label}: confidence must be a finite number`);
if (Array.isArray(candidate.files)) {
if (!candidate.files.every((f) => typeof f === 'string' && f.length > 0)) {
errors.push(`${label}: files must contain only non-empty strings`);
}
} else {
errors.push(`${label}: files must be an array`);
}
if (!nonEmptyString(candidate.reason)) errors.push(`${label}: reason must be a non-empty string`);
if (!nonEmptyString(candidate.question)) errors.push(`${label}: question must be a non-empty string`);
if (candidate.scope === 'route') {
const hasRoute = nonEmptyString(candidate.route);
const hasHostname = nonEmptyString(candidate.hostname);
if (!hasRoute && !hasHostname) {
errors.push(`${label}: route-scoped candidates must set route or hostname`);
}
}
if (candidate.scope === 'file') {
if (candidate.route != null || candidate.hostname != null) {
errors.push(`${label}: file-scoped candidates must not set route or hostname`);
}
if (!Array.isArray(candidate.files) || candidate.files.length === 0) {
errors.push(`${label}: file-scoped candidates must include at least one file`);
}
}
if (candidate.scope === 'account') {
if (candidate.route != null || candidate.hostname != null) {
errors.push(`${label}: account-scoped candidates must not set route or hostname`);
}
}
return { ok: errors.length === 0, errors };
}
function candidateLabel(candidate, ctx) {
const source = ctx.source ?? 'gate';
const index = ctx.index == null ? '?' : ctx.index;
const kind = candidate?.kind ?? '?';
return `${source}[${index}] ${kind}`;
}
function nonEmptyString(value) {
return typeof value === 'string' && value.trim().length > 0;
}
@@ -0,0 +1,87 @@
// Thresholds are Google's "Poor" band (https://web.dev/articles/vitals): LCP p75 > 2500ms, INP > 200ms, CLS > 0.1.
// When Speed Insights isn't wired up the metrics come back empty and the gate is a no-op.
import { withRouteShapeWarnings } from '../route-normalize.mjs';
export const metadata = {
id: 'cwv_poor',
threshold: 'LCP p75>2500 OR INP p75>200 OR CLS p75>0.1, AND speed_insights count > 50',
billingDimension: 'speed-insights',
scope: 'route',
sourceCitation: 'https://web.dev/articles/vitals',
description:
'Routes where Core Web Vitals fall into Google\'s "Poor" band on real-user traffic. LCP > 2500ms, INP > 200ms, or CLS > 0.1 each hurt SEO and conversion. Surfaces one candidate per (route, metric) pair to keep recommendations focused.',
};
// Below this floor p75 is too noisy to act on.
const MIN_PER_ROUTE_SAMPLES = 50;
export function gate(signals) {
const totalSamples = sumRows(signals.metrics?.cwvCount?.rows);
if (totalSamples === 0) return [];
const countByRoute = byRoute(signals.metrics?.cwvCountByRoute?.rows);
const lcpBy = byRoute(signals.metrics?.cwvLcpByRoute?.rows);
const inpBy = byRoute(signals.metrics?.cwvInpByRoute?.rows);
const clsBy = byRoute(signals.metrics?.cwvClsByRoute?.rows);
const routes = new Set([...lcpBy.keys(), ...inpBy.keys(), ...clsBy.keys()]);
const out = [];
for (const route of routes) {
const routeSamples = countByRoute.get(route) ?? 0;
if (routeSamples < MIN_PER_ROUTE_SAMPLES) continue;
const lcp = lcpBy.get(route);
const inp = inpBy.get(route);
const cls = clsBy.get(route);
const issues = [];
if (lcp != null && lcp > 2500) issues.push({ metric: 'LCP', value: Math.round(lcp), threshold: 2500, unit: 'ms' });
if (inp != null && inp > 200) issues.push({ metric: 'INP', value: Math.round(inp), threshold: 200, unit: 'ms' });
if (cls != null && cls > 0.1) issues.push({ metric: 'CLS', value: round2(cls), threshold: 0.1, unit: '' });
if (issues.length === 0) continue;
const summary = issues.map((i) => `${i.metric}=${i.value}${i.unit}`).join(',');
out.push(withRouteShapeWarnings({
kind: metadata.id,
scope: 'route',
route,
files: [],
priority: issues.reduce((s, i) => s + ratioOverThreshold(i), 0) * 10,
confidence: 0.82,
o11ySignal: summary,
reason: 'real-user Core Web Vitals in poor band',
question: `On ${route}, ${summary}. Which client-side work (bundle weight, blocking scripts, layout shifts, hydration) is responsible, and which change would land first?`,
evidence: {
metric: 'cwv',
route,
lcpMs: lcp != null ? Math.round(lcp) : null,
inpMs: inp != null ? Math.round(inp) : null,
cls: cls != null ? round2(cls) : null,
issues,
totalSpeedInsightsSamples: totalSamples,
routeSpeedInsightsSamples: routeSamples,
},
}, signals));
}
return out;
}
function byRoute(rows) {
const m = new Map();
for (const r of rows ?? []) {
if (!r.route || r.value == null) continue;
m.set(r.route, r.value);
}
return m;
}
function sumRows(rows) {
if (!Array.isArray(rows)) return 0;
return rows.reduce((s, r) => s + (r.value ?? 0), 0);
}
function round2(n) {
return Math.round(n * 100) / 100;
}
function ratioOverThreshold(i) {
return i.value / (i.threshold || 1);
}
@@ -0,0 +1,55 @@
// Volume floor pairs p75 with call_count so a single 5s cron/day doesn't fire the gate.
const MIN_CALL_COUNT = 500;
export const metadata = {
id: 'external_api_slow',
threshold: `p75Ms > 2000 AND callCount >= ${MIN_CALL_COUNT}`,
billingDimension: 'function-duration',
scope: 'route',
sourceCitation: 'vercel-optimize gate threshold',
description:
'External API hostnames with p75 latency above 2 seconds AND at least 500 calls in the window. External API latency is a primary driver of function duration cost when the upstream is on a hot path; a single slow stale call isn\'t worth recommending against.',
};
export function gate(signals) {
const apis = extractExternalApis(signals);
const calls = extractCallCounts(signals);
return apis
.map((a) => ({ ...a, callCount: calls.get(a.hostname) ?? 0 }))
.filter((a) => a.p75Ms > 2000 && a.callCount >= MIN_CALL_COUNT)
.map((a) => ({
kind: metadata.id,
scope: 'route',
route: null,
files: [],
hostname: a.hostname,
// Weight by latency × call volume so 100k-call/2.1s outranks 1k-call/8s.
priority: Math.round((a.p75Ms * a.callCount) / 1000),
confidence: 0.88,
o11ySignal: `host=${a.hostname},p75=${a.p75Ms}ms,calls=${a.callCount}`,
reason: 'slow external dependency on hot path',
question: `Which routes call ${a.hostname} (p75=${a.p75Ms}ms across ${a.callCount} calls), and can the call be parallelized, cached, or moved off the critical path?`,
evidence: { metric: 'externalApiP75', hostname: a.hostname, p75Ms: a.p75Ms, callCount: a.callCount },
}));
}
function extractExternalApis(signals) {
const m = signals.metrics?.externalApiP75;
if (!m?.ok && !Array.isArray(m?.rows)) return [];
return (m?.rows ?? [])
.map((r) => ({
hostname: r.origin_hostname,
p75Ms: Math.round(r.value ?? 0),
}))
.filter((a) => a.hostname);
}
function extractCallCounts(signals) {
const m = signals.metrics?.externalApiCount;
const out = new Map();
if (!m) return out;
for (const r of m.rows ?? []) {
if (r?.origin_hostname) out.set(r.origin_hostname, r.value ?? 0);
}
return out;
}
@@ -0,0 +1,73 @@
import { canonicalizeRoute } from '../route-normalize.mjs';
export const FLAGS_ENDPOINT = '/.well-known/vercel/flags';
export const VERCEL_FLAGS_PACKAGES = [
'@vercel/flags',
'@vercel/flags/next',
'@vercel/flags/sveltekit',
'@vercel/flags/nuxt',
];
export const WORKFLOW_ENDPOINT_PREFIXES = [
'/.well-known/workflow',
'/api/.well-known/workflow',
];
export function applyHardGates(candidates, signals = {}) {
const allowed = [];
const gated = [];
for (const candidate of candidates) {
if (isFlagsEndpointCandidate(candidate)) {
gated.push({
...candidate,
gatedReason: flagsEndpointReason(signals),
});
continue;
}
if (isWorkflowRuntimeEndpointCandidate(candidate)) {
gated.push({
...candidate,
gatedReason: workflowEndpointReason(signals),
});
continue;
}
allowed.push(candidate);
}
return { allowed, gated };
}
export function isFlagsEndpointCandidate(candidate) {
if (!candidate || candidate.scope === 'account') return false;
const route = normalizeRoute(candidate.route);
return route === FLAGS_ENDPOINT;
}
export function isWorkflowRuntimeEndpointCandidate(candidate) {
if (!candidate || candidate.scope === 'account') return false;
const route = normalizeRoute(candidate.route);
if (!route) return false;
return WORKFLOW_ENDPOINT_PREFIXES.some((prefix) => (
route === prefix || route.startsWith(`${prefix}/`)
));
}
function normalizeRoute(route) {
if (typeof route !== 'string') return null;
const normalized = canonicalizeRoute(route).replace(/\/+$/, '');
return normalized === '' ? '/' : normalized;
}
function flagsEndpointReason(signals) {
const packages = signals.stack?.vercelFlagsPackages;
if (Array.isArray(packages) && packages.length > 0) {
return `hardGated: ${FLAGS_ENDPOINT} is the Vercel Flags endpoint (${packages.join(', ')} detected), not an optimization target`;
}
return `hardGated: ${FLAGS_ENDPOINT} is the Vercel Flags endpoint, not an optimization target`;
}
function workflowEndpointReason(signals) {
const packages = signals.stack?.workflowPackages;
if (Array.isArray(packages) && packages.length > 0) {
return `hardGated: Vercel Workflow runtime endpoint (${packages.join(', ')} detected); long-running step/flow requests are expected orchestration, not an app-route optimization target`;
}
return 'hardGated: Vercel Workflow runtime endpoint; long-running step/flow requests are expected orchestration, not an app-route optimization target';
}
@@ -0,0 +1,45 @@
import * as uncachedRoute from './uncached-route.mjs';
import * as slowRoute from './slow-route.mjs';
import * as routeErrors from './route-errors.mjs';
import * as coldStart from './cold-start.mjs';
import * as isrOverrevalidation from './isr-overrevalidation.mjs';
import * as cwvPoor from './cwv-poor.mjs';
import * as platformFluidCompute from './platform-fluid-compute.mjs';
import * as platformBotProtection from './platform-bot-protection.mjs';
import * as middlewareHeavy from './middleware-heavy.mjs';
import * as externalApiSlow from './external-api-slow.mjs';
import * as scannerDriven from './scanner-driven.mjs';
import * as observabilityEventsAttribution from './observability-events-attribution.mjs';
import * as usageSpikeTriage from './usage-spike-triage.mjs';
import * as buildMinutesFanout from './build-minutes-fanout.mjs';
import * as regionMisconfig from './region-misconfig.mjs';
// Intentionally NOT registered:
// - `oversized_memory`: Fluid Compute floor is 2GB; per-route memory right-sizing isn't a customer lever.
// - `deploy_regression`: overlaps Vercel Agent Investigations; `vercel inspect` 404s across teams. slow_route deep-dive already carries per-deployment p95 trend.
export const gates = [
uncachedRoute,
slowRoute,
routeErrors,
coldStart,
isrOverrevalidation,
cwvPoor,
externalApiSlow,
scannerDriven,
// Account-scoped last so platform-scoped sort doesn't dilute code-scoped priority ordering during budget application.
platformFluidCompute,
platformBotProtection,
middlewareHeavy,
observabilityEventsAttribution,
usageSpikeTriage,
buildMinutesFanout,
regionMisconfig,
];
// Overridable via `--max-candidates N` or `VERCEL_OPTIMIZE_MAX_CANDIDATES` (accepts `all`).
// `MAX_CODE_CANDIDATES` is a back-compat alias for tests importing the old name.
export const DEFAULT_MAX_CODE_CANDIDATES = 6;
export const MAX_CODE_CANDIDATES = DEFAULT_MAX_CODE_CANDIDATES;
// Bump on any threshold change so report + iteration baselines can detect gate-logic drift.
export const GATE_VERSION = '1.8.0';
@@ -0,0 +1,62 @@
// ISR writes re-execute the page render. A w/r ratio above 0.5 means writes are
// happening at least once for every two reads — high enough for the default
// audit to spend investigation budget. writes>100 avoids flapping on quiet routes.
export const metadata = {
id: 'isr_overrevalidation',
threshold: 'writes/reads > 0.5 AND writes > 100',
billingDimension: 'isr',
scope: 'route',
sourceCitation: 'https://vercel.com/docs/incremental-static-regeneration',
description:
'ISR routes with > 1 write per 2 reads. The revalidate interval is too aggressive relative to read traffic — many reads pay to regenerate. Investigate whether the page can tolerate a longer revalidate window or on-demand revalidation via revalidateTag.',
};
export function gate(signals) {
const rows = extractRows(signals);
return rows
.filter((r) => r.writes > 100 && r.reads > 0 && r.writes / r.reads > 0.5)
.map((r) => {
const ratio = r.writes / r.reads;
return {
kind: metadata.id,
scope: 'route',
route: r.route,
files: [],
priority: Math.round(r.writes),
confidence: 0.88,
o11ySignal: `writes=${r.writes},reads=${r.reads},w/r=${ratio.toFixed(2)}`,
reason: 'ISR revalidating faster than read traffic justifies',
question: `On ${r.route}, ${r.writes} ISR writes against ${r.reads} reads (${(ratio * 100).toFixed(0)} writes per 100 reads) — what is the current revalidate interval and can it be lengthened or switched to on-demand?`,
evidence: {
metric: 'isrWritesByRoute',
route: r.route,
writes: r.writes,
reads: r.reads,
ratio,
},
};
});
}
function extractRows(signals) {
const writes = signals.metrics?.isrWritesByRoute?.rows ?? [];
const reads = signals.metrics?.isrReadsByRoute?.rows ?? [];
const writeByRoute = new Map();
for (const r of writes) {
if (!r.route) continue;
writeByRoute.set(r.route, (writeByRoute.get(r.route) ?? 0) + (r.value ?? 0));
}
const readByRoute = new Map();
for (const r of reads) {
if (!r.route) continue;
readByRoute.set(r.route, (readByRoute.get(r.route) ?? 0) + (r.value ?? 0));
}
const routes = new Set([...writeByRoute.keys(), ...readByRoute.keys()]);
return [...routes].map((route) => ({
route,
writes: writeByRoute.get(route) ?? 0,
reads: readByRoute.get(route) ?? 0,
}));
}
@@ -0,0 +1,51 @@
// Middleware runs in front of every matching request and is billed as edge invocations.
// If >50% of traffic hits middleware, the matcher is probably broader than necessary.
export const metadata = {
id: 'middleware_heavy',
threshold: 'middlewareInv/totalInv > 0.5 AND middlewareInv > 1000',
billingDimension: 'edge-requests',
scope: 'account',
sourceCitation: 'https://nextjs.org/docs/app/building-your-application/routing/middleware',
description:
'Middleware invocations cover > 50% of total requests at non-trivial volume. The matcher is probably broader than necessary; narrow it to the paths that actually need auth/rewrites/headers.',
};
export function gate(signals) {
const middlewareInv = sumRows(signals.metrics?.middlewareCount?.rows);
if (middlewareInv < 1000) return [];
const totalInv = sumRows(signals.metrics?.requestsByRouteCache?.rows);
if (totalInv === 0) return [];
const ratio = middlewareInv / totalInv;
if (ratio <= 0.5) return [];
const top = [...(signals.metrics?.middlewareCount?.rows ?? [])]
.filter((r) => r.request_path)
.sort((a, b) => (b.value ?? 0) - (a.value ?? 0))
.slice(0, 5)
.map((r) => ({ request_path: r.request_path, count: r.value ?? 0 }));
return [{
kind: metadata.id,
scope: 'account',
files: [],
priority: Math.round(middlewareInv / 1000),
confidence: 0.84,
o11ySignal: `middleware_inv=${middlewareInv},total_req=${totalInv},ratio=${(ratio * 100).toFixed(0)}%`,
reason: 'middleware ran on more than half of all requests',
question: `Middleware invocations (${middlewareInv}) are ${(ratio * 100).toFixed(0)}% of all requests (${totalInv}). Which paths in middleware.ts require interception, and can the matcher be narrowed to exclude static assets, images, and routes that do not need rewriting?`,
evidence: {
metric: 'middlewareCount',
middlewareInv,
totalInv,
ratio,
topPaths: top,
},
}];
}
function sumRows(rows) {
if (!Array.isArray(rows)) return 0;
return rows.reduce((s, r) => s + (r.value ?? 0), 0);
}
@@ -0,0 +1,56 @@
// Observability Events is the metered SKU under Observability Plus.
// Threshold at >20% surfaces material spend; >30% is the critical band.
// Drivers correlate with low cache hit rate, high middleware invocation, and high custom-span cardinality.
export const metadata = {
id: 'observability_events_attribution',
threshold: 'observabilityEventsShare > 0.20 (critical at > 0.30)',
billingDimension: 'observability-events',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Observability Events line item exceeds 20% of total billed cost. High share usually traces to low cache hit rate, middleware-heavy traffic, or unconstrained custom-span cardinality. No sampling lever exists for Observability Plus; reduce upstream invocations instead.',
};
const EVENTS_RE = /^Observability Events$/i;
export function gate(signals) {
const services = signals?.usage?.services;
if (!Array.isArray(services) || services.length === 0) return [];
const total = sumBilled(services);
if (total <= 0) return [];
const eventsBilled = services
.filter((s) => EVENTS_RE.test(String(s?.name ?? '')))
.reduce((acc, s) => acc + Number(s.billedCost ?? s.cost ?? 0), 0);
if (eventsBilled <= 0) return [];
const share = eventsBilled / total;
if (share <= 0.20) return [];
const critical = share > 0.30;
return [{
kind: metadata.id,
scope: 'account',
files: [],
priority: critical ? 70 : 55,
confidence: 0.82,
o11ySignal: `observability_events_share=${(share * 100).toFixed(0)}%`,
reason: critical
? 'observability events exceed 30% of total billed cost'
: 'observability events exceed 20% of total billed cost',
question: `Observability Events are ${(share * 100).toFixed(0)}% of the bill. Which routes drive event volume — low-cache-hit traffic, broad middleware invocation, or high custom-span cardinality — and can event volume be reduced upstream of the meter?`,
evidence: {
metric: 'usage.services',
eventsBilled,
totalBilled: total,
observabilityEventsShare: share,
critical,
},
}];
}
function sumBilled(services) {
return services.reduce((acc, s) => acc + Number(s.billedCost ?? s.cost ?? 0), 0);
}
@@ -0,0 +1,115 @@
// Recommend BotID only when there's EVIDENCE of bot traffic or scale large enough that the rec is defensible.
// Without an evidence gate the rec fires on quiet hobby sites and erodes trust.
const MIN_BOT_PCT = 0.05;
const MIN_EDGE_COST = 25; // halved for 14d window
const MIN_TOTAL_REQUESTS = 14_000; // ~14k/14d matches the prior 30k/30d rate
const MIN_TOTAL_FDT_BYTES = 1_000_000;
export const metadata = {
id: 'platform_bot_protection',
threshold: 'botIdEnabled=false AND (botPct >= 0.05 OR edge_cost >= $25/window OR requests >= 14k/14d)',
billingDimension: 'edge-requests',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
'When BotID is disabled AND there is evidence (observed bot bandwidth share, edge cost, or substantial request volume) that bot traffic is non-trivial. Bot traffic inflates edge request counts without delivering user value; staged bot protection can reduce waste on bot-heavy projects. Skipped on quiet projects with no bot evidence — the recommendation would be noise.',
};
export function gate(signals) {
// BotID surfaces under several legacy fields; check all.
const botEnabled =
signals.project?.security?.botIdEnabled === true
|| signals.project?.security?.botProtection === true
|| signals.project?.botProtection?.enabled === true
|| signals.project?.delegatedProtection?.bot === true;
if (botEnabled) return [];
// Project config failed — we can't tell if BotID is on, so stay silent.
if (signals.project?.error) return [];
const totalRequests = totalRequestsFromSignals(signals);
const botShare = computeBotShare(signals);
const edgeService = (signals.usage?.services ?? []).find(
(s) => /edge.request/i.test(s.name ?? '')
);
const edgeCost = edgeService?.billedCost ?? null;
// Require observable bot share, edge cost, OR substantial traffic — otherwise rec is just config nagging.
const hasObservedBots = botShare?.botPct != null && botShare.botPct >= MIN_BOT_PCT;
const hasMaterialEdgeCost = edgeCost != null && edgeCost >= MIN_EDGE_COST;
const hasSubstantialTraffic = totalRequests >= MIN_TOTAL_REQUESTS;
if (!hasObservedBots && !hasMaterialEdgeCost && !hasSubstantialTraffic) return [];
const challengeRule = signals.project?.security?.managedRules?.bot_filter;
const ruleNote = challengeRule?.active
? `firewall bot_filter rule active (action=${challengeRule.action ?? '?'})`
: 'no firewall bot_filter rule';
// Kicker on high observed bot share — harder evidence than config alone.
let priority = edgeCost != null ? Math.max(20, Math.round(edgeCost)) : 30;
if (botShare?.botPct != null && botShare.botPct > 0.2) priority += 20;
// Confidence bumps when we can SEE bot traffic, not just infer from config.
let confidence = edgeCost != null ? 0.85 : 0.6;
if (botShare?.botPct != null && botShare.botPct > 0.2) confidence = Math.min(0.95, confidence + 0.05);
const botShareNote = botShare?.botPct != null
? `bot_fdt_pct=${(botShare.botPct * 100).toFixed(0)}%`
: 'bot_fdt_pct=unknown';
return [{
kind: metadata.id,
scope: 'account',
files: [],
priority,
confidence,
o11ySignal: edgeCost != null
? `edge_cost=${edgeCost.toFixed(0)},bot_protection=disabled,${botShareNote},${ruleNote}`
: `requests=${totalRequests},bot_protection=disabled,${botShareNote},${ruleNote}`,
reason: botShare?.botPct != null && botShare.botPct > 0.2
? 'BotID disabled with observable bot bandwidth share'
: 'BotID disabled with observable traffic',
question: botShare?.botPct != null && botShare.botPct > 0.2
? `Bot traffic accounts for ${(botShare.botPct * 100).toFixed(0)}% of FDT bytes (top category: ${botShare.topCategory ?? 'unknown'}). Would enabling BotID + a challenge rule reduce that share?`
: 'Would enabling BotID (Bot Protection) reduce edge request volume from automated traffic?',
evidence: {
botEnabled: false,
edgeCost,
totalRequests,
managedRules: challengeRule ?? null,
botShare: botShare ?? null,
},
}];
}
function totalRequestsFromSignals(signals) {
const rows = signals.metrics?.requestsByRouteCache?.rows;
if (!Array.isArray(rows)) return 0;
return rows.reduce((s, r) => s + (r.value ?? 0), 0);
}
// CLI convention: bot_category="" means "not classified as a bot" (human + unclassified); any non-empty = bot.
function computeBotShare(signals) {
const rows = signals.metrics?.fdtByBot?.rows;
if (!Array.isArray(rows) || rows.length === 0) return null;
let humanBytes = 0;
let botBytes = 0;
let topCategory = null;
let topBytes = 0;
for (const r of rows) {
const v = r.value ?? 0;
const cat = r.bot_category ?? '';
if (cat === '') {
humanBytes += v;
} else {
botBytes += v;
if (v > topBytes) {
topBytes = v;
topCategory = cat;
}
}
}
const total = humanBytes + botBytes;
if (total < MIN_TOTAL_FDT_BYTES) return null;
return { humanBytes, botBytes, botPct: botBytes / total, topCategory };
}
@@ -0,0 +1,83 @@
// Second branch (slow p95 + traffic floor) keeps the gate useful on teams where
// cold-start isn't directly observable — common on CLI v53 — trading specificity for coverage.
export const metadata = {
id: 'platform_fluid_compute',
threshold: 'fluid=false AND (any cold_start signal OR any route with p95>1000ms AND inv>1000)',
billingDimension: 'function-duration',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
'When Fluid Compute is disabled on a project that shows cold-start pressure (high cold-start rate) or sustained slow function p95 on hot routes. Fluid Compute reduces cold starts via instance reuse — recommend turning it on at the project level rather than per-route.',
};
export function gate(signals) {
// If project config failed to load we can't tell if Fluid is on; recommending it when already-on
// erodes trust badly, so stay silent and let Strengths note the gap.
if (signals.project?.error) return [];
const fluidEnabled =
signals.project?.resourceConfig?.fluid === true
|| signals.project?.defaultResourceConfig?.fluid === true;
if (fluidEnabled) return [];
const cold = extractHighColdRoutes(signals);
const slow = extractSlowHotRoutes(signals);
if (cold.length === 0 && slow.length === 0) return [];
return [{
kind: metadata.id,
scope: 'account',
files: [],
priority: 50,
confidence: cold.length > 0 ? 0.85 : 0.65,
o11ySignal: cold.length > 0
? `${cold.length} route(s) with high cold-start rate`
: `${slow.length} hot route(s) with p95>1s; cold-start not directly observable`,
reason: cold.length > 0
? 'cold starts observed and Fluid Compute is disabled'
: 'slow hot routes and Fluid Compute is disabled',
question: 'Would enabling Fluid Compute reduce cold-start and warm-instance reuse overhead for the observed hot routes?',
evidence: { fluidEnabled, highColdRoutes: cold.slice(0, 5), slowHotRoutes: slow.slice(0, 5) },
}];
}
function extractHighColdRoutes(signals) {
const live = signals.metrics?.fnStartTypeByRoute?.rows;
if (Array.isArray(live) && live.some((r) => 'coldCount' in r || 'coldPct' in r)) {
return live.filter((r) => r.route && (r.coldPct ?? 0) > 0.3 && (r.total ?? 0) > 100);
}
// Legacy pre-derived fixture shape.
const direct = signals.metrics?.coldStartByRoute?.rows;
if (Array.isArray(direct)) {
return direct.filter((r) => r.route && (r.coldPct ?? 0) > 0.3 && (r.total ?? 0) > 100);
}
const legacy = signals.metrics?.coldStarts?.series;
if (Array.isArray(legacy)) {
return legacy
.map((s) => {
const total = s.summary?.count ?? 0;
const coldCount = s.summary?.coldCount ?? s.summary?.sum ?? 0;
return { route: s.groupValues?.route, total, coldPct: total > 0 ? coldCount / total : 0 };
})
.filter((r) => r.route && r.coldPct > 0.3 && r.total > 100);
}
return [];
}
function extractSlowHotRoutes(signals) {
const dur = signals.metrics?.fnDurationP95ByRoute?.rows;
const cache = signals.metrics?.requestsByRouteCache?.rows;
if (!Array.isArray(dur)) return [];
// Sum requests per route across cache_result.
const inv = new Map();
for (const r of (cache ?? [])) {
if (!r.route) continue;
inv.set(r.route, (inv.get(r.route) ?? 0) + (r.value ?? 0));
}
return dur
.filter((r) => r.route)
.map((r) => ({ route: r.route, p95Ms: Math.round(r.value ?? 0), invocations: inv.get(r.route) ?? 0 }))
// inv>500 floor is the 14d-window equivalent of the old 1000/30d.
.filter((r) => r.p95Ms > 1000 && r.invocations > 500);
}
@@ -0,0 +1,64 @@
// Region-misconfig gate. Branch 2 (scanner-only) — per-region TTFB data gap.
//
// The intended Branch 1 (region-grouped TTFB metric) was preflight-tested but the
// CLI returned INTERNAL_ERROR for the `--group-by route --group-by function_region`
// combination, and SAML re-auth blocked single-dim verification (see Phase 0 in
// plans/wild-splashing-flamingo.md). Ship scanner-only with `evidence.dataGap` and
// add the query later when verifiable.
//
// Fires when a single-region pin is found AND the project has meaningful surface area
// (routes.length > 20). Skips multi-region configs (informational only).
export const metadata = {
id: 'region_misconfig',
threshold: 'single-region pin found AND routes.length > 20 (scanner-only branch)',
billingDimension: 'function-duration',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
"A single function region is pinned in `vercel.json` or per-route `preferredRegion`. Without per-region TTFB data (data gap), the gate can't quantify the geographic latency cost — but a single-region pin on a project with 20+ routes is worth auditing against Speed Insights traffic geo.",
};
const ROUTE_FLOOR = 20;
const SCANNER_PATTERN = 'region-pin-in-config';
export function gate(signals) {
const findings = (signals?.codebase?.findings ?? []).filter((f) => f.pattern === SCANNER_PATTERN);
if (findings.length === 0) return [];
const routes = signals?.codebase?.routes ?? [];
if (routes.length < ROUTE_FLOOR) return [];
const singleRegionFindings = findings.filter((f) => Array.isArray(f.regions) && f.regions.length === 1);
if (singleRegionFindings.length === 0) return [];
const allPinned = new Set();
for (const f of singleRegionFindings) {
for (const r of f.regions ?? []) allPinned.add(r);
}
const regionList = [...allPinned];
// If multiple distinct single-region pins exist across files, the surface is partly
// multi-region by accident; that's noteworthy but lower priority.
const homogeneous = regionList.length === 1;
return [{
kind: metadata.id,
scope: 'account',
files: singleRegionFindings.map((f) => f.file).slice(0, 6),
priority: homogeneous ? 42 : 38,
confidence: 0.6, // low — no per-region TTFB data
o11ySignal: `pinned_regions=${regionList.join(',')} routes=${routes.length}`,
reason: homogeneous
? `all functions pinned to a single region (${regionList[0]}) on a project with ${routes.length} routes`
: `${regionList.length} different single-region pins across files`,
question: 'Are the pinned function regions aligned with the dominant user geography and the data source location? Speed Insights TTFB-by-country can ground the comparison.',
evidence: {
metric: 'codebase.findings',
pinnedRegions: regionList,
findingsCount: singleRegionFindings.length,
routeCount: routes.length,
sampleFiles: singleRegionFindings.slice(0, 3).map((f) => ({ file: f.file, regions: f.regions, subtype: f.subtype })),
dataGap: 'region-grouped-TTFB-unavailable',
},
}];
}
@@ -0,0 +1,80 @@
// Errored function invocations still bill at full duration, so high-volume 5xx is a cost issue, not just reliability.
import { withRouteShapeWarnings } from '../route-normalize.mjs';
const MIN_VOLUME_FOR_RATE_EMISSION = 1000;
export const metadata = {
id: 'route_errors',
threshold: `count > 250 OR (totalRequests >= ${MIN_VOLUME_FOR_RATE_EMISSION} AND errorRate > 0.01)`,
billingDimension: 'function-duration',
scope: 'route',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Routes producing > 250 5xx errors over the window, or with > 1% error rate on at least 1,000 total requests. Errored function invocations still bill at full duration; high error rates also poison user experience.',
};
export function gate(signals) {
const errors = extractErrors(signals);
return errors
.filter((e) => e.count > 250 || (e.total >= MIN_VOLUME_FOR_RATE_EMISSION && (e.errorRate ?? 0) > 0.01))
.map((e) => withRouteShapeWarnings({
kind: metadata.id,
scope: 'route',
route: e.route,
files: [],
priority: e.count,
confidence: 0.93,
o11ySignal: e.errorRate != null
? `errs=${e.count},rate=${(e.errorRate * 100).toFixed(1)}%`
: `errs=${e.count}`,
reason: 'concentrated 5xx errors',
question: `Why does ${e.route} produce ${e.count} 5xx errors over the window, and what code path is failing?`,
evidence: { metric: e.metric, route: e.route, count: e.count, totalRequests: e.total, errorRate: e.errorRate },
}, signals));
}
function extractErrors(signals) {
const fnStatus = signals.metrics?.fnStatusByRoute;
if (Array.isArray(fnStatus?.rows)) return extractFromStatusRows(fnStatus.rows, 'fnStatusByRoute');
const m = signals.metrics?.requestsByRouteStatus;
const cache = signals.metrics?.requestsByRouteCache;
if (!m?.ok && !Array.isArray(m?.rows)) return [];
const errors = extractFromStatusRows(m?.rows ?? [], 'requestsByRouteStatus');
// cache rollup is summed across cache_result, giving per-route total request count.
const totalByRoute = new Map();
for (const row of (cache?.rows ?? [])) {
if (!row.route) continue;
totalByRoute.set(row.route, (totalByRoute.get(row.route) ?? 0) + (row.value ?? 0));
}
return errors.map((e) => {
const total = totalByRoute.get(e.route) ?? 0;
return {
...e,
total,
errorRate: total > 0 ? e.count / total : null,
};
});
}
function extractFromStatusRows(rows, metric) {
const errByRoute = new Map();
const totalByRoute = new Map();
for (const row of rows) {
const route = row.route;
if (!route) continue;
const v = row.value ?? 0;
const status = String(row.http_status ?? '');
if (/^5\d\d$/.test(status)) errByRoute.set(route, (errByRoute.get(route) ?? 0) + v);
totalByRoute.set(route, (totalByRoute.get(route) ?? 0) + v);
}
return [...errByRoute.entries()].map(([route, count]) => {
const total = totalByRoute.get(route) ?? 0;
const errorRate = total > 0 ? count / total : null;
return { route, count, total, errorRate, metric };
});
}
@@ -0,0 +1,122 @@
// Signal source is the codebase itself, not traffic. COLD-PATH and NO-ROUTE-MAPPING findings
// are dropped unless the scanner sets trafficIndependent (build configs, middleware matchers, etc.).
// Annotation happens in scan-codebase.mjs; gates here just read scanner.o11ySignal.
export const SCANNER_GATES = [
{ id: 'image_optimization', patterns: ['unoptimized-image'], threshold: 2,
billingDimension: 'image-optimization', priority: 30 },
{ id: 'cache_header_gap', patterns: ['max-age-without-s-maxage', 'missing-cache-headers'], threshold: 1,
billingDimension: 'edge-requests', priority: 40 },
{ id: 'rendering_candidate', patterns: ['force-dynamic', 'headers-in-page'], threshold: 3,
billingDimension: 'function-duration', priority: 35 },
{ id: 'use_cache_date_stamp', patterns: ['use-cache-date-stamp'], threshold: 1,
billingDimension: 'isr', priority: 45 },
{ id: 'cache_components_suspense_dedupe', patterns: ['cache-components-suspense-dedupe'], threshold: 1,
billingDimension: 'function-duration', priority: 38 },
];
export const metadata = {
id: 'scanner-driven',
threshold: 'per-kind: scanner matches.length >= threshold',
billingDimension: 'mixed',
scope: 'mixed',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Configured kinds emitted from scanner output. Each requires a minimum match count to avoid noise. Findings on cold-path or unmappable files are dropped unless the underlying scanner is trafficIndependent.',
};
export function gate(signals) {
const findings = signals.codebase?.findings ?? [];
if (findings.length === 0) return [];
const candidates = [];
for (const cfg of SCANNER_GATES) {
const matched = findings.filter((f) => {
if (!cfg.patterns.includes(f.pattern)) return false;
if (!f.trafficIndependent) {
if (!f.o11ySignal || f.o11ySignal === 'scanner-only') return false;
if (f.o11ySignal === 'COLD-PATH') return false;
if (f.o11ySignal === 'NO-ROUTE-MAPPING') return false;
}
if (cfg.id === 'cache_header_gap' && observedCacheHitRate(f.o11ySignal) >= 90) return false;
return true;
});
for (const group of groupFindings(cfg, matched)) {
if (group.findings.length < cfg.threshold) continue;
candidates.push(candidateForGroup(cfg, group));
}
}
return candidates;
}
function groupFindings(cfg, findings) {
const groups = new Map();
for (const finding of findings) {
const scope = finding.route ? 'route' : 'file';
const target = scope === 'route' ? finding.route : finding.file;
if (!target) continue;
const key = `${cfg.id}:${scope}:${target}`;
if (!groups.has(key)) groups.set(key, { scope, target, findings: [] });
groups.get(key).findings.push(finding);
}
return [...groups.values()];
}
function candidateForGroup(cfg, group) {
const matched = group.findings;
const route = group.scope === 'route' ? group.target : null;
return {
kind: cfg.id,
scope: group.scope,
route,
files: uniqueStrings(matched.map((m) => m.file)).slice(0, 6),
priority: cfg.priority + Math.min(matched.length, 10),
confidence: 0.88,
o11ySignal: matched
.map((m) => m.o11ySignal)
.find((s) => s && s !== 'COLD-PATH' && s !== 'NO-ROUTE-MAPPING')
?? 'scanner-only',
reason: `${matched.length} ${cfg.patterns.join('+')} finding(s)`,
question: questionFor(cfg.id, matched),
evidence: {
scannerMatches: matched.length,
patterns: cfg.patterns,
scope: group.scope,
route,
sampleFiles: matched.slice(0, 3).map((m) => ({ file: m.file, line: m.line })),
},
};
}
function questionFor(kindId, matched) {
const sample = matched.slice(0, 3).map((m) => m.file).join(', ');
switch (kindId) {
case 'image_optimization':
return `Which raw <img> tags in ${sample} should move to next/image (or the framework's image component)?`;
case 'cache_header_gap':
return `Should the route handlers in ${sample} set Cache-Control with s-maxage to serve from the CDN?`;
case 'rendering_candidate':
return `Why are the routes in ${sample} forced to dynamic rendering, and can any of them tolerate ISR or static generation?`;
case 'use_cache_date_stamp':
return `Which 'use cache' boundaries in ${sample} embed new Date()/Date.now()/Math.random() that destabilizes cache keys, and can the timestamps be hoisted to a build constant or moved into a client useEffect?`;
case 'cache_components_suspense_dedupe':
return `In ${sample}, which repeated fetch or helper is being re-invoked across separate <Suspense> boundaries, and can the promise be hoisted to the page level or moved to 'use cache: remote' for cross-boundary dedupe?`;
default:
return `Investigate ${matched.length} ${kindId} finding(s).`;
}
}
function uniqueStrings(values) {
return [...new Set(values.filter((v) => typeof v === 'string' && v.length > 0))];
}
function observedCacheHitRate(signal) {
if (typeof signal !== 'string') return null;
const m = /\bcache=([\d.]+)%/.exec(signal);
if (!m) return null;
const n = Number(m[1]);
return Number.isFinite(n) ? n : null;
}
@@ -0,0 +1,134 @@
// Deterministic launch selection for the code-scope investigation budget.
//
// Raw priority still orders candidates inside each pass. The default budget is
// impact-first, with failure-mode diversity when a kind's top signal is large
// enough to justify taking a first-pass slot.
const DEFAULT_KIND_CAPS = new Map([
['slow_route', 2],
['uncached_route', 2],
['route_errors', 2],
]);
const DIVERSITY_ELIGIBILITY = new Map([
// A handful of 5xx errors can pass the route_errors gate because the rate is
// high, but that should not displace much larger cost/performance signals in
// the default six-candidate pass.
['route_errors', (candidate) => numberFromEvidence(candidate, 'count') >= 1000],
// Scanner-driven cache findings are valuable, but the default pass should
// spend a slot only when observability shows meaningful route traffic or a
// very slow route handler.
['cache_header_gap', (candidate) => {
const invocations = numberFromSignal(candidate?.o11ySignal, 'inv');
const p95Ms = durationMsFromSignal(candidate?.o11ySignal, 'p95');
return invocations >= 50_000 || p95Ms >= 2000;
}],
['rendering_candidate', (candidate) => numberFromSignal(candidate?.o11ySignal, 'inv') >= 50_000],
]);
export function selectLaunchCandidates(candidates, budget, { diversify = false } = {}) {
const pool = Array.isArray(candidates) ? candidates : [];
if (budget === Infinity) {
return { selected: pool, skipped: [], selectionMode: 'all' };
}
if (!Number.isInteger(budget) || budget < 1) {
throw new TypeError('selectLaunchCandidates budget must be a positive integer or Infinity');
}
if (!diversify) {
return {
selected: pool.slice(0, budget),
skipped: pool.slice(budget),
selectionMode: 'priority',
};
}
const selected = [];
const selectedKeys = new Set();
const countsByKind = new Map();
const add = (candidate) => {
const key = candidateIdentity(candidate);
if (selectedKeys.has(key)) return false;
selectedKeys.add(key);
selected.push(candidate);
const kind = candidate.kind ?? '<unknown>';
countsByKind.set(kind, (countsByKind.get(kind) ?? 0) + 1);
return true;
};
// First pass: one candidate per failure mode, preserving the existing sorted
// order. This is where the default run gets broad coverage, but only for
// kinds whose signal is strong enough for a default slot.
for (const candidate of pool) {
if (selected.length >= budget) break;
const kind = candidate.kind ?? '<unknown>';
if ((countsByKind.get(kind) ?? 0) > 0) continue;
if (!isDiversityEligible(candidate)) continue;
add(candidate);
}
// Second pass: allow a second entry for high-frequency families, but avoid
// letting slow_route consume the entire default budget when other kinds exist.
for (const candidate of pool) {
if (selected.length >= budget) break;
const kind = candidate.kind ?? '<unknown>';
const cap = DEFAULT_KIND_CAPS.get(kind) ?? 1;
if ((countsByKind.get(kind) ?? 0) >= cap) continue;
if (!isDiversityEligible(candidate)) continue;
add(candidate);
}
// Final fill: if the project only has one or two candidate kinds, use the
// whole requested budget rather than leaving slots empty.
for (const candidate of pool) {
if (selected.length >= budget) break;
add(candidate);
}
return {
selected,
skipped: pool.filter((candidate) => !selectedKeys.has(candidateIdentity(candidate))),
selectionMode: 'diverse-default',
};
}
function candidateIdentity(candidate) {
return [
candidate?.kind ?? '',
candidate?.route ?? '',
candidate?.hostname ?? '',
candidate?.scope ?? '',
candidate?.o11ySignal ?? '',
].join('\u0000');
}
function isDiversityEligible(candidate) {
const fn = DIVERSITY_ELIGIBILITY.get(candidate?.kind);
return fn ? fn(candidate) : true;
}
function numberFromEvidence(candidate, key) {
const value = candidate?.evidence?.[key];
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
}
function numberFromSignal(signal, key) {
if (typeof signal !== 'string') return 0;
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(`(?:^|,)${escaped}=([\\d.]+)`);
const m = re.exec(signal);
if (!m) return 0;
const n = Number(m[1]);
return Number.isFinite(n) ? n : 0;
}
function durationMsFromSignal(signal, key) {
if (typeof signal !== 'string') return 0;
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(`(?:^|,)${escaped}=([\\d.]+)ms`);
const m = re.exec(signal);
if (!m) return 0;
const n = Number(m[1]);
return Number.isFinite(n) ? n : 0;
}
@@ -0,0 +1,88 @@
// Primary threshold (p95>500 AND inv>=1400) WHY: 1.4k/14d is the floor where p95 stabilizes statistically
// and a 3-5x performance win still pays for engineering time. Secondary (p95>1500 AND inv>=250) catches "catastrophically
// slow at any volume" — usually a broken sync call or cold-start chain the customer wants to know about.
//
// 5xx disqualifier: when error rate >50% the route is failing, not slow — latency reflects crash time,
// not work time. route_errors covers it independently; we disqualify here so budget isn't spent on a
// sub-agent that will correctly abstain.
import { withRouteShapeWarnings } from '../route-normalize.mjs';
const ERROR_RATE_DISQUALIFY_THRESHOLD = 0.5;
export const metadata = {
id: 'slow_route',
threshold: '(p95 > 500 AND inv >= 1400) OR (p95 > 1500 AND inv >= 250); disqualified when 5xx rate > 50%; Vercel Workflow runtime endpoints are hard-gated',
billingDimension: 'function-duration',
scope: 'route',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Routes with p95 function duration above 500ms at meaningful traffic (>=1,400 invocations in window), OR catastrophically slow routes (>1500ms p95 at any volume >=250). High duration drives both function-duration cost and user-perceived latency. Investigate sequential awaits, slow external APIs, missing caching, N+1 patterns. Routes with >50% 5xx rate are disqualified — those are reliability problems, not performance tuning targets, and surface via route_errors instead. Vercel Workflow runtime endpoints (`/.well-known/workflow/v1/*`) are hard-gated before launch because long-running step/flow requests are expected orchestration, not app-route bottlenecks.',
};
export function gate(signals) {
const routes = extractFunctionRoutes(signals);
const errorRates = extractErrorRatesByRoute(signals);
return routes
.filter((r) => (r.p95Ms > 500 && r.invocations >= 1400) || (r.p95Ms > 1500 && r.invocations >= 250))
.map((r) => {
const errorRate = errorRates.get(r.route);
const candidate = {
kind: metadata.id,
scope: 'route',
route: r.route,
files: [],
priority: Math.round(r.p95Ms * Math.max(r.invocations, 1) / 1000),
confidence: 0.94,
o11ySignal: `inv=${r.invocations},p95=${r.p95Ms}ms${errorRate != null ? `,5xx=${(errorRate * 100).toFixed(0)}%` : ''}`,
reason: 'slow high-traffic route',
question: `What is the concrete bottleneck in ${r.route} (p95=${r.p95Ms}ms over ${r.invocations} invocations), and which file-level change would reduce it?`,
evidence: { metric: 'fnDurationP95ByRoute', route: r.route, p95Ms: r.p95Ms, invocations: r.invocations, errorRate },
};
if (errorRate != null && errorRate > ERROR_RATE_DISQUALIFY_THRESHOLD) {
candidate.disqualified = true;
candidate.disqualifyReason = `high error rate (${(errorRate * 100).toFixed(0)}% 5xx — reliability issue, not performance; covered by route_errors gate)`;
}
return withRouteShapeWarnings(candidate, signals);
});
}
// Routes without status data are absent from the map → gate falls back to "no disqualification".
function extractErrorRatesByRoute(signals) {
const m = signals.metrics?.fnStatusByRoute;
const out = new Map();
if (!Array.isArray(m?.rows)) return out;
const perRoute = new Map();
for (const row of m.rows) {
if (!row?.route) continue;
const v = row.value ?? 0;
const prior = perRoute.get(row.route) ?? { errors5xx: 0, total: 0 };
if (/^5/.test(String(row.http_status ?? ''))) prior.errors5xx += v;
prior.total += v;
perRoute.set(row.route, prior);
}
for (const [route, r] of perRoute) {
if (r.total > 0) out.set(route, r.errors5xx / r.total);
}
return out;
}
function extractFunctionRoutes(signals) {
const dur = signals.metrics?.fnDurationP95ByRoute;
if (!dur?.ok && !Array.isArray(dur?.rows)) return [];
const req = signals.metrics?.requestsByRouteCache;
const invByRoute = new Map();
for (const row of (req?.rows ?? [])) {
if (!row.route) continue;
invByRoute.set(row.route, (invByRoute.get(row.route) ?? 0) + (row.value ?? 0));
}
return (dur?.rows ?? [])
.filter((r) => r.route)
.map((r) => ({
route: r.route,
p95Ms: Math.round(r.value ?? 0),
invocations: invByRoute.get(r.route) ?? 0,
}));
}
@@ -0,0 +1,38 @@
export type CandidateScope = 'route' | 'file' | 'account';
export interface GateMetadata {
id: string;
threshold: string;
billingDimension: string;
scope: CandidateScope | 'mixed';
sourceCitation?: string;
description?: string;
}
export interface Candidate {
kind: string;
scope: CandidateScope;
route?: string | null;
hostname?: string | null;
files: string[];
priority: number;
confidence: number;
o11ySignal?: string;
reason: string;
question: string;
evidence?: Record<string, unknown>;
disqualified?: boolean;
disqualifyReason?: string;
warnings?: string[];
}
export interface Signals {
metrics?: Record<string, unknown>;
codebase?: {
findings?: Array<Record<string, unknown>>;
routes?: Array<Record<string, unknown>>;
};
project?: Record<string, unknown>;
usage?: Record<string, unknown>;
stack?: Record<string, unknown>;
}
@@ -0,0 +1,93 @@
// getShare>0.20 filter WHY: a route that's >80% POST/PUT/DELETE is a mutation endpoint
// where 0% cache is correct — recommending caching there is wrong.
// cache_result values STALE/REVALIDATED/BYPASS fold into "total but not HIT" — matches the "uncached" framing.
import { withRouteShapeWarnings } from '../route-normalize.mjs';
const MIN_GET_SHARE = 0.20;
/** @type {import('./types.d.ts').GateMetadata} */
export const metadata = {
id: 'uncached_route',
threshold: `requests > 500 AND hitRate < 0.5 AND getShare > ${MIN_GET_SHARE} (missing getShare is gated)`,
billingDimension: 'edge-requests',
scope: 'route',
sourceCitation: 'vercel-optimize gate threshold',
description:
'Routes serving > 500 requests/period at < 50% cache hit AND at least 20% GET traffic. Each uncached GET request reaches the function, costing edge requests + function duration. Routes that are mostly POST/PUT/DELETE (Server Actions, mutations) are skipped — 0% cache is correct behavior there. Routes with missing method-share data are gated instead of launched. Auth-gated routes are disqualified separately.',
};
/**
* @param {import('./types.d.ts').Signals} signals
* @returns {import('./types.d.ts').Candidate[]}
*/
export function gate(signals) {
const rates = extractCacheHitRates(signals);
const methods = extractMethodShares(signals);
return rates
.map((r) => ({ ...r, getShare: methods.get(r.route) ?? null }))
.filter((r) => r.requests > 500 && r.hitRate < 0.5)
.filter((r) => r.getShare === null || r.getShare > MIN_GET_SHARE)
.map((r) => {
const candidate = withRouteShapeWarnings({
kind: metadata.id,
scope: 'route',
route: r.route,
files: [],
priority: Math.round(r.requests * (1 - r.hitRate)),
confidence: r.getShare === null ? 0.5 : 0.92,
o11ySignal: `requests=${r.requests},cache=${(r.hitRate * 100).toFixed(0)}%${r.getShare !== null ? `,get=${(r.getShare * 100).toFixed(0)}%` : ''}`,
reason: 'uncached high-traffic route',
question: `Why does ${r.route} have ${(r.hitRate * 100).toFixed(0)}% cache hit rate on ${r.requests} requests in this metrics window, and is it safe to cache at the edge?`,
evidence: { metric: 'requestsByRouteCache', route: r.route, requests: r.requests, hitRate: r.hitRate, getShare: r.getShare },
}, signals);
if (r.getShare !== null) return candidate;
return {
...candidate,
disqualified: true,
disqualifyReason: 'missing GET-share data — route method mix is required before recommending edge caching',
warnings: [...new Set([...(candidate.warnings ?? []), 'method-share:missing'])],
};
});
}
function extractCacheHitRates(signals) {
const m = signals.metrics?.requestsByRouteCache;
if (!m?.ok && !Array.isArray(m?.rows)) return [];
const perRoute = new Map();
for (const row of (m?.rows ?? [])) {
const route = row.route;
if (!route) continue;
const value = row.value ?? 0;
const prior = perRoute.get(route) ?? { route, hits: 0, total: 0 };
if (row.cache_result === 'HIT') prior.hits += value;
prior.total += value;
perRoute.set(route, prior);
}
return [...perRoute.values()].map((r) => ({
route: r.route,
requests: r.total,
hitRate: r.total > 0 ? r.hits / r.total : 0,
}));
}
function extractMethodShares(signals) {
const m = signals.metrics?.requestsByRouteMethod;
const out = new Map();
if (!Array.isArray(m?.rows)) return out;
const perRoute = new Map();
for (const row of m.rows) {
if (!row?.route) continue;
const v = row.value ?? 0;
const prior = perRoute.get(row.route) ?? { gets: 0, total: 0 };
if ((row.request_method ?? '').toUpperCase() === 'GET') prior.gets += v;
prior.total += v;
perRoute.set(row.route, prior);
}
for (const [route, r] of perRoute) {
if (r.total > 0) out.set(route, r.gets / r.total);
}
return out;
}
@@ -0,0 +1,121 @@
// Detects per-day billing spikes by inspecting usage.breakdown.data[] (daily granularity).
// Fires when any single day's total bill > 2× the window mean, OR a single SKU's day value > 3× its window mean.
// Emits one candidate per spiking SKU (or 'total' when the spike is broad).
// Degrades gracefully when daily data is unavailable — common path because the skill prefers --group-by project, which omits daily breakdown.
export const metadata = {
id: 'usage_spike_triage',
threshold: 'any-day total > 2x mean OR any-day SKU > 3x SKU mean',
billingDimension: 'mixed',
scope: 'account',
sourceCitation: 'vercel-optimize gate threshold',
description:
'A single day in the billing window deviates sharply from the window baseline. Triage branches: bot or AI crawler spike, viral moment, pricing-model migration (legacy SKU → new), code regression. Without daily-granularity data, this gate stays dormant.',
};
const TOTAL_MULTIPLIER = 2;
const SKU_MULTIPLIER = 3;
const MIN_BILLED_FLOOR = 5; // skip spikes whose absolute value is too small to matter
export function gate(signals) {
const days = signals?.usage?.breakdown?.data;
if (!Array.isArray(days) || days.length < 3) return [];
const dayTotals = days.map(dayTotal);
const mean = dayTotals.reduce((a, b) => a + b, 0) / dayTotals.length;
if (mean <= MIN_BILLED_FLOOR) return [];
const totalSpikeDays = dayTotals
.map((value, idx) => ({ idx, value }))
.filter((d) => d.value > mean * TOTAL_MULTIPLIER && d.value > MIN_BILLED_FLOOR);
const skuStats = aggregateSkuStats(days);
const skuSpikes = [];
for (const stat of skuStats) {
if (stat.mean <= MIN_BILLED_FLOOR) continue;
for (const sample of stat.samples) {
if (sample.value > stat.mean * SKU_MULTIPLIER && sample.value > MIN_BILLED_FLOOR) {
skuSpikes.push({
name: stat.name,
dayIndex: sample.idx,
dayValue: sample.value,
skuMean: stat.mean,
multiplier: stat.mean > 0 ? sample.value / stat.mean : null,
});
}
}
}
if (totalSpikeDays.length === 0 && skuSpikes.length === 0) return [];
const candidates = [];
if (totalSpikeDays.length > 0) {
const peak = totalSpikeDays.reduce((a, b) => (a.value > b.value ? a : b));
candidates.push({
kind: metadata.id,
scope: 'account',
files: [],
priority: 60,
confidence: 0.78,
o11ySignal: `total_spike day_idx=${peak.idx} day_billed=${peak.value.toFixed(2)} window_mean=${mean.toFixed(2)} mult=${(peak.value / mean).toFixed(1)}x`,
reason: 'total billed cost on one day exceeds 2× the window mean',
question: 'Which workload generated the day-over-day spike — bot or AI-crawler traffic on a cacheable route, a viral event, a pricing-model migration, or a code regression?',
evidence: {
metric: 'usage.breakdown.data.total',
spikeDay: peak.idx,
spikeBilled: peak.value,
windowMean: mean,
multiplier: peak.value / mean,
skuName: 'total',
},
});
}
// Up to 3 SKU-specific candidates; the rest fold into 'multiple SKUs spiking' framing.
const orderedSkuSpikes = skuSpikes.sort((a, b) => b.dayValue - a.dayValue).slice(0, 3);
for (const spike of orderedSkuSpikes) {
candidates.push({
kind: metadata.id,
scope: 'account',
files: [],
priority: 55,
confidence: 0.78,
o11ySignal: `sku_spike sku="${spike.name}" day_idx=${spike.dayIndex} day_billed=${spike.dayValue.toFixed(2)} sku_mean=${spike.skuMean.toFixed(2)} mult=${spike.multiplier.toFixed(1)}x`,
reason: `${spike.name} on one day exceeds 3× its window mean`,
question: `${spike.name} spiked ${spike.multiplier.toFixed(1)}× on day ${spike.dayIndex}. Which event (bot traffic, viral content, deploy regression, integration sync) drove it, and is the spiking SKU one the skill already covers?`,
evidence: {
metric: 'usage.breakdown.data.services',
skuName: spike.name,
spikeDay: spike.dayIndex,
spikeBilled: spike.dayValue,
skuMean: spike.skuMean,
multiplier: spike.multiplier,
},
});
}
return candidates;
}
function dayTotal(day) {
if (Array.isArray(day?.services)) {
return day.services.reduce((a, s) => a + Number(s.billedCost ?? s.cost ?? 0), 0);
}
return Number(day?.billedCost ?? day?.cost ?? 0);
}
function aggregateSkuStats(days) {
const byName = new Map();
days.forEach((day, idx) => {
const services = Array.isArray(day?.services) ? day.services : [];
for (const svc of services) {
const name = String(svc?.name ?? '').trim();
if (!name) continue;
const value = Number(svc.billedCost ?? svc.cost ?? 0);
if (!byName.has(name)) byName.set(name, { name, samples: [] });
byName.get(name).samples.push({ idx, value });
}
});
for (const stat of byName.values()) {
const sum = stat.samples.reduce((a, s) => a + s.value, 0);
stat.mean = stat.samples.length > 0 ? sum / stat.samples.length : 0;
}
return [...byName.values()];
}