Compare commits

..

2 Commits

Author SHA1 Message Date
fc1e9dc27c feat: say which checks use the two periods and which use all the data
'Aug 2 – Sep 13 compared with Jun 7 – Aug 1' reads as if the review ignored
everything older. Rates are windowed; appeal deadlines, payer speed, overturn
rates and the finance reconcile are not — the coverage block now says so and
names the full span of the table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 15:58:30 +05:30
250c56b14d fix: label the findings list in review coverage
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 15:54:31 +05:30
2 changed files with 52 additions and 14 deletions

View File

@ -29,11 +29,14 @@ export function Verdict({
slice = null,
kind = '',
dates = { anchor: null, ceiling: null, submittedTo: null },
dataSpan = null,
}: {
row: Row;
slice?: Slice | null;
kind?: string;
dates?: LinkDates;
/** The full span of the claims table, for the "checked across all data" note. */
dataSpan?: { from: string; to: string } | null;
}) {
const summary = str(row.summary);
if (!summary) return null;
@ -65,7 +68,7 @@ export function Verdict({
)}
<span className="ml-auto">AI analysis · Ava</span>
</div>
{scanned && <WorkStatement text={scanned} />}
{scanned && <WorkStatement text={scanned} dataSpan={dataSpan} />}
</div>
<div className="grid gap-px bg-line sm:grid-cols-3">
@ -97,7 +100,7 @@ export function Verdict({
* as labelled lines; older cases wrote prose, which falls back to sentence
* bullets so nothing renders as a wall of text. */
/** The comparison, drawn: this period against that one, then what was set aside. */
function Periods({ f }: { f: ReviewedFacts }) {
function Periods({ f, dataSpan = null }: { f: ReviewedFacts; dataSpan?: { from: string; to: string } | null }) {
// longDate passes non-ISO text through unchanged, so an already-humanised
// range renders as it was written.
const span = (r: { from: string; to: string } | null) => (r ? `${longDate(r.from)} – ${longDate(r.to)}` : '—');
@ -128,13 +131,33 @@ function Periods({ f }: { f: ReviewedFacts }) {
</>
)}
{f.ceiling && <> · Nothing after {longDate(f.ceiling)} was used</>}
</p>
{/* The two periods above are the RATE comparison. Deadlines, payer speed
and overturn rates are properties of the whole book, so they are
checked across everything — saying so stops the reasonable question
"why only six weeks?". */}
<p className="mt-1 text-xs text-muted">
Denial rates are compared between these two periods. Appeal deadlines, insurer payment
speed and appeal-overturn rates are checked across all claims
{dataSpan ? ` (${longDate(dataSpan.from)} – ${longDate(dataSpan.to)})` : ''}, and every
month is reconciled against the finance report.
{f.requested && <> · Requested {span(f.requested)}; the last 6 weeks of it were compared with the 8 before them</>}
</p>
</div>
);
}
function WorkStatement({ text, heading = 'Review coverage', bare = false }: { text: string; heading?: string; bare?: boolean }) {
function WorkStatement({
text,
heading = 'Review coverage',
bare = false,
dataSpan = null,
}: {
text: string;
heading?: string;
bare?: boolean;
dataSpan?: { from: string; to: string } | null;
}) {
const rows = workStatement(text);
const reviewed = rows ? reviewedFacts(rows.find((r) => r.key === 'REVIEWED')?.items ?? []) : null;
const row = (k: string) => rows?.find((r) => r.key === k);
@ -164,20 +187,23 @@ function WorkStatement({ text, heading = 'Review coverage', bare = false }: { te
return (
<div className={bare ? '' : 'mt-3 border-t border-ai-edge/60 pt-3'}>
{heading && <p className="text-[11px] font-semibold tracking-wide text-faint uppercase">{heading}</p>}
{reviewed && <Periods f={reviewed} />}
{reviewed && <Periods f={reviewed} dataSpan={dataSpan} />}
{!reviewed && row('REVIEWED') && (
<p className="mt-2 text-[13px] text-muted">{row('REVIEWED')!.items.map(prose).join(' · ')}</p>
)}
{found && found.items.length > 0 && (
<ul className="mt-3 space-y-1.5">
{found.items.map((it, i) => (
<li key={i} className="flex gap-2 text-[13px] leading-relaxed text-ink">
<span aria-hidden="true" className="mt-[7px] h-1.5 w-1.5 shrink-0 rounded-full bg-warn" />
<span>{prose(it)}</span>
</li>
))}
</ul>
<>
<p className="mt-3 text-[11px] font-semibold tracking-wide text-faint uppercase">{found.label}</p>
<ul className="mt-1.5 space-y-1.5">
{found.items.map((it, i) => (
<li key={i} className="flex gap-2 text-[13px] leading-relaxed text-ink">
<span aria-hidden="true" className="mt-[7px] h-1.5 w-1.5 shrink-0 rounded-full bg-warn" />
<span>{prose(it)}</span>
</li>
))}
</ul>
</>
)}
{rest.map((r) => (

View File

@ -73,7 +73,9 @@ export function CaseScreen() {
// service date — read from the stats view, NOT from the briefing: the charts
// take seconds to load and a link rendered without the anchor would silently
// drop the deadline window and open thousands of rows instead of hundreds.
const lake = useQuery(() => client.rows('dni-rv-lakehouse-tables', { limit: 10 }), [], !asOf && hasFindings);
// Also used for the "checked across all claims (Mar 2 – Sep 13)" note, so it
// is fetched for replayed cases too.
const lake = useQuery(() => client.rows('dni-rv-lakehouse-tables', { limit: 10 }), [], hasFindings);
const claimsStats = lake.data?.find((r) => str(r.table_name) === 'claims');
const linkDates = {
ceiling: asOf,
@ -184,7 +186,17 @@ export function CaseScreen() {
{/* ---------- The findings: what happened, how much, what to approve ---------- */}
{hasFindings && (
<>
<Verdict row={row} slice={slice} kind={kind} dates={linkDates} />
<Verdict
row={row}
slice={slice}
kind={kind}
dates={linkDates}
dataSpan={
str(claimsStats?.from_date) && str(claimsStats?.to_date)
? { from: str(claimsStats?.from_date).slice(0, 10), to: str(claimsStats?.to_date).slice(0, 10) }
: null
}
/>
{briefing.data ? (
<Briefing data={briefing.data} slice={slice} kind={kind} />
) : (