Draw the error series terracotta on Home

Failures were slot 1 of a ramp that carries identity by lightness alone, so at
a 2px stroke the line that matters read as one picture with avg and lag. It
takes --brand-secondary now — the same terracotta the brain graph above it
already spends on a flow that cannot run. A palette entry naming a token is
resolved off the chart's element, since a canvas cannot parse var().

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 16:15:14 +02:00
co-authored by Claude Opus 5
parent 5da5606f79
commit 530dd3587c
2 changed files with 16 additions and 4 deletions
@@ -176,13 +176,16 @@ function token(name: string, from: Element): string {
/** /**
* What one line is drawn in. * What one line is drawn in.
* *
* A palette entry is either a slot of the app's own ramp — the shape a * A palette entry is one of three things: a slot of the app's own ramp — the
* dashboard stored before it could name colours — or a colour, which is what a * shape a dashboard stored before it could name colours — a token, for a line
* palette writes today. A colour is used as it stands. * that means something the ramp has no step for, or a colour, which is what a
* dashboard palette writes today. A colour is used as it stands; the other two
* are resolved here, since the canvas cannot read a custom property.
*/ */
const seriesColor = (index: number, slots: string[], from: Element) => { const seriesColor = (index: number, slots: string[], from: Element) => {
const slot = slots[index % slots.length] const slot = slots[index % slots.length]
return CHART_SLOTS.includes(slot) ? token(`--chart-${slot}`, from) : slot if (CHART_SLOTS.includes(slot)) return token(`--chart-${slot}`, from)
return slot.startsWith("--") ? token(slot, from) : slot
} }
/** /**
@@ -102,12 +102,15 @@ function Chart({
plots, plots,
pending, pending,
moment, moment,
palette,
}: { }: {
title: string title: string
labels: string[] labels: string[]
plots: HistoryPoint[][] plots: HistoryPoint[][]
pending: boolean pending: boolean
moment: Moment moment: Moment
/** Only where a line means something the ramp has no step for. */
palette?: string[]
}) { }) {
return ( return (
<div <div
@@ -128,6 +131,7 @@ function Chart({
<UplotChart <UplotChart
labels={labels} labels={labels}
plots={plots} plots={plots}
palette={palette}
empty="Nothing has run yet." empty="Nothing has run yet."
pending={pending} pending={pending}
onCursor={moment.onCursor} onCursor={moment.onCursor}
@@ -304,6 +308,11 @@ export function HealthActivity({ range }: { range: Range }) {
]} ]}
pending={seriesPending} pending={seriesPending}
moment={failuresAt} moment={failuresAt}
// Failures are the one line here that is not a measurement of how
// much ran, and five steps of one blue ramp cannot say so — at a
// 2px stroke they read as one picture. Terracotta is what the brain
// graph above already spends on a flow that cannot run.
palette={["--brand-secondary", "3", "5"]}
/> />
</section> </section>