playbook/antigravity-awesome-skills/skills/vercel-optimize/lib/gates/build-minutes-fanout.mjs

70 lines
2.9 KiB
JavaScript

// 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)];
}