diff --git a/finverify-terminal/frontend/ACCESSIBILITY.md b/finverify-terminal/frontend/ACCESSIBILITY.md new file mode 100644 index 0000000..0766fa5 --- /dev/null +++ b/finverify-terminal/frontend/ACCESSIBILITY.md @@ -0,0 +1,37 @@ +# Workspace trust-score accessibility + +Audit date: 2026-08-14 + +## Scope + +This audit covers the trust and confidence indicators in `components/workspace`, including the default verification-coverage view and the selected-company integrity view. + +## Implemented behavior + +- Numeric trust and integrity scores expose a named ARIA `meter` with a 0–100 range and descriptive value text. +- Confidence levels are communicated in text and through accessible names, not by color alone. +- Trust scores and confidence bars are reachable with `Tab` and display a 2px visible focus outline. +- The verification-coverage grid uses native table, header, and caption semantics. +- The transaction-monitor filters have programmatic labels. + +The score indicators are read-only. Focusing them exposes their value and context; Enter and Space intentionally perform no action. + +## Verification + +Automated checks used axe-core 4.10.3 with WCAG 2 A/AA and WCAG 2.1 A/AA tags. + +| View | Passed checks | Critical violations | +| --- | ---: | ---: | +| Default workspace | 26 | 0 | +| NVIDIA integrity view | 21 | 0 | + +Keyboard verification confirmed that all seven company trust scores and the selected-company integrity score plus its three confidence bars are reachable in DOM order and receive a visible focus indicator. + +Repository checks: + +- `npm run lint` — passes with no errors; existing warnings remain outside this change. +- `npm run build` — passes. + +## Known follow-up work + +The full workspace audit still reports pre-existing serious findings for low-contrast secondary text and some scrollable regions that are not keyboard focusable. They are outside the trust-score component scope and should be handled separately. diff --git a/finverify-terminal/frontend/components/workspace/AccessibleScore.tsx b/finverify-terminal/frontend/components/workspace/AccessibleScore.tsx new file mode 100644 index 0000000..2035dd0 --- /dev/null +++ b/finverify-terminal/frontend/components/workspace/AccessibleScore.tsx @@ -0,0 +1,40 @@ +"use client"; + +import React from "react"; + +interface AccessibleScoreProps { + label: string; + value: number; + valueText: string; + className?: string; + children: React.ReactNode; +} + +/** + * Exposes a visual score as a named ARIA meter and gives keyboard users a + * visible focus target without adding button-like behavior. + */ +export default function AccessibleScore({ + label, + value, + valueText, + className = "", + children, +}: AccessibleScoreProps) { + const boundedValue = Math.max(0, Math.min(value, 100)); + + return ( + + {children} + + ); +} diff --git a/finverify-terminal/frontend/components/workspace/FocusView.tsx b/finverify-terminal/frontend/components/workspace/FocusView.tsx index 707ab7b..6066839 100644 --- a/finverify-terminal/frontend/components/workspace/FocusView.tsx +++ b/finverify-terminal/frontend/components/workspace/FocusView.tsx @@ -10,6 +10,7 @@ import NeedsAttention from "@/components/workspace/NeedsAttention"; import VerificationCoverage from "@/components/workspace/VerificationCoverage"; import LiveVerificationTrace from "@/components/workspace/LiveVerificationTrace"; import CommandBar from "@/components/workspace/CommandBar"; +import AccessibleScore from "@/components/workspace/AccessibleScore"; import { getFundamentals, type QueryResponse, @@ -56,7 +57,12 @@ function TrustBadge({ trust }: { trust: string }) { ? "bg-t-amber/10 text-t-amber border-t-amber/20" : "bg-t-red/10 text-t-red border-t-red/20"; return ( - + {trust} ); @@ -246,18 +252,25 @@ export default function FocusView({ selectedSymbol, onDeselect, onSelectSymbol }
Integrity: - - {integrityScore} - - - {band.label} - + + + {integrityScore} + + + {band.label} + + DEMO @@ -328,7 +341,17 @@ function IntegrityTab({ symbol, score }: { symbol: string; score: number }) { { label: "SEC Agreement", weight: "30%", value: Math.min(secAgreement, 100), color: "bg-t-cyan" }, { label: "DVL Confidence", weight: "30%", value: Math.min(dvlConfidence, 100), color: "bg-t-blue" }, ].map(({ label, weight, value, color }) => ( -
+
{label} ({weight}) = 80 ? "text-t-green" : value >= 50 ? "text-t-amber" : "text-t-red"}`}> diff --git a/finverify-terminal/frontend/components/workspace/GlobalTransactionMonitor.tsx b/finverify-terminal/frontend/components/workspace/GlobalTransactionMonitor.tsx index e99f70f..649387b 100644 --- a/finverify-terminal/frontend/components/workspace/GlobalTransactionMonitor.tsx +++ b/finverify-terminal/frontend/components/workspace/GlobalTransactionMonitor.tsx @@ -104,20 +104,20 @@ export default function GlobalTransactionMonitor({ onSelectSymbol: _onSelectSymb
-
+
-
+ +
+
diff --git a/finverify-terminal/frontend/components/workspace/VerificationCoverage.tsx b/finverify-terminal/frontend/components/workspace/VerificationCoverage.tsx index 8ef2220..92a5932 100644 --- a/finverify-terminal/frontend/components/workspace/VerificationCoverage.tsx +++ b/finverify-terminal/frontend/components/workspace/VerificationCoverage.tsx @@ -1,6 +1,7 @@ "use client"; import React from "react"; +import AccessibleScore from "./AccessibleScore"; /** * VerificationCoverage — Table showing per-company verification coverage. @@ -31,6 +32,12 @@ function getTrustColor(score: number): string { return "text-t-red"; } +function getTrustLevel(score: number): string { + if (score >= 97) return "high"; + if (score >= 93) return "medium"; + return "low"; +} + export default function VerificationCoverage() { return (
@@ -41,35 +48,59 @@ export default function VerificationCoverage() { TOP COMPANIES
- {/* Table header */} -
- COMPANY - VERIFIED - CORRECTED - CONFLICTS - TRUST SCORE -
- - {/* Table body */}
- {DEMO_COVERAGE.map((row) => ( -
- {row.company} - {row.verified} - 4 ? "text-t-amber" : "text-t-muted"}`}> - {row.corrected} - - 0 ? "text-t-red" : "text-t-muted"}`}> - {row.conflicts} - - - {row.trustScore.toFixed(1)}% - -
- ))} + + + + + + + + + + + + + + + + + + + + {DEMO_COVERAGE.map((row) => { + const trustLevel = getTrustLevel(row.trustScore); + + return ( + + + + + + + + ); + })} + +
Verification coverage and trust scores for top companies
COMPANYVERIFIEDCORRECTEDCONFLICTSTRUST SCORE
+ {row.company} + {row.verified} 4 ? "text-t-amber" : "text-t-muted"}`}> + {row.corrected} + 0 ? "text-t-red" : "text-t-muted"}`}> + {row.conflicts} + + + {row.trustScore.toFixed(1)}% + +