evalstate's picture
download
raw
62.8 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Candle code review — evals/code-review/source.diff</title>
<style data-birch-system>
/*
Birch HTML Design System
Opinionated single-option stylesheet for reliable LLM-generated artifacts.
Model:
1. Design tokens as CSS variables.
2. Layout primitives as classes.
3. Semantic components as classes with data-* variants.
*/
/* ==================== 1. TOKENS ==================== */
:root {
color-scheme: light;
/* Palette */
--color-ivory: #FAF9F5;
--color-slate: #141413;
--color-clay: #D97757;
--color-clay-dark: #B85C3E;
--color-oat: #E3DACC;
--color-olive: #788C5D;
--color-rust: #B04A3F;
--color-sky: #6A8CAF;
--color-white: #FFFFFF;
--color-gray-50: #F7F5EE;
--color-gray-100: #F0EEE6;
--color-gray-150: #E8E4DA;
--color-gray-200: #DED9CD;
--color-gray-300: #D1CFC5;
--color-gray-500: #87867F;
--color-gray-700: #3D3D3A;
--color-gray-800: #242421;
/* Semantic colors */
--bg: var(--color-ivory);
--surface: var(--color-white);
--surface-tint: var(--color-gray-100);
--surface-warm: var(--color-oat);
--text: var(--color-slate);
--text-muted: var(--color-gray-500);
--text-soft: var(--color-gray-700);
--muted: var(--text-muted);
--border-color: var(--color-gray-300);
--accent: var(--color-clay);
--accent-strong: var(--color-clay-dark);
--success: var(--color-olive);
--warning: #C78E3F;
--danger: var(--color-rust);
--info: var(--color-sky);
/* Typography */
--font-serif: ui-serif, Georgia, "Times New Roman", serif;
--font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
--text-xs: 11px;
--text-sm: 12px;
--text-md: 14px;
--text-base: 15px;
--text-lg: 17px;
--text-xl: 21px;
--text-2xl: 26px;
--text-3xl: 36px;
--text-4xl: 44px;
--leading-tight: 1.15;
--leading-title: 1.25;
--leading-body: 1.55;
--leading-loose: 1.7;
/* Spacing */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 48px;
--space-8: 64px;
--space-9: 96px;
/* Shape */
--radius-xs: 4px;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 20px;
--radius-pill: 999px;
--border: 1.5px solid var(--border-color);
--border-thin: 1px solid var(--border-color);
--shadow-sm: 0 1px 2px rgba(20, 20, 19, 0.06);
--shadow-md: 0 4px 14px rgba(20, 20, 19, 0.08);
--shadow-lg: 0 12px 28px rgba(20, 20, 19, 0.12);
/* Motion */
--ease: cubic-bezier(0.2, 0, 0, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--dur-fast: 120ms;
--dur: 180ms;
--hover-y: -2px;
/* Page sizing */
--page-max: 1100px;
--page-pad: 28px;
--page-pad-block: 48px;
/* Legacy aliases used by source examples */
--ivory: var(--color-ivory);
--slate: var(--color-slate);
--clay: var(--color-clay);
--clay-d: var(--color-clay-dark);
--oat: var(--color-oat);
--olive: var(--color-olive);
--rust: var(--color-rust);
--sky: var(--color-sky);
--white: var(--color-white);
--gray-50: var(--color-gray-50);
--gray-100: var(--color-gray-100);
--gray-150: var(--color-gray-150);
--gray-200: var(--color-gray-200);
--gray-300: var(--color-gray-300);
--gray-500: var(--color-gray-500);
--gray-700: var(--color-gray-700);
--gray-800: var(--color-gray-800);
--serif: var(--font-serif);
--sans: var(--font-sans);
--mono: var(--font-mono);
}
/* ==================== BASE ==================== */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
background: var(--bg);
color: var(--text);
font-family: var(--font-sans);
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--font-sans);
font-size: var(--text-base);
line-height: var(--leading-body);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
img,
svg {
max-width: 100%;
}
a {
color: inherit;
text-decoration-color: rgba(217, 119, 87, 0.45);
text-underline-offset: 3px;
}
a:hover {
color: var(--accent);
}
h1,
h2,
h3,
p {
margin-block: 0;
}
h1,
h2,
h3 {
font-family: var(--font-serif);
font-weight: 500;
letter-spacing: -0.01em;
line-height: var(--leading-title);
}
h1 {
font-size: clamp(32px, 5vw, var(--text-4xl));
}
h2 {
font-size: var(--text-2xl);
}
h3 {
font-size: var(--text-xl);
}
code,
kbd,
pre {
font-family: var(--font-mono);
}
code {
font-size: 0.92em;
white-space: normal;
word-break: normal;
}
h1 code,
h2 code,
h3 code {
overflow-wrap: anywhere;
word-break: break-word;
}
button,
input,
textarea,
select {
font: inherit;
}
button {
cursor: pointer;
}
::selection {
background: rgba(217, 119, 87, 0.24);
}
/* ==================== 2. LAYOUT PRIMITIVES ==================== */
.page {
width: min(100% - (var(--page-pad) * 2), var(--page-max));
margin-inline: auto;
padding-block: var(--page-pad-block) var(--space-9);
}
.page[data-size="narrow"] {
--page-max: 820px;
}
.page[data-size="wide"] {
--page-max: 1280px;
}
.page[data-size="full"] {
--page-max: 1440px;
}
.section {
margin-block: var(--section-gap, var(--space-5));
}
.section[data-gap="lg"] {
--section-gap: var(--space-6);
}
.section[data-gap="xl"] {
--section-gap: var(--space-7);
}
.section:first-child {
margin-block-start: 0;
}
.stack > .section {
margin-block: 0;
}
.rule {
border: 0;
border-top: var(--border-thin);
margin: var(--space-3) 0 var(--space-5);
}
.stack {
display: flex;
flex-direction: column;
gap: var(--stack-gap, var(--space-4));
}
.stack[data-gap="xs"] { --stack-gap: var(--space-2); }
.stack[data-gap="sm"] { --stack-gap: var(--space-3); }
.stack[data-gap="md"] { --stack-gap: var(--space-4); }
.stack[data-gap="lg"] { --stack-gap: var(--space-6); }
.stack[data-gap="xl"] { --stack-gap: var(--space-8); }
.stack > :is(.button, .btn, .chip, .badge) {
align-self: flex-start;
}
.cluster {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--cluster-gap, var(--space-3));
}
.cluster[data-align="start"] { align-items: flex-start; }
.cluster[data-align="end"] { align-items: flex-end; }
.cluster[data-justify="between"] { justify-content: space-between; }
.cluster[data-justify="end"] { justify-content: flex-end; }
.grid {
display: grid;
gap: var(--grid-gap, var(--space-5));
}
.grid[data-cols="2"] {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid[data-cols="3"] {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid[data-cols="4"] {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min, 240px)), 1fr));
gap: var(--grid-gap, var(--space-5));
}
.auto-grid > * {
min-width: 0;
}
.split {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(280px, var(--split-side, 360px));
gap: var(--split-gap, var(--space-6));
align-items: start;
}
.split > * {
min-width: 0;
}
.section-head {
min-width: 0;
}
.section-rail {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(280px, var(--rail-width, 360px));
column-gap: var(--rail-gap, var(--space-6));
row-gap: var(--space-5);
align-items: start;
}
.section-rail > .section-head {
grid-column: 1 / -1;
}
.section-rail > .reference-panel,
.section-rail > aside {
align-self: start;
}
.sidebar-layout {
display: grid;
grid-template-columns: var(--sidebar-width, 240px) minmax(0, 1fr);
gap: var(--sidebar-gap, var(--space-7));
align-items: start;
}
.sidebar-layout > :first-child,
.sticky {
position: sticky;
top: var(--sticky-top, var(--space-5));
}
.bleed {
margin-inline: calc(var(--page-pad) * -1);
}
.scroll-x {
overflow-x: auto;
overscroll-behavior-inline: contain;
}
.center {
display: grid;
place-items: center;
}
.spacer {
flex: 1;
}
@media (max-width: 860px) {
:root {
--page-pad: 20px;
--page-pad-block: 40px;
}
.grid[data-cols],
.split,
.section-rail,
.sidebar-layout {
grid-template-columns: 1fr;
}
.sidebar-layout > :first-child,
.sticky {
position: static;
}
}
/* ==================== TYPOGRAPHY UTILITIES ==================== */
.eyebrow {
display: inline-flex;
align-items: center;
gap: var(--space-2);
color: var(--accent);
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.eyebrow::before {
content: "";
width: 24px;
height: 1.5px;
background: currentColor;
}
.lede {
max-width: 720px;
color: var(--text-soft);
font-size: var(--text-lg);
line-height: 1.6;
}
.muted {
color: var(--text-muted);
}
.caption {
color: var(--text-muted);
font-family: var(--font-mono);
font-size: var(--text-sm);
}
.stat-value {
display: block;
color: var(--text);
font-family: var(--font-serif);
font-size: clamp(30px, 3.2vw, 42px);
font-variant-numeric: tabular-nums;
font-weight: 550;
letter-spacing: -0.025em;
line-height: 1;
}
.stat-card {
gap: var(--space-2);
}
.stat-card .caption {
letter-spacing: 0.08em;
text-transform: uppercase;
}
.stat-card .muted {
max-width: 34ch;
font-size: var(--text-sm);
}
.mono {
font-family: var(--font-mono);
}
/* ==================== 3. SEMANTIC COMPONENTS ==================== */
.panel,
.card {
background: var(--surface);
border: var(--border);
border-radius: var(--radius-md);
}
.panel {
padding: var(--panel-pad, var(--space-5));
}
.card {
padding: var(--card-pad, var(--space-5));
transition:
transform var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease),
box-shadow var(--dur-fast) var(--ease),
background-color var(--dur-fast) var(--ease);
}
.card[data-hover="lift"]:hover,
.card[data-clickable]:hover {
transform: translateY(var(--hover-y));
border-color: rgba(217, 119, 87, 0.55);
box-shadow: var(--shadow-md);
}
.card[data-clickable] {
cursor: pointer;
}
.card[data-variant="flat"] {
background: transparent;
border-color: transparent;
box-shadow: none;
}
.card[data-variant="outlined"] {
background: var(--surface);
border: var(--border);
}
.card[data-variant="elevated"] {
border-color: transparent;
box-shadow: var(--shadow-md);
}
.card[data-variant="filled"],
.card[data-tone="oat"] {
background: var(--surface-warm);
}
.card[data-tone],
.panel[data-tone],
.callout[data-tone] {
background: var(--surface);
}
.card[data-tone="danger"],
.panel[data-tone="danger"],
.callout[data-tone="danger"] {
border-color: rgba(176, 74, 63, 0.36);
}
.card[data-tone="warning"],
.panel[data-tone="warning"],
.callout[data-tone="warning"] {
border-color: rgba(199, 142, 63, 0.38);
}
.card[data-tone="success"],
.panel[data-tone="success"],
.callout[data-tone="success"] {
border-color: rgba(120, 140, 93, 0.38);
}
.card[data-tone="info"],
.panel[data-tone="info"],
.callout[data-tone="info"] {
border-color: rgba(106, 140, 175, 0.36);
}
.card[data-accent] {
position: relative;
overflow: hidden;
}
.card[data-accent]::before {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 5px;
background: var(--accent);
}
.card-head {
display: flex;
align-items: center;
gap: var(--space-3);
min-width: 0;
max-width: 100%;
}
.card-head > :first-child {
flex: 0 0 auto;
}
.card-titles {
flex: 1 1 0;
min-width: 0;
max-width: 100%;
}
.card-title {
max-width: 100%;
margin: 0;
font-family: var(--font-serif);
font-size: var(--text-xl);
font-weight: 550;
line-height: var(--leading-title);
overflow-wrap: anywhere;
}
.card-sub {
margin: 2px 0 0;
color: var(--text-muted);
font-size: var(--text-sm);
overflow-wrap: anywhere;
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-4);
padding: var(--space-4) var(--space-5);
background: var(--surface);
border: var(--border);
border-radius: var(--radius-md);
}
.toolbar[data-sticky] {
position: sticky;
top: 0;
z-index: 10;
}
.chip,
.badge {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
border-radius: var(--radius-pill);
white-space: nowrap;
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 650;
line-height: 1;
}
.chip {
min-height: 24px;
padding: 0 10px;
color: var(--text-soft);
background: var(--surface-tint);
border: 1px solid transparent;
}
.badge {
min-height: 22px;
padding: 0 9px;
color: var(--text-muted);
background: var(--surface);
border: var(--border-thin);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.chip[data-tone="clay"],
.badge[data-tone="clay"] {
color: var(--accent);
background: rgba(217, 119, 87, 0.14);
}
.chip[data-tone="olive"],
.badge[data-tone="olive"],
.chip[data-tone="success"],
.badge[data-tone="success"] {
color: var(--success);
background: rgba(120, 140, 93, 0.15);
}
.chip[data-tone="warning"],
.badge[data-tone="warning"] {
color: var(--warning);
background: rgba(199, 142, 63, 0.16);
}
.chip[data-tone="rust"],
.badge[data-tone="rust"],
.chip[data-tone="danger"],
.badge[data-tone="danger"] {
color: var(--danger);
background: rgba(176, 74, 63, 0.13);
}
.chip[data-tone="sky"],
.badge[data-tone="sky"],
.chip[data-tone="info"],
.badge[data-tone="info"] {
color: var(--info);
background: rgba(106, 140, 175, 0.14);
}
.finding {
border-left: 6px solid var(--border-color);
}
.finding[data-severity="blocker"],
.finding[data-severity="critical"],
.finding[data-severity="danger"],
.finding[data-tone="danger"] {
border-left-color: var(--danger);
}
.finding[data-severity="high"],
.finding[data-severity="warning"],
.finding[data-tone="warning"] {
border-left-color: var(--warning);
}
.finding[data-severity="medium"],
.finding[data-severity="info"],
.finding[data-tone="info"] {
border-left-color: var(--info);
}
.finding[data-severity="low"],
.finding[data-severity="success"],
.finding[data-tone="success"] {
border-left-color: var(--success);
}
.button,
.btn {
appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 36px;
padding: 0 14px;
border: 1.5px solid transparent;
border-radius: var(--radius-sm);
font-family: var(--font-sans);
font-size: var(--text-md);
font-weight: 650;
line-height: 1;
text-decoration: none;
transition:
transform var(--dur-fast) var(--ease),
background-color var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease),
box-shadow var(--dur-fast) var(--ease);
}
.button:hover,
.btn:hover {
transform: translateY(-1px);
}
.button[data-variant="primary"],
.btn-primary {
color: var(--color-white);
background: var(--color-slate);
}
.button[data-variant="primary"]:hover,
.btn-primary:hover {
background: var(--color-gray-700);
}
.button[data-variant="secondary"],
.btn-secondary {
color: var(--text);
background: var(--surface-tint);
border-color: var(--border-color);
}
.button[data-variant="ghost"],
.btn-ghost {
color: var(--text-soft);
background: transparent;
}
.button[data-variant="ghost"]:hover,
.btn-ghost:hover {
color: var(--text);
background: var(--surface-tint);
}
.button[data-variant="danger"],
.btn-danger {
color: var(--color-white);
background: var(--danger);
}
.input {
width: 100%;
min-height: 38px;
padding: 0 12px;
color: var(--text);
background: var(--surface);
border: var(--border);
border-radius: var(--radius-sm);
outline: none;
}
.input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(217, 119, 87, 0.16);
}
.avatar {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--avatar-size, 38px);
height: var(--avatar-size, 38px);
border-radius: 50%;
color: var(--text-soft);
background: var(--surface-warm);
font-family: var(--font-mono);
font-size: var(--text-sm);
font-weight: 700;
letter-spacing: 0.02em;
flex: 0 0 auto;
}
.code-block {
margin: 0;
padding: var(--space-4) var(--space-5);
overflow-x: auto;
color: #E8E6DC;
background: var(--color-slate);
border-radius: var(--radius-md);
font-family: var(--font-mono);
font-size: var(--text-sm);
line-height: var(--leading-loose);
}
.code-block[data-kind="command"],
.code-block[data-wrap="true"],
.command-block {
max-width: 100%;
min-width: 0;
box-sizing: border-box;
white-space: pre-wrap;
overflow-wrap: anywhere;
word-break: break-word;
overflow-x: hidden;
}
.code-block[data-wrap="true"] code,
.code-block[data-kind="command"] code {
display: block;
max-width: 100%;
white-space: pre-wrap;
overflow-wrap: anywhere;
word-break: break-word;
}
.copyable {
position: relative;
}
.copyable > .code-block {
padding-inline-end: 88px;
}
.copy-button {
appearance: none;
position: absolute;
inset-block-start: var(--space-2);
inset-inline-end: var(--space-2);
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 26px;
padding: 0 9px;
border: 1px solid rgba(250, 249, 245, 0.18);
border-radius: var(--radius-sm);
color: var(--color-gray-100);
background: rgba(255, 255, 255, 0.08);
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
transition:
background-color var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease),
transform var(--dur-fast) var(--ease);
}
.copy-button:hover {
transform: translateY(-1px);
border-color: rgba(250, 249, 245, 0.35);
background: rgba(255, 255, 255, 0.14);
}
.copy-button[data-copied="true"] {
color: var(--color-white);
background: rgba(120, 140, 93, 0.55);
border-color: rgba(120, 140, 93, 0.75);
}
.reference-panel {
--panel-pad: var(--space-5);
}
.callout {
padding: var(--space-5);
color: var(--text-soft);
background: var(--surface-tint);
border: var(--border);
border-inline-start: 4px solid var(--accent);
border-radius: var(--radius-md);
}
.callout[data-tone="success"] {
border-inline-start-color: var(--success);
background: rgba(120, 140, 93, 0.10);
}
.callout[data-tone="warning"] {
border-inline-start-color: var(--warning);
background: rgba(199, 142, 63, 0.11);
}
.callout[data-tone="danger"] {
border-inline-start-color: var(--danger);
background: rgba(176, 74, 63, 0.10);
}
.callout[data-tone="info"] {
border-inline-start-color: var(--info);
background: rgba(106, 140, 175, 0.11);
}
.callout-label {
display: block;
margin-bottom: var(--space-2);
color: var(--text-muted);
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 700;
letter-spacing: 0.09em;
text-transform: uppercase;
}
.callout > :last-child {
margin-bottom: 0;
}
.checklist {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-3);
}
.checklist li {
display: block !important;
position: relative !important;
min-width: 0;
padding-inline-start: calc(18px + var(--space-3));
overflow-wrap: anywhere;
}
.checklist li::before {
content: "✓";
position: absolute !important;
inset-block-start: 2px;
inset-inline-start: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
border-radius: 50%;
color: var(--success);
background: rgba(120, 140, 93, 0.12);
font-family: var(--font-mono);
font-size: 12px;
font-weight: 700;
line-height: 1;
}
.checklist code {
white-space: normal;
overflow-wrap: anywhere;
word-break: break-word;
}
.plain-list {
margin: 0;
padding-inline-start: 1.15em;
color: var(--text-soft);
}
.plain-list li {
overflow-wrap: anywhere;
}
.plain-list li + li {
margin-top: var(--space-2);
}
.plain-list li::marker {
color: var(--text-muted);
}
.insight-list,
.takeaway-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-3);
}
.insight-list li,
.takeaway-list li {
position: relative;
display: block;
padding-inline-start: calc(10px + var(--space-3));
color: var(--text-soft);
}
.insight-list li::before,
.takeaway-list li::before {
content: "";
position: absolute;
inset-block-start: 0.65em;
inset-inline-start: 0;
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--accent);
}
.insight-list li > *,
.takeaway-list li > * {
min-width: 0;
}
.insight-list[data-tone="success"] li::before,
.takeaway-list[data-tone="success"] li::before {
background: var(--success);
}
.insight-list[data-tone="info"] li::before,
.takeaway-list[data-tone="info"] li::before {
background: var(--info);
}
.metric-list {
--metric-label: 132px;
--metric-value: 64px;
display: grid;
gap: var(--space-3);
}
.metric-row {
display: grid;
grid-template-columns: var(--metric-label) minmax(120px, 1fr) var(--metric-value);
gap: var(--space-3);
align-items: center;
}
.metric-row > :first-child {
min-width: 0;
}
.metric-row > :last-child {
justify-self: end;
font-family: var(--font-mono);
font-size: var(--text-sm);
}
.meter {
height: 9px;
overflow: hidden;
border-radius: var(--radius-pill);
background: var(--surface-tint);
}
.meter span {
display: block;
width: var(--value);
height: 100%;
background: var(--tone, var(--accent));
}
.flow-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-3);
}
.flow-step {
position: relative;
display: grid;
grid-template-columns: 42px minmax(0, 1fr);
gap: var(--space-3);
align-items: start;
padding: var(--space-4);
background: var(--surface);
border: var(--border);
border-radius: var(--radius-md);
}
.flow-step > .flow-num {
grid-column: 1;
}
.flow-step > :not(.flow-num) {
grid-column: 2;
min-width: 0;
}
.flow-step::after {
content: "";
position: absolute;
inset-block-start: calc(100% + 1px);
inset-inline-start: 36px;
width: 1.5px;
height: var(--space-3);
background: var(--border-color);
}
.flow-step:last-child::after {
display: none;
}
.flow-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: var(--radius-pill);
color: var(--text);
background: var(--surface-warm);
box-shadow: inset 0 0 0 1px rgba(20, 20, 19, 0.10);
font-family: var(--font-mono);
font-size: var(--text-sm);
font-weight: 700;
}
.flow-title {
margin: 0 0 var(--space-1);
font-family: var(--font-serif);
font-size: var(--text-xl);
font-weight: 550;
line-height: var(--leading-title);
}
.flow-detail {
margin: 0;
color: var(--text-soft);
}
.flow-branch {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-3);
}
.flow-branch .flow-step::after {
display: none;
}
.flow-step[data-tone="success"] {
border-color: rgba(120, 140, 93, 0.38);
background: rgba(120, 140, 93, 0.08);
}
.flow-step[data-tone="warning"] {
border-color: rgba(199, 142, 63, 0.42);
background: rgba(199, 142, 63, 0.09);
}
@media (max-width: 620px) {
.metric-row {
grid-template-columns: 1fr max-content;
}
.metric-row .meter {
grid-column: 1 / -1;
order: 3;
}
.flow-branch {
grid-template-columns: 1fr;
}
}
/* ---------- Charts and numeric data ---------- */
.chart-panel {
max-width: 100%;
min-width: 0;
overflow: hidden;
}
.chart-panel > * {
min-width: 0;
}
.chart-panel svg,
svg.chart-svg {
display: block;
width: 100%;
height: auto;
}
.chart-caption {
color: var(--text-muted);
font-size: var(--text-sm);
}
.numeric-table-wrap {
overflow-x: auto;
background: var(--surface);
border: var(--border);
border-radius: var(--radius-md);
}
.numeric-table {
width: 100%;
min-width: 720px;
border-collapse: collapse;
}
.numeric-table th,
.numeric-table td {
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-gray-200);
vertical-align: middle;
}
.numeric-table th {
color: var(--text-muted);
background: var(--surface-tint);
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 700;
letter-spacing: 0.08em;
text-align: left;
text-transform: uppercase;
}
.numeric-table tr:last-child td {
border-bottom: 0;
}
.numeric-table .metric,
.numeric-table .num {
text-align: right;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.numeric-table .entity,
.numeric-table .label-cell {
font-weight: 650;
}
.numeric-table .note {
color: var(--text-soft);
}
.numeric-table code {
white-space: normal;
overflow-wrap: anywhere;
word-break: break-word;
}
.numeric-table .subtle {
display: block;
margin-top: 2px;
color: var(--text-muted);
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: 400;
}
@media (max-width: 620px) {
.numeric-table {
min-width: 0;
}
.numeric-table thead {
display: none;
}
.numeric-table tbody,
.numeric-table tr,
.numeric-table td {
display: block;
}
.numeric-table tr {
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-gray-200);
}
.numeric-table tr:last-child {
border-bottom: 0;
}
.numeric-table td {
padding: var(--space-1) 0;
border-bottom: 0;
}
.numeric-table td[data-label] {
display: flex;
justify-content: space-between;
gap: var(--space-4);
}
.numeric-table td[data-label]::before {
content: attr(data-label);
color: var(--text-muted);
font-family: var(--font-mono);
font-size: var(--text-xs);
text-transform: uppercase;
}
}
/* ---------- Diff ---------- */
.diff {
overflow-x: auto;
color: #E8E6DC;
background: var(--color-slate);
border-radius: var(--radius-md);
font-family: var(--font-mono);
font-size: 12.5px;
line-height: var(--leading-loose);
}
.diff-row {
display: grid;
grid-template-columns: 48px 18px minmax(max-content, 1fr);
align-items: baseline;
min-width: max-content;
padding-inline-end: var(--space-4);
white-space: pre;
}
.diff-row .ln {
padding-inline-end: 14px;
color: var(--color-gray-500);
text-align: right;
user-select: none;
}
.diff-row .mark {
color: var(--color-gray-500);
text-align: center;
}
.diff-row .code {
color: #E8E6DC;
}
.diff-row.ctx .code,
.diff-row[data-kind="ctx"] .code {
color: #B8B6AC;
}
.diff-row.add,
.diff-row[data-kind="add"] {
background: rgba(120, 140, 93, 0.24);
box-shadow: inset 3px 0 0 rgba(120, 140, 93, 0.78);
}
.diff-row.add .mark,
.diff-row[data-kind="add"] .mark {
color: #B9D394;
font-weight: 800;
}
.diff-row.del,
.diff-row[data-kind="del"] {
background: rgba(176, 74, 63, 0.24);
box-shadow: inset 3px 0 0 rgba(176, 74, 63, 0.82);
}
.diff-row.del .mark,
.diff-row[data-kind="del"] .mark {
color: #F19A8D;
font-weight: 800;
}
.diff-row.hunk,
.diff-row[data-kind="hunk"] {
background: rgba(255, 255, 255, 0.045);
}
.diff-row.hunk .code,
.diff-row[data-kind="hunk"] .code {
color: var(--color-gray-500);
}
.diff[data-wrap="true"] {
overflow-x: hidden;
}
.diff[data-wrap="true"] .diff-row {
grid-template-columns: 42px 18px minmax(0, 1fr);
min-width: 0;
white-space: normal;
}
.diff[data-wrap="true"] .code {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
/* ---------- Timeline ---------- */
.timeline {
position: relative;
display: grid;
gap: 0;
padding-inline-start: var(--space-6);
}
.timeline:is(ol, ul) {
margin: 0;
list-style: none;
}
.timeline::before {
content: "";
position: absolute;
inset-block: 4px 4px;
inset-inline-start: 9px;
width: 1.5px;
background: var(--border-color);
}
.timeline-item,
.tl-entry {
position: relative;
display: grid;
grid-template-columns: minmax(84px, max-content) minmax(0, 1fr);
gap: var(--space-4);
padding-block: 0 var(--space-5);
}
.timeline-item:last-child,
.tl-entry:last-child {
padding-block-end: 0;
}
.timeline-item::before,
.tl-entry::before {
content: "";
position: absolute;
inset-block-start: 4px;
inset-inline-start: calc(4.25px - var(--space-6));
width: 11px;
height: 11px;
border: 2px solid var(--surface);
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 0 1.5px var(--accent);
}
.timeline-item:not(:has(> .timeline-time, > .tl-time)),
.tl-entry:not(:has(> .timeline-time, > .tl-time)) {
display: block;
}
.timeline-time,
.tl-time {
color: var(--text-muted);
font-family: var(--font-mono);
font-size: var(--text-sm);
white-space: nowrap;
}
.timeline-body,
.tl-body {
min-width: 0;
color: var(--text-soft);
}
.timeline-body strong,
.tl-body strong {
color: var(--text);
}
@media (max-width: 620px) {
.timeline-item,
.tl-entry {
grid-template-columns: 1fr;
gap: var(--space-1);
}
}
/* ---------- Flowchart ---------- */
.flowchart {
display: block;
width: 100%;
height: auto;
}
svg.flow,
svg.flowchart {
display: block;
width: 100%;
height: auto;
}
.flow text,
.flowchart text {
fill: var(--text);
font-family: var(--font-sans);
font-size: 12px;
}
.flow .sub,
.flowchart .sub {
fill: var(--text-muted);
font-size: 10px;
}
.flow-edge,
.edge {
fill: none;
stroke: var(--text-muted);
stroke-width: 1.5;
}
.flow-edge[data-kind="yes"],
.edge.yes {
stroke: var(--success);
}
.flow-edge[data-kind="no"],
.edge.no {
stroke: var(--danger);
stroke-dasharray: 4 4;
}
/* SVG flow nodes */
.flow-node,
.flow .node {
cursor: pointer;
transition: transform var(--dur-fast) var(--ease);
}
.flow-node:hover,
.flow .node:hover {
transform: translateY(-1px);
}
.flow-node rect,
.flow .node rect {
fill: var(--surface);
stroke: var(--border-color);
stroke-width: 1.5;
rx: 8;
}
.flow-node path,
.flow .node.gate path {
fill: var(--surface);
stroke: var(--border-color);
stroke-width: 1.5;
}
.flow-node[data-shape="term"] rect,
.flow .node.term rect {
fill: var(--surface-tint);
rx: 22;
}
.flow-node[data-kind="ok"] rect,
.flow .node.ok rect {
fill: rgba(120, 140, 93, 0.12);
stroke: var(--success);
}
.flow-node[data-kind="bad"] rect,
.flow .node.bad rect {
fill: rgba(176, 74, 63, 0.10);
stroke: var(--danger);
}
.flow-node.active rect,
.flow-node.active path,
.flow .node.active rect,
.flow .node.active path {
stroke: var(--accent);
stroke-width: 2;
}
/* HTML flow nodes, for non-SVG diagrams */
div.flow-node {
padding: var(--space-3) var(--space-4);
background: var(--surface);
border: var(--border);
border-radius: var(--radius-sm);
transition:
transform var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease),
box-shadow var(--dur-fast) var(--ease);
}
div.flow-node:hover {
transform: translateY(var(--hover-y));
border-color: rgba(217, 119, 87, 0.55);
box-shadow: var(--shadow-sm);
}
div.flow-node[data-shape="term"] {
border-radius: var(--radius-pill);
background: var(--surface-tint);
}
div.flow-node[data-kind="ok"] {
border-color: var(--success);
background: rgba(120, 140, 93, 0.12);
}
div.flow-node[data-kind="bad"] {
border-color: var(--danger);
background: rgba(176, 74, 63, 0.10);
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}
/* Responsive safety net for generated artifacts. */
p,
li {
overflow-wrap: anywhere;
}
@media (max-width: 860px) {
.split,
.section-rail,
.sidebar-layout {
grid-template-columns: minmax(0, 1fr) !important;
}
.split > *,
.section-rail > *,
.sidebar-layout > *,
.chart-panel {
width: 100%;
max-width: 100%;
min-width: 0;
}
}
</style>
<style>
.diff { max-height: 14rem; overflow-y: auto; }
</style>
</head>
<body>
<main class="page stack" data-gap="lg">
<header class="stack" data-gap="sm">
<div class="eyebrow">Code review</div>
<h1>Patch adds rendering-checker parsers and a chart-brief fixture; three new &ldquo;fail&rdquo; severities are breaking</h1>
<p class="lede">Review of commit <code>5703e01</code> touching <code>scripts/check_candle_renderings.py</code> (+208/−48), plus new <code>evals/charts/build_chart_brief.py</code> and <code>evals/charts/run_eval.py</code>.</p>
<div class="cluster">
<span class="chip" data-tone="danger">3 blocking</span>
<span class="chip" data-tone="accent">2 high</span>
<span class="chip">3 medium</span>
<span class="chip">2 low</span>
</div>
</header>
<!-- ═══ BLOCKING FINDINGS ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Blocking</span>
<h2>New &ldquo;fail&rdquo; severities will break existing CI pipelines</h2>
</div>
<span class="badge" data-tone="danger">Must fix before merge</span>
</div>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>B1 · <code>layout_overflow</code> upgraded from warn → fail</h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, function <code>geometry_findings()</code></p>
<div class="stack" data-gap="sm">
<div>
<span class="badge" data-tone="danger">Severity: blocking</span>
<span class="badge">Evidence: diff hunk</span>
</div>
<p><strong>Evidence.</strong> The function previously returned <code>Finding("warn", ...)</code> for overflow. The patch promotes it to <code>"fail"</code> and adds a second fail condition for document-level horizontal overflow:</p>
<div class="diff" data-wrap="true">
<div class="diff-row del"><span class="ln">1157</span><span class="mark">-</span><span class="code">"warn",</span></div>
<div class="diff-row add"><span class="ln">1158</span><span class="mark">+</span><span class="code">"fail",</span></div>
<div class="diff-row add"><span class="ln">1169</span><span class="mark">+</span><span class="code">findings.append(Finding("fail", "layout_overflow", f"document overflows viewport horizontally by {page_overflow_x}px"))</span></div>
</div>
<p><strong>Impact.</strong> Any page with even 3px of text overflow (previously a warning) will now cause <code>SystemExit(1)</code> in <code>main()</code>. Existing CI pipelines that pass today will break on the next run against the same pages. The alert threshold (<code>overX &gt; 2</code>) in the JS audit is tight&mdash;subpixel rounding alone can trip it.</p>
<p><strong>Fix.</strong> Either keep the existing warn severity for the element-level overflow path and introduce the new document-level check as a separate warn, or gate this behind a new <code>--fail-on-overflow</code> flag (analogous to <code>--fail-on-warn</code>). Add a changelog note that existing users should expect new failures.</p>
</div>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>B2 · Three new static-parser checks all emit &ldquo;fail&rdquo;</h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, function <code>contract_findings()</code></p>
<div class="stack" data-gap="sm">
<div>
<span class="badge" data-tone="danger">Severity: blocking</span>
<span class="badge">Evidence: contract scope</span>
</div>
<p><strong>Evidence.</strong> The patch adds <code>GridListParser</code>, <code>MetricRowParser</code>, and <code>TimelineParser</code> classes (~120 lines total), then wires them into <code>contract_findings()</code> with <code>"fail"</code> severity:</p>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">738</span><span class="mark">+</span><span class="code">"fail",</span></div>
<div class="diff-row add"><span class="ln">739</span><span class="mark">+</span><span class="code">"grid_list_item_children",</span></div>
<div class="diff-row add"><span class="ln">749</span><span class="mark">+</span><span class="code">"fail",</span></div>
<div class="diff-row add"><span class="ln">750</span><span class="mark">+</span><span class="code">"metric_row_contract",</span></div>
<div class="diff-row add"><span class="ln">760</span><span class="mark">+</span><span class="code">"fail",</span></div>
<div class="diff-row add"><span class="ln">761</span><span class="mark">+</span><span class="code">"timeline_item_contract",</span></div>
<div class="diff-row add"><span class="ln">781</span><span class="mark">+</span><span class="code">"fail",</span></div>
<div class="diff-row add"><span class="ln">782</span><span class="mark">+</span><span class="code">"missing_data_visualization",</span></div>
</div>
<p>These checks apply to <em>all</em> candidate pages processed by <code>check_candle_renderings.py</code>, not only the new chart brief. Four new fail conditions are retroactively enforced on every existing artifact in the repo.</p>
<p><strong>Impact.</strong> Any existing page with a multi-child <code>&lt;li&gt;</code> inside <code>.insight-list</code> or <code>.takeaway-list</code>, a <code>.metric-row</code> deviating from the caption+meter+code contract, a <code>.timeline-item</code> missing time/body children, or a numeric-rich page without a chart will now fail. This is a silent breaking change; the commit message (&ldquo;updates&rdquo;) gives no warning.</p>
<p><strong>Fix.</strong> (a) Run the new checks against all existing pages to quantify the blast radius before landing. (b) For the first release, downgrade to <code>"warn"</code> and add an opt-in <code>--strict-contracts</code> flag. (c) Bump to fail in a follow-up after existing pages are compliant.</p>
</div>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>B3 · Division by zero in <code>build_chart_brief.py</code></h3>
<p><strong>File:</strong> <code>evals/charts/build_chart_brief.py</code>, lines 151&ndash;154</p>
<div class="stack" data-gap="sm">
<div>
<span class="badge" data-tone="danger">Severity: blocking</span>
<span class="badge">Evidence: source lines</span>
</div>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">151</span><span class="mark">+</span><span class="code">avg_pass = sum(float(row["static_pass_rate"]) for row in latest) / len(latest)</span></div>
<div class="diff-row add"><span class="ln">153</span><span class="mark">+</span><span class="code">avg_vision = sum(float(row["vision_score"]) for row in latest) / len(latest)</span></div>
<div class="diff-row add"><span class="ln">154</span><span class="mark">+</span><span class="code">avg_delta = sum(float(row["mean_rgb_delta"]) for row in latest) / len(latest)</span></div>
</div>
<p><strong>Impact.</strong> <code>latest_rows()</code> filters to the latest week. If <code>sample-data.csv</code> is empty or corrupted (zero rows for any week), <code>len(latest)</code> is 0 and <code>main()</code> raises <code>ZeroDivisionError</code>. The script is called unconditionally by <code>run_eval.py</code> before the rendering checker, so an empty CSV blocks the entire eval pipeline with an unhelpful traceback.</p>
<p><strong>Fix.</strong> Guard with <code>if not latest: sys.exit("No data for latest week")</code> before the division. Optionally, add a similar guard in <code>previous_latest()</code> (line 105: <code>weeks[-2]</code> will <code>IndexError</code> if fewer than two weeks exist).</p>
</div>
</article>
</section>
<!-- ═══ HIGH FINDINGS ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">High</span>
<h2>Behavioral shifts and fragile assumptions</h2>
</div>
</div>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>H1 · <code>geometry_audit()</code> base-element insertion is a semantic fix with side effects</h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, function <code>geometry_audit()</code></p>
<div class="stack" data-gap="sm">
<div>
<span class="badge" data-tone="accent">Severity: high</span>
<span class="badge">Evidence: diff hunk</span>
</div>
<p><strong>Evidence.</strong> The old code inserted <code>&lt;base&gt;</code> just before <code>&lt;/head&gt;</code>, meaning it appeared <em>after</em> stylesheet <code>&lt;link&gt;</code> elements. Per the HTML spec, <code>&lt;base&gt;</code> only affects URLs in elements that follow it in tree order, so stylesheets linked earlier in <code>&lt;head&gt;</code> resolved against the temp-directory location&mdash;not <code>ROOT</code>&mdash;and silently failed to load. The new code inserts <code>&lt;base&gt;</code> immediately after <code>&lt;head&gt;</code>:</p>
<div class="diff" data-wrap="true">
<div class="diff-row del"><span class="ln">1109</span><span class="mark">-</span><span class="code">if "&lt;/head&gt;" in source:</span></div>
<div class="diff-row del"><span class="ln">1110</span><span class="mark">-</span><span class="code"> source = source.replace("&lt;/head&gt;", base + audit_js + "&lt;/head&gt;", 1)</span></div>
<div class="diff-row add"><span class="ln">1110</span><span class="mark">+</span><span class="code">if re.search(r"&lt;head(?:\s[^&gt;]*)?&gt;", source, flags=re.I):</span></div>
<div class="diff-row add"><span class="ln">1114</span><span class="mark">+</span><span class="code"> source = re.sub(r"(&lt;head(?:\s[^&gt;]*)?&gt;)", lambda m: m.group(1) + base, source, count=1, flags=re.I)</span></div>
</div>
<p><strong>Impact.</strong> The fix is correct, but it changes the visual output of every prior geometry audit. Previous runs compared unstyled candidate pages; future runs will compare correctly styled pages. Layout overflow, timeline geometry, split-rail alignment, and metric-bar spread will all produce different results. Combined with B1 (overflow severity upgrade), the next CI run may produce a large number of new failures that are <em>real</em> (previously hidden by the base bug) but appear as a regression.</p>
<p><strong>Fix.</strong> Accept the fix but pair it with a re-baseline of all existing artifacts. Run the checker with the new code against every page and triage failures before landing.</p>
</div>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>H2 · <code>run_eval.py</code> self-compare masks genuine drift</h3>
<p><strong>File:</strong> <code>evals/charts/run_eval.py</code>, line 42</p>
<div class="stack" data-gap="sm">
<div>
<span class="badge" data-tone="accent">Severity: high</span>
<span class="badge">Evidence: source line</span>
</div>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">42</span><span class="mark">+</span><span class="code">"24-candle-chart-brief.html:24-candle-chart-brief.html",</span></div>
</div>
<p><strong>Impact.</strong> The <code>--pair</code> argument uses the same file for both original and candidate. In <code>compare_stats()</code>, this makes the &ldquo;original&rdquo; and &ldquo;candidate&rdquo; identical, so checks like <code>text_coverage</code>, <code>section_count_drift</code>, and <code>component_density_drop</code> always pass trivially. <code>compare_pair()</code> also skips screenshot capture when the paths are identical (since there is nothing to diff). The eval becomes a contract-only check, missing any visual regression that would be visible against a known-good baseline.</p>
<p><strong>Fix.</strong> Either commit a golden <code>24-candle-chart-brief.baseline.html</code> and pair against it, or add a dedicated <code>--single</code> mode that skips comparison checks and clearly reports &ldquo;no baseline available&rdquo; rather than silently passing them.</p>
</div>
</article>
</section>
<!-- ═══ MEDIUM FINDINGS ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Medium</span>
<h2>Code-quality and robustness concerns</h2>
</div>
</div>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>M1 · <code>TimelineParser</code> uses bare <code>assert isinstance</code> for type narrowing</h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, class <code>TimelineParser</code></p>
<div class="stack" data-gap="sm">
<div>
<span class="badge">Severity: medium</span>
<span class="badge">Evidence: diff hunk</span>
</div>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">241</span><span class="mark">+</span><span class="code">assert isinstance(children, list)</span></div>
<div class="diff-row add"><span class="ln">247</span><span class="mark">+</span><span class="code">assert isinstance(children, list)</span></div>
<div class="diff-row add"><span class="ln">248</span><span class="mark">+</span><span class="code">assert isinstance(timeline_classes, set)</span></div>
</div>
<p><strong>Impact.</strong> If the <code>item_stack</code> dict shape is corrupted (e.g., by a concurrent mutation or an unhandled edge case in <code>handle_starttag</code>), the <code>AssertionError</code> kills the entire checker instead of producing a graceful finding. This is defense-in-depth code that should degrade, not crash.</p>
<p><strong>Fix.</strong> Replace with early <code>continue</code> or a <code>Finding("warn", "timeline_parse_error", ...)</code> appended to <code>bad_items</code>.</p>
</div>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>M2 · Audit JSON extraction regex may miss escaped quotes</h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, function <code>geometry_audit()</code>, around line 1130</p>
<div class="stack" data-gap="sm">
<div>
<span class="badge">Severity: medium</span>
<span class="badge">Evidence: pattern analysis</span>
</div>
<p><strong>Evidence.</strong> The audit JS writes a JSON blob into <code>data-candle-audit</code>, and the Python side extracts it with <code>re.search(r'data-candle-audit="([^"]+)"', ...)</code>. If the JS audit captures text containing a literal double-quote character (e.g., from a <code>textContent</code> value like <code>He said "hello"</code>), the regex stops at that quote, producing truncated JSON that fails <code>json.loads</code>. The <code>text()</code> helper in the audit JS does not escape quotes.</p>
<p><strong>Impact.</strong> Silent fallback: <code>geometry_audit()</code> returns <code>None</code>, and <code>geometry_findings()</code> logs a &ldquo;browser geometry audit unavailable&rdquo; note. Actual geometry problems go undetected.</p>
<p><strong>Fix.</strong> Either escape double-quotes in the JS <code>text()</code> helper (<code>.replace(/"/g, '&amp;quot;')</code>) or use a <code>&lt;script type="application/json" data-candle-audit&gt;</code> element and extract with <code>re.search(r'&lt;script[^&gt;]*data-candle-audit[^&gt;]*&gt;(.*?)&lt;/script&gt;', ...)</code> plus <code>html_lib.unescape</code>.</p>
</div>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>M3 · SVG class injection regex is fragile</h3>
<p><strong>File:</strong> <code>evals/charts/build_chart_brief.py</code>, line 86</p>
<div class="stack" data-gap="sm">
<div>
<span class="badge">Severity: medium</span>
<span class="badge">Evidence: source line</span>
</div>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">86</span><span class="mark">+</span><span class="code">svg = re.sub(r"&lt;svg\b", '&lt;svg class="chart-svg" role="img" aria-label="Line chart showing weekly static pass rate by artifact"', svg, count=1)</span></div>
</div>
<p><strong>Impact.</strong> If Matplotlib changes its SVG output (e.g., adds attributes before <code>&lt;svg</code> or uses a different casing), the regex silently stops matching and the SVG loses its Birch class and accessibility label. The chart still renders visually, but it breaks the Birch component contract and the <code>chart-svg</code> class count in <code>contract_findings()</code>.</p>
<p><strong>Fix.</strong> Use an XML parser (e.g., <code>xml.etree.ElementTree</code>) to set attributes on the root element, or at minimum assert after the substitution that <code>'class="chart-svg"' in svg</code> and fail loudly on mismatch.</p>
</div>
</article>
</section>
<!-- ═══ LOW FINDINGS ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Low</span>
<h2>Minor observations</h2>
</div>
</div>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>L1 · <code>geometry_audit</code> JS still uses <code>var</code></h3>
<p><strong>File:</strong> <code>scripts/check_candle_renderings.py</code>, inline JS in <code>geometry_audit()</code></p>
<p>Consistent with the existing audit code, but the new blocks (timeline detection, split-rail alignment, numeric-header alignment) introduce ~50 additional <code>var</code> declarations. Not a correctness issue, but worth modernizing to <code>const</code>/<code>let</code> in a follow-up cleanup pass.</p>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3>L2 · <code>build_chart_brief.py</code> hardcodes output path</h3>
<p><strong>File:</strong> <code>evals/charts/build_chart_brief.py</code>, line 27</p>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">27</span><span class="mark">+</span><span class="code">OUT = ROOT / "24-candle-chart-brief.html"</span></div>
</div>
<p>The output path is a module-level constant, making the script non-reusable for other chart briefs. Consider accepting <code>--out</code> via <code>argparse</code>.</p>
</article>
</section>
<!-- ═══ DIFF / CODE EVIDENCE SECTION ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Diff evidence</span>
<h2>Key changed regions</h2>
</div>
</div>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3><code>contract_findings()</code> — new checks appended</h3>
<p class="caption">scripts/check_candle_renderings.py, lines 735–786</p>
<div class="diff" data-wrap="true">
<div class="diff-row add"><span class="ln">735</span><span class="mark">+</span><span class="code">grid_list_parser = GridListParser()</span></div>
<div class="diff-row add"><span class="ln">736</span><span class="mark">+</span><span class="code">grid_list_parser.feed(html)</span></div>
<div class="diff-row add"><span class="ln">737</span><span class="mark">+</span><span class="code">if grid_list_parser.bad_items:</span></div>
<div class="diff-row add"><span class="ln">738</span><span class="mark">+</span><span class="code"> findings.append(Finding("fail", "grid_list_item_children", ...))</span></div>
<div class="diff-row add"><span class="ln">745</span><span class="mark">+</span><span class="code">metric_row_parser = MetricRowParser()</span></div>
<div class="diff-row add"><span class="ln">746</span><span class="mark">+</span><span class="code">metric_row_parser.feed(html)</span></div>
<div class="diff-row add"><span class="ln">747</span><span class="mark">+</span><span class="code">if metric_row_parser.bad_rows:</span></div>
<div class="diff-row add"><span class="ln">749</span><span class="mark">+</span><span class="code"> findings.append(Finding("fail", "metric_row_contract", ...))</span></div>
<div class="diff-row add"><span class="ln">756</span><span class="mark">+</span><span class="code">timeline_parser = TimelineParser()</span></div>
<div class="diff-row add"><span class="ln">757</span><span class="mark">+</span><span class="code">timeline_parser.feed(html)</span></div>
<div class="diff-row add"><span class="ln">758</span><span class="mark">+</span><span class="code">if timeline_parser.bad_items:</span></div>
<div class="diff-row add"><span class="ln">760</span><span class="mark">+</span><span class="code"> findings.append(Finding("fail", "timeline_item_contract", ...))</span></div>
<div class="diff-row add"><span class="ln">768</span><span class="mark">+</span><span class="code">numeric_rich = (stats.class_counts.get("numeric-table", 0) &gt; 0 and ...)</span></div>
<div class="diff-row add"><span class="ln">781</span><span class="mark">+</span><span class="code"> findings.append(Finding("fail", "missing_data_visualization", ...))</span></div>
</div>
<p class="caption">Each of these four new checks emits at <code>"fail"</code> severity and applies to every candidate page processed by the checker&mdash;not only the new chart brief.</p>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3><code>geometry_audit()</code> — base tag fix + expanded JS audit</h3>
<p class="caption">scripts/check_candle_renderings.py, ~lines 940–1150</p>
<div class="diff" data-wrap="true">
<div class="diff-row del"><span class="ln">1109</span><span class="mark">-</span><span class="code">if "&lt;/head&gt;" in source: source = source.replace("&lt;/head&gt;", base + audit_js + "&lt;/head&gt;", 1)</span></div>
<div class="diff-row add"><span class="ln">1110</span><span class="mark">+</span><span class="code">if re.search(r"&lt;head(?:\s[^&gt;]*)?&gt;", source, flags=re.I):</span></div>
<div class="diff-row add"><span class="ln">1114</span><span class="mark">+</span><span class="code"> source = re.sub(r"(&lt;head(?:\s[^&gt;]*)?&gt;)", lambda m: m.group(1) + base, ...)</span></div>
<div class="diff-row add"><span class="ln">1115</span><span class="mark">+</span><span class="code"> source = re.sub(r"&lt;/head&gt;", lambda _m: audit_js + "&lt;/head&gt;", ...)</span></div>
</div>
<p class="caption">The base element is now placed before stylesheet links, fixing a silent audit bug. The JS audit block also grew ~60 lines to add viewport-overflow, timeline-geometry, split-rail-heading, and numeric-header-alignment checks.</p>
</article>
<article class="card stack" data-gap="md" data-variant="outlined">
<h3><code>geometry_findings()</code> — severity bump + new finding types</h3>
<p class="caption">scripts/check_candle_renderings.py, lines 1155–1235</p>
<div class="diff" data-wrap="true">
<div class="diff-row del"><span class="ln">1157</span><span class="mark">-</span><span class="code">"warn",</span></div>
<div class="diff-row add"><span class="ln">1158</span><span class="mark">+</span><span class="code">"fail", # layout_overflow severity upgrade</span></div>
<div class="diff-row add"><span class="ln">1176</span><span class="mark">+</span><span class="code">Finding("fail", "timeline_geometry", ...) # new</span></div>
<div class="diff-row add"><span class="ln">1214</span><span class="mark">+</span><span class="code">Finding("warn", "split_rail_heading_alignment", ...) # new</span></div>
<div class="diff-row add"><span class="ln">1228</span><span class="mark">+</span><span class="code">Finding("warn", "numeric_header_alignment", ...) # new</span></div>
</div>
<p class="caption">One severity promotion plus three new geometry findings. Of these, only <code>timeline_geometry</code> and the promoted <code>layout_overflow</code> are fail-level; the others are warn.</p>
</article>
</section>
<!-- ═══ CHECKLIST ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Reviewer checklist</span>
<h2>Merge gate</h2>
</div>
</div>
<div class="card" data-variant="flat">
<ul class="checklist">
<li><strong>Required.</strong> Run new checker against all existing Candle artifacts and publish the findings summary. Confirm zero unexpected failures, or document every new failure with justification.</li>
<li><strong>Required.</strong> Add a zero-row guard in <code>main()</code> of <code>build_chart_brief.py</code> before division by <code>len(latest)</code>.</li>
<li><strong>Required.</strong> Decide whether <code>layout_overflow</code> stays at fail or is gated behind a flag. If kept at fail, add a changelog entry and migration note.</li>
<li><strong>Recommended.</strong> Commit a golden baseline for <code>24-candle-chart-brief.html</code> and update <code>run_eval.py</code> to pair against it rather than self-compare.</li>
<li><strong>Recommended.</strong> Replace <code>assert isinstance</code> in <code>TimelineParser</code> with graceful error handling.</li>
<li><strong>Recommended.</strong> Escape double-quotes in the JS audit <code>text()</code> helper, or switch to a <code>&lt;script&gt;</code>-based JSON extraction.</li>
<li><strong>Optional.</strong> Add an assertion after the SVG regex substitution in <code>build_chart_brief.py</code> to catch Matplotlib output format changes.</li>
</ul>
</div>
</section>
<!-- ═══ RESIDUAL RISKS ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Residual risks</span>
<h2>After merge</h2>
</div>
</div>
<div class="card" data-variant="flat">
<ul class="plain-list">
<li><strong>Undiscovered broken pages.</strong> The four new fail checks in <code>contract_findings()</code> have not been run against the full artifact corpus. Until that is done, the blast radius is unknown. A page that passes today may fail tomorrow with no code changes of its own.</li>
<li><strong>Geometry audit false positives.</strong> The viewport-overflow threshold in JS (<code>offRight &gt; 2 || offLeft &gt; 2</code>) may flag legitimate scrollbars, system font variations, or subpixel layout differences across Chrome versions.</li>
<li><strong>Chart-brief data dependency.</strong> If <code>evals/charts/sample-data.csv</code> is regenerated with a different schema or fewer weeks, both <code>build_chart_brief.py</code> and the rendering checker will break in ways not covered by the existing test surface.</li>
<li><strong>No screenshot diff on self-compare.</strong> Until a golden baseline is committed, the chart brief eval has no visual regression coverage&mdash;only contract and geometry checks.</li>
</ul>
</div>
</section>
<!-- ═══ PATCH SUMMARY TABLE ═══ -->
<section class="section stack" data-gap="lg">
<div class="section-head">
<div>
<span class="eyebrow">Patch summary</span>
<h2>Touched files</h2>
</div>
</div>
<div class="numeric-table-wrap">
<table class="numeric-table">
<thead>
<tr>
<th>File</th>
<th class="metric">Status</th>
<th class="metric">+Lines</th>
<th class="metric">−Lines</th>
<th>Risk</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>evals/charts/build_chart_brief.py</code></td>
<td class="metric">new</td>
<td class="metric">267</td>
<td class="metric">0</td>
<td>Division-by-zero (B3), fragile SVG regex (M3)</td>
</tr>
<tr>
<td><code>evals/charts/run_eval.py</code></td>
<td class="metric">new</td>
<td class="metric">55</td>
<td class="metric">0</td>
<td>Self-compare (H2)</td>
</tr>
<tr>
<td><code>scripts/check_candle_renderings.py</code></td>
<td class="metric">modified</td>
<td class="metric">208</td>
<td class="metric">48</td>
<td>Severity upgrades (B1), new fail checks (B2), base fix (H1), asserts (M1), regex (M2)</td>
</tr>
</tbody>
</table>
</div>
</section>
</main>
</body>
</html>

Xet Storage Details

Size:
62.8 kB
·
Xet hash:
b71a51c3614472aa5695ba9a9fc2bde3e6e1255876892942f2902e53edd77911

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.