---
phase: 06-
reviewed: 2026-04-15T03:54:20Z
depth: standard
files_reviewed: 5
files_reviewed_list:
  - frontend/src/components/workspace/input-box.tsx
  - frontend/src/core/threads/submit-files.ts
  - frontend/src/core/threads/hooks.ts
  - frontend/src/core/threads/hooks.test.ts
  - frontend/tests/e2e/input-and-compose.spec.ts
findings:
  critical: 0
  warning: 5
  info: 1
  total: 6
status: issues
advisory: true
---

# Phase 06: 代码评审报告（聚焦 06-04 gap-closure）

**Reviewed:** 2026-04-15T03:54:20Z  
**Depth:** standard  
**Files Reviewed:** 5  
**Status:** issues（建议性、非阻塞）

## Summary

本次重点审查了 06-04 涉及的输入引用与提交流程。未发现高危安全漏洞，但存在若干会导致行为偏差或可观测性不足的问题：附件仅发送路径被阻断、文件 URL 拉取缺少响应状态校验、上传失败被静默吞掉、缓存更新回调对空数据不安全，以及一个永久 skip 的 E2E 用例导致回归覆盖不足。

## Warnings

### WR-01: 仅附件消息会被前端拦截，无法提交

**File:** `frontend/src/components/workspace/input-box.tsx:297`  
**Issue:** `handleSubmit` 只判断 `message.text` 和 `references`，忽略 `message.files`。当用户仅上传附件而不输入文本时会直接 `return`，与常见聊天上传行为不一致。  
**Fix:**
```tsx
if (!message.text && (message.files?.length ?? 0) === 0 && references.length === 0) {
  return;
}
```

### WR-02: 文件 URL 转 File 时未校验 HTTP 状态，可能上传错误内容

**File:** `frontend/src/core/threads/hooks.ts:509`, `frontend/src/core/threads/hooks.ts:723`  
**Issue:** 两处 `fetch(fileUIPart.url)` 后直接 `response.blob()`，未检查 `response.ok`。当 URL 失效返回 404/500 时，错误页面内容也可能被当作文件上传。  
**Fix:**
```ts
const response = await fetch(fileUIPart.url);
if (!response.ok) {
  throw new Error(`Failed to fetch file blob: ${response.status}`);
}
const blob = await response.blob();
```

### WR-03: `useSubmitThread` 上传失败后继续发送，存在“静默丢附件”

**File:** `frontend/src/core/threads/hooks.ts:747-749`  
**Issue:** `useSubmitThread` 中上传失败仅 `console.error`，未 toast、未中断提交，用户会看到消息发送成功但附件未随消息进入上下文。  
**Fix:**
```ts
} catch (error) {
  console.error("Failed to upload files:", error);
  toast.error("附件上传失败，请重试。");
  return; // 或 throw error，阻断本次 submit
}
```

### WR-04: React Query 缓存更新回调假设 `oldData` 非空，存在运行时异常风险

**File:** `frontend/src/core/threads/hooks.ts:218-219`, `frontend/src/core/threads/hooks.ts:940-941`  
**Issue:** 两处 `setQueriesData` 回调直接 `oldData.map(...)`；当缓存尚未建立时 `oldData` 可能为 `undefined`，会触发 `TypeError`。  
**Fix:**
```ts
(oldData: Array<AgentThread> | undefined) => oldData?.map((t) => { ... }) ?? oldData
```

### WR-05: E2E 用例 DF-INPUT-008 被永久 skip，回归覆盖缺口持续存在

**File:** `frontend/tests/e2e/input-and-compose.spec.ts:159`  
**Issue:** `testInfo.skip(true, ...)` 是硬编码永久跳过，导致“stale 引用不阻断发送”的端到端行为无法被自动回归验证。  
**Fix:** 改为条件 skip（基于 fixture 能力探测），或通过 mock/测试路由注入 stale 引用，使该用例在可控环境可执行。

## Info

### IN-01: 留有 TODO 占位，后续建议纳入工单

**File:** `frontend/src/components/workspace/input-box.tsx:662`, `frontend/src/components/workspace/input-box.tsx:1045`  
**Issue:** 仍有连接器/skill 取消能力相关 TODO，表明交互与后端契约尚未完全收敛。  
**Fix:** 将 TODO 关联到明确 issue/phase，避免长期悬置。

---

_Reviewed: 2026-04-15T03:54:20Z_  
_Reviewer: Claude (gsd-code-reviewer)_  
_Depth: standard_
