// One-shot dry-run audit of a single PR. Useful for verifying check // behavior (kb_query scrum surfacing, inference prompts, etc.) without // posting to Gitea. Does NOT touch state.json and does NOT post // commit status or PR comments. // // Run: bun run auditor/audit_one.ts import { getPrSnapshot } from "./gitea.ts"; import { auditPr } from "./audit.ts"; async function main() { const prNumRaw = process.argv[2]; if (!prNumRaw) { console.error("usage: bun run auditor/audit_one.ts "); process.exit(2); } const prNum = Number(prNumRaw); if (!Number.isFinite(prNum)) { console.error(`invalid PR number: ${prNumRaw}`); process.exit(2); } console.log(`[audit_one] fetching PR #${prNum}...`); const pr = await getPrSnapshot(prNum); console.log(`[audit_one] PR #${pr.number}: "${pr.title}" (head=${pr.head_sha.slice(0, 12)})`); console.log(`[audit_one] files in diff: ${pr.files.length}`); for (const f of pr.files) console.log(` - ${f.path} (+${f.additions}/-${f.deletions})`); console.log(""); const verdict = await auditPr(pr, { dry_run: true, // no Gitea posting skip_dynamic: true, // don't run fixture skip_inference: process.env.LH_AUDITOR_SKIP_INFERENCE === "1", }); console.log("\n═══ VERDICT ═══"); console.log(`overall: ${verdict.overall}`); console.log(`one-liner: ${verdict.one_liner}`); console.log(`findings: total=${verdict.metrics.findings_total} block=${verdict.metrics.findings_block} warn=${verdict.metrics.findings_warn} info=${verdict.metrics.findings_info}`); console.log(""); // Print findings, highlighting kb_query scrum surfacing const byCheck: Record = {}; for (const f of verdict.findings) (byCheck[f.check] ||= []).push(f); for (const [check, findings] of Object.entries(byCheck)) { console.log(`── ${check} (${findings.length}) ──`); for (const f of findings) { const tag = f.severity === "block" ? "🛑" : f.severity === "warn" ? "⚠️ " : "ℹ️ "; console.log(` ${tag} [${f.severity}] ${f.summary}`); if (f.summary.includes("scrum-master")) { for (const e of f.evidence) { console.log(` → ${e.slice(0, 200)}`); } } } } const scrumFindings = verdict.findings.filter(f => f.summary.includes("scrum-master")); console.log(""); console.log(`═══ SCRUM WIRE CHECK: ${scrumFindings.length} scrum-master findings surfaced by kb_query ═══`); if (scrumFindings.length === 0) { console.log(" (none — either no matching scrum_reviews.jsonl rows, or files didn't match PR diff)"); } process.exit(0); } main().catch(e => { console.error("[audit_one] fatal:", e); process.exit(1); });