hotfix(ci): compact ai review comments and switch to glm-5-turbo

This commit is contained in:
Tam Nhu Tran
2026-04-02 01:07:03 -04:00
parent f6779a503a
commit 25dddf4707
6 changed files with 160 additions and 93 deletions
+119 -50
View File
@@ -14,6 +14,11 @@ const SEVERITY_HEADERS = {
medium: '### 🟡 Medium',
low: '### 🟢 Low',
};
const SEVERITY_SUMMARY_LABELS = {
high: '🔴 High',
medium: '🟡 Medium',
low: '🟢 Low',
};
const STATUS_LABELS = {
pass: '✅',
@@ -41,6 +46,7 @@ const CODE_BLOCK_LANGUAGE_PATTERN = /^[A-Za-z0-9#+.-]{1,20}$/u;
const MAX_FINDING_SNIPPETS = 2;
const MAX_SNIPPET_LINES = 20;
const MAX_SNIPPET_CHARACTERS = 1200;
const TOP_FINDINGS_LIMIT = 3;
function cleanText(value) {
return typeof value === 'string' ? value.trim().replace(/\s+/g, ' ') : '';
@@ -224,35 +230,40 @@ function formatReviewContext(rendering) {
const parts = [];
if (rendering.mode) {
parts.push(`mode ${renderCode(rendering.mode)}`);
parts.push(REVIEW_MODE_DETAILS[rendering.mode]);
parts.push(renderCode(rendering.mode));
}
const scopeSummary = formatScopeSummary(rendering);
if (scopeSummary) {
parts.push(`scope ${scopeSummary}`);
if (
typeof rendering.selectedFiles === 'number' &&
typeof rendering.reviewableFiles === 'number'
) {
parts.push(`${rendering.selectedFiles}/${rendering.reviewableFiles} files`);
}
const packetCoverage = formatPacketCoverage(rendering);
if (packetCoverage) {
parts.push(`packet ${packetCoverage}`);
if (
typeof rendering.selectedChanges === 'number' &&
typeof rendering.reviewableChanges === 'number'
) {
parts.push(`${rendering.selectedChanges}/${rendering.reviewableChanges} lines`);
}
const turnBudget = formatTurnBudget(rendering);
if (turnBudget) {
parts.push(`turn budget ${turnBudget}`);
if (
typeof rendering.packetIncludedFiles === 'number' &&
typeof rendering.packetTotalFiles === 'number'
) {
parts.push(`packet ${rendering.packetIncludedFiles}/${rendering.packetTotalFiles}`);
}
const timeBudget = formatTimeBudget(rendering);
if (timeBudget) {
parts.push(`workflow cap ${timeBudget}`);
const runtimeBudget = formatCombinedBudget(rendering) || formatTimeBudget(rendering) || formatTurnBudget(rendering);
if (runtimeBudget) {
parts.push(runtimeBudget);
}
if (parts.length === 0) {
return null;
}
return `> 🧭 Review context: ${parts.join('; ')}.`;
return `> 🧭 ${parts.join(' ')}`;
}
function classifyFallbackReason(reason) {
@@ -612,8 +623,8 @@ export function normalizeStructuredOutput(raw) {
return { ok: true, value };
}
function renderChecklistTable(title, labelHeader, labelKey, rows) {
const lines = ['', title, '', `| ${labelHeader} | Status | Notes |`, '|---|---|---|'];
function renderChecklistTable(labelHeader, labelKey, rows) {
const lines = [`| ${labelHeader} | Status | Notes |`, '|---|---|---|'];
for (const row of rows) {
lines.push(
`| ${renderInlineText(row[labelKey])} | ${STATUS_LABELS[row.status]} | ${renderInlineText(row.notes)} |`
@@ -622,9 +633,9 @@ function renderChecklistTable(title, labelHeader, labelKey, rows) {
return lines;
}
function renderBulletSection(title, items) {
function renderBulletSection(items) {
if (items.length === 0) return [];
return ['', title, ...items.map((item) => `- ${renderInlineText(item)}`)];
return items.map((item) => `- ${renderInlineText(item)}`);
}
function renderFindingSnippets(snippets) {
@@ -646,46 +657,104 @@ function renderFindingSnippets(snippets) {
return lines;
}
function renderDetailsBlock(summary, bodyLines) {
if (!bodyLines.length) {
return [];
}
return ['', '<details>', `<summary>${escapeMarkdown(summary)}</summary>`, '', ...bodyLines, '', '</details>'];
}
function renderFindingReference(finding) {
return finding.line ? `${finding.file}:${finding.line}` : finding.file;
}
function getOrderedFindings(findings) {
return SEVERITY_ORDER.flatMap((severity) => findings.filter((finding) => finding.severity === severity));
}
function renderTopFindings(findings) {
if (findings.length === 0) {
return ['No confirmed issues found after reviewing the diff and surrounding code.'];
}
const orderedFindings = getOrderedFindings(findings);
const lines = orderedFindings
.slice(0, TOP_FINDINGS_LIMIT)
.map(
(finding) =>
`- ${SEVERITY_SUMMARY_LABELS[finding.severity]} ${renderCode(renderFindingReference(finding))}${renderInlineText(finding.title)}`
);
if (orderedFindings.length > TOP_FINDINGS_LIMIT) {
const remaining = orderedFindings.length - TOP_FINDINGS_LIMIT;
lines.push(`- ${remaining} more finding${remaining === 1 ? '' : 's'} in the details below.`);
}
return lines;
}
function renderDetailedFindings(findings) {
if (findings.length === 0) {
return [];
}
const lines = [];
for (const severity of SEVERITY_ORDER) {
const scopedFindings = findings.filter((finding) => finding.severity === severity);
if (scopedFindings.length === 0) continue;
lines.push(`**${SEVERITY_SUMMARY_LABELS[severity]} (${scopedFindings.length})**`, '');
for (const finding of scopedFindings) {
lines.push(`- **${renderCode(renderFindingReference(finding))}${renderInlineText(finding.title)}**`);
lines.push(` Problem: ${renderInlineText(finding.what)}`);
lines.push(` Why it matters: ${renderInlineText(finding.why)}`);
lines.push(` Suggested fix: ${renderInlineText(finding.fix)}`);
lines.push(...renderFindingSnippets(finding.snippets));
lines.push('');
}
}
if (lines[lines.length - 1] === '') {
lines.pop();
}
return lines;
}
export function renderStructuredReview(review, { model, rendering: renderOptions } = {}) {
const rendering = mergeRenderingMetadata(review?.rendering, renderOptions);
const lines = ['### 📋 Summary', '', renderInlineText(review.summary), '', '### 🔍 Findings'];
const lines = [
'### Verdict',
'',
`**${ASSESSMENTS[review.overallAssessment]}** — ${renderInlineText(review.overallRationale)}`,
'',
renderInlineText(review.summary),
];
const reviewContext = formatReviewContext(rendering);
if (reviewContext) {
lines.splice(4, 0, reviewContext, '');
lines.push('', reviewContext);
}
if (review.findings.length === 0) {
lines.push('No confirmed issues found after reviewing the diff and surrounding code.');
} else {
for (const severity of SEVERITY_ORDER) {
const findings = review.findings.filter((finding) => finding.severity === severity);
if (findings.length === 0) continue;
lines.push('', SEVERITY_HEADERS[severity], '');
for (const finding of findings) {
const location = finding.line ? `${finding.file}:${finding.line}` : finding.file;
lines.push(`- **${renderCode(location)}${renderInlineText(finding.title)}**`);
lines.push(` Problem: ${renderInlineText(finding.what)}`);
lines.push(` Why it matters: ${renderInlineText(finding.why)}`);
lines.push(` Suggested fix: ${renderInlineText(finding.fix)}`);
lines.push(...renderFindingSnippets(finding.snippets));
lines.push('');
}
}
if (lines[lines.length - 1] === '') lines.pop();
}
lines.push(...renderChecklistTable('### 🔒 Security Checklist', 'Check', 'check', review.securityChecklist));
lines.push(...renderChecklistTable('### 📊 CCS Compliance', 'Rule', 'rule', review.ccsCompliance));
lines.push(...renderBulletSection('### 💡 Informational', review.informational));
lines.push(...renderBulletSection("### ✅ What's Done Well", review.strengths));
lines.push('', '### Top Findings', '', ...renderTopFindings(review.findings));
lines.push(...renderDetailsBlock(`Full Findings (${review.findings.length})`, renderDetailedFindings(review.findings)));
lines.push(
...renderDetailsBlock(
`Security Checklist (${review.securityChecklist.length})`,
renderChecklistTable('Check', 'check', review.securityChecklist)
)
);
lines.push(
...renderDetailsBlock(
`CCS Compliance (${review.ccsCompliance.length})`,
renderChecklistTable('Rule', 'rule', review.ccsCompliance)
)
);
lines.push(...renderDetailsBlock(`Informational (${review.informational.length})`, renderBulletSection(review.informational)));
lines.push(...renderDetailsBlock(`What's Done Well (${review.strengths.length})`, renderBulletSection(review.strengths)));
lines.push(
'',
'### 🎯 Overall Assessment',
'',
`**${ASSESSMENTS[review.overallAssessment]}** — ${renderInlineText(review.overallRationale)}`,
'',
`> 🤖 Reviewed by \`${model}\``
);
+3 -3
View File
@@ -283,7 +283,7 @@ export async function writeDirectReviewFromEnv(env = process.env, fetchImpl = gl
const responseJson = await postReviewRequest({
apiUrl: cleanText(env.ANTHROPIC_BASE_URL),
apiKey: cleanText(env.ANTHROPIC_AUTH_TOKEN),
model: cleanText(env.REVIEW_MODEL || env.ANTHROPIC_MODEL || 'glm-5.1'),
model: cleanText(env.REVIEW_MODEL || env.ANTHROPIC_MODEL || 'glm-5-turbo'),
system,
prompt: attemptPrompt,
timeoutMs: attemptWindow.timeoutMs,
@@ -318,11 +318,11 @@ export async function writeDirectReviewFromEnv(env = process.env, fetchImpl = gl
const markdown = finalValidation
? renderStructuredReview(finalValidation, {
model: cleanText(env.REVIEW_MODEL || 'glm-5.1'),
model: cleanText(env.REVIEW_MODEL || 'glm-5-turbo'),
rendering,
})
: renderIncompleteReview({
model: cleanText(env.REVIEW_MODEL || 'glm-5.1'),
model: cleanText(env.REVIEW_MODEL || 'glm-5-turbo'),
reason: lastReason,
runUrl: cleanText(env.AI_REVIEW_RUN_URL || '#'),
selectedFiles: coveredSelectedFiles,