一键导入
audit-error-ux
Audit error handling UX — error boundaries, silent failures, loading states, empty states
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Audit error handling UX — error boundaries, silent failures, loading states, empty states
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Fill missing type, title, and description frontmatter on documents using structured AI output
Download a web page by URL and save it as clean markdown with images
Audit for accessibility — keyboard navigation, ARIA labels, contrast, focus indicators
Produce a full dependency health report (SBOM, vulnerabilities, staleness, upgrades, licenses)
Audit for unnecessary re-renders — Zustand subscriptions, missing memoization, inline callbacks
Audit test coverage — inventory tests by type, find critical untested paths
| name | audit-error-ux |
| description | Audit error handling UX — error boundaries, silent failures, loading states, empty states |
| user-invocable | true |
Audit how errors and edge cases surface to the user. This is a research-only audit — do not modify any code.
Find React error boundaries (ErrorBoundary components or componentDidCatch):
grep -rn "ErrorBoundary" src/ --include="*.tsx" | grep -v "import\|//"
<Editor /> (typically already wrapped per ErrorBoundary.tsx usage)<FloatingCommandBar /> — primary AI interaction surface; a malformed ACP response or chat-store corruption crashes the entire app if unprotected<AgentOrb /> — ambient agent indicator; unprotected crashes during agent task renderingQuietLayout that wraps only <Editor /> but leaves <FloatingCommandBar /> and <AgentOrb /> unwrapped — an exception in either unmounts the whole app and loses all unsaved content). Check the file/line where each surface is mounted so a regression is easy to re-verify.Find operations that can fail without any user feedback:
catch {} or .catch(() => {}) — swallowed errors with no toast, log, or UI change (High)try/catch blocks that only console.error or console.warn — developer-visible only, user sees nothing (Medium)invoke() calls that are not awaited and not chained with .catch() (Medium–High depending on consequence)invoke calls: Every call to invoke(commandName, args) from @tauri-apps/api/core can reject with a string error from Rust. The correct pattern for user-visible operations is:
try {
await invoke('command_name', args);
} catch (error) {
toast.error(`Operation failed: ${error}`);
}
Fire-and-forget invoke without any catch is only acceptable for telemetry/logging commands where failure is truly inconsequential. Flag all others.sonner (via the toast import) as the designated notification surface. A console.error-only catch where the user triggered the operation is always a violation.listen() event handlers, not invoke() rejections. Errors in these flows can be silently swallowed if the event handler has no error branch.
listen( or appWindow.listen( call sites in src/hooks/:
grep -rn "listen(" src/hooks/ --include="*.ts" --include="*.tsx"
event.payload.error) are surfaced to the user via toast.useAcpSessionListeners.ts, useDirectApiChat.ts, and useCopilotChat.ts — these are the primary streaming consumers.payload.error field or catches exceptions with only console.error as Medium severity.What to check: Would the user know something went wrong? If not, flag it.
Beyond whether an error surfaces, audit what it says:
if (someStore.errorMessage) {
return <p>Something went wrong.</p>; // actual error not shown
}
Grep:
grep -rn "File not found\|Something went wrong\|An error occurred" src/components/ --include="*.tsx"
For each hit, check whether the actual error string from state is displayed (even in small text-xs text-muted-foreground font-mono text below the friendly message). If the error string is available and not shown at all, flag as Low (misleading diagnosis wastes user time). (e.g. an editor that stores the full Tauri error in loadError but always renders the hardcoded "File not found" regardless of the actual cause.)<p>Could not open file</p>
<p className="text-xs text-muted-foreground font-mono mt-1">{activeTab.loadError}</p>
Find async operations and check if they show loading indicators:
File tree loading — is there a skeleton or spinner while list_directory runs?
AI chat responses — is there a typing indicator while waiting for the first token?
Model downloads — is progress shown?
Settings that require async validation — does the UI indicate "checking..."?
Loading indicators must be announced: A spinner or skeleton loader (Loader2 animate-spin) that has no aria-live region or aria-label is invisible to screen readers. When a load state starts, an aria-live="polite" region should announce "Loading..." and when complete should announce the result or clear. At minimum, the button or container that entered the loading state should expose aria-busy="true" while loading.
Grep for unannounced loading:
grep -rn "Loader2\|animate-spin\|isLoading\|loading" src/components/ --include="*.tsx" | grep -v "aria-label\|aria-live\|aria-busy"
Flag any loading state on a user-triggered action (button click, form submit) that has no accessible loading announcement as Low severity.
Check views for what they show when data is absent:
Check what happens under failure conditions:
localStorage / Zustand persist: grep for JSON.parse calls in store hydration without try/catch. Zustand's built-in onRehydrateStorage error handler should be present in each persisted store.index.db: check src-tauri/src/index/db.rs for error handling on Connection::open. A corrupt or locked index.db must log a warning and fall back to empty-index mode, not panic. Grep:
grep -n "Connection::open\|rusqlite::Connection" src-tauri/src/index/db.rs
For each finding:
### <SEVERITY>: <Short title>
**File:** `<path>:<line>`
<What the user experiences and why it's bad.>
**Fix:** <How to improve the user experience.>
End with a ### Confirmed Good Patterns section.
File: src/hooks/useAIOperations.ts:312
When an AI API call fails, the raw error string from Rust is shown in a toast: "Failed to connect to api.anthropic.com: connection refused". This is confusing for non-technical users.
Fix: Map common errors to user-friendly messages: