清掉错误类型相关的过时文档

- 删两份 ADR:`AGC命令错误结构化与错误报告口径`、`AGC认证失败的JS侧载体与抛出时机`;错误通道的现行口径只留在代码与该专题技术方案里;
- 删导出面板的【实施计划】与【里程碑】两份计划,落地情况回到技术方案里一句话;
- `docs/README.md` 去掉对上述四份的链接,技术方案里的失败通道段落跟着删;
- `decision-log` 去掉 2026-10-01 那一段,2026-10-05 那段的标题与四条决策改成「同步细节与文案归属」;`pitfalls` 去掉两份 ADR 的引用。
This commit is contained in:
2026-10-06 14:32:16 +08:00
parent 8837fc5cd5
commit af19af0a2f
9 changed files with 9 additions and 449 deletions
@@ -8,7 +8,7 @@ AI Game Creator Shell 采用 IDEA 风格的当前进程错误报告:错误事
- 诊断 URL 保留可定位的 API 路由路径,隐藏 origin、URL 账号密码、查询参数、fragment 和路径中的敏感标识;普通资源 URL 与本地文件路径继续隐藏。网络错误、HTTP 错误与响应体超时均应带安全路由,不能只剩 `<url>`。历史已经脱敏的归档不推测或补造原路由。
- 报告池只收**没有任何调用方处理**的错误:React render error、`window.onerror`、`unhandledrejection`,以及调用方判定为真故障后带上下文交给错误池(`ClientAuthErrorWrapper`)的错误。Agent Runtime 的终态失败、预算耗尽和启动确认失败由 Rust 失败投影统一入池;Direct Codex 与专业 Agent 的前台裸 Tauri invoke catch 作为补充入口,重复事件由同一 fingerprint 合并,主动取消和“同一 turn 已在运行”不作为错误采集。分层口径见 [`【ADR】AGC命令错误结构化与错误报告口径-2026-10-01`](../adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md) 与 [`【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01`](../adr/【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01.md)。
- 报告池只收**没有任何调用方处理**的错误:React render error、`window.onerror`、`unhandledrejection`,以及调用方判定为真故障后带上下文交给错误池(`ClientAuthErrorWrapper`)的错误。Agent Runtime 的终态失败、预算耗尽和启动确认失败由 Rust 失败投影统一入池;Direct Codex 与专业 Agent 的前台裸 Tauri invoke catch 作为补充入口,重复事件由同一 fingerprint 合并,主动取消和“同一 turn 已在运行”不作为错误采集。
- 事件字段包括 eventId、fingerprint、source、message、stack、时间和次数;重复事件合并。不再携带 severity、errorCode、page、action、requestId 等无法稳定关联的字段。
- 指纹计算可使用调用方的 page/action 及脱敏后的首个调用点作为进程内区分输入,但这些上下文不会作为事件字段上传;消息与 stack 在入池前统一脱敏,WebCrypto 失败时降级为稳定可读指纹,采集本身不得产生新的未处理拒绝。
- 命令失败按具体变体建模(Rust 枚举 + ts-rs 导出的 `type` 判别联合;顶层只放调用方要分流的类别,可枚举细分收进类型化枚举 `reason` 字段,无字段变体生成 `{ type }`,带载荷变体生成 `{ type } & 载荷类型`),前端按变体分流,**任何地方都不对错误文案做判断**:认得的业务变体(用户输入 / 前置条件 / 预期 4xx)由调用方消化并给用户反馈,永不进池;系统变体、未识别变体和结构化之外的拒绝原样抛出,走上面的兜底入口。认证命令的封装形态:`invokeClientAuth` 只是薄包装,把结构化拒绝原样装进**已有**的 `ClientAuthErrorWrapper`(载体只有一个 `ClientAuthError` 类型的 `error` 字段,值就是 ts-rs 生成的判别联合;不读变体字段、不塞 `context`,构造时把整份载荷 `JSON.stringify` 进 `Error.message`,上报事件因此拿到机器事实),不新增手写错误类;判定只写在 catch 子句里,无字段变体用本 catch 的固定文案,带载荷变体先 `as` 取自己的具名载荷类型(`reason` 是枚举时再 `switch (payload.reason)`)、再用它自己的字段拼上本次操作的上下文前缀,`default` 用 `expectNever` 在编译期挡住漏接变体。
@@ -10,12 +10,11 @@
- 构建契约:项目 npm 包里存在脚本 `build:xhs-minitool`(冒号形式是既有 `command.exec` 白名单 `build:*` 的要求),由宿主负责运行;跑完必须存在 `.export/xhs-minitool.zip`。脚本内部怎么 `vite build`、怎么调 `pack.mjs`、用什么中间目录由 agent 决定并写进脚本;**每次导出都重新构建 zip**,不做「产物已存在」的短路。
- 首次适配:用户点显式按钮 → 前端组装适配指令(正文在 `view/project-development/export/state/xhsMinitoolInstruction.ts`,纯函数 + 契约常量)→ 经 `useDirectProjectChatController` 的 `chat.submit` 入队(该链路自带会话写权限门与 clientTurnId),进的就是同一个项目主 Direct 会话,不另开「直接调 agent」的旁路。不自动跑构建、不自动叫 agent;内容与脚本判据按固定间隔(2 秒,窗口在后台时跳过)自动重读,所以没有刷新按钮——agent 回合结束后用户只需要点「导出」。重读时两条事实分开处理:`hasScript` 是宿主的现算事实,任何时刻都采纳;表单是用户的编辑对象,只有用户手上没有未保存输入(也不在冲突里)时才覆盖,否则只更新 `hasScript`,绝不覆盖正在打的字。没有构建脚本时,「还没适配」的结论只由注册表读回来之后下(`hasScript` 初值是 `false`,读取中不下结论),提示卡片自带那颗入队按钮,按钮行里就不再重复一颗;失败卡片按变体的 `action` 分派三颗按钮——`adapt` 发首次适配指令(还没适配,修复指令会引用一份还不存在的适配说明)、`repair` 发同一份契约加宿主失败现场、`retry` 只重试,同一时刻只有一张卡片、一个入口。
- 命令切分:`read_xhs_minitool_export` 只返回**内容**(`form` + `hasScript`),自动刷新反复调的就是这一条;**注册表指纹**(写回时的 `baseHash`)由 `read_xhs_minitool_export_hash` 单独给,只在进编辑会话、或重读到的新内容真的被采纳时取一次。两者分开是刻意的:刷新这条高频路径在类型上就动不了写回基线,否则「顺手刷新」会把两次刷新之间的外部改动认成自己的基线、把冲突吞掉。指纹是同步细节,不进前端对外状态(hook 里只在 `baselineRef`),界面也不显示任何同步状态(没有「保存中」「待保存」文案)。`save_xhs_minitool_export_form` 成功后回新的指纹。
- 失败通道:命令失败是 typed 变体(`XHSMiniToolExportError`,ts-rs 导出到 `export/generated/`),前端只按 `type` 分流、`expectNever` 钉死穷尽性,**不对任何文案做判断**,也不把裸 message 当成业务失败的解释。分流沿用 [`【ADR】AGC命令错误结构化与错误报告口径-2026-10-01`](../adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md) 与 [`【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01`](../adr/【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01.md) 的两道口子:预期拒绝(表单不合法、脚本缺失、冲突、权限策略拒绝 `commandDenied`、脚本非零退出、产物不在、注册表坏)留在面板里就地消化,一句话按变体写死、宿主现场照原样展示;**宿主侧事实故障(`exportUnavailable`)与认不出形状的拒绝(Tauri 传输失败 / 命令 panic / 参数序列化失败)先给现场再原样抛出**,由全局 `unhandledrejection` 送进错误池。抛出按指纹去重:面板每 2 秒重读,同一个故障只抛一次、变了再抛,否则报告池里的 `count` 统计的是「面板开了多久」。策略拒绝与宿主故障必须是两个变体:`enforce_project_permission_policy` 那版把「策略拒绝」与「策略读不出来」拼成同一句人话,调用方就分不出该不该上报,所以导出链路走 typed 的 `enforce_project_permission_policy_rejection`。宿主也不预拼用户可见文案:构建输出尾部只回原文 + `omittedCharacters` 两个事实,「已省略前 N 个字符」那句话由前端拼(`export/state/xhsMinitoolOutputTail.ts`,失败卡片与成功提示共用)。同一口径也管界面自己的失败:复制字段走 Tauri 剪贴板插件(`clipboard-manager:allow-write-text`,与 `UiEditorCopyPathButton` 等三处同一条路;`navigator.clipboard` 在 WebView 里可能根本没有、失败还静默),写失败时按钮显示「复制失败」,不假装成功。
- 冲突:注册表可被 agent(改文件)与用户(面板编辑)两方写入。宿主保存时带 `baseHash`;宿主重读比对,hash 不同再逐字段 diff,只要有字段真的不同就判冲突,**绝不覆盖**,返回两侧值让前端逐字段选择;纯格式化改动静默吸收。注册表内不存 revision / updatedAt 之类 token。
- 权限与副作用:跑脚本复用 `command.exec` 的权限口径(只查 deny,UI 按钮即用户确认),**不新增** `GAME_CREATION_APP_COMMANDS` 条目;导出链路**不拿项目写锁、不推进全局 revision**(`.export/` 不进 manifest、素材、UI State 或客户端投影)。发布包是白名单收集,`.export/` 不会进入。
- 非目标:平台自动上传(无 API)、PNG/JPG 之外的 icon 格式转换、宿主侧 zip 结构校验、非 vite 项目、第二个导出目标,以及 `GAME_CREATION_APP_COMMANDS` / `shared-contracts` / SpacetimeDB / OpenAPI 的任何改动。
- 验收:注册表自动建空表单与严格解析拒绝、表单首错、`hasScript` 判定、内容与指纹两条命令的切分(自动刷新拿不到写回基线)、`contentHash` 冲突与逐字段选择、icon 越界与符号链接拒绝、产物路径;失败按 typed 变体分流(策略拒绝与宿主故障是两个变体、认不出形状的拒绝与宿主故障原样抛出、同一故障只抛一次、输出省略量由前端写进提示);自动重读不覆盖用户未保存的输入、agent 事后加上脚本不用点刷新就能亮起导出按钮;首次适配在真实 vite 项目上由 agent 跑通并产出可人工上传的 zip,二次导出零 agent 调用;变更 skill 脚本后指纹同步。证据与未验证项见[里程碑](../project-memory/plans/【里程碑】导出产物面板与小红书小工具导出-2026-10-05.md)。
- 落地情况:Rust(`export/{mod,registry,draft/xhs_minitool/*}` 四个命令)、前端(`export/{state,tabs/xiaohongshu,generated}`)、skill(`pack.mjs --zip-out`)与 `.export/` 快照同步排除均已实现;失败通道已按上面两条 ADR 收口(`commandDenied` 与 `exportUnavailable` 分开、宿主故障与未分类拒绝原样抛出并去重、输出尾部只回事实)。定向单测与前端 vitest 通过,**真实 vite 项目上的首轮适配仍是唯一未验证项**。
- 验收:注册表自动建空表单与严格解析拒绝、表单首错、`hasScript` 判定、内容与指纹两条命令的切分(自动刷新拿不到写回基线)、`contentHash` 冲突与逐字段选择、icon 越界与符号链接拒绝、产物路径;自动重读不覆盖用户未保存的输入、agent 事后加上脚本不用点刷新就能亮起导出按钮;首次适配在真实 vite 项目上由 agent 跑通并产出可人工上传的 zip,二次导出零 agent 调用;变更 skill 脚本后指纹同步。
- 落地情况:Rust(`export/{mod,registry,draft/xhs_minitool/*}` 四个命令)、前端(`export/{state,tabs/xiaohongshu,generated}`)、skill(`pack.mjs --zip-out`)与 `.export/` 快照同步排除均已实现。定向单测与前端 vitest 通过,**真实 vite 项目上的首轮适配仍是唯一未验证项**。
## 2026-10-02 退役自建 Agent Runtime 与 CLI 执行面