playbook/antigravity-awesome-skills/plugins/antigravity-awesome-skills-.../skills/vercel-optimize/scripts/render-report.mjs

438 lines
17 KiB
JavaScript

#!/usr/bin/env node
// Final pipeline step. Emits customer-facing markdown from
// recommendations.json + gate.json + signals.json.
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';
import { buildFinalReportMessage, renderReport } from '../lib/render-report.mjs';
import { dedupeRecommendations } from '../lib/dedup-recs.mjs';
import { canonicalizeRoute } from '../lib/route-normalize.mjs';
import { hasUnsupportedCacheLifeCdnText, splitCustomerSafeObservations } from '../lib/observation-safety.mjs';
const log = (...a) => console.error('[render-report]', ...a);
const HARD_REGEN_TRIGGERS = new Set([
'project_config_contradiction',
'cache_vary_safety',
'semantic_safety',
]);
async function main() {
const args = parseArgs(process.argv.slice(2));
if (!args.recsPath || !args.gatePath || !args.signalsPath) {
console.error('usage: node scripts/render-report.mjs <recommendations.json> <gate.json> <signals.json> [--project NAME] [--out FILE] [--message-out FILE] [--no-timestamp] [--debug-out FILE]');
process.exit(1);
}
const [recsRaw, gateRaw, signalsRaw] = await Promise.all([
readFile(args.recsPath, 'utf-8').then(JSON.parse),
readFile(args.gatePath, 'utf-8').then(JSON.parse),
readFile(args.signalsPath, 'utf-8').then(JSON.parse),
]);
// Accept either a raw rec array OR the verify-and-regen wrapper
// {recsGraded, qualityDropped, ...}. Stale-rec defense: when verify-and-regen
// flagged a hard-safety issue but the orchestrator skipped re-spawn, the
// original rec is still in recsGraded. Filter it here so it can't ship; it
// surfaces in "Investigated, no change recommended" instead.
const hardRegenRefs = new Set(
Array.isArray(recsRaw.regenPlan)
? recsRaw.regenPlan
.filter((p) => HARD_REGEN_TRIGGERS.has(p.regenTrigger))
.map((p) => p.candidateRef)
.filter(Boolean)
: []
);
const activeCandidates = [
...(Array.isArray(gateRaw.toLaunch) ? gateRaw.toLaunch : []),
...(Array.isArray(gateRaw.platform) ? gateRaw.platform : []),
];
const enforceCurrentGate = !Array.isArray(recsRaw) && activeCandidates.length > 0;
const staleRecommendationDrops = [];
const wrapperRecommendations = Array.isArray(recsRaw.renderableRecommendations)
? recsRaw.renderableRecommendations
: (recsRaw.recsGraded ?? []);
const needsReviewDrops = [];
const candidateRecommendations = Array.isArray(recsRaw)
? recsRaw.filter((r) => r?.abstain !== true)
: wrapperRecommendations
.filter((r, i) => (r.quality?.overall ?? 0) >= 0.55)
.filter((r) => !hardRegenRefs.has(r.candidateRef));
const recommendationsRaw = candidateRecommendations
.filter((r) => {
if (r?.abstain === true || r?.needsReview !== true) return true;
needsReviewDrops.push({
candidateRef: r.candidateRef ?? null,
reason: 'This recommendation needs a manual safety review before it is ready to apply.',
});
return false;
})
.filter((r) => {
if (!enforceCurrentGate) return true;
if (recommendationMatchesActiveCandidate(r, activeCandidates)) return true;
staleRecommendationDrops.push({
candidateRef: r.candidateRef ?? null,
reason: 'This recommendation came from a candidate that is not in the current run output. Re-run from a clean run directory before applying it.',
});
return false;
});
const recommendations = dedupeRecommendations(recommendationsRaw);
const readyTargets = new Set(
recommendations
.map((r) => candidateTarget(r?.candidateRef))
.filter(Boolean)
);
const droppedContradictions = !Array.isArray(recsRaw)
? (recsRaw.recsGraded ?? [])
.map((r, i) => ({ r, i }))
.filter(({ r }) => hardRegenRefs.has(r.candidateRef))
.map(({ r, i }) => ({
candidateRef: r.candidateRef ?? null,
reason: publicHardRegenReason(recsRaw.regenPlan?.find((p) => p.index === i || p.candidateRef === r.candidateRef)),
}))
: [];
const gated = Array.isArray(gateRaw.gated) ? gateRaw.gated : [];
// No-change findings are first-class investigation outputs ("the hypothesis didn't hold").
// Contradiction-dropped recs ride alongside them so customers see WHY a rec
// was held back instead of it silently disappearing.
const baseAbstentions = Array.isArray(recsRaw)
? recsRaw.filter((r) => r?.abstain === true).map((r) => ({
candidateRef: r.candidateRef ?? null,
reason: publicNoChangeReason(r.reason ?? '(no reason recorded)'),
}))
: (recsRaw.abstentions ?? []).map((r) => ({
...r,
reason: publicNoChangeReason(r.reason ?? '(no reason recorded)'),
}));
const publicBaseAbstentions = baseAbstentions.filter((r) => !readyTargets.has(candidateTarget(r?.candidateRef)));
// Observations: no-change findings carrying a structured non-perf finding
// (deployment regression, error storm, etc.).
const flattenedObservations = Array.isArray(recsRaw)
? flattenObservations(recsRaw.filter((r) => r?.abstain === true))
: flattenObservations([
...(Array.isArray(recsRaw.observations) ? recsRaw.observations : []),
...(Array.isArray(recsRaw.abstentions) ? recsRaw.abstentions : []),
]);
const { observations: safeObservations, heldBackObservations } = splitCustomerSafeObservations(flattenedObservations, baseAbstentions, signalsRaw);
const observations = suppressReadyCoveredObservations(safeObservations, recommendations);
const abstentions = [
...publicBaseAbstentions,
...droppedContradictions,
...staleRecommendationDrops,
...needsReviewDrops,
...(Array.isArray(recsRaw.withheldRecommendations) ? recsRaw.withheldRecommendations.map((d) => ({
candidateRef: d.candidateRef ?? null,
reason: publicWithheldReason(d),
needsEvidence: true,
})) : []),
...(Array.isArray(recsRaw.sanitizerDropped) ? recsRaw.sanitizerDropped.map((d) => ({
candidateRef: d.candidateRef ?? null,
reason: `This needs a closer review before it is safe to apply: ${d.reason ?? 'review required'}.`,
needsEvidence: true,
})) : []),
...(Array.isArray(recsRaw.heldBackObservations) ? recsRaw.heldBackObservations.map((d) => ({
...d,
needsEvidence: true,
})) : []),
...heldBackObservations,
];
// Full catalog lets the renderer recover o11ySignal + aliasRoutes that recs
// didn't propagate, and canonicalize segment-tree candidateRefs.
const allCandidates = [
...activeCandidates,
...gated,
];
const md = renderReport({
recommendations,
gated,
abstentions,
observations,
signals: signalsRaw,
candidates: allCandidates,
opts: {
projectName: args.projectName,
generatedAt: args.noTimestamp ? null : new Date().toISOString(),
heldBackCount: (Number.isInteger(recsRaw.summary?.withheldRecommendations)
? recsRaw.summary.withheldRecommendations
: (Array.isArray(recsRaw.regenPlan) ? recsRaw.regenPlan.length : 0) +
(Array.isArray(recsRaw.qualityDropped) ? recsRaw.qualityDropped.length : 0)) +
(Array.isArray(recsRaw.sanitizerDropped) ? recsRaw.sanitizerDropped.length : 0) +
(Array.isArray(recsRaw.heldBackObservations) ? recsRaw.heldBackObservations.length : 0) +
heldBackObservations.length,
noChangeCount: Number.isInteger(recsRaw.summary?.abstentions)
? Math.min(recsRaw.summary.abstentions, publicBaseAbstentions.length)
: publicBaseAbstentions.length,
},
});
if (args.debugOutPath) {
const debugArtifact = buildDebugArtifact({
recsRaw,
recommendationsRaw,
recommendations,
gateRaw,
abstentions,
observations,
heldBackObservations,
staleRecommendationDrops,
droppedContradictions,
});
const serializedDebug = JSON.stringify(debugArtifact, null, 2) + '\n';
await mkdir(dirname(args.debugOutPath), { recursive: true });
await writeFile(args.debugOutPath, serializedDebug, 'utf-8');
log(`wrote debug ${serializedDebug.length}B → ${args.debugOutPath}`);
}
if (args.messageOutPath) {
const messageArtifact = buildFinalReportMessage({
reportPath: args.outPath ?? '(stdout)',
markdown: md,
recommendations,
signals: signalsRaw,
});
const serializedMessage = JSON.stringify(messageArtifact, null, 2) + '\n';
await mkdir(dirname(args.messageOutPath), { recursive: true });
await writeFile(args.messageOutPath, serializedMessage, 'utf-8');
log(`wrote final message ${serializedMessage.length}B → ${args.messageOutPath}`);
}
if (args.outPath) {
await mkdir(dirname(args.outPath), { recursive: true });
await writeFile(args.outPath, md + '\n', 'utf-8');
log(`wrote ${md.length}B → ${args.outPath}`);
} else {
process.stdout.write(md + '\n');
}
}
function parseArgs(argv) {
const out = { positional: [] };
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a === '--project') out.projectName = argv[++i];
else if (a.startsWith('--project=')) out.projectName = a.slice('--project='.length);
else if (a === '--out') out.outPath = resolve(argv[++i]);
else if (a.startsWith('--out=')) out.outPath = resolve(a.slice('--out='.length));
else if (a === '--message-out') out.messageOutPath = resolve(argv[++i]);
else if (a.startsWith('--message-out=')) out.messageOutPath = resolve(a.slice('--message-out='.length));
else if (a === '--no-timestamp') out.noTimestamp = true;
else if (a === '--debug-out') out.debugOutPath = resolve(argv[++i]);
else if (a.startsWith('--debug-out=')) out.debugOutPath = resolve(a.slice('--debug-out='.length));
else if (a === '--debug') {
console.error('[render-report] --debug no longer writes internal details into customer markdown; use --debug-out FILE');
}
else out.positional.push(a);
}
out.recsPath = out.positional[0];
out.gatePath = out.positional[1];
out.signalsPath = out.positional[2];
return out;
}
function publicWithheldReason(record) {
switch (record?.reason) {
case 'needs_review':
return 'Automated checks added a safety caveat, so this run kept the recommendation out of the ready-to-apply list.';
case 'quality_floor':
return 'The recommendation did not meet the evidence bar for this report.';
case 'project_config_contradiction':
case 'cache_vary_safety':
case 'semantic_safety':
return publicHardRegenReason({ regenTrigger: record.reason });
default:
return 'This recommendation needs stronger evidence before it is safe to apply.';
}
}
function publicHardRegenReason(plan) {
switch (plan?.regenTrigger) {
case 'project_config_contradiction':
return 'The recommendation tried to turn on a project setting that is already enabled. Re-run the investigation with refreshed project-config evidence.';
case 'cache_vary_safety':
return 'The recommendation added shared CDN caching to output that varies by request geography without the required Vary header. Re-run the investigation with the cache-safety failure in scope.';
case 'semantic_safety':
return 'This recommendation needs stronger framework evidence before it is safe to apply. Re-run the investigation with that evidence in scope.';
default:
return 'This recommendation needs stronger evidence before it is safe to apply. Re-run the investigation with those checks in scope.';
}
}
function recommendationMatchesActiveCandidate(rec, candidates) {
const ref = parseCandidateRef(rec?.candidateRef);
if (!ref) return true;
return candidates.some((candidate) => candidateMatchesRef(candidate, ref));
}
function parseCandidateRef(ref) {
if (typeof ref !== 'string' || ref.length === 0) return null;
const [kind, ...targetParts] = ref.split(':');
if (!kind) return null;
return { kind, target: targetParts.join(':') };
}
function candidateMatchesRef(candidate, ref) {
if (!candidate || candidate.kind !== ref.kind) return false;
if (candidate.scope === 'account' || ref.target === '<account>') return true;
const candidateTarget = candidate.route ?? candidate.hostname ?? candidate.file ?? candidate.target ?? null;
if (!candidateTarget || !ref.target) return false;
const a = String(candidateTarget);
const b = String(ref.target);
return a === b || canonicalizeRoute(a) === canonicalizeRoute(b);
}
function suppressReadyCoveredObservations(observations, recommendations = []) {
if (!Array.isArray(observations) || observations.length === 0) return [];
const readyFamiliesByTarget = new Map();
for (const rec of recommendations) {
const parsed = parseCandidateRef(rec?.candidateRef);
const target = candidateTarget(rec?.candidateRef);
const family = candidateFamily(parsed?.kind);
if (!target || !family) continue;
const set = readyFamiliesByTarget.get(target) ?? new Set();
set.add(family);
readyFamiliesByTarget.set(target, set);
}
return observations.filter((observation) => {
const parsed = parseCandidateRef(observation?.candidateRef);
const target = candidateTarget(observation?.candidateRef);
const family = candidateFamily(parsed?.kind);
if (!target || !family) return true;
return !readyFamiliesByTarget.get(target)?.has(family);
});
}
function candidateFamily(kind) {
switch (kind) {
case 'uncached_route':
case 'cache_header_gap':
case 'missing_cache_headers':
case 'max_age_without_s_maxage':
return 'cache';
case 'slow_route':
case 'cold_start':
case 'external_api_slow':
case 'cwv_poor':
return 'performance';
case 'route_errors':
return 'reliability';
case 'isr_overrevalidation':
return 'isr';
case 'middleware_heavy':
return 'middleware';
case 'build_minutes_fanout':
return 'build';
default:
return kind || null;
}
}
function candidateTarget(ref) {
if (typeof ref !== 'string') return null;
const idx = ref.indexOf(':');
if (idx === -1) return null;
return ref.slice(idx + 1);
}
function publicNoChangeReason(reason) {
if (hasUnsupportedCacheLifeCdnText(reason)) {
return 'This candidate overlapped a cache-lifetime draft that did not meet the framework evidence bar. No supported change shipped from this run.';
}
return reason;
}
function buildDebugArtifact({
recsRaw,
recommendationsRaw,
recommendations,
gateRaw,
abstentions = [],
observations = [],
heldBackObservations = [],
staleRecommendationDrops = [],
droppedContradictions = [],
}) {
const wrapper = Array.isArray(recsRaw) ? null : recsRaw;
const sourceRecords = Array.isArray(recsRaw)
? recsRaw
: (recsRaw.recsGraded ?? []);
const summary = wrapper?.summary
? {
...wrapper.summary,
rawRecommendationCount: recommendationsRaw.length,
renderedRecommendationCount: recommendations.length,
}
: null;
return {
schemaVersion: '1.0',
summary,
regenPlan: wrapper?.regenPlan ?? [],
qualityDropped: wrapper?.qualityDropped ?? [],
withheldRecommendations: wrapper?.withheldRecommendations ?? [],
abstentions,
observations,
heldBackObservations,
staleRecommendationDrops,
droppedContradictions,
sanitizerDropped: wrapper?.sanitizerDropped ?? [],
renderedRecommendationCount: recommendations.length,
rawRecommendationCount: recommendationsRaw.length,
gateBudget: gateRaw?.budget ?? null,
recommendations: sourceRecords
.filter((record) => record && record.abstain !== true)
.map((record) => ({
candidateRef: record.candidateRef ?? null,
what: record.what ?? null,
verification: record.verification ?? null,
quality: record.quality ?? null,
passRate: record.passRate ?? record.verification?.passRate ?? null,
avgQuality: record.avgQuality ?? null,
needsReview: record.needsReview === true,
sanitizerTrail: Array.isArray(record.sanitizerTrail) ? record.sanitizerTrail : [],
})),
};
}
function flattenObservations(records) {
const out = [];
for (const record of records) {
if (!record || typeof record !== 'object') continue;
if (record.observation && typeof record.observation === 'object') {
out.push({
candidateRef: record.candidateRef ?? null,
summary: coerceOptionalString(record.observation.summary),
evidence: record.observation.evidence ?? null,
suggestedAction: record.observation.suggestedAction ?? null,
kind: record.observation.kind ?? 'other',
});
continue;
}
if ('summary' in record || 'evidence' in record || 'suggestedAction' in record || 'kind' in record) {
out.push({
candidateRef: record.candidateRef ?? null,
summary: coerceOptionalString(record.summary),
evidence: record.evidence ?? null,
suggestedAction: record.suggestedAction ?? null,
kind: record.kind ?? 'other',
});
}
}
return out;
}
function coerceOptionalString(value) {
return value == null ? value : String(value);
}
main().catch((err) => {
console.error('[render-report] FAILED:', err.message);
console.error(err.stack);
process.exit(1);
});