AGC 错误报告缺少分类:登录业务校验失败与真实缺陷同等入池并触发「发现问题」通知 #562

Closed
opened 2026-10-01 11:55:46 +08:00 by suzmii · 2 comments
Member

现象

报告问题面板截图:错误事件(2)

「报告问题」面板把两条用户输入类的预期业务错误和真实系统缺陷放在同一张列表里,默认全选,并且会先弹「发现问题」通知:

  • 登录失败:密码长度需要在 6 到 128 位之间 — auth · 1 次
  • 手机号或密码错误 — auth · 1 次

截图:报告面板「错误事件(2)」平铺两行,视觉上与 react-render、5xx、agent-runtime 终态失败完全等价。

用户只是输错一次密码,就会被当成「客户端出问题了」引导上报。

根因(已定位,三处叠加)

  1. 采集期过滤对 Tauri invoke 失效。 shouldCaptureClientError(apps/ai-game-creator-shell/src/services/errorReporting.ts:24-31)靠 HTTP status 放行网络错误与 408/5xx、拦截其余 4xx;但 2026-09-24 认证下沉 Rust 后,login_client_with_password / send_client_phone_login_code 等命令以 Err(String) 拒绝,Tauri 抛出的是纯字符串,首行 typeof error !== 'object' 直接 return true。
  2. 上报点无条件采集。 apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx:349-354(send-login-code)与 :419-422(login)两条 catch 里,业务失败也直接 captureClientError(...)。
  3. 整条链路没有分类维度。 Rust ErrorReportEvent(src-tauri/src/error_report/queue.rs:18-29)字段只有 eventId / fingerprint / source / message / stack / occurredAt / lastOccurredAt / count;source 是自由字符串(无枚举、无白名单),只表示「哪个入口上报的」,auth 下既可能是真缺陷也可能只是用户输错。report_diagnostic_error 只丢弃空 message,snapshot() 按插入序返回;前端 ClientErrorEvent、跨端 shared-contracts Event、SpacetimeDB error_report 表、Admin 列表同样没有 category / severity / kind。

链路:输错密码 → 服务端 400/401(server-rs/crates/api-server/src/password_entry.rs:140-160)→ auth_session.rs::map_auth_failure 抛字符串 → 上面第 1、2 步放行入池 → 5 秒聚合唤醒(error_report/notifications.rs)→ 通知 + 面板。

这同时违反既有文档口径:docs/technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md 已声明「预期的 4xx 登录/鉴权失败不进入错误报告池」,该口径在 Tauri invoke 路径上不成立。

影响

  • 误报通知稀释真实缺陷;用户对「发现问题」脱敏。
  • 诊断包里混入业务噪声;管理员只能在批次级打 review_status,无法按类别筛选或剔除。
  • source 自由字符串让后续任何分类都缺稳定基点。

期望(错误分类处理)

最小闭环,具体口径待拍板:

  1. 事件引入稳定分类字段 category(例如 defect / expected-business / environment-network / agent-runtime),Rust 侧为唯一真相源,随事件上传、落 events.jsonl,Admin 列表与详情可展示与筛选。
  2. 采集期按类别决定默认行为:预期业务错误不入池(首选,直接恢复文档口径);或入池但标为预期错误——默认不选中、不触发「发现问题」、不进默认提交集。
  3. 修掉字符串拒绝的过滤失效:认证命令返回结构化错误(kind / status),或 auth 上报点显式声明分类,不再靠 status 猜。
  4. source 收敛为枚举 + 入池校验,禁止任意字符串。
  5. 迁移口径:error_report 表与归档新增字段按仓库红线(字段放最后 + 默认值)处理,历史归档不推测补造。

