From 5df97f989c72eca8cc876e46a8f8b9b37919c707 Mon Sep 17 00:00:00 2001 From: Yashas Date: Wed, 16 Sep 2026 15:17:01 +0530 Subject: [PATCH] fix: "$1.56M" is not two sentences, and one attempt is not two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recommendation titles were cut at the first period, so "$1.56M billed" rendered as a title of "$1" and a body starting "56M". The split now breaks only on a period followed by a space, a colon, or a newline — decimals and codes like CO-197 survive. Her evidence counted every attempt on the case: a run that failed to submit leaves its queries in the trace beside the run that succeeded, and 16 + 20 read as "36 database queries". The panel now scopes to the attempt whose decision was submitted (trace events carry decision_id), so the count is what she actually did to reach these findings. Co-Authored-By: Claude Fable 5.1 --- src/components/Findings.tsx | 11 ++++++++--- src/format.ts | 14 +++++++++++--- src/screens/CaseScreen.tsx | 4 ++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/components/Findings.tsx b/src/components/Findings.tsx index b5a89f6..2d2692b 100644 --- a/src/components/Findings.tsx +++ b/src/components/Findings.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { AlertTriangle, CheckCircle2, ChevronDown, FileSearch } from 'lucide-react'; import { Badge, Card, Facts } from './core'; -import type { AvaTraceStep, Row } from '../api/types'; +import type { AvaDecision, AvaTraceStep, Row } from '../api/types'; import { firstDeadline, headline, @@ -159,9 +159,14 @@ export function FullStory({ row }: { row: Row }) { * paste 16 full queries into a form field was what blew the tool call past * the output cap and lost a whole investigation. */ -export function SqlEvidence({ row, steps }: { row: Row; steps: AvaTraceStep[] }) { +export function SqlEvidence({ row, steps, decisions }: { row: Row; steps: AvaTraceStep[]; decisions: AvaDecision[] }) { const [open, setOpen] = useState(false); - const queries = steps.filter((s) => s.type === 'api' && s.detail); + // Only the attempt that produced the findings. A case can carry an earlier + // attempt that failed to submit (its queries are still in the trace); showing + // both would double the count and make her look twice as busy as she was. + const submitted = decisions.filter((d) => d.status === 'submitted').slice(-1)[0]; + const scoped = submitted ? steps.filter((s) => s.decision_id == null || String(s.decision_id) === String(submitted.id)) : steps; + const queries = scoped.filter((s) => s.type === 'api' && s.detail); const notes = sqlSteps(row.sql_log); if (queries.length === 0 && notes.length === 0) return null; diff --git a/src/format.ts b/src/format.ts index dacbf78..9ac217d 100644 --- a/src/format.ts +++ b/src/format.ts @@ -101,9 +101,17 @@ export function recommendations(v: unknown): string[] { /** "1. APPEALS — FILE RETRO-AUTH ($1,091,000 …)" → title + body. */ export function splitRecommendation(block: string): { title: string; body: string } { - const m = block.match(/^\s*(\d+)\.\s*([^.\n]+?)(?:\.|\n|$)([\s\S]*)$/); - if (!m) return { title: '', body: block }; - return { title: m[2].trim(), body: (m[3] ?? '').trim() }; + // Strip the leading "N." and take the title up to the first sentence break — + // a period FOLLOWED BY A SPACE, a colon, or a newline. Never a bare period: + // "$1.56M" and "CO-197" must survive intact. + const rest = block.replace(/^\s*\d+\.\s*/, ''); + const m = rest.match(/^([\s\S]*?)(?:\.\s|:\s|\n|$)([\s\S]*)$/); + if (!m) return { title: '', body: rest }; + const title = m[1].trim(); + const body = (m[2] ?? '').trim(); + // A "title" that swallowed the whole block means there was no break — show it as body. + if (title.length > 140) return { title: '', body: rest }; + return { title, body }; } /** Ava's SQL log is one statement per block, each prefixed with its step. */ diff --git a/src/screens/CaseScreen.tsx b/src/screens/CaseScreen.tsx index 9aa51f9..a088267 100644 --- a/src/screens/CaseScreen.tsx +++ b/src/screens/CaseScreen.tsx @@ -198,7 +198,7 @@ export function CaseScreen() { {hasFindings && ( <> - + {!aiOwned && ( - + setShowWork(!showWork)}