fix: her evidence comes from the trace, not from a form field

Case 58325 died submitting findings: the submit_decision call arrived with
no `data` at all. The final model reply was exactly 4,096 output tokens —
the service's cap — so the JSON was cut off mid-call. Asking Ava to paste
16 full SQL statements into sql_log, on top of a summary, root cause, five
recommendations and a scanned-summary, is what pushed one tool call past
the limit and lost the whole investigation.

The platform already records every statement the agentic tool sends,
verbatim, with Databricks' own SUCCEEDED/FAILED and the row count. So
SqlEvidence now renders from the trace and treats sql_log as a one-line
index per step. Her charter gained hard per-field character limits to
match (sm2/custom-apps/denials-investigator/05_ai_employee.sql).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Yashas 2026-09-16 13:56:52 +05:30
parent e294df6eba
commit 92ea27d27e
2 changed files with 51 additions and 19 deletions

View File

@ -1,7 +1,7 @@
import { useState } from 'react';
import { AlertTriangle, CheckCircle2, ChevronDown, FileSearch } from 'lucide-react';
import { Badge, Card, Facts } from './core';
import type { Row } from '../api/types';
import type { AvaTraceStep, Row } from '../api/types';
import {
firstDeadline,
headline,
@ -148,11 +148,22 @@ export function FullStory({ row }: { row: Row }) {
);
}
/** Every SQL statement she ran. For the sceptic in the room. Collapsed. */
export function SqlEvidence({ row }: { row: Row }) {
/**
* Every SQL statement she ran. For the sceptic in the room. Collapsed.
*
* SOURCE OF TRUTH IS THE TRACE, not her sql_log field. The platform records
* every statement the agentic tool sent, verbatim, with Databricks' own
* SUCCEEDED/FAILED and the row count — so that is what is shown. Her sql_log
* is now a one-line-per-step index ("3c: department cut -> Cardiology +13
* pts") and is used only as the note beside each statement. Asking her to
* 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[] }) {
const [open, setOpen] = useState(false);
const steps = sqlSteps(row.sql_log);
if (steps.length === 0) return null;
const queries = steps.filter((s) => s.type === 'api' && s.detail);
const notes = sqlSteps(row.sql_log);
if (queries.length === 0 && notes.length === 0) return null;
return (
<Disclosure
@ -160,19 +171,40 @@ export function SqlEvidence({ row }: { row: Row }) {
onToggle={() => setOpen(!open)}
icon={<CheckCircle2 className="h-4 w-4 text-good" />}
title="Her evidence"
hint={`${steps.length} database queries, exactly as she ran them — anyone can re-run these`}
hint={
queries.length
? `${queries.length} database queries, exactly as she ran them — anyone can re-run these`
: `${notes.length} steps, in her own words`
}
>
<ol className="divide-y divide-line">
{steps.map((s, i) => (
<li key={i} className="px-5 py-3">
{s.label && (
<p className="text-[11px] font-semibold tracking-wide text-faint uppercase">{s.label}</p>
)}
<pre className="sql mt-1 text-muted">{s.sql}</pre>
{s.note && <p className="mt-1.5 text-xs text-ink">{s.note}</p>}
</li>
))}
</ol>
{queries.length > 0 ? (
<ol className="divide-y divide-line">
{queries.map((q, i) => (
<li key={`${q.seq}-${i}`} className="px-5 py-3">
<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>
) : q.rows_returned != null ? (
<span className="tnum font-normal normal-case">{q.rows_returned} row{q.rows_returned === 1 ? '' : 's'}</span>
) : null}
</p>
<pre className="sql mt-1 text-muted">{q.detail}</pre>
{notes[i]?.note && <p className="mt-1.5 text-xs text-ink">{notes[i].note}</p>}
</li>
))}
</ol>
) : (
<ol className="divide-y divide-line">
{notes.map((s, i) => (
<li key={i} className="px-5 py-3">
{s.label && <p className="text-[11px] font-semibold tracking-wide text-faint uppercase">{s.label}</p>}
<p className="mt-1 text-sm text-ink">{s.sql}</p>
{s.note && <p className="mt-1 text-xs text-muted">{s.note}</p>}
</li>
))}
</ol>
)}
</Disclosure>
);
}

View File

@ -167,7 +167,7 @@ export function CaseScreen() {
{hasFindings && (
<>
<FullStory row={row} />
<SqlEvidence row={row} />
<SqlEvidence row={row} steps={trace.data ?? []} />
{!aiOwned && (
<Disclosure
open={showWork}
@ -185,7 +185,7 @@ export function CaseScreen() {
)}
{quiet && (
<>
<SqlEvidence row={row} />
<SqlEvidence row={row} steps={trace.data ?? []} />
<Disclosure
open={showWork}
onToggle={() => setShowWork(!showWork)}