copy: an application, not a transcript

Every user-facing string rewritten from a narrator's voice into an
application's. "What she wants you to approve" is now "Recommended actions";
"Her evidence" is "Query log"; "Watch how she did it" is "Activity trace";
"The full story" is "Analysis"; "Ava is reviewing" is "Review in progress";
"Nothing needs your attention this morning" is "No findings". Chart captions
state what the chart shows ("Gray: 8-week baseline · Blue: last 6 weeks")
instead of commenting on it ("One insurer moved").

The AI is an attribution — "AI analysis · Ava · Confidence 97%" — not a
character the page talks about. Labels are nouns, hints are facts, and the
queue and action names use the workflow's own vocabulary (Approve actions,
Request changes, Resume review, Close case).

Same treatment on the exported slides: Summary, Trend, Comparison, Recovery,
Recommended actions, Method.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Yashas 2026-09-16 15:38:50 +05:30
parent 5df97f989c
commit d41583c68b
10 changed files with 125 additions and 123 deletions

View File

@ -90,12 +90,12 @@ export interface Queue {
}
export const QUEUES: Queue[] = [
{ path: 'review', label: 'Awaiting Review', stage: 'Awaiting Review', hint: 'Findings on your desk' },
{ path: 'investigating', label: 'Investigating', stage: 'Investigating', hint: 'Ava is working' },
{ path: 'monitoring', label: 'Monitoring', stage: 'Monitoring', hint: 'Waiting on the re-check' },
{ path: 'needs-human', label: 'Needs Human', stage: NEEDS_HUMAN, hint: 'Ava could not finish' },
{ path: 'closed', label: 'Closed', stage: 'Closed', hint: 'Done, with an outcome' },
{ path: 'all', label: 'All Investigations', stage: null, hint: 'Every case' },
{ path: 'review', label: 'Awaiting Review', stage: 'Awaiting Review', hint: 'Awaiting your decision' },
{ path: 'investigating', label: 'In Progress', stage: 'Investigating', hint: 'Review running' },
{ path: 'monitoring', label: 'Monitoring', stage: 'Monitoring', hint: 'Awaiting scheduled re-check' },
{ path: 'needs-human', label: 'Escalated', stage: NEEDS_HUMAN, hint: 'Requires a person' },
{ path: 'closed', label: 'Closed', stage: 'Closed', hint: 'Completed cases' },
{ path: 'all', label: 'All Cases', stage: null, hint: 'Every review' },
];
// ---------------------------------------------------------------------------
@ -124,34 +124,34 @@ export const STAGE_ACTIONS: Record<string, Action[]> = {
'Awaiting Review': [
{
activity: ACT.APPROVE,
label: 'Approve Actions',
label: 'Approve actions',
roles: ['revenue_cycle_manager'],
kind: 'primary',
hint: 'Books the re-check; Ava reports back on whether it worked',
hint: 'Schedules the follow-up re-check',
},
{
activity: ACT.CHANGES,
label: 'Send Back to Ava',
label: 'Request changes',
roles: ['revenue_cycle_manager'],
kind: 'secondary',
// The only way a person asks Ava anything: in the context of something
// she already found. There is deliberately no "ask a question" door.
hint: 'She re-runs the review with your note',
hint: 'Re-runs the review with your note attached',
},
{ activity: ACT.REJECT, label: 'Reject', roles: ['revenue_cycle_manager'], kind: 'danger' },
],
Approved: [
{ activity: ACT.CLOSE, label: 'Close Case', roles: ['revenue_cycle_manager'], kind: 'secondary' },
{ activity: ACT.CLOSE, label: 'Close case', roles: ['revenue_cycle_manager'], kind: 'secondary' },
],
'Needs Human': [
{
activity: ACT.RESUME,
label: 'Resume Investigation',
label: 'Resume review',
roles: ['revenue_cycle_manager'],
kind: 'primary',
hint: 'Send it back to Ava with guidance',
hint: 'Re-runs the review with your guidance attached',
},
{ activity: ACT.CLOSE, label: 'Close Case', roles: ['revenue_cycle_manager'], kind: 'secondary' },
{ activity: ACT.CLOSE, label: 'Close case', roles: ['revenue_cycle_manager'], kind: 'secondary' },
],
};

View File

