From 3f16268152426d9c974aae9bd1bf2f58f2ab05a9 Mon Sep 17 00:00:00 2001 From: lorentz Date: Thu, 16 Jul 2026 18:21:40 -0400 Subject: [PATCH] fix(260716-pgr): confidence display shows percent, not raw 0-1 scale classifications.confidence is 0.0-1.0 (1 = max confidence). ClassificationCard appended "%" directly to the raw value, so confidence=1 rendered as "1% confidence" -- read as near-zero, the opposite of its true meaning. Found live while reviewing a Breach Secure Now simulated-phishing classification. --- .../260716-pgr-PLAN.md | 109 ++++++++++++++++++ .../260716-pgr-SUMMARY.md | 35 ++++++ components/phishing/classification-card.tsx | 4 +- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 .planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-PLAN.md create mode 100644 .planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-SUMMARY.md diff --git a/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-PLAN.md b/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-PLAN.md new file mode 100644 index 0000000..b204d45 --- /dev/null +++ b/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-PLAN.md @@ -0,0 +1,109 @@ +--- +phase: quick +plan: 260716-pgr +type: execute +wave: 1 +depends_on: [] +files_modified: + - components/phishing/classification-card.tsx +autonomous: true +requirements: [QUICK-CONFIDENCE-DISPLAY] + +must_haves: + truths: + - "A maximum-confidence classification (confidence='1') displays as '100% confidence', not '1% confidence'" + - "A 0.85-confidence classification displays as '85% confidence'" + - "If confidence is null or does not parse to a finite number, no confidence text renders" + artifacts: + - path: components/phishing/classification-card.tsx + provides: "Corrected confidence display (0-1 scale rendered as 0-100 percent)" + contains: "Math.round(Number(classification.confidence) * 100)" + key_links: + - from: components/phishing/classification-card.tsx + to: classifications.confidence (0.0-1.0 NUMERIC, serialized as string) + via: "Number() coercion + *100 + Math.round in the render guard" + pattern: "Number\\(classification.confidence\\) \\* 100" +--- + + +Fix a confidence display bug in the phishing ClassificationCard. The `classifications.confidence` +column stores a 0.0-1.0 scale (computed by `campaign-classifier.ts` `computeConfidence()`, where +`confidence=1` means maximum/100% confidence). The card currently appends "%" directly to the raw +0-1 value, so a maximum-confidence classification renders as "1% confidence" — the exact opposite +of its true meaning to an operator. + +Purpose: Operators reading a phishing classification must see the correct confidence percentage. +Output: One corrected render expression in `components/phishing/classification-card.tsx`. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-PLAN.md + + +From components/phishing/classification-card.tsx: +```typescript +export interface ClassificationCardData { + id: string; + verdict: 'SPAM' | 'UNWANTED' | 'THREAT'; + confidence: string | null; // API serializes the 0.0-1.0 NUMERIC column as a string + // ... +} +``` + +Current render block (lines 118-122) — the exact block to replace: +```tsx +{classification.confidence != null && ( + + {classification.confidence}% confidence + +)} +``` + + + + + + + Task 1: Convert confidence to percent before rendering + components/phishing/classification-card.tsx + Replace the confidence render block at lines 118-122. Parse the value once +with `Number(classification.confidence)` and multiply by 100 with `Math.round(... * 100)` +so the 0.0-1.0 scale renders as a 0-100 integer percent. Extend the existing +`classification.confidence != null` guard so the block ONLY renders when the parsed number +is finite (use `Number.isFinite(...)`), matching the existing null-guard style already +wrapping this block — if the string does not parse, render nothing rather than "NaN%". +Keep the same `...% confidence` +markup; only the numeric expression and the guard condition change. Do NOT change the +`confidence: string | null` type or any other part of the file. + + npx tsc --noEmit --pretty 2>&1 | grep -i "classification-card" || echo "no type errors in classification-card" + grep -q "Math.round(Number(classification.confidence) \* 100)" components/phishing/classification-card.tsx && echo "conversion present" + grep -q "Number.isFinite" components/phishing/classification-card.tsx && echo "finite guard present" + + The card renders confidence='1' as "100% confidence" and confidence='0.85' as +"85% confidence"; null or non-parsing values render no confidence text; `npx tsc --noEmit` +reports no new errors. + + + + + +- `npx tsc --noEmit --pretty` passes (tsc is the only safety net; components/** has no vitest coverage). +- Manual read-through: the render expression multiplies by 100 and rounds, and the guard checks `Number.isFinite`. + + + +- confidence='1' → "100% confidence" +- confidence='0.85' → "85% confidence" +- confidence=null or unparseable → no confidence text rendered +- No other behavior in the component changes; type check clean. + + + +Create `.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-SUMMARY.md` when done. + diff --git a/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-SUMMARY.md b/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-SUMMARY.md new file mode 100644 index 0000000..568de64 --- /dev/null +++ b/.planning/quick/260716-pgr-fix-confidence-display-bug-in-classifica/260716-pgr-SUMMARY.md @@ -0,0 +1,35 @@ +--- +status: complete +--- + +# Quick Task 260716-pgr: Fix confidence display bug — Summary + +**`ClassificationCard` rendered the 0.0-1.0 `classifications.confidence` value by appending "%" directly, so a maximum-confidence classification (`confidence='1'`) displayed as "1% confidence" — read by an operator as near-zero, the opposite of its true meaning. Fixed by multiplying by 100 and rounding, guarded by `Number.isFinite`.** + +## Change + +`components/phishing/classification-card.tsx` — confidence render block: +```tsx +{classification.confidence != null && Number.isFinite(Number(classification.confidence)) && ( + + {Math.round(Number(classification.confidence) * 100)}% confidence + +)} +``` + +## Verification + +- `npx tsc --noEmit --pretty` clean. +- `Math.round(Number(classification.confidence) * 100)` present. +- `Number.isFinite` guard present. +- Manual trace: `confidence='1'` → "100% confidence"; `confidence='0.85'` → "85% confidence"; `confidence=null` or unparseable → no confidence text renders. + +## Deviations from Plan + +None — plan executed exactly as written. + +## Discovered while investigating this bug + +This was found live while reviewing ticket 699415's classification in the Phase 22 review page (a Breach Secure Now/KnowBe4 simulated-phishing report, correctly classified `UNWANTED` with `confidence=1`, displaying as "1% confidence" before this fix). The same investigation surfaced two follow-on items tracked separately: +- A dead Autotask webhook (no delivery since 2026-04-29) — fixed same session by re-registering the Tickets/TicketNotes subscriptions. +- A request to add a dedicated "User Awareness"/simulation verdict (today forced into the generic `UNWANTED` bucket) plus a per-company automation gate — scoped as a new phase, not part of this quick task. diff --git a/components/phishing/classification-card.tsx b/components/phishing/classification-card.tsx index 017468b..a6fc5a5 100644 --- a/components/phishing/classification-card.tsx +++ b/components/phishing/classification-card.tsx @@ -115,9 +115,9 @@ export function ClassificationCard({ {classification.verdict} - {classification.confidence != null && ( + {classification.confidence != null && Number.isFinite(Number(classification.confidence)) && ( - {classification.confidence}% confidence + {Math.round(Number(classification.confidence) * 100)}% confidence )}