fix: "$1.56M" is not two sentences, and one attempt is not two
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 <noreply@anthropic.com>
This commit is contained in:
parent
5eb0890e97
commit
5df97f989c
@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { AlertTriangle, CheckCircle2, ChevronDown, FileSearch } from 'lucide-react';
|
import { AlertTriangle, CheckCircle2, ChevronDown, FileSearch } from 'lucide-react';
|
||||||
import { Badge, Card, Facts } from './core';
|
import { Badge, Card, Facts } from './core';
|
||||||
import type { AvaTraceStep, Row } from '../api/types';
|
import type { AvaDecision, AvaTraceStep, Row } from '../api/types';
|
||||||
import {
|
import {
|
||||||
firstDeadline,
|
firstDeadline,
|
||||||
headline,
|
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
|
* paste 16 full queries into a form field was what blew the tool call past
|
||||||
* the output cap and lost a whole investigation.
|
* 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 [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);
|
const notes = sqlSteps(row.sql_log);
|
||||||
if (queries.length === 0 && notes.length === 0) return null;
|
if (queries.length === 0 && notes.length === 0) return null;
|
||||||
|
|
||||||
|
|||||||
@ -101,9 +101,17 @@ export function recommendations(v: unknown): string[] {
|
|||||||
|
|
||||||
/** "1. APPEALS — FILE RETRO-AUTH ($1,091,000 …)" → title + body. */
|
/** "1. APPEALS — FILE RETRO-AUTH ($1,091,000 …)" → title + body. */
|
||||||
export function splitRecommendation(block: string): { title: string; body: string } {
|
export function splitRecommendation(block: string): { title: string; body: string } {
|
||||||
const m = block.match(/^\s*(\d+)\.\s*([^.\n]+?)(?:\.|\n|$)([\s\S]*)$/);
|
// Strip the leading "N." and take the title up to the first sentence break —
|
||||||
if (!m) return { title: '', body: block };
|
// a period FOLLOWED BY A SPACE, a colon, or a newline. Never a bare period:
|
||||||
return { title: m[2].trim(), body: (m[3] ?? '').trim() };
|
// "$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. */
|
/** Ava's SQL log is one statement per block, each prefixed with its step. */
|
||||||
|
|||||||
@ -198,7 +198,7 @@ export function CaseScreen() {
|
|||||||
{hasFindings && (
|
{hasFindings && (
|
||||||
<>
|
<>
|
||||||
<FullStory row={row} />
|
<FullStory row={row} />
|
||||||
<SqlEvidence row={row} steps={trace.data ?? []} />
|
<SqlEvidence row={row} steps={trace.data ?? []} decisions={decisions.data ?? []} />
|
||||||
{!aiOwned && (
|
{!aiOwned && (
|
||||||
<Disclosure
|
<Disclosure
|
||||||
open={showWork}
|
open={showWork}
|
||||||
@ -216,7 +216,7 @@ export function CaseScreen() {
|
|||||||
)}
|
)}
|
||||||
{quiet && (
|
{quiet && (
|
||||||
<>
|
<>
|
||||||
<SqlEvidence row={row} steps={trace.data ?? []} />
|
<SqlEvidence row={row} steps={trace.data ?? []} decisions={decisions.data ?? []} />
|
||||||
<Disclosure
|
<Disclosure
|
||||||
open={showWork}
|
open={showWork}
|
||||||
onToggle={() => setShowWork(!showWork)}
|
onToggle={() => setShowWork(!showWork)}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user