From 2d9c072572228b3ea9984d0e5ef38c29b22c46c3 Mon Sep 17 00:00:00 2001 From: Yashas Date: Mon, 7 Sep 2026 17:42:36 +0530 Subject: [PATCH] lead: one entry per submission, and the finding above the fold MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things on the lead page. THE AUDIT TRAIL REPEATED ITSELF. "Qualify Lead" appeared three times in a row and "Partner Agent Lead" twice, which reads as the AI having done the same thing three times. It had not. One submission writes several rows, told apart by execution_state: zk-act-qualify TRIGGER_PERFORMED the trigger's commit zk-act-qualify TRIGGER_PERFORMED again, on the settle path zk-act-qualify zk-state-qualified the one that moved the lead Only the last means anything to somebody reading the file. They are now collapsed into one entry carrying the earliest timestamp — when the operator acted — and whichever state and payload is populated. Matched on (same activity, within fifteen seconds) rather than on execution_state, so a genuine repeat survives: Collect Documents really is performed twice on a lead whose first upload was short, and those are minutes apart. And matched by looking BACK through recent entries rather than at the previous one, because the platform interleaves a DATA_UPDATE row between the two halves of a submission — the rows to merge are near each other in time but not adjacent in the list. THE AI PARAGRAPHS HAD NO SUMMARY. attribution_reason and eligibility_reason run to a paragraph each and opened folded, so the finding could not be read without expanding. ClampText now lifts the first sentence out as a headline and puts the rest behind "Show the reasoning" — no new field, and nothing invented: the employees already write a conclusion and then its evidence. It falls back to plain folding when the split would be useless — no sentence terminator, a first sentence that is the whole paragraph, or one short enough to be a fragment rather than a finding. The other half of that is in the charter (70_verdict_first.sql). The headline is only as good as the sentence, and Intake was opening with "Tool 29601 confirmed..." — an internal id — because it had been told to "name the evidence, not the conclusion". Right about content, wrong about order: it now leads with what it decided and gives the evidence second. --- src/components/ClampText.css | 24 ++++++++++++++++ src/components/ClampText.jsx | 47 +++++++++++++++++++++++++++---- src/components/Timeline.jsx | 54 +++++++++++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/src/components/ClampText.css b/src/components/ClampText.css index 1c320be..08de61e 100644 --- a/src/components/ClampText.css +++ b/src/components/ClampText.css @@ -57,3 +57,27 @@ .clamp.is-open .clamp__more svg { transform: rotate(180deg); } + +/* The headline lifted out of an AI paragraph. Slightly heavier than the body + and never clamped — it is one sentence by construction, and the point of it + is that the finding can be read without opening anything. */ +.clamp__lead { + margin: 0; + font-size: 0.9rem; + line-height: 1.5; + color: var(--zk-ink); + font-weight: 500; +} +.clamp__lead + .clamp__text { margin-top: 8px; } + +/* The finding, lifted out of an AI paragraph. Heavier than the body and never + clamped — it is one sentence by construction, and the whole point is that it + can be read without opening anything. */ +.clamp__lead { + margin: 0; + font-size: 0.9rem; + line-height: 1.5; + font-weight: 500; + color: var(--zk-ink); +} +.clamp__lead + .clamp__text { margin-top: 8px; } diff --git a/src/components/ClampText.jsx b/src/components/ClampText.jsx index d0be5c1..4e559ff 100644 --- a/src/components/ClampText.jsx +++ b/src/components/ClampText.jsx @@ -1,15 +1,33 @@ import { useState } from 'react' import './ClampText.css' +/** + * Splits a block of AI prose into a finding and its working. + * + * The employees write the conclusion first and the evidence after it — + * "POSP-77341 is active and empanelled for motor." then four sentences of + * registry detail. So the first sentence already IS the summary, and lifting it + * out gives one without inventing text or asking the model for a second field + * it would have to be trusted to keep in step with the first. + * + * Returns null when the split would be useless: no sentence terminator, a first + * sentence so long it is the paragraph again, or one so short it is a fragment + * rather than a finding. Those fall back to plain folding. + */ +function splitLead(value) { + const m = value.match(/^(.{40,220}?[.!?])(\s+)(\S[\s\S]*)$/) + if (!m) return null + return { lead: m[1].trim(), rest: m[3].trim() } +} + /** * Prose, folded. * * The AI employees write at length — a recommendation rationale runs past 1,500 * characters — and a lead file that prints all of it is a document, not a - * screen. Anything long opens as a few lines with the rest one click away, so - * the page can be scanned and still holds everything for whoever wants it. + * screen. Anything long shows its finding, with the reasoning one click away. * - * Whether to fold is decided on length, not on measuring the rendered box: a + * Whether to fold is decided on length, not by measuring the rendered box: a * ref-and-measure pass would reflow on every resize to answer a question the * string itself already answers. */ @@ -19,11 +37,30 @@ export default function ClampText({ text, lines = 3, threshold = 150 }) { if (value.length <= threshold) return

{value}

+ const split = splitLead(value) + + // No sensible headline — fold the whole thing, as before. + if (!split) { + return ( +
+

{value}

+ +
+ ) + } + return (
-

{value}

+

{split.lead}

+ {open ?

{split.rest}

: null}