Merge DS4 (design): billboards — STREAKS row, grade reveal, CLV reframe, /u profile

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

# Conflicts:
#	web/src/app/ledger/page.tsx
This commit is contained in:
Kev
2026-07-12 19:27:15 -04:00
7 changed files with 452 additions and 74 deletions
+29 -7
View File
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useState } from 'react';
import { GradePill } from '@/components/GradeCard';
import { useAuth } from '@/contexts/AuthContext';
import { Skeleton } from '@/components/vyndr';
import { clvMode, CLV_FLAT_LINE } from '@/lib/clvDisplay';
/**
* The Ledger (Session 58, Phase 1) — the truth surface, now backed by the
@@ -197,15 +198,36 @@ function TierCalibration({ agg, minSample }: { agg: ModelAggregate; minSample: n
);
}
/** S6 (A1 board) — compact settled-CLV distribution strip. Bars are DATA
* (mono, tabular): green = beat-the-close side, red = faded side, dim = flat.
* Renders only when the server passed the n≥20 gate (clv_distribution set). */
/** S6 (A1 board) · reframed DS4 — settled-CLV display. The n≥20 gate lives
* in the server (clv_distribution set). DESIGN-SPEC Part 3 #16: a near-flat
* distribution renders as one giant bar + six empty stubs — it reads as
* BROKEN. When CLV is flat we SAY so in one confident VOICE line (the record
* is the best data on the site; it must look the most premium, never errored)
* and show the bars only when there is real spread. */
function ClvDistribution({ agg }: { agg: ModelAggregate }) {
const dist = agg.clv_distribution;
if (!Array.isArray(dist) || dist.length === 0) return null;
const total = dist.reduce((n, b) => n + b.count, 0);
const { mode } = clvMode(dist as Parameters<typeof clvMode>[0]);
if (mode === 'none') return null;
if (mode === 'flat') {
// Flat CLV is a FEATURE, not an error: the model grades outcomes, not the
// close. State it plainly — premium, confident, no broken histogram.
return (
<div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--border)' }}>
<div className="mono" style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.1em', color: 'var(--text-tertiary)', marginBottom: 6 }}>
CLOSING-LINE VALUE
</div>
<p className="mono" style={{ fontSize: 14, fontWeight: 600, color: 'var(--text-primary)', margin: 0, letterSpacing: '0.01em' }}>
{CLV_FLAT_LINE}
</p>
</div>
);
}
const distArr = dist as ClvBucket[];
const total = distArr.reduce((n, b) => n + b.count, 0);
if (total === 0) return null;
const max = Math.max(...dist.map((b) => b.count));
const max = Math.max(...distArr.map((b) => b.count));
const color = (side: ClvBucket['side']) =>
side === 'beat' ? 'var(--g-a, #00D4A0)' : side === 'faded' ? 'var(--miss, #FF6B6B)' : 'var(--text-tertiary)';
return (
@@ -214,7 +236,7 @@ function ClvDistribution({ agg }: { agg: ModelAggregate }) {
CLV DISTRIBUTION · {total} SETTLED
</div>
<div style={{ display: 'flex', gap: 8, alignItems: 'flex-end', maxWidth: 420 }}>
{dist.map((b) => (
{distArr.map((b) => (
<div key={b.label} title={`${b.label}: ${b.count}`} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, minWidth: 0 }}>
<span className="mono" style={{ fontSize: 10, fontVariantNumeric: 'tabular-nums', color: b.count > 0 ? 'var(--text-secondary)' : 'var(--text-tertiary)' }}>
{b.count}