correctness-and-error-handling
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCorrectness & Error Handling Fix
正确性与错误处理修复
Find and fix correctness issues and missing error handling in $ARGUMENTS (or the whole app if no argument is given). Work through every step below. Each step searches for problems and then fixes them in place. Only report issues that cannot be auto-fixed.
查找并修复**$ARGUMENTS中的正确性问题与缺失的错误处理逻辑(若未指定参数则检查整个应用)。请按以下每一步操作,每一步都会先排查问题,然后就地修复**。仅报告无法自动修复的问题。
Step 1 — Map data flows and fix known defects
步骤1 — 映射数据流并修复已知缺陷
Read these files before checking anything:
- /
src/main.tsx— top-level error boundaries and auth flowsrc/App.tsx - All files matching ,
**/hooks/*.ts— shared async state**/contexts/*.tsx - All files matching ,
**/api/*.ts— CDF SDK call sites**/services/*.ts
For each async data source, note:
- What happens when the request fails (network error, CDF 403, timeout)?
- What does the UI show while loading?
- What does the UI show if the result is empty?
在检查任何内容前,请先阅读以下文件:
- /
src/main.tsx— 顶层错误边界与认证流程src/App.tsx - 所有匹配、
**/hooks/*.ts的文件 — 共享异步状态**/contexts/*.tsx - 所有匹配、
**/api/*.ts的文件 — CDF SDK调用站点**/services/*.ts
针对每个异步数据源,需确认:
- 请求失败时(网络错误、CDF 403、超时)会发生什么?
- 加载过程中UI会显示什么?
- 结果为空时UI会显示什么?
Find and fix known defects in critical paths
查找并修复关键路径中的已知缺陷
bash
undefinedbash
undefinedFind TODO/FIXME/HACK in critical code paths (not test files)
在关键代码路径中查找TODO/FIXME/HACK标记(排除测试文件)
grep -rn --include=".ts" --include=".tsx" -E "(TODO|FIXME|HACK|XXX):" src/ | grep -v ".test." | grep -v ".spec."
grep -rn --include=".ts" --include=".tsx" -E "(TODO|FIXME|HACK|XXX):" src/ | grep -v ".test." | grep -v ".spec."
Find "fix" or "broken" or "workaround" markers
查找包含"fix"、"broken"或"workaround"的标记
grep -rn --include=".ts" --include=".tsx" -i -E "(TODO.*fix|workaround|broken|known.?bug|temporary.?hack)" src/
For each match in a critical path (data fetching, rendering, auth, navigation):
1. **Read the surrounding code** to understand the incomplete/broken behavior.
2. **Fix the underlying issue** — implement the missing logic, correct the broken behavior, or add proper error handling.
3. If the fix requires significant architectural changes beyond this skill's scope, **replace the TODO with a safe failure mode**: graceful error handling, a sensible fallback value, or an explicit user-facing message explaining degraded functionality.
4. **Remove the TODO/FIXME/HACK comment** after fixing. The code should speak for itself.
Do not leave TODOs in critical paths. Every one must be resolved or converted to a safe fallback.
---grep -rn --include=".ts" --include=".tsx" -i -E "(TODO.*fix|workaround|broken|known.?bug|temporary.?hack)" src/
针对关键路径(数据获取、渲染、认证、导航)中的每个匹配项:
1. **阅读周边代码**以理解未完成/损坏的行为逻辑。
2. **修复底层问题** — 实现缺失的逻辑、修正损坏的行为,或添加适当的错误处理。
3. 若修复需要超出本技能范围的重大架构变更,**将TODO替换为安全的故障模式**:优雅的错误处理、合理的回退值,或明确的面向用户的降级功能说明。
4. **修复后移除TODO/FIXME/HACK注释**,代码应自我说明。
关键路径中不得遗留TODO项,所有TODO必须得到解决或转换为安全回退方案。
---Step 2 — Add top-level error boundary
步骤2 — 添加顶层错误边界
Every Flows app must have at least one React Error Boundary wrapping the main content so that an unexpected render-time exception shows a user-friendly message instead of a blank screen.
bash
grep -rn --include="*.tsx" --include="*.ts" -E "ErrorBoundary|componentDidCatch|getDerivedStateFromError" src/If no error boundary exists, create the ErrorFallback component and add the ErrorBoundary wrapper to . Install if not present:
App.tsxreact-error-boundarybash
pnpm add react-error-boundaryThen add to :
App.tsxtsx
import { ErrorBoundary } from "react-error-boundary";
function ErrorFallback({ error }: { error: Error }) {
return (
<div role="alert" className="p-8 text-center">
<p className="text-lg font-semibold">Something went wrong</p>
<pre className="mt-2 text-sm text-muted-foreground">{error.message}</pre>
</div>
);
}
// Wrap the main content:
<ErrorBoundary FallbackComponent={ErrorFallback}>
<MainContent />
</ErrorBoundary>Write the updated with the ErrorBoundary in place. Do not just suggest it — make the edit.
App.tsx每个Flows应用必须至少有一个React Error Boundary包裹主内容,以便在发生意外渲染时异常时显示用户友好的消息,而非空白屏幕。
bash
grep -rn --include="*.tsx" --include="*.ts" -E "ErrorBoundary|componentDidCatch|getDerivedStateFromError" src/若不存在错误边界,请创建ErrorFallback组件并将ErrorBoundary包装器添加到中。若未安装则先安装:
App.tsxreact-error-boundarybash
pnpm add react-error-boundary然后添加到:
App.tsxtsx
import { ErrorBoundary } from "react-error-boundary";
function ErrorFallback({ error }: { error: Error }) {
return (
<div role="alert" className="p-8 text-center">
<p className="text-lg font-semibold">出现错误</p>
<pre className="mt-2 text-sm text-muted-foreground">{error.message}</pre>
</div>
);
}
// 包裹主内容:
<ErrorBoundary FallbackComponent={ErrorFallback}>
<MainContent />
</ErrorBoundary>编写已添加ErrorBoundary的更新版,请勿仅提出建议——直接完成修改。
App.tsxStep 3 — Wrap unhandled async functions in try/catch
步骤3 — 用try/catch包裹未处理的异步函数
Search for every function and chain that does not have error handling:
asyncPromisebash
undefined查找所有未添加错误处理的函数与链:
asyncPromisebash
undefinedFind async functions
查找async函数
grep -rn --include=".ts" --include=".tsx" -E "async\s+function|async\s+(" src/
grep -rn --include=".ts" --include=".tsx" -E "async\s+function|async\s+(" src/
Find .then() without .catch()
查找无.catch()的.then()
grep -rn --include=".ts" --include=".tsx" -E ".then(" src/ | grep -v ".catch("
**Fix each one:**
- For bare `async` functions that lack try/catch: **wrap the function body** in try/catch. Log the error with context and re-throw so callers/query layers can handle it:
```ts
async function fetchAssets(sdk: CogniteClient) {
try {
const result = await sdk.assets.list({ limit: 100 });
return result.items;
} catch (error) {
console.error("Failed to fetch assets:", error);
throw error;
}
}- For without
.then(): add.catch()to the chain:.catch()
ts
somePromise.then(handleResult).catch((error) => {
console.error("Operation failed:", error);
});- For TanStack Query consumers (/
useQuery) missinguseMutationhandling: add the error check and error UI to the component:isError
tsx
const { data, isLoading, isError, error } = useQuery({
queryKey: ["assets"],
queryFn: () => fetchAssets(sdk),
});
if (isError) return <ErrorMessage error={error} />;Read each file, make the edit, and write it back.
grep -rn --include=".ts" --include=".tsx" -E ".then(" src/ | grep -v ".catch("
**逐一修复:**
- 对于缺少try/catch的裸`async`函数:**将函数体包裹在try/catch中**。记录带上下文的错误并重新抛出,以便调用者/查询层处理:
```ts
async function fetchAssets(sdk: CogniteClient) {
try {
const result = await sdk.assets.list({ limit: 100 });
return result.items;
} catch (error) {
console.error("获取资产失败:", error);
throw error;
}
}- 对于无的
.catch():**添加.then()**到链中:.catch()
ts
somePromise.then(handleResult).catch((error) => {
console.error("操作失败:", error);
});- 对于缺少处理的TanStack Query消费者(
isError/useQuery):在组件中添加错误检查与错误UI:useMutation
tsx
const { data, isLoading, isError, error } = useQuery({
queryKey: ["assets"],
queryFn: () => fetchAssets(sdk),
});
if (isError) return <ErrorMessage error={error} />;阅读每个文件,完成修改并写回。
Step 4 — Add missing loading, error, and empty states to components
步骤4 — 为组件添加缺失的加载、错误与空状态
For each component that fetches data, it must have three distinct UI states:
| State | Required UI |
|---|---|
| Loading | Spinner, skeleton, or loading indicator |
| Error | User-readable message (not a raw error object or blank space) |
| Empty | "No results" / "Nothing here yet" message (not a blank list) |
Search for components that render data without checking loading state:
bash
grep -rn --include="*.tsx" -E "\.(map|filter|find)\(" src/ | grep -v "isLoading\|isPending\|skeleton\|Skeleton"For each hit, read the component and add the missing states directly:
- Missing loading state — add before the data render:
tsx
if (isLoading) {
return <div className="flex items-center justify-center p-8"><Spinner /></div>;
}- Missing error state — add after the loading check:
tsx
if (isError) {
return (
<div role="alert" className="p-4 text-center text-destructive">
<p>Failed to load data. Please try again.</p>
</div>
);
}- Missing empty state — add after the error check, before the :
.map()
tsx
if (!data || data.length === 0) {
return (
<div className="p-8 text-center text-muted-foreground">
<p>No results found.</p>
</div>
);
}Insert these checks in the correct order (loading, then error, then empty) above the existing data render. Write each fixed file.
每个获取数据的组件必须具备三种不同的UI状态:
| 状态 | 所需UI |
|---|---|
| 加载中 | 加载动画、骨架屏或加载指示器 |
| 错误 | 用户可读的消息(而非原始错误对象或空白区域) |
| 空数据 | "无结果" / "暂无内容"消息(而非空白列表) |
查找未检查加载状态就渲染数据的组件:
bash
grep -rn --include="*.tsx" -E "\.(map|filter|find)\(" src/ | grep -v "isLoading\|isPending\|skeleton\|Skeleton"针对每个匹配项,阅读组件并直接添加缺失的状态:
- 缺失加载状态 — 在数据渲染前添加:
tsx
if (isLoading) {
return <div className="flex items-center justify-center p-8"><Spinner /></div>;
}- 缺失错误状态 — 在加载检查后添加:
tsx
if (isError) {
return (
<div role="alert" className="p-4 text-center text-destructive">
<p>数据加载失败,请重试。</p>
</div>
);
}- 缺失空状态 — 在错误检查后、前添加:
.map()
tsx
if (!data || data.length === 0) {
return (
<div className="p-8 text-center text-muted-foreground">
<p>未找到结果。</p>
</div>
);
}按正确顺序(加载中→错误→空数据)将这些检查插入现有数据渲染代码上方。编写每个修复后的文件。
Step 5 — Add type narrowing for external data
步骤5 — 为外部数据添加类型收窄
External data (CDF responses, URL params, , ) must be validated before use. TypeScript types alone are not runtime guarantees.
localStorageJSON.parsebash
undefined外部数据(CDF响应、URL参数、、结果)在使用前必须验证。仅靠TypeScript类型无法提供运行时保障。
localStorageJSON.parsebash
undefinedFind JSON.parse without validation
查找无验证的JSON.parse
grep -rn --include=".ts" --include=".tsx" -E "JSON.parse(" src/
grep -rn --include=".ts" --include=".tsx" -E "JSON.parse(" src/
Find localStorage reads
查找localStorage读取操作
grep -rn --include=".ts" --include=".tsx" -E "localStorage.(get|set)Item" src/
grep -rn --include=".ts" --include=".tsx" -E "localStorage.(get|set)Item" src/
Find useSearchParams usage
查找useSearchParams用法
grep -rn --include=".ts" --include=".tsx" -E "useSearchParams|searchParams.get" src/
**Fix each one:**
- **`JSON.parse(x) as T`** — replace with Zod safeParse:
```ts
import { z } from "zod";
const MySchema = z.object({ /* fields */ });
const parseResult = MySchema.safeParse(JSON.parse(raw));
if (!parseResult.success) {
console.warn("Invalid stored data, using defaults:", parseResult.error);
return defaultValue;
}
const validated = parseResult.data;- without null check — add nullish fallback:
searchParams.get("id")
ts
const id = searchParams.get("id") ?? defaultId;- used directly — add type guard and fallback:
localStorage.getItem(key)
ts
const raw = localStorage.getItem(key);
if (raw === null) return defaultValue;
try {
const parsed = JSON.parse(raw);
// validate parsed shape
return isValidShape(parsed) ? parsed : defaultValue;
} catch {
return defaultValue;
}Do not cast external data with — that bypasses runtime safety. Read, fix, and write each file.
as MyTypegrep -rn --include=".ts" --include=".tsx" -E "useSearchParams|searchParams.get" src/
**逐一修复:**
- **`JSON.parse(x) as T`** — 替换为Zod的safeParse:
```ts
import { z } from "zod";
const MySchema = z.object({ /* 字段定义 */ });
const parseResult = MySchema.safeParse(JSON.parse(raw));
if (!parseResult.success) {
console.warn("存储数据无效,使用默认值:", parseResult.error);
return defaultValue;
}
const validated = parseResult.data;- 未做空值检查的— 添加空值回退:
searchParams.get("id")
ts
const id = searchParams.get("id") ?? defaultId;- 直接使用的— 添加类型守卫与回退:
localStorage.getItem(key)
ts
const raw = localStorage.getItem(key);
if (raw === null) return defaultValue;
try {
const parsed = JSON.parse(raw);
// 验证解析后的结构
return isValidShape(parsed) ? parsed : defaultValue;
} catch {
return defaultValue;
}请勿使用强制转换外部数据——这会绕过运行时安全检查。阅读、修复并写回每个文件。
as MyTypeStep 6 — Fix null, undefined, and unsafe array access
步骤6 — 修复null、undefined与不安全的数组访问
Read every component that accesses properties of data returned from CDF or passed via props.
bash
grep -rn --include="*.tsx" --include="*.ts" -E "\w+\[0\]\." src/Fix each unsafe pattern found:
- Unsafe nested property access — add optional chaining and nullish coalescing:
tsx
// Before: asset.properties.space.Asset.name
// After:
const name = asset.properties?.["my-space"]?.["Asset"]?.name ?? "Unknown";- Unguarded on possibly-undefined array — add nullish fallback:
.map()
tsx
// Before: items.map(renderItem)
// After:
(items ?? []).map(renderItem)- Unsafe array index access — use with optional chaining:
.at()
tsx
// Before: items[0].name
// After:
const first = items.at(0)?.name ?? "—";Read each file with a match, apply the fix, and write it back.
阅读所有访问CDF返回数据或通过props传递数据属性的组件。
bash
grep -rn --include="*.tsx" --include="*.ts" -E "\w+\[0\]\." src/修复所有找到的不安全模式:
- 不安全的嵌套属性访问 — 添加可选链与空值合并:
tsx
// 修复前: asset.properties.space.Asset.name
// 修复后:
const name = asset.properties?.["my-space"]?.["Asset"]?.name ?? "未知";- 对可能为undefined的数组执行无保护的— 添加空值回退:
.map()
tsx
// 修复前: items.map(renderItem)
// 修复后:
(items ?? []).map(renderItem)- 不安全的数组索引访问 — 使用与可选链:
.at()
tsx
// 修复前: items[0].name
// 修复后:
const first = items.at(0)?.name ?? "—";阅读每个匹配的文件,应用修复并写回。
Step 7 — Add useEffect cleanup functions
步骤7 — 添加useEffect清理函数
Every that sets up a subscription, timer, event listener, or async operation that can outlive the component must return a cleanup function.
useEffectbash
grep -rn --include="*.tsx" --include="*.ts" -B 2 -A 15 "useEffect" src/For each , check whether cleanup is needed and add the cleanup function if missing:
useEffect| Pattern | Fix to add |
|---|---|
| Add |
| Add |
| CDF streaming / SSE | Add |
| Add AbortController: |
| Zustand / event emitter subscription | Add |
Reference pattern for async effects:
ts
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const data = await fetchWithSignal(controller.signal);
if (!controller.signal.aborted) setState(data);
} catch (err) {
if (err instanceof Error && err.name !== "AbortError") {
setError(err);
}
}
}
load();
return () => controller.abort();
}, [id]);Read each effect, add the missing cleanup, and write the file.
每个设置了订阅、定时器、事件监听器或可能在组件销毁后仍运行的异步操作的,必须返回清理函数。
useEffectbash
grep -rn --include="*.tsx" --include="*.ts" -B 2 -A 15 "useEffect" src/针对每个,检查是否需要清理,若缺失则添加清理函数:
useEffect| 模式 | 需添加的修复 |
|---|---|
| 添加 |
| 添加 |
| CDF流 / SSE | 添加 |
| 添加AbortController:在顶部创建 |
| Zustand / 事件发射器订阅 | 添加 |
异步effect参考模式:
ts
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const data = await fetchWithSignal(controller.signal);
if (!controller.signal.aborted) setState(data);
} catch (err) {
if (err instanceof Error && err.name !== "AbortError") {
setError(err);
}
}
}
load();
return () => controller.abort();
}, [id]);阅读每个effect,添加缺失的清理函数并写回文件。
Step 8 — Add edge case guards
步骤8 — 添加边缘场景守卫
For each feature, check and add guards for:
- Empty data: If zero-item lists are not handled, add an empty state check before rendering.
- Single item: If list rendering has off-by-one bugs with a single entry, fix the logic.
- Maximum data / pagination: If CDF returns the full and there are more pages, ensure pagination is communicated to the user. Add a "Load more" or pagination indicator if missing.
limit - Concurrent requests / stale results: If the user can trigger a new request before the previous completes, add stale request cancellation (AbortController or a request ID check).
- Network offline: If the app silently fails when offline, add a meaningful error message.
For Atlas tool functions, add argument validation at the top of every execute function:
executets
execute: async (args) => {
if (!args.assetId || typeof args.assetId !== "string") {
return { output: "Missing or invalid assetId", details: null };
}
// ... safe to proceed
}Search for functions, read each one, add the validation, and write the file.
execute针对每个功能,检查并添加守卫逻辑:
- 空数据:若未处理零项列表,则在渲染前添加空状态检查。
- 单条数据:若列表渲染在仅含一条数据时存在差一错误,则修复逻辑。
- 最大数据量 / 分页:若CDF返回满数据且存在更多页面,需确保向用户传达分页信息。若缺失则添加"加载更多"或分页指示器。
limit - 并发请求 / 过期结果:若用户可在前一个请求完成前触发新请求,添加过期请求取消逻辑(AbortController或请求ID检查)。
- 网络离线:若应用在离线时静默失败,添加有意义的错误消息。
对于Atlas工具的函数,在每个execute函数顶部添加参数验证:
executets
execute: async (args) => {
if (!args.assetId || typeof args.assetId !== "string") {
return { output: "缺少或无效的assetId", details: null };
}
// ... 可安全执行后续逻辑
}查找函数,阅读每个函数,添加验证并写回文件。
executeStep 9 — Report remaining findings
步骤9 — 报告剩余问题
Produce a structured report covering:
- What was fixed in each step — summarize the changes made (files edited, patterns fixed).
- Remaining issues — only list issues that could not be auto-fixed (e.g., require architectural changes, need product decisions, or are outside the scope of this skill).
| Severity | File | Line | Issue | Status |
|---|---|---|---|---|
| HIGH | | 34 | Unhandled promise rejection | FIXED — wrapped in try/catch |
| MEDIUM | | 12 | No empty state | FIXED — added empty state check |
| MEDIUM | | 45 | Auth error handling needs product decision | UNFIXED — requires team input |
If no issues are found in a step, state "No issues found" for that step. Do not skip steps silently.
生成结构化报告,涵盖:
- 每一步修复的内容 — 总结所做的更改(编辑的文件、修复的模式)。
- 剩余问题 — 仅列出无法自动修复的问题(例如,需要架构变更、产品决策或超出本技能范围的问题)。
| 严重程度 | 文件 | 行号 | 问题 | 状态 |
|---|---|---|---|---|
| 高 | | 34 | 未处理的Promise拒绝 | 已修复 — 用try/catch包裹 |
| 中 | | 12 | 无空状态 | 已修复 — 添加空状态检查 |
| 中 | | 45 | 认证错误处理需产品决策 | 未修复 — 需要团队输入 |
若某一步未发现问题,需注明"未发现问题",请勿静默跳过步骤。
Done
完成
Summarize what was fixed by severity. Flag any remaining HIGH issues that could cause data loss, crashes in production, or misleading UI states, and list them first for immediate attention.
按严重程度总结修复内容。标记任何可能导致数据丢失、生产环境崩溃或误导性UI状态的剩余高优先级问题,并将其列为首要处理项。