@ -39,14 +39,14 @@ const TYPE_META: Record<
string,
{ label: string; icon: typeof Database; tone: 'violet' | 'sky' | 'slate' | 'emerald' }
> = {
context: { label: 'Read the case file', icon: FileSearch, tone: 'slate' },
tool: { label: 'Read the case file', icon: FileSearch, tone: 'slate' },
knowledge: { label: 'Checked her notes', icon: FileSearch, tone: 'slate' },
llm: { label: 'Thought about it', icon: Brain, tone: 'violet' },
plan: { label: 'Planned', icon: Brain, tone: 'violet' },
api: { label: `Asked the data (${LAKEHOUSE.platform})`, icon: Database, tone: 'sky' },
decision: { label: 'Wrote up her decision', icon: Gavel, tone: 'emerald' },
escalation: { label: 'Asked for a person', icon: AlertTriangle, tone: 'slate' },
context: { label: 'Read case data', icon: FileSearch, tone: 'slate' },
tool: { label: 'Read case data', icon: FileSearch, tone: 'slate' },
knowledge: { label: 'Knowledge lookup', icon: FileSearch, tone: 'slate' },
llm: { label: 'Reasoning', icon: Brain, tone: 'violet' },
plan: { label: 'Planning', icon: Brain, tone: 'violet' },
api: { label: `${LAKEHOUSE.platform} query`, icon: Database, tone: 'sky' },
decision: { label: 'Decision submitted', icon: Gavel, tone: 'emerald' },
escalation: { label: 'Escalated', icon: AlertTriangle, tone: 'slate' },
};
function meta(type: string) {
@ -95,19 +95,19 @@ export function AvaLive({
<header className="flex flex-wrap items-center gap-3 border-b border-ai-edge bg-ai-soft px-4 py-3">
<Brain className="h-4 w-4 text-ai" />
<div className="min-w-0">
<h2 className="text-sm font-semibold text-ai">How Ava is working this out</h2>
<h2 className="text-sm font-semibold text-ai">Activity trace</h2>
<p className="mt-0.5 text-xs text-ai/75">
Every step she takes, recorded by the platform as she takes it
Step-by-step execution log, recorded by the platform
</p>
</div>
<div className="ml-auto flex flex-wrap items-center gap-2">
{working && (
<Badge tone="violet" dot>
working
in progress
</Badge>
)}
<Badge tone="sky">{queries.length} queries</Badge>
{failed > 0 && <Badge tone="amber">{failed} corrected</Badge>}
{failed > 0 && <Badge tone="amber">{failed} query error{failed === 1 ? '' : 's'}</Badge>}
{elapsed > 0 && <Badge tone="slate">{Math.round(elapsed)}s</Badge>}
{spend > 0 && <Badge tone="slate">{money(spend.toFixed(2))}</Badge>}
</div>
@ -117,7 +117,7 @@ export function AvaLive({
<p className="flex items-center gap-2 px-4 py-8 text-sm text-faint">
{working && <Loader2 className="h-4 w-4 animate-spin text-ai" />}
{working
? 'Ava has picked up the case. Her first question to the data appears here within a few seconds.'
? 'Review started. Steps appear here as they complete.'
: 'No steps recorded for this case.'}
</p>
) : (
@ -202,14 +202,14 @@ export function AvaLive({
<footer className="flex flex-wrap items-center gap-2 border-t border-line bg-panel2 px-4 py-2.5 text-[11px] text-faint">
<Database className="h-3.5 w-3.5" />
<span>
Read-only against{' '}
Read-only access ·{' '}
<span className="font-semibold text-muted">
{LAKEHOUSE.platform} · {LAKEHOUSE.catalog}.{LAKEHOUSE.schema}
</span>
</span>
<span className="ml-auto inline-flex items-center gap-1">
<CheckCircle2 className="h-3.5 w-3.5" />
She can only read — nothing she does can change the data
No write access to any source system
</span>
</footer>
</section>

View File

@ -155,8 +155,8 @@ function SpikeChart({ data, slice, c, title }: { data: BriefingData; slice: Slic
const rows = pts.map((p) => ({ ...p, label: shortDate(p.week) }));
return (
<Frame
title={isSlice ? `Denied claims per week — ${title}` : 'Hospital denial rate per week'}
caption={spike ? `Vertical line: the payer's rule change, ${shortDate(spike)}. Bars after it are the spike.` : 'Six months, one point per week'}
title={isSlice ? `Weekly denied claims — ${title}` : 'Weekly denial rate — all claims'}
caption={spike ? `Dashed line: payer policy effective ${shortDate(spike)}` : 'Service weeks, pending claims excluded'}
table={{ head: ['Week', isSlice ? 'Denied' : 'Denial %'], rows: rows.map((r) => [r.label, isSlice ? r.denied : `${r.pct}%`]) }}
>
<ResponsiveContainer width="100%" height="100%">
@ -179,7 +179,7 @@ function SpikeChart({ data, slice, c, title }: { data: BriefingData; slice: Slic
x={shortDate(spike)}
stroke={c.ai}
strokeDasharray="4 3"
label={{ value: 'rule change', position: 'insideTopLeft', fill: c.ai, fontSize: 11 }}
label={{ value: 'policy effective', position: 'insideTopLeft', fill: c.ai, fontSize: 11 }}
/>
)}
</ComposedChart>
@ -193,8 +193,8 @@ function PayerChart({ data, slice, c }: { data: BriefingData; slice: Slice | nul
const rows = data.payers.map((p) => ({ ...p, short: p.payer.replace(' Health Plan', '').replace(' Health', '').replace(' Mutual', '') }));
return (
<Frame
title="Denial rate by insurer — before vs now"
caption="Gray is the 8-week baseline; blue is the last 6 weeks. One insurer moved."
title="Denial rate by insurer"
caption="Gray: 8-week baseline · Blue: last 6 weeks"
table={{ head: ['Insurer', 'Before', 'Now'], rows: rows.map((r) => [r.payer, `${r.rateBase}%`, `${r.rateRecent}%`]) }}
>
<ResponsiveContainer width="100%" height="100%">
@ -221,8 +221,8 @@ function RecoveryChart({ data, c, title }: { data: BriefingData; c: typeof HUES.
const one = Object.fromEntries(data.recovery.map((b) => [b.bucket, b.billed])) as Record<string, number>;
return (
<Frame
title={`Where the money stands — ${title}`}
caption={`${money(total)} denied since the baseline began. Orange is still recoverable if appeals are filed.`}
title={`Denied claims by appeal status — ${title}`}
caption={`${money(total)} denied since baseline start. Orange: still within appeal window, unfiled.`}
table={{ head: ['Status', 'Claims', 'Billed'], rows: data.recovery.map((b) => [b.bucket, b.claims, money(b.billed)]) }}
>
<div className="flex h-full flex-col justify-center gap-3">
@ -264,8 +264,8 @@ function ExpiringChart({ data, c }: { data: BriefingData; c: typeof HUES.light }
const total = rows.reduce((t, r) => t + r.billed, 0);
return (
<Frame
title="Appeals about to expire, by insurer"
caption={`${money(total)} of unfiled appeals close within 14 days. Nobody has to find these — she did.`}
title="Unfiled appeals expiring within 14 days"
caption={`${money(total)} across ${rows.length} insurer${rows.length === 1 ? '' : 's'} · first deadline ${shortDate(rows.slice().sort((a, b) => a.firstDeadline.localeCompare(b.firstDeadline))[0]?.firstDeadline ?? null)}`}
table={{ head: ['Insurer', 'Claims', 'Billed', 'First deadline'], rows: rows.map((r) => [r.payer, r.claims, money(r.billed), shortDate(r.firstDeadline)]) }}
>
<ResponsiveContainer width="100%" height="100%">

View File

@ -44,18 +44,19 @@ export function Verdict({ row }: { row: Row }) {
return (
<section className="lift rounded-xl border border-ai-edge bg-panel">
<div className="border-b border-ai-edge bg-ai-soft px-5 py-4">
<p className="text-[11px] font-semibold tracking-wide text-ai uppercase">What Ava found</p>
<p className="text-[11px] font-semibold tracking-wide text-ai uppercase">Summary</p>
<p className="mt-1.5 text-[21px] leading-snug font-semibold text-ink">{line}</p>
<div className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted">
<span className="inline-flex items-center gap-1">
<CheckCircle2 className={`h-3.5 w-3.5 ${reconciled ? 'text-good' : 'text-warn'}`} />
{reconciled ? 'Numbers checked against Finance' : 'Numbers NOT yet checked against Finance'}
{reconciled ? 'Reconciled with finance summary' : 'Not reconciled with finance summary'}
</span>
{confidence != null && (
<span>
Ava is <span className="font-semibold text-ink">{pct(confidence * 100, 0)}</span> sure
Confidence <span className="font-semibold text-ink">{pct(confidence * 100, 0)}</span>
</span>
)}
<span className="ml-auto">AI analysis · Ava</span>
</div>
</div>
@ -86,8 +87,8 @@ export function Recommendations({ row }: { row: Row }) {
return (
<section className="lift rounded-xl border border-line bg-panel">
<header className="border-b border-line px-5 py-3.5">
<h2 className="text-base font-semibold text-ink">What she wants you to approve</h2>
<p className="mt-0.5 text-xs text-muted">Ranked by money. Each has an owner.</p>
<h2 className="text-base font-semibold text-ink">Recommended actions</h2>
<p className="mt-0.5 text-xs text-muted">Ranked by financial impact. Each names an owner.</p>
</header>
<ol className="divide-y divide-line">
{recs.map((block, i) => {
@ -123,22 +124,22 @@ export function FullStory({ row }: { row: Row }) {
open={open}
onToggle={() => setOpen(!open)}
icon={<FileSearch className="h-4 w-4 text-ai" />}
title="The full story"
hint={hasSecondary ? 'Analysis, root cause, and a second pattern she noticed' : 'Her full analysis and the root cause'}
title="Analysis"
hint={hasSecondary ? 'Full analysis, root cause, and a secondary finding' : 'Full analysis and root cause'}
tone="ai"
>
<div className="space-y-4 px-5 py-4">
<p className="text-sm leading-relaxed whitespace-pre-wrap text-ink">{summary}</p>
{cause && (
<div className="rounded-md border border-line bg-panel2 px-4 py-3">
<p className="text-[11px] font-semibold tracking-wide text-faint uppercase">Why it happened</p>
<p className="text-[11px] font-semibold tracking-wide text-faint uppercase">Root cause</p>
<p className="mt-1 text-sm leading-relaxed whitespace-pre-wrap text-ink">{cause}</p>
</div>
)}
{hasSecondary && (
<div className="rounded-md border border-warn-edge bg-warn-soft px-4 py-3">
<p className="inline-flex items-center gap-1.5 text-[11px] font-semibold tracking-wide text-warn uppercase">
<AlertTriangle className="h-3.5 w-3.5" /> A second, separate problem
<AlertTriangle className="h-3.5 w-3.5" /> Secondary finding
</p>
<p className="mt-1 text-sm leading-relaxed whitespace-pre-wrap text-ink">{secondary}</p>
</div>
@ -175,11 +176,11 @@ export function SqlEvidence({ row, steps, decisions }: { row: Row; steps: AvaTra
open={open}
onToggle={() => setOpen(!open)}
icon={<CheckCircle2 className="h-4 w-4 text-good" />}
title="Her evidence"
title="Query log"
hint={
queries.length
? `${queries.length} database queries, exactly as she ran them — anyone can re-run these`
: `${notes.length} steps, in her own words`
? `${queries.length} queries executed against Databricks — reproducible`
: `${notes.length} analysis steps`
}
>
{queries.length > 0 ? (
@ -189,7 +190,7 @@ export function SqlEvidence({ row, steps, decisions }: { row: Row; steps: AvaTra
<p className="flex items-center gap-2 text-[11px] font-semibold tracking-wide text-faint uppercase">
Query {i + 1}
{q.query_state === 'FAILED' ? (
<Badge tone="amber">error — corrected next</Badge>
<Badge tone="amber">error — corrected in next query</Badge>
) : q.rows_returned != null ? (
<span className="tnum font-normal normal-case">{q.rows_returned} row{q.rows_returned === 1 ? '' : 's'}</span>
) : null}
@ -225,17 +226,17 @@ export function Recheck({ row }: { row: Row }) {
return (
<Card
title={better ? 'The fix worked' : 'The fix has not landed yet'}
subtitle="Ava came back on her own to check"
actions={<Badge tone={better ? 'emerald' : 'amber'}>{better ? 'back to normal' : 'still elevated'}</Badge>}
title="Re-check result"
subtitle="Scheduled re-check after approval"
actions={<Badge tone={better ? 'emerald' : 'amber'}>{better ? 'Within baseline' : 'Still elevated'}</Badge>}
>
<div className="space-y-3 px-5 py-4">
<Facts
cols={3}
rows={[
{ label: 'Denial rate now', value: pct(current), tone: better ? 'emerald' : 'rose' },
{ label: 'Normal is', value: pct(baseline) },
{ label: 'Recovered so far', value: recovered == null ? '—' : money(recovered), tone: 'emerald' },
{ label: 'Current denial rate', value: pct(current), tone: better ? 'emerald' : 'rose' },
{ label: 'Baseline', value: pct(baseline) },
{ label: 'Recovered to date', value: recovered == null ? '—' : money(recovered), tone: 'emerald' },
]}
/>
<p className="text-sm leading-relaxed whitespace-pre-wrap text-muted">{summary}</p>

View File

@ -33,7 +33,7 @@ export function Shell() {
decides what is worth a person's time. */}
<Button kind="primary" onClick={() => navigate('/review')}>
<Radar className="h-4 w-4" />
Run daily review
Run review
</Button>
{user && (

View File

@ -46,7 +46,7 @@ const RECOVERY_COLOR: Record<string, string> = {
export async function buildDeck(row: Row, data: BriefingData, slice: Slice | null): Promise<void> {
const pres = new pptxgen();
pres.layout = 'LAYOUT_WIDE'; // 13.33 x 7.5 in
pres.author = 'Ava — Denials Analyst, Northlake Health';
pres.author = 'Northlake Health — Denials Desk (AI analyst: Ava)';
pres.title = `Denials briefing — case #${str(row.instance_id)}`;
const caseNo = str(row.instance_id);
@ -57,13 +57,13 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 13.33, h: 0.08, fill: { color: BRAND } });
if (kicker) s.addText(kicker.toUpperCase(), { x: 0.6, y: 0.35, w: 12, h: 0.3, fontSize: 10, bold: true, color: AI, charSpacing: 1 });
s.addText(title, { x: 0.6, y: kicker ? 0.62 : 0.4, w: 12.1, h: 0.7, fontSize: 22, bold: true, color: INK, valign: 'top' });
s.addText(`Northlake Health · Denials Desk · case #${caseNo} · prepared by Ava`, { x: 0.6, y: 7.0, w: 12, h: 0.3, fontSize: 9, color: FAINT });
s.addText(`Northlake Health · Denials Desk · Case #${caseNo} · AI analysis (Ava) · for manager review`, { x: 0.6, y: 7.0, w: 12, h: 0.3, fontSize: 9, color: FAINT });
};
// ---- 1. What happened -------------------------------------------------------
{
const s = pres.addSlide();
chrome(s, headline(row.summary, 240), 'What Ava found');
chrome(s, headline(row.summary, 240), 'Summary');
const tiles: Array<[string, string, string]> = [
['Claims denied', num(row.affected_claims)?.toLocaleString('en-US') ?? '—', INK],
['Money at stake', money(row.amount_at_risk), 'B31E23'],
@ -77,7 +77,7 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
});
const cause = str(row.root_cause);
if (cause) {
s.addText('WHY IT HAPPENED', { x: 0.6, y: 3.95, w: 12, h: 0.3, fontSize: 10, bold: true, color: MUTED, charSpacing: 1 });
s.addText('ROOT CAUSE', { x: 0.6, y: 3.95, w: 12, h: 0.3, fontSize: 10, bold: true, color: MUTED, charSpacing: 1 });
s.addText(cause, { x: 0.6, y: 4.25, w: 12.1, h: 2.5, fontSize: 13, color: INK, valign: 'top' });
}
}
@ -87,7 +87,7 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
if (spikePts.length) {
const s = pres.addSlide();
const isSlice = data.weeklySlice.length > 0;
chrome(s, isSlice ? `Denied claims per week — ${sliceTitle}` : 'Hospital denial rate per week', 'The spike');
chrome(s, isSlice ? `Weekly denied claims — ${sliceTitle}` : 'Weekly denial rate — all claims', 'Trend');
const labels = spikePts.map((p) => shortDate(p.week));
const spike = slice?.spikeStart;
if (isSlice) {
@ -114,13 +114,13 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
valGridLine: { color: GRID, size: 0.5 }, catGridLine: { style: 'none' }, showLegend: false,
});
}
if (spike) s.addText(`Rule change effective ${shortDate(spike)}. Everything to the right of it is the spike.`, { x: 0.6, y: 6.65, w: 12, h: 0.3, fontSize: 11, color: AI, italic: true });
if (spike) s.addText(`Payer policy effective ${shortDate(spike)}. Weeks from that date shown in blue.`, { x: 0.6, y: 6.65, w: 12, h: 0.3, fontSize: 11, color: AI, italic: true });
}
// ---- 3. Where it sits -------------------------------------------------------
if (data.payers.length) {
const s = pres.addSlide();
chrome(s, 'Denial rate by insurer — before vs now', 'Where it sits');
chrome(s, 'Denial rate by insurer', 'Comparison');
const labels = data.payers.map((p) => p.payer);
s.addChart(
pres.ChartType.bar,
@ -138,14 +138,14 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
);
if (slice?.payer) {
const p = data.payers.find((x) => x.payer === slice.payer);
if (p) s.addText(`${p.payer}: ${p.rateBase}% → ${p.rateRecent}%. Every other insurer is within noise.`, { x: 0.6, y: 6.55, w: 12, h: 0.35, fontSize: 12, bold: true, color: INK });
if (p) s.addText(`${p.payer}: ${p.rateBase}% → ${p.rateRecent}%. Other insurers within normal variation.`, { x: 0.6, y: 6.55, w: 12, h: 0.35, fontSize: 12, bold: true, color: INK });
}
}
// ---- 4. Where the money stands ----------------------------------------------
if (data.recovery.length || data.expiring.length) {
const s = pres.addSlide();
chrome(s, 'Where the money stands', 'The money');
chrome(s, 'Financial position', 'Recovery');
if (data.recovery.length) {
const ordered = RECOVERY_ORDER.filter((b) => data.recovery.some((r) => r.bucket === b));
s.addText(sliceTitle.toUpperCase(), { x: 0.6, y: 1.45, w: 6, h: 0.3, fontSize: 10, bold: true, color: MUTED, charSpacing: 1 });
@ -197,7 +197,7 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
const recs = recommendations(row.recommendations);
if (recs.length) {
const s = pres.addSlide();
chrome(s, 'What she recommends', 'For your approval');
chrome(s, 'Recommended actions', 'For approval');
let y = 1.5;
recs.slice(0, 5).forEach((block, i) => {
const { title, body } = splitRecommendation(block);
@ -217,18 +217,18 @@ export async function buildDeck(row: Row, data: BriefingData, slice: Slice | nul
// ---- 6. How she got there ----------------------------------------------------
{
const s = pres.addSlide();
chrome(s, 'How she got there', 'Method');
chrome(s, 'Method', 'Method');
const reconciled = row.data_reconciled === true || str(row.data_reconciled) === 'true';
const conf = num(row.confidence);
const bullets = [
str(row.scanned_summary) || 'Reviewed every payer, department and front desk against an 8-week baseline.',
reconciled ? 'Claims data reconciled against the finance report before any analysis.' : 'Claims data could not be fully reconciled against finance — treat numbers as provisional.',
`Cause matched to the payer's own policy bulletin${slice?.spikeStart ? ` effective ${shortDate(slice.spikeStart)}` : ''}.`,
conf != null ? `Ava's stated confidence: ${Math.round(conf * 100)}%.` : '',
'Read-only against Databricks (workspace.rcm). Every query is recorded and reviewable on the case.',
conf != null ? `Stated confidence: ${Math.round(conf * 100)}%.` : '',
'Read-only access to Databricks (workspace.rcm). Every query is logged and reproducible from the case.',
].filter(Boolean);
s.addText(bullets.map((b) => ({ text: b, options: { bullet: true, breakLine: true, fontSize: 13, color: INK, paraSpaceAfter: 8 } })), { x: 0.6, y: 1.5, w: 12.1, h: 4.8, valign: 'top' });
s.addText('Ava proposes; a revenue-cycle manager decides. She has no write access to any system.', { x: 0.6, y: 6.4, w: 12, h: 0.4, fontSize: 11, italic: true, color: AI });
s.addText('AI analysis requires manager approval before any action. The analyst has no write access to any system.', { x: 0.6, y: 6.4, w: 12, h: 0.4, fontSize: 11, italic: true, color: AI });
}
await pres.writeFile({ fileName: `Northlake-denials-briefing-case-${caseNo}.pptx` });

View File

@ -57,7 +57,7 @@ export function Login() {
<NorthlakeMark size={34} />
<h1 className="mt-5 text-lg font-semibold text-ink">Sign in</h1>
<p className="mt-1 text-sm text-muted">
Denials Desk — revenue cycle, Northlake Health.
Revenue cycle — denials management.
</p>
<div className="mt-5 space-y-3">

View File

@ -103,23 +103,23 @@ export function CaseScreen() {
const work = <AvaLive steps={trace.data ?? []} decisions={decisions.data ?? []} working={aiOwned} />;
return (
<div className="mx-auto max-w-4xl space-y-4">
<div className="mx-auto max-w-5xl space-y-4">
<div className="flex flex-wrap items-center gap-3">
<Link to="/q/review" className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-ink">
<ArrowLeft className="h-4 w-4" /> Back
</Link>
<span className="tnum text-sm text-faint">Case #{str(row.instance_id)}</span>
<Badge tone={quiet ? 'slate' : (STAGE_TONE[state] ?? 'slate')} dot={aiOwned}>
{quiet ? 'Nothing to report' : state}
{quiet ? 'No findings' : state}
</Badge>
{kind && FINDING_KIND[kind] && <Badge tone="violet">{FINDING_KIND[kind]}</Badge>}
<span className="ml-auto text-[11px] text-faint">
Daily review · {dateTime(row.created_at)}
Daily review · opened {dateTime(row.created_at)}
{str(row.review_as_of) ? ` · as of ${str(row.review_as_of).slice(0, 10)}` : ''}
</span>
{hasFindings && (
<Button kind="secondary" onClick={exportDeck} busy={exporting} disabled={!briefing.data} title="Six slides: what happened, the spike, where it sits, the money, the recommendations, the method">
<Download className="h-4 w-4" /> Slides
<Button kind="secondary" onClick={exportDeck} busy={exporting} disabled={!briefing.data} title="Export a six-slide briefing (.pptx)">
<Download className="h-4 w-4" /> Export slides
</Button>
)}
</div>
@ -131,13 +131,13 @@ export function CaseScreen() {
<>
<section className="lift rounded-xl border border-ai-edge bg-ai-soft px-5 py-4">
<p className="inline-flex items-center gap-2 text-[11px] font-semibold tracking-wide text-ai uppercase">
<Brain className="h-4 w-4" /> Ava is reviewing
<Brain className="h-4 w-4" /> Review in progress
</p>
<p className="mt-1.5 text-[19px] leading-snug font-semibold text-ink">
Every payer, department and front desk — checking whether anything is materially off.
Checking all payers, departments and front desks against the 8-week baseline.
</p>
<p className="mt-1 text-sm text-muted">
Takes about four minutes. If nothing clears the bar, she closes this case herself.
Typical duration 4–5 minutes. If no change clears the materiality threshold, the case closes with no findings.
</p>
</section>
{work}
@ -148,10 +148,10 @@ export function CaseScreen() {
{quiet && (
<section className="lift rounded-xl border border-line bg-panel px-5 py-5">
<p className="inline-flex items-center gap-2 text-[11px] font-semibold tracking-wide text-faint uppercase">
<Radar className="h-4 w-4" /> Reviewed — nothing to report
<Radar className="h-4 w-4" /> Review complete
</p>
<p className="mt-1.5 text-[21px] leading-snug font-semibold text-ink">
Nothing needs your attention this morning.
No findings. No material change across payers, departments or front desks.
</p>
{scanned && <p className="mt-3 text-sm leading-relaxed whitespace-pre-wrap text-muted">{scanned}</p>}
</section>
@ -160,7 +160,7 @@ export function CaseScreen() {
{/* ---------- Needs a human ---------- */}
{state === NEEDS_HUMAN && (
<section className="lift rounded-xl border border-bad-edge bg-bad-soft px-5 py-4">
<p className="text-[11px] font-semibold tracking-wide text-bad uppercase">Ava stopped and asked for you</p>
<p className="text-[11px] font-semibold tracking-wide text-bad uppercase">Escalated — requires a decision</p>
<p className="mt-1.5 text-[17px] leading-snug font-semibold text-ink">
{str(row.escalation_reason) || 'No reason recorded.'}
</p>
@ -180,7 +180,7 @@ export function CaseScreen() {
{/* ---------- The decision ---------- */}
{actions.length > 0 && (
<section className="lift rounded-xl border border-warn-edge bg-warn-soft px-5 py-4">
<p className="text-[11px] font-semibold tracking-wide text-warn uppercase">Your decision</p>
<p className="text-[11px] font-semibold tracking-wide text-warn uppercase">Review decision</p>
<div className="mt-3 flex flex-wrap items-start gap-3">
{actions.map((a) => (
<div key={a.activity}>
@ -204,8 +204,8 @@ export function CaseScreen() {
open={showWork}
onToggle={() => setShowWork(!showWork)}
icon={<Brain className="h-4 w-4 text-ai" />}
title="Watch how she did it"
hint="Her every step, from the platform's own trace — read the case, think, query, think, decide"
title="Activity trace"
hint="Step-by-step execution log for this review"
tone="ai"
>
<div className="p-3">{work}</div>
@ -221,8 +221,8 @@ export function CaseScreen() {
open={showWork}
onToggle={() => setShowWork(!showWork)}
icon={<Brain className="h-4 w-4 text-ai" />}
title="Watch how she did it"
hint="Her every step — the proof that a quiet morning was checked, not skipped"
title="Activity trace"
hint="Step-by-step execution log — the checks performed for this no-findings result"
tone="ai"
>
<div className="p-3">{work}</div>
@ -235,11 +235,11 @@ export function CaseScreen() {
<Facts
cols={3}
rows={[
{ label: 'Started by', value: str(row.review_as_of) ? 'Replay of a past morning' : 'Daily review' },
{ label: 'Anchored on', value: str(row.review_as_of) ? str(row.review_as_of).slice(0, 10) : 'Latest data' },
{ label: 'Trigger', value: str(row.review_as_of) ? 'Manual run (historical date)' : 'Daily review' },
{ label: 'Data as of', value: str(row.review_as_of) ? str(row.review_as_of).slice(0, 10) : 'Latest available' },
{ label: 'Look-back', value: row.period_weeks ? `${str(row.period_weeks)} weeks` : '6 weeks' },
...(str(row.review_note) ? [{ label: 'Sent back with', value: str(row.review_note), wide: true }] : []),
...(str(row.approval_note) ? [{ label: 'Approved with', value: str(row.approval_note), wide: true }] : []),
...(str(row.review_note) ? [{ label: 'Reviewer note', value: str(row.review_note), wide: true }] : []),
...(str(row.approval_note) ? [{ label: 'Approval note', value: str(row.approval_note), wide: true }] : []),
]}
/>
</section>
@ -292,6 +292,6 @@ function Rail({ state }: { state: string }) {
function defaultApprovalNote(row: Record<string, unknown>): string {
const recoverable = row.recoverable_amount;
return recoverable
? `Approved. Proceed with the appeals and the process fix as recommended; expected recovery $${Number(recoverable).toLocaleString('en-US')}. Re-check when the timer fires.`
: 'Approved. Proceed as recommended and re-check when the timer fires.';
? `Approved. Proceed with the recommended appeals and process changes. Expected recovery $${Number(recoverable).toLocaleString('en-US')}.`
: 'Approved. Proceed with the recommended actions.';
}

View File

@ -41,7 +41,7 @@ export function QueueScreen() {
const list = rows.data ?? [];
return (
<div className="mx-auto max-w-4xl space-y-4">
<div className="mx-auto max-w-5xl space-y-4">
<Briefing rows={all.data ?? []} onRun={() => navigate('/review')} />
<header className="flex flex-wrap items-end justify-between gap-3 pt-2">
@ -55,7 +55,7 @@ export function QueueScreen() {
{rows.error && <ErrorNote>{rows.error}</ErrorNote>}
{rows.loading && !rows.data && <Spinner label="Loading cases…" />}
{rows.data && list.length === 0 && (
<Empty>Nothing here.{queue.stage === 'Awaiting Review' && ' When Ava finds something worth your time, it lands here.'}</Empty>
<Empty>No cases in this queue.</Empty>
)}
<div className="space-y-3">
@ -84,28 +84,28 @@ function Briefing({ rows, onRun }: { rows: Row[]; onRun: () => void }) {
</span>
<div className="min-w-0 flex-1">
<p className="text-[11px] font-semibold tracking-wide text-faint uppercase">
This morning{latest ? ` · last review ${dateTime(latest.updated_at)}` : ''}
Daily review{latest ? ` · last run ${dateTime(latest.updated_at)}` : ''}
</p>
<p className="mt-0.5 text-[19px] leading-snug font-semibold text-ink">
{waiting.length === 0 && working.length === 0 && needsHuman.length === 0
? 'Nothing needs your attention.'
? 'No cases awaiting decision.'
: [
waiting.length > 0 &&
`${waiting.length} decision${waiting.length === 1 ? '' : 's'} waiting for you${
recoverable > 0 ? ` — ${money(recoverable)} recoverable` : ''
`${waiting.length} case${waiting.length === 1 ? '' : 's'} awaiting decision${
recoverable > 0 ? ` · ${money(recoverable)} recoverable` : ''
}`,
working.length > 0 && `${working.length} case${working.length === 1 ? '' : 's'} Ava is working on`,
needsHuman.length > 0 && `${needsHuman.length} she could not finish`,
working.length > 0 && `${working.length} review${working.length === 1 ? '' : 's'} in progress`,
needsHuman.length > 0 && `${needsHuman.length} escalated`,
]
.filter(Boolean)
.join(' · ')}
</p>
<p className="mt-0.5 text-xs text-muted">
Ava reviews every payer, department and front desk each morning and only opens a case when something clears the bar.
Automated review of all payers, departments and front desks. A case is opened only when a change clears the materiality threshold.
</p>
</div>
<Button kind="primary" onClick={onRun}>
<Radar className="h-4 w-4" /> Run the review now
<Radar className="h-4 w-4" /> Run review
</Button>
</div>
</section>
@ -133,7 +133,7 @@ function CaseCard({ row, onOpen }: { row: Row; onOpen: () => void }) {
>
<div className="flex flex-wrap items-center gap-2">
<Badge tone={quiet ? 'slate' : (STAGE_TONE[state] ?? 'slate')} dot={aiOwned}>
{quiet ? 'Nothing to report' : waiting ? 'Needs your decision' : state}
{quiet ? 'No findings' : waiting ? 'Awaiting decision' : state}
</Badge>
{kind && FINDING_KIND[kind] && <Badge tone="violet">{FINDING_KIND[kind]}</Badge>}
<span className="ml-auto text-[11px] text-faint">
@ -146,8 +146,8 @@ function CaseCard({ row, onOpen }: { row: Row; onOpen: () => void }) {
{summary
? headline(summary, 160)
: quiet
? 'Reviewed everything — nothing needs attention.'
: 'Ava is reviewing every payer, department and front desk…'}
? 'No material change detected across payers, departments or front desks.'
: 'Review in progress…'}
</p>
{recoverable != null && recoverable > 0 && (
<span className="shrink-0 text-right">

View File

@ -45,10 +45,11 @@ export function RunReviewScreen() {
return (
<div className="mx-auto max-w-2xl space-y-4">
<header>
<h1 className="text-xl font-semibold text-ink">Daily review</h1>
<h1 className="text-xl font-semibold text-ink">Run daily review</h1>
<p className="mt-0.5 text-sm text-muted">
Ava looks at every payer, department and front desk, and only opens a case if
something clears the bar. Most mornings she reports nothing.
Runs the full review now across all payers, departments and front desks. A case is
opened only if a change clears the materiality threshold; otherwise the run closes
with no findings.
</p>
</header>
@ -60,19 +61,19 @@ export function RunReviewScreen() {
<Brain className="h-4 w-4" />
</span>
<div className="min-w-0 flex-1 text-sm text-muted">
<p className="font-semibold text-ink">What she checks</p>
<p className="font-semibold text-ink">Checks performed</p>
<ul className="mt-1.5 list-disc space-y-0.5 pl-4">
<li>That the claims data reconciles with the finance report</li>
<li>Denial rate vs baseline — by payer, reason code, department, front desk, week</li>
<li>Money about to fall out of an appeal window unfiled</li>
<li>Claims data reconciled against the finance monthly summary</li>
<li>Denial rate vs 8-week baseline: by payer, reason code, department, front desk, week</li>
<li>Unfiled appeals with deadlines within 14 days</li>
</ul>
<p className="mt-2 text-xs text-faint">
The bar: a denied count up more than 40% on meaningful volume, or more than $100K
expiring. Below it, she watches and says nothing.
Materiality threshold: denied count up more than 40% on at least 25 claims, or more
than $100K in appeals expiring. Items below the threshold are listed, not flagged.
</p>
<p className="mt-2 inline-flex items-center gap-1.5 text-xs text-faint">
<Database className="h-3.5 w-3.5" />
Read-only against {LAKEHOUSE.platform} · {LAKEHOUSE.catalog}.{LAKEHOUSE.schema}
Read-only · {LAKEHOUSE.platform} · {LAKEHOUSE.catalog}.{LAKEHOUSE.schema}
</p>
</div>
</div>
@ -81,20 +82,20 @@ export function RunReviewScreen() {
<div>
<Button kind="primary" onClick={() => run()} busy={busy === 'now'} disabled={busy !== null}>
<Radar className="h-4 w-4" />
Run the review now
Run review
</Button>
<p className="mt-1 max-w-[16rem] text-[11px] text-faint">
Normally fires at 6am on its own. This is the same activity.
Scheduled daily at 06:00. This runs the same activity immediately.
</p>
</div>
<div>
<Button kind="secondary" onClick={() => run(QUIET_MORNING_AS_OF)} busy={busy === 'quiet'} disabled={busy !== null}>
<Moon className="h-4 w-4" />
Replay a quiet morning
Run as of {QUIET_MORNING_AS_OF}
</Button>
<p className="mt-1 max-w-[16rem] text-[11px] text-faint">
Anchored on {QUIET_MORNING_AS_OF}, before anything went wrong — to see what
&ldquo;nothing to report&rdquo; looks like.
Runs the review against data as of this date — a period with no material change,
to show a no-findings outcome.
</p>
</div>
</div>