Docs/dolt plan clarifications #1

Merged
dennisthiessen merged 34 commits from docs/dolt-plan-clarifications into main 2026-07-23 13:27:08 +02:00
Showing only changes of commit 103b182598 - Show all commits
@@ -10,39 +10,31 @@ interface FundamentalsPanelProps {
data: FundamentalResponse;
}
/** Positive / neutral / negative styling, always paired with the read text. */
type Tone = 'up' | 'flat' | 'down';
/** Favorable / neutral / adverse — always paired with the read text. */
type Tone = 'good' | 'flat' | 'bad';
const TONE_TEXT: Record<Tone, string> = {
up: 'text-emerald-400',
flat: 'text-gray-400',
down: 'text-rose-400',
};
const TONE_CELL: Record<Tone, string> = {
up: 'bg-emerald-400/10 text-emerald-200 ring-emerald-400/20',
flat: 'bg-white/5 text-gray-200 ring-white/10',
down: 'bg-rose-400/10 text-rose-200 ring-rose-400/20',
};
const TONE_BAR: Record<Tone, string> = {
up: 'bg-emerald-400',
flat: 'bg-gray-400',
down: 'bg-rose-400',
// Horizon tokens (native to the rest of the product).
const HZ = {
text: '#EDEEF3',
muted: '#9AA0B0',
track: '#5D6373',
fav: '#6EC9DB', // cyan
adv: '#EF9182', // coral
};
const toneColor = (t: Tone) => (t === 'good' ? HZ.fav : t === 'bad' ? HZ.adv : HZ.muted);
const POSITIVE_READS = new Set([
'accelerating', 'improving', 'above peers', 'buying back', 'attractively valued',
'conservative leverage',
'accelerating', 'improving', 'above peers', 'above own average', 'buying back',
'attractively valued', 'conservative leverage',
]);
const NEGATIVE_READS = new Set([
'decelerating', 'deteriorating', 'priced above peers', 'elevated leverage',
'below peers',
'decelerating', 'deteriorating', 'priced above peers', 'elevated leverage', 'below peers',
]);
function readTone(read: string | null | undefined): Tone {
if (!read) return 'flat';
if (POSITIVE_READS.has(read)) return 'up';
if (NEGATIVE_READS.has(read)) return 'down';
if (read.includes('dilution')) return 'down';
if (POSITIVE_READS.has(read)) return 'good';
if (NEGATIVE_READS.has(read)) return 'bad';
if (read.includes('dilution')) return 'bad';
return 'flat';
}
@@ -62,9 +54,11 @@ function money(v: number | null | undefined): string {
if (abs >= 1e6) return `$${(v / 1e6).toFixed(1)}M`;
return `$${v.toFixed(0)}`;
}
function signedPp(v: number): string {
return `${v >= 0 ? '+' : ''}${Math.round(v * 10) / 10}pp`;
}
/** Parse a YYYY-MM-DD string as a LOCAL calendar date (avoids the UTC-midnight
* off-by-one that shows the previous day west of UTC). */
/** Parse YYYY-MM-DD as a LOCAL calendar date (no UTC off-by-one west of UTC). */
function parseLocalDate(s: string): Date {
const [y, m, d] = s.split('-').map(Number);
return new Date(y, (m ?? 1) - 1, d ?? 1);
@@ -81,22 +75,22 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
const reads = data.reads?.by_key ?? {};
const val = data.valuation;
const earnings = data.earnings;
// per-metric provenance/freshness (all SEC snapshot metrics share the latest filing)
const provenance = (data.metrics ?? []).find((m) => m.period_end) ?? null;
const hasAny = (data.metrics ?? []).some((m) => m.value != null) || !!val || !!earnings?.next
|| (earnings?.recent?.length ?? 0) > 0;
const tapeRows = [
{ key: 'revenue_growth_yoy', label: 'Revenue growth', fmt: pct },
{ key: 'eps_growth_yoy', label: 'EPS growth', fmt: pct },
{ key: 'operating_margin', label: 'Operating margin', fmt: pct },
{ key: 'fcf_margin', label: 'FCF margin', fmt: pct },
{ key: 'share_count_change_yoy', label: 'Share count', fmt: pct },
// Operating trend: value vs a truthful reference (prior quarter / prior avg / zero).
const trendRows: { key: string; label: string; kind: 'growth' | 'margin' | 'share' }[] = [
{ key: 'revenue_growth_yoy', label: 'Revenue growth', kind: 'growth' },
{ key: 'eps_growth_yoy', label: 'EPS growth', kind: 'growth' },
{ key: 'operating_margin', label: 'Operating margin', kind: 'margin' },
{ key: 'fcf_margin', label: 'FCF margin', kind: 'margin' },
{ key: 'share_count_change_yoy', label: 'Share count', kind: 'share' },
];
const valuationRows: {
// Valuation & balance: favorable percentile vs peer median.
const valueRows: {
label: string; value: number | null; industry: MetricIndustry | null;
readKey: string; fmt: (v: number | null) => string;
}[] = [
@@ -110,41 +104,37 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
return (
<section className="glass p-5" aria-label="Fundamentals">
<div className="mb-1 flex flex-wrap items-baseline justify-between gap-x-3 gap-y-0.5">
<h3 className="text-xs font-medium uppercase tracking-widest text-gray-500">Fundamentals</h3>
<h3 className="text-xs font-medium uppercase tracking-widest" style={{ color: HZ.muted }}>Fundamentals</h3>
{data.reads?.header && (
<p className="text-[11.5px] text-gray-400 sm:text-right">{data.reads.header}</p>
<p className="text-[11.5px] sm:text-right" style={{ color: HZ.muted }}>{data.reads.header}</p>
)}
</div>
{!hasAny ? (
<p className="mt-3 text-sm text-gray-500">No fundamentals reported yet.</p>
<p className="mt-3 text-sm" style={{ color: HZ.muted }}>No fundamentals reported yet.</p>
) : (
<>
<EarningsStrip earnings={earnings} />
{/* Quarter tape — the panel's signature device */}
<div className="mt-4">
<div className="mb-1.5 flex items-baseline justify-between">
<span className="text-[10px] font-medium uppercase tracking-widest text-gray-500">Quarter tape</span>
<span className="hidden text-[10px] uppercase tracking-widest text-gray-600 sm:inline">Latest · read</span>
</div>
<div className="space-y-2 sm:space-y-1.5">
{tapeRows.map((row) => (
<TapeRow key={row.key} label={row.label} metric={metrics[row.key]}
read={reads[row.key]} fmt={row.fmt} />
<div className="mt-4 grid gap-x-8 gap-y-5 sm:grid-cols-2">
<div>
<SectionLabel>Operating trend</SectionLabel>
<div className="mt-2 space-y-3.5">
{trendRows.map((r) => (
<TrendRow key={r.key} label={r.label} kind={r.kind}
metric={metrics[r.key]} read={reads[r.key]} />
))}
</div>
</div>
{/* Balance & valuation — restrained peer strips */}
<div className="mt-4">
<span className="text-[10px] font-medium uppercase tracking-widest text-gray-500">Balance &amp; valuation</span>
<div className="mt-1.5 space-y-2.5 sm:space-y-2">
{valuationRows.map((row) => (
<ValuationRow key={row.label} {...row} read={reads[row.readKey]} />
<div>
<SectionLabel>Valuation &amp; balance</SectionLabel>
<div className="mt-2 space-y-3.5">
{valueRows.map((r) => (
<ValueRow key={r.label} {...r} read={reads[r.readKey]} />
))}
</div>
</div>
</div>
<Provenance provenance={provenance} priceDate={val?.price_date ?? null}
marketCap={val?.market_cap_est ?? null} />
@@ -154,90 +144,147 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
);
}
function TapeRow({ label, metric, read, fmt }: {
label: string; metric: MetricItem | undefined; read: string | null | undefined;
fmt: (v: number | null) => string;
function SectionLabel({ children }: { children: React.ReactNode }) {
return <span className="text-[10px] font-medium uppercase tracking-widest" style={{ color: HZ.muted }}>{children}</span>;
}
// ---- operating-trend row: value vs reference, shown as a delta rail ----------
function TrendRow({ label, kind, metric, read }: {
label: string; kind: 'growth' | 'margin' | 'share';
metric: MetricItem | undefined; read: string | null | undefined;
}) {
const history = metric?.history ?? [];
const tone = readTone(read);
const cells = (
<div className="flex justify-end gap-1" role="img"
aria-label={`${label} last ${history.length}: ${history.map((h) => fmt(h.value)).join(', ') || 'no data'}`}>
{history.length === 0 && <span className="num text-xs text-gray-600"></span>}
{history.map((h, i) => {
const latest = i === history.length - 1;
const value = metric?.value ?? null;
const history = (metric?.history ?? []).map((h) => h.value).filter((v): v is number => v != null);
// reference + neutral band per the backend's deterministic rules
let ref: number | null = null;
let refLabel = '';
let halfRange = 8;
let neutral = 2;
if (kind === 'growth') {
ref = history.length >= 2 ? history[history.length - 2] : null;
refLabel = ref != null ? `prior ${pct(ref)}` : '';
halfRange = 8; neutral = 2;
} else if (kind === 'margin') {
const prior = history.slice(0, -1);
ref = prior.length ? prior.reduce((a, b) => a + b, 0) / prior.length : null;
refLabel = ref != null ? `avg ${pct(ref)}` : '';
halfRange = 4; neutral = 1;
} else {
ref = 0; refLabel = 'vs zero'; halfRange = 5; neutral = 1;
}
const delta = value != null && ref != null ? value - ref : null;
return (
<span key={i}
className={`num rounded px-1.5 py-0.5 text-[11px] ring-1 ${latest ? TONE_CELL[tone] : 'bg-white/5 text-gray-400 ring-white/5'}`}>
{fmt(h.value)}
</span>
);
})}
<div>
<div className="flex items-baseline justify-between gap-2">
<span className="truncate text-sm" style={{ color: HZ.muted }}>{label}</span>
<span className="num text-sm" style={{ color: HZ.text }}>{pct(value)}</span>
</div>
);
return (
<div className="sm:grid sm:grid-cols-[minmax(0,7rem)_1fr_auto] sm:items-center sm:gap-3">
{/* mobile: label + read on one line, cells below (avoids narrow-width overflow) */}
<div className="flex items-baseline justify-between gap-2 sm:hidden">
<span className="text-sm text-gray-400">{label}</span>
<span className={`text-[11.5px] font-medium ${TONE_TEXT[tone]}`}>{read ?? '—'}</span>
<div className="text-[11.5px] font-medium" style={{ color: toneColor(tone) }}>{read ?? '—'}</div>
{delta != null ? (
<div className="mt-1 flex items-center gap-2">
<span className="w-20 shrink-0 text-[10px]" style={{ color: HZ.muted }}>{refLabel}</span>
<DeltaRail delta={delta} halfRange={halfRange} neutral={neutral} tone={tone}
ariaLabel={`${label} ${pct(value)}, ${refLabel || 'reference'}, change ${signedPp(delta)}, ${read ?? 'no read'}`} />
<span className="num w-14 shrink-0 text-right text-[10px]" style={{ color: toneColor(tone) }}>{signedPp(delta)}</span>
</div>
<span className="hidden truncate text-sm text-gray-400 sm:block">{label}</span>
<div className="mt-1 sm:mt-0">{cells}</div>
<span className={`hidden text-right text-[11.5px] font-medium sm:block sm:w-24 ${TONE_TEXT[tone]}`}>
{read ?? '—'}
</span>
) : (
value == null && <div className="mt-1 text-[10px]" style={{ color: HZ.track }}>n/a</div>
)}
</div>
);
}
function ValuationRow({ label, value, industry, read, fmt }: {
/** A comparison rail centered on a reference line (not a progress bar): a dot at
* the current delta with a bar connecting it back to the reference. */
function DeltaRail({ delta, halfRange, neutral, tone, ariaLabel }: {
delta: number; halfRange: number; neutral: number; tone: Tone; ariaLabel: string;
}) {
const clamped = Math.max(-halfRange, Math.min(halfRange, delta));
const pos = 50 + (clamped / halfRange) * 50; // %
const barLeft = Math.min(50, pos);
const barWidth = Math.abs(pos - 50);
const bandHalf = (neutral / halfRange) * 50;
const color = toneColor(tone);
return (
<span className="relative block h-1.5 flex-1 rounded-full" role="img" aria-label={ariaLabel}
style={{ background: 'rgba(93,99,115,0.22)' }}>
<span className="absolute inset-y-0 rounded-full" aria-hidden
style={{ left: `${50 - bandHalf}%`, width: `${2 * bandHalf}%`, background: 'rgba(93,99,115,0.4)' }} />
<span className="absolute inset-y-[-2px] w-px" aria-hidden style={{ left: '50%', background: 'rgba(237,238,243,0.55)' }} />
<span className="absolute inset-y-0 rounded-full" aria-hidden style={{ left: `${barLeft}%`, width: `${barWidth}%`, background: color }} />
<span className="absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full" aria-hidden
style={{ left: `${pos}%`, background: color, boxShadow: '0 0 0 2px #11131C' }} />
</span>
);
}
// ---- valuation/balance row: favorable percentile vs peer median -------------
function ValueRow({ label, value, industry, read, fmt }: {
label: string; value: number | null; industry: MetricIndustry | null;
read: string | null | undefined; fmt: (v: number | null) => string;
}) {
const tone = readTone(read);
return (
<div className="grid grid-cols-[minmax(0,8.5rem)_auto_1fr] items-center gap-x-3 gap-y-0.5">
<span className="truncate text-sm text-gray-400">{label}</span>
<span className="num text-sm text-gray-100">{fmt(value)}</span>
<div className="flex items-center justify-end gap-2 text-right">
{industry ? (
<div>
<div className="flex items-baseline justify-between gap-2">
<span className="truncate text-sm" style={{ color: HZ.muted }}>{label}</span>
<span className="num text-sm" style={{ color: HZ.text }}>{fmt(value)}</span>
</div>
{value == null ? (
<div className="mt-1 text-[10px]" style={{ color: HZ.track }}>n/a</div>
) : industry ? (
<>
{/* visible compact peer context (also the only peer info on mobile) */}
<span className="text-[11px] text-gray-500">med {fmt(industry.median)} · {industry.peer_count}p</span>
<PercentileStrip industry={industry} tone={tone} label={label} fmt={fmt} />
<span className={`text-[11.5px] font-medium ${TONE_TEXT[tone]}`}>{read ?? 'in line'}</span>
<div className="text-[11.5px] font-medium" style={{ color: toneColor(tone) }}>{read ?? 'in line'}</div>
<div className="mt-1 flex items-center gap-2">
<span className="w-3 text-[9px]" style={{ color: HZ.track }}>0</span>
<PercentileRail percentile={industry.favorable_percentile} tone={tone}
ariaLabel={`${label}: ${industry.favorable_percentile}th favorable percentile vs ${industry.label}, median ${fmt(industry.median)}, ${industry.peer_count} peers`} />
<span className="w-6 text-right text-[9px]" style={{ color: HZ.track }}>100</span>
</div>
<div className="mt-0.5 pl-5 text-[10px]" style={{ color: HZ.muted }}>
median {fmt(industry.median)} · {industry.peer_count} peers
</div>
</>
) : (
<span className="text-[11px] text-gray-600">peers n/a</span>
<div className="text-[11px]" style={{ color: HZ.track }}>peers n/a</div>
)}
</div>
</div>
);
}
function PercentileStrip({ industry, tone, label, fmt }: {
industry: MetricIndustry; tone: Tone; label: string; fmt: (v: number | null) => string;
/** Percentile rail 0-100 with the peer median fixed at 50; right = more favorable
* (the percentile is already polarity-aware). */
function PercentileRail({ percentile, tone, ariaLabel }: {
percentile: number; tone: Tone; ariaLabel: string;
}) {
const p = Math.max(0, Math.min(100, industry.favorable_percentile));
const p = Math.max(0, Math.min(100, percentile));
const barLeft = Math.min(50, p);
const barWidth = Math.abs(p - 50);
const color = toneColor(tone);
return (
<span
className="relative hidden h-1.5 w-16 rounded-full bg-white/10 sm:block"
role="img"
aria-label={`${label}: ${industry.favorable_percentile}th favorable percentile vs ${industry.label}, median ${fmt(industry.median)}, ${industry.peer_count} peers`}
>
<span className={`absolute inset-y-0 left-0 rounded-full ${TONE_BAR[tone]}`} style={{ width: `${p}%` }} />
<span className="absolute inset-y-[-2px] left-1/2 w-px bg-white/40" aria-hidden />
<span className="relative block h-1.5 flex-1 rounded-full" role="img" aria-label={ariaLabel}
style={{ background: 'rgba(93,99,115,0.22)' }}>
<span className="absolute inset-y-[-2px] w-px" aria-hidden style={{ left: '50%', background: 'rgba(237,238,243,0.55)' }} />
<span className="absolute inset-y-0 rounded-full" aria-hidden style={{ left: `${barLeft}%`, width: `${barWidth}%`, background: color }} />
<span className="absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full" aria-hidden
style={{ left: `${p}%`, background: color, boxShadow: '0 0 0 2px #11131C' }} />
</span>
);
}
// ---- earnings + provenance (unchanged behavior) ----------------------------
function Provenance({ provenance, priceDate, marketCap }: {
provenance: MetricItem | null; priceDate: string | null; marketCap: number | null;
}) {
if (!provenance && !priceDate) return null;
if (!provenance?.period_end && !priceDate) return null;
return (
<p className="mt-4 border-t border-white/10 pt-2 text-[10px] leading-relaxed text-gray-600">
<p className="mt-4 border-t border-white/10 pt-2 text-[10px] leading-relaxed" style={{ color: HZ.track }}>
{provenance?.period_end && (
<>SEC filings · latest {shortDate(provenance.period_end)}
{provenance.filed_date && <> (filed {shortDate(provenance.filed_date)})</>}</>
@@ -252,27 +299,25 @@ function Provenance({ provenance, priceDate, marketCap }: {
function EarningsStrip({ earnings }: { earnings: FundamentalResponse['earnings'] }) {
const next = earnings?.next;
const recent = earnings?.recent ?? [];
const when = next
? next.days_until === 0 ? 'today' : `in ${next.days_until}d`
: null;
const when = next ? (next.days_until === 0 ? 'today' : `${next.days_until}d`) : null;
return (
<div className="mt-2 flex flex-wrap items-center justify-between gap-x-4 gap-y-1">
<span className="text-sm text-gray-300">
<span className="text-gray-500">Next earnings </span>
<span className="text-sm" style={{ color: HZ.text }}>
<span style={{ color: HZ.muted }}>Next earnings </span>
{next ? (
<>
{shortDate(next.date)}
{' · '}
<span className="uppercase">{next.session === 'unknown' ? 'TBD' : next.session}</span>
<span className="text-gray-500"> · {when}</span>
<span style={{ color: HZ.muted }}> · {when}</span>
</>
) : (
<span className="text-gray-500">no date</span>
<span style={{ color: HZ.muted }}>no date</span>
)}
</span>
{recent.length > 0 && (
<span className="flex items-center gap-1.5">
<span className="text-[10px] uppercase tracking-widest text-gray-600">Last {recent.length}</span>
<span className="text-[10px] uppercase tracking-widest" style={{ color: HZ.track }}>Last {recent.length}</span>
{recent.slice().reverse().map((e, i) => <EarningsBar key={i} e={e} />)}
</span>
)}
@@ -282,15 +327,13 @@ function EarningsStrip({ earnings }: { earnings: FundamentalResponse['earnings']
function EarningsBar({ e }: { e: EarningsRecent }) {
const beat = e.eps_actual != null && e.eps_estimate != null ? e.eps_actual - e.eps_estimate : null;
const tone: Tone = beat == null ? 'flat' : beat > 0 ? 'up' : beat < 0 ? 'down' : 'flat';
const tone: Tone = beat == null ? 'flat' : beat > 0 ? 'good' : beat < 0 ? 'bad' : 'flat';
const label = beat == null ? 'n/a' : beat > 0 ? 'beat' : beat < 0 ? 'miss' : 'in line';
const arrow = beat == null ? '·' : beat > 0 ? '▲' : beat < 0 ? '▼' : '';
return (
<span
className={`num rounded px-1 text-[10px] ring-1 ${TONE_CELL[tone]}`}
<span className="num text-xs" style={{ color: toneColor(tone) }}
title={`${e.announce_date}: ${label}${e.surprise_pct != null ? ` ${e.surprise_pct > 0 ? '+' : ''}${e.surprise_pct}%` : ''}`}
aria-label={`${e.announce_date} ${label}`}
>
aria-label={`${e.announce_date} ${label}`}>
{arrow}
</span>
);