涉及范围

  • apps/ai-game-creator-shell/src-tauri/src/error_report/{queue.rs,notifications.rs,commands.rs,sanitize.rs}
  • apps/ai-game-creator-shell/src-tauri/src/auth_session.rs(错误结构化)
  • apps/ai-game-creator-shell/src/services/{errorReporting.ts,errorReportingBridge.ts,clientAuth.ts}
  • apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx、src/components/error-report/*
  • server-rs/crates/shared-contracts/src/error_reports.rs、spacetime-module/src/error_report.rs、api-server/src/error_reports.rs、apps/admin-web/src/pages/AdminErrorReportsPage.tsx
  • docs/technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md

验收

  • 输错密码 / 手机号格式错 / 密码长度不足 / 验证码过期:不产生错误事件、不弹「发现问题」(或按选定口径标为非缺陷且默认不提交、不通知)。
  • react-render / window.onerror / unhandledrejection / 5xx / 网络错误 / agent-runtime 终态失败:入池、通知、默认选中行为不变。
  • 管理员可按类别筛选;历史批次仍可读、可下载。
  • 定向验证:apps/ai-game-creator-shell/tests/errorReporting.test.ts、ErrorReportDialog.test.tsx、cargo test ... runtime_error、cargo test -p api-server error_reports、admin-web 路由/页面测试。
## 现象 ![报告问题面板截图:错误事件(2)](https://git.genarrative.world/git/attachments/67d77db5-32d0-4e11-bdf8-7616b7116840) 「报告问题」面板把两条**用户输入类的预期业务错误**和真实系统缺陷放在同一张列表里,默认全选,并且会先弹「发现问题」通知: - `登录失败:密码长度需要在 6 到 128 位之间` — `auth · 1 次` - `手机号或密码错误` — `auth · 1 次` 截图:报告面板「错误事件(2)」平铺两行,视觉上与 `react-render`、5xx、`agent-runtime` 终态失败完全等价。 用户只是输错一次密码,就会被当成「客户端出问题了」引导上报。 ## 根因(已定位,三处叠加) 1. **采集期过滤对 Tauri invoke 失效。** `shouldCaptureClientError`(`apps/ai-game-creator-shell/src/services/errorReporting.ts:24-31`)靠 HTTP `status` 放行网络错误与 408/5xx、拦截其余 4xx;但 2026-09-24 认证下沉 Rust 后,`login_client_with_password` / `send_client_phone_login_code` 等命令以 `Err(String)` 拒绝,Tauri 抛出的是**纯字符串**,首行 `typeof error !== 'object'` 直接 `return true`。 2. **上报点无条件采集。** `apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx:349-354`(send-login-code)与 `:419-422`(login)两条 catch 里,业务失败也直接 `captureClientError(...)`。 3. **整条链路没有分类维度。** Rust `ErrorReportEvent`(`src-tauri/src/error_report/queue.rs:18-29`)字段只有 `eventId / fingerprint / source / message / stack / occurredAt / lastOccurredAt / count`;`source` 是自由字符串(无枚举、无白名单),只表示「哪个入口上报的」,`auth` 下既可能是真缺陷也可能只是用户输错。`report_diagnostic_error` 只丢弃空 message,`snapshot()` 按插入序返回;前端 `ClientErrorEvent`、跨端 `shared-contracts` `Event`、SpacetimeDB `error_report` 表、Admin 列表同样没有 `category / severity / kind`。 链路:输错密码 → 服务端 400/401(`server-rs/crates/api-server/src/password_entry.rs:140-160`)→ `auth_session.rs::map_auth_failure` 抛字符串 → 上面第 1、2 步放行入池 → 5 秒聚合唤醒(`error_report/notifications.rs`)→ 通知 + 面板。 这同时**违反既有文档口径**:`docs/technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md` 已声明「预期的 4xx 登录/鉴权失败不进入错误报告池」,该口径在 Tauri invoke 路径上不成立。 ## 影响 - 误报通知稀释真实缺陷;用户对「发现问题」脱敏。 - 诊断包里混入业务噪声;管理员只能在**批次级**打 `review_status`,无法按类别筛选或剔除。 - `source` 自由字符串让后续任何分类都缺稳定基点。 ## 期望(错误分类处理) 最小闭环,具体口径待拍板: 1. 事件引入稳定分类字段 `category`(例如 `defect` / `expected-business` / `environment-network` / `agent-runtime`),Rust 侧为唯一真相源,随事件上传、落 `events.jsonl`,Admin 列表与详情可展示与筛选。 2. 采集期按类别决定默认行为:预期业务错误**不入池**(首选,直接恢复文档口径);或入池但标为预期错误——默认不选中、不触发「发现问题」、不进默认提交集。 3. 修掉字符串拒绝的过滤失效:认证命令返回结构化错误(`kind` / `status`),或 auth 上报点显式声明分类,不再靠 `status` 猜。 4. `source` 收敛为枚举 + 入池校验,禁止任意字符串。 5. 迁移口径:`error_report` 表与归档新增字段按仓库红线(字段放最后 + 默认值)处理,历史归档不推测补造。 ## 涉及范围 - `apps/ai-game-creator-shell/src-tauri/src/error_report/{queue.rs,notifications.rs,commands.rs,sanitize.rs}` - `apps/ai-game-creator-shell/src-tauri/src/auth_session.rs`(错误结构化) - `apps/ai-game-creator-shell/src/services/{errorReporting.ts,errorReportingBridge.ts,clientAuth.ts}` - `apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx`、`src/components/error-report/*` - `server-rs/crates/shared-contracts/src/error_reports.rs`、`spacetime-module/src/error_report.rs`、`api-server/src/error_reports.rs`、`apps/admin-web/src/pages/AdminErrorReportsPage.tsx` - `docs/technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md` ## 验收 - 输错密码 / 手机号格式错 / 密码长度不足 / 验证码过期:不产生错误事件、不弹「发现问题」(或按选定口径标为非缺陷且默认不提交、不通知)。 - `react-render` / `window.onerror` / `unhandledrejection` / 5xx / 网络错误 / `agent-runtime` 终态失败:入池、通知、默认选中行为不变。 - 管理员可按类别筛选;历史批次仍可读、可下载。 - 定向验证:`apps/ai-game-creator-shell/tests/errorReporting.test.ts`、`ErrorReportDialog.test.tsx`、`cargo test ... runtime_error`、`cargo test -p api-server error_reports`、admin-web 路由/页面测试。
suzmii added the Kind/EnhancementKind/Bug
Priority
Medium
3
labels 2026-10-01 11:55:46 +08:00
k88936 self-assigned this 2026-10-01 13:28:10 +08:00
Member

emm 不用分类, 这个报告只报告没有被catch处理的错误, 在这种前置条件未满足/用户输入错误 在对应的地方catch住,给用户反馈就好了, 我的锅

emm 不用分类, 这个报告只报告没有被catch处理的错误, 在这种前置条件未满足/用户输入错误 在对应的地方catch住,给用户反馈就好了, 我的锅
Author
Member

emm 不用分类, 这个报告只报告没有被catch处理的错误, 在这种前置条件未满足/用户输入错误 在对应的地方catch住,给用户反馈就好了, 我的锅

🤔以后如果有时间,统一区分预期业务错误、网络/上游错误和内部错误应该会更好。比如:

用户输入不符合要求 => UserErr(ErrCode.xx, Hint)
网络或上游暂时失败 => TransientErr(ErrCode.xx, Hint)
内部异常 => InternalErr(ErrCode.xx)

处理上可以让错误统一向上冒泡,由最外层根据错误类型处理,减少各处重复 catch;只有需要局部恢复或清理状态的地方,再单独处理。

> emm 不用分类, 这个报告只报告没有被catch处理的错误, 在这种前置条件未满足/用户输入错误 在对应的地方catch住,给用户反馈就好了, 我的锅 🤔以后如果有时间,统一区分预期业务错误、网络/上游错误和内部错误应该会更好。比如: 用户输入不符合要求 => UserErr(ErrCode.xx, Hint) 网络或上游暂时失败 => TransientErr(ErrCode.xx, Hint) 内部异常 => InternalErr(ErrCode.xx) 处理上可以让错误统一向上冒泡,由最外层根据错误类型处理,减少各处重复 catch;只有需要局部恢复或清理状态的地方,再单独处理。
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: GenarrativeAI/Genarrative#562