mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-29 06:36:51 +00:00
359 lines
12 KiB
HTML
359 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Code review results</title>
|
|
<style>
|
|
:root {
|
|
--bg: #f7f7f5;
|
|
--surface: #ffffff;
|
|
--ink: #1c1c1a;
|
|
--muted: #6b6b66;
|
|
--line: #e3e3de;
|
|
--accent: #2f5f8f;
|
|
--high: #b0362c;
|
|
--high-bg: #fbeae8;
|
|
--medium: #9a6200;
|
|
--medium-bg: #fcf2df;
|
|
--low: #3c6e46;
|
|
--low-bg: #e9f2ea;
|
|
--chip-bg: #eeeeea;
|
|
--code-bg: #f2f2ee;
|
|
--highlight-bg: #fdf3d0;
|
|
--banner-bg: #fcf2df;
|
|
--banner-line: #e6c789;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--bg: #191917;
|
|
--surface: #21211f;
|
|
--ink: #e8e8e4;
|
|
--muted: #9a9a93;
|
|
--line: #343430;
|
|
--accent: #7aa7d0;
|
|
--high: #e0766c;
|
|
--high-bg: #3a2320;
|
|
--medium: #d9a04a;
|
|
--medium-bg: #362b19;
|
|
--low: #8dbb95;
|
|
--low-bg: #21301f;
|
|
--chip-bg: #2c2c29;
|
|
--code-bg: #1d1d1b;
|
|
--highlight-bg: #3a3320;
|
|
--banner-bg: #362b19;
|
|
--banner-line: #6d5a2c;
|
|
}
|
|
}
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
Helvetica, Arial, sans-serif;
|
|
}
|
|
main { max-width: 60rem; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
|
|
h1 { font-size: 1.5rem; margin: 0 0 0.25rem; }
|
|
h2 { font-size: 1.1rem; margin: 2rem 0 0.75rem; }
|
|
.meta { color: var(--muted); font-size: 0.9rem; margin: 0 0 1.5rem; }
|
|
.meta span + span::before { content: " · "; color: var(--line); }
|
|
.summary { font-size: 1rem; margin: 0 0 1rem; }
|
|
.banner {
|
|
background: var(--banner-bg);
|
|
border: 1px solid var(--banner-line);
|
|
border-radius: 8px;
|
|
padding: 0.75rem 1rem;
|
|
margin: 0 0 1.5rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
.banner ul { margin: 0.25rem 0 0; padding-left: 1.25rem; }
|
|
.finding {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line);
|
|
border-radius: 10px;
|
|
margin: 0 0 1rem;
|
|
padding: 1rem 1.25rem;
|
|
}
|
|
.finding-head { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: baseline; }
|
|
.finding-id { font-weight: 600; color: var(--muted); font-size: 0.85rem; }
|
|
.finding-title { font-weight: 600; font-size: 1rem; flex: 1 1 auto; }
|
|
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.5rem 0 0; }
|
|
.chip {
|
|
font-size: 0.75rem;
|
|
padding: 0.1rem 0.55rem;
|
|
border-radius: 999px;
|
|
background: var(--chip-bg);
|
|
color: var(--muted);
|
|
white-space: nowrap;
|
|
}
|
|
.chip.sev-HIGH { background: var(--high-bg); color: var(--high); }
|
|
.chip.sev-MEDIUM { background: var(--medium-bg); color: var(--medium); }
|
|
.chip.sev-LOW { background: var(--low-bg); color: var(--low); }
|
|
.location {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.85rem;
|
|
color: var(--accent);
|
|
margin: 0.5rem 0 0;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
.finding p { margin: 0.6rem 0 0; }
|
|
.label { font-weight: 600; }
|
|
details { margin: 0.6rem 0 0; }
|
|
details summary { cursor: pointer; color: var(--muted); font-size: 0.9rem; }
|
|
pre.code {
|
|
background: var(--code-bg);
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
padding: 0.6rem 0;
|
|
margin: 0.6rem 0 0;
|
|
overflow-x: auto;
|
|
font: 0.82rem/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
}
|
|
pre.code .row { display: block; padding: 0 0.9rem; white-space: pre; }
|
|
pre.code .row.hl { background: var(--highlight-bg); }
|
|
pre.code .num {
|
|
display: inline-block;
|
|
min-width: 3ch;
|
|
margin-right: 1ch;
|
|
text-align: right;
|
|
color: var(--muted);
|
|
user-select: none;
|
|
}
|
|
.coverage { color: var(--muted); font-size: 0.9rem; }
|
|
.coverage ul { padding-left: 1.25rem; margin: 0.5rem 0 0; }
|
|
.empty { color: var(--muted); font-style: italic; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Code review results</h1>
|
|
<p class="meta" id="meta"></p>
|
|
<p class="summary" id="summary"></p>
|
|
<div id="banner"></div>
|
|
<section id="findings"></section>
|
|
<h2>Coverage</h2>
|
|
<div class="coverage" id="coverage"></div>
|
|
</main>
|
|
<script>
|
|
"use strict";
|
|
const DATA = __CODE_REVIEW_PAYLOAD__;
|
|
|
|
function el(tag, className, text) {
|
|
const node = document.createElement(tag);
|
|
if (className) node.className = className;
|
|
if (text !== undefined) node.textContent = text;
|
|
return node;
|
|
}
|
|
|
|
function renderMeta() {
|
|
const meta = DATA.meta || {};
|
|
const holder = document.getElementById("meta");
|
|
const parts = [
|
|
meta.target,
|
|
meta.revision,
|
|
"effort " + meta.effort + (meta.model ? " · model " + meta.model : ""),
|
|
"verification " + meta.verification,
|
|
"completion " + meta.completion,
|
|
meta.completed_at,
|
|
];
|
|
for (const part of parts) {
|
|
if (part) holder.appendChild(el("span", null, String(part)));
|
|
}
|
|
if (meta.guidance) {
|
|
const guidance = el("p", "meta");
|
|
guidance.appendChild(el("span", "label", "Guidance: "));
|
|
guidance.appendChild(document.createTextNode(meta.guidance));
|
|
holder.insertAdjacentElement("afterend", guidance);
|
|
}
|
|
const findings = DATA.findings || [];
|
|
const bugs = findings.filter(f => f.category === "correctness").length;
|
|
document.getElementById("summary").textContent =
|
|
findings.length + " finding(s) reported (" + bugs + " correctness, " +
|
|
(findings.length - bugs) + " cleanup)." +
|
|
(meta.effort === "low"
|
|
? " Low-effort single pass: findings were not independently verified."
|
|
: "");
|
|
}
|
|
|
|
function renderBanner() {
|
|
const reasons = DATA.partialReasons || [];
|
|
if (!reasons.length) return;
|
|
const banner = el("div", "banner");
|
|
banner.appendChild(el("span", "label", "Partial review."));
|
|
const list = el("ul");
|
|
for (const reason of reasons) list.appendChild(el("li", null, reason));
|
|
banner.appendChild(list);
|
|
document.getElementById("banner").appendChild(banner);
|
|
}
|
|
|
|
function renderCode(code) {
|
|
if (!code || !Array.isArray(code.lines) || !code.lines.length) return null;
|
|
const details = el("details");
|
|
details.open = true;
|
|
details.appendChild(el("summary", null, code.label || "Excerpt"));
|
|
const pre = el("pre", "code");
|
|
for (const line of code.lines) {
|
|
const row = el("span", line.highlight ? "row hl" : "row");
|
|
row.appendChild(el("span", "num", String(line.number)));
|
|
row.appendChild(document.createTextNode(line.text));
|
|
pre.appendChild(row);
|
|
}
|
|
details.appendChild(pre);
|
|
return details;
|
|
}
|
|
|
|
function renderSuggestedChange(finding) {
|
|
if (!finding.suggestion || !finding.location ||
|
|
!finding.location.existing_code) return null;
|
|
const details = el("details");
|
|
details.appendChild(el("summary", null, "Suggested change"));
|
|
details.appendChild(el("p", "label", "Before"));
|
|
details.appendChild(el("pre", "code", finding.location.existing_code));
|
|
details.appendChild(el("p", "label", "After"));
|
|
details.appendChild(el("pre", "code",
|
|
finding.suggestion.replacement_code || ""));
|
|
return details;
|
|
}
|
|
|
|
function renderFinding(finding) {
|
|
const card = el("article", "finding");
|
|
const head = el("div", "finding-head");
|
|
head.appendChild(el("span", "finding-id", finding.id));
|
|
head.appendChild(el("span", "finding-title", finding.short_summary));
|
|
card.appendChild(head);
|
|
const chips = el("div", "chips");
|
|
chips.appendChild(el("span", "chip sev-" + finding.severity,
|
|
finding.severity + " severity"));
|
|
chips.appendChild(el("span", "chip", finding.category));
|
|
chips.appendChild(el("span", "chip", finding.issue_type));
|
|
if ((finding.rule_ids || []).length) {
|
|
chips.appendChild(el("span", "chip",
|
|
"rule " + finding.rule_ids.join(", ")));
|
|
}
|
|
chips.appendChild(el("span", "chip", "verdict " + finding.verdict));
|
|
chips.appendChild(el("span", "chip", "confidence " + finding.confidence));
|
|
chips.appendChild(el("span", "chip",
|
|
finding.reports + " report(s): " + (finding.reporters || []).join(", ")));
|
|
card.appendChild(chips);
|
|
const loc = finding.location || {};
|
|
const span = loc.start_line && loc.end_line && loc.start_line !== loc.end_line
|
|
? loc.start_line + "-" + loc.end_line
|
|
: (loc.end_line || finding.line);
|
|
card.appendChild(el("p", "location", finding.file + ":" + span));
|
|
if ((finding.anchors || []).length) {
|
|
card.appendChild(el("p", "location", "Also reported at " +
|
|
finding.anchors.map(a => a.file + ":" + a.line + " (" + a.category +
|
|
", " + a.id + ")").join(", ") +
|
|
" — judged the same defect and folded in."));
|
|
}
|
|
if (finding.summary.trim() !== finding.short_summary.trim()) {
|
|
card.appendChild(el("p", null, finding.summary));
|
|
}
|
|
const scenario = el("p");
|
|
scenario.appendChild(el("span", "label", "Failure scenario. "));
|
|
scenario.appendChild(document.createTextNode(finding.failure_scenario));
|
|
card.appendChild(scenario);
|
|
if (finding.verdict_reasoning) {
|
|
const verifier = el("details");
|
|
verifier.appendChild(el("summary", null, "Verifier reasoning"));
|
|
verifier.appendChild(el("p", null, finding.verdict_reasoning));
|
|
card.appendChild(verifier);
|
|
}
|
|
const suggestion = renderSuggestedChange(finding);
|
|
if (suggestion) card.appendChild(suggestion);
|
|
const code = renderCode(finding.code);
|
|
if (code) card.appendChild(code);
|
|
return card;
|
|
}
|
|
|
|
function renderFindings() {
|
|
const holder = document.getElementById("findings");
|
|
const findings = DATA.findings || [];
|
|
if (!findings.length) {
|
|
holder.appendChild(el("p", "empty", "No findings survived review."));
|
|
return;
|
|
}
|
|
for (const finding of findings) holder.appendChild(renderFinding(finding));
|
|
}
|
|
|
|
function renderCoverage() {
|
|
const holder = document.getElementById("coverage");
|
|
const coverage = DATA.coverage || {};
|
|
const list = el("ul");
|
|
const finders = coverage.finders || {};
|
|
list.appendChild(el("li", null,
|
|
"Finder angles: " + finders.returned + " of " + finders.dispatched +
|
|
" returned a usable result."));
|
|
const verification = coverage.verification || {};
|
|
list.appendChild(el("li", null,
|
|
"Verification: " + verification.votesCompleted + " of " +
|
|
verification.votesDispatched + " verdict(s) returned (" +
|
|
verification.status + ")."));
|
|
const rules = coverage.rules;
|
|
if (rules) {
|
|
const effective = rules.effectiveChecksByFile || {};
|
|
let auditedFiles = 0;
|
|
const distinct = new Set();
|
|
for (const ids of Object.values(effective)) {
|
|
if ((ids || []).length) auditedFiles++;
|
|
(ids || []).forEach(id => distinct.add(id));
|
|
}
|
|
const cells = ((coverage.finders || {}).byKind || {})["rule-audit"] || {};
|
|
const counts = rules.counts || {};
|
|
const ruleFindings = (DATA.findings || [])
|
|
.filter(f => (f.rule_ids || []).length);
|
|
const filtered0 = (coverage.filteredFindingReports || []).length;
|
|
const folded = (((DATA.meta || {}).counts) || {}).duplicates || 0;
|
|
list.appendChild(el("li", null,
|
|
"Rules: audited " + distinct.size + " check(s) (" +
|
|
(counts.builtin_packs || 0) + " built-in + " +
|
|
(counts.repo_packs || 0) + " repository pack(s)) across " +
|
|
auditedFiles + " file(s) in " + (cells.returned || 0) + " of " +
|
|
(cells.dispatched || 0) + " audit cell(s); " + ruleFindings.length +
|
|
" violation(s) reported; " + filtered0 + " filtered; " +
|
|
folded + " folded."));
|
|
if (ruleFindings.length) {
|
|
const perCheck = {};
|
|
for (const finding of ruleFindings) {
|
|
for (const id of finding.rule_ids) {
|
|
perCheck[id] = (perCheck[id] || 0) + 1;
|
|
}
|
|
}
|
|
const item = el("li", null, "Violations by check:");
|
|
const sub = el("ul");
|
|
Object.entries(perCheck)
|
|
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
.forEach(([id, n]) => sub.appendChild(el("li", null, id + " x" + n)));
|
|
item.appendChild(sub);
|
|
list.appendChild(item);
|
|
}
|
|
}
|
|
const rejected = coverage.rejectedFindingReports || [];
|
|
if (rejected.length) {
|
|
const item = el("li", null,
|
|
"Rejected finding reports (" + rejected.length + "):");
|
|
const sub = el("ul");
|
|
for (const entry of rejected) sub.appendChild(el("li", null, entry));
|
|
item.appendChild(sub);
|
|
list.appendChild(item);
|
|
}
|
|
const filtered = coverage.filteredFindingReports || [];
|
|
if (filtered.length) {
|
|
const item = el("li", null,
|
|
"Filtered by review policy (" + filtered.length + "):");
|
|
const sub = el("ul");
|
|
for (const entry of filtered) sub.appendChild(el("li", null, entry));
|
|
item.appendChild(sub);
|
|
list.appendChild(item);
|
|
}
|
|
holder.appendChild(list);
|
|
}
|
|
|
|
renderMeta();
|
|
renderBanner();
|
|
renderFindings();
|
|
renderCoverage();
|
|
</script>
|
|
</body>
|
|
</html>
|