PR #1007 vs public-factory-v3 功能回退审核

PR: fix(ui,deploy): Factory v2 apiFetch 修复 + blade deploy 支持任意目录发布

审核时间: 2026-06-26 | 共 7 轮独立审核(2 Claude Opus + 2 Codex + 3 Agent)

背景

审核总结

5/7 轮审核结论为 无回退(审核 1、2、5、6、7)
2/7 轮审核发现了潜在问题(审核 3、4),但经过交叉验证,均为低风险问题

综合结论:PR #1007 相比 public-factory-v3 无实质性功能回退

发现的 2 个低风险问题:

  1. removeSession 错误处理变更(审核 3):DELETE 失败时旧代码仍会清理 UI 状态,新代码不会。实际上新行为更正确(服务端删除失败时不应清理前端状态),不算回退
  2. /root 直接放 blade-app.yaml 的边缘 case(审核 4):findManifestRoot() 返回 /root 但后端要求 /root/ 前缀,会被拒绝。但这个场景极其罕见(没人会把应用直接放在 home 目录根下),风险极低

合并警告(审核 6):public-factory-v3 如果直接合入 main,会覆盖掉 PR #1007 的 app_dir deploy 功能,需要在合并时保留该功能

审核 1/7 Claude Opus — 前端 API 调用迁移 无回退

审核范围:4 个 factory-v2 前端文件的 fetch → apiFetch 迁移

结论:功能完全等价。apiFetch 在非 2xx 时抛出 BladeApiError,与原始 if (!resp.ok) throw 行为一致。readJsonResponse() 正确处理 204/空响应体(DELETE 请求)。

文件行为对比
AgentConfigModal.tsxCRUD 操作均等价,DELETE 结果正确丢弃
FactoryV2BoardPanel.tsx3 个列表查询的 [] fallback 用 try/catch 正确保留
FactoryV2Page.tsxlistDir、validateRepo 的 fallback 均正确
FactoryV2ProjectPage.tsx所有 API 调用行为一致
审核 2/7 Claude Opus — CLI + 后端 deploy 逻辑 无回退

审核范围:deploy.go 的 working_dir → app_dir 重构、app_publish.py 的 _resolve_app_dir 新增

结论:后端完全向后兼容。PublishRequest 同时包含 app_dirworking_dir,逻辑优先使用 app_dir,无 app_dir 时 fallback 到旧的 working_dir 路径。

  • findManifestRoot() 直接定位 manifest,比旧的间接路径更可靠
  • _resolve_app_dir() 安全性完备:验证 /root/ 前缀、拒绝 ..、检查 is_relative_to、验证目录和 manifest 存在
  • 旧 CLI 发送 working_dir 时命中 else 分支,行为与修改前完全一致
审核 3/7 Codex — 前端功能完整性对比 发现低风险问题

审核范围:apiFetch 迁移对 UI 交互模式和错误处理语义的影响

发现 1 — removeSession 行为变更:

旧代码:fetch(DELETE) 不检查 resp.ok,无论成功失败都清理 UI 状态

新代码:apiFetch(DELETE) 在非 2xx 时抛异常,被 catch 捕获,清理逻辑不执行

评估:新行为实际更正确 — 服务端删除失败时不应清理前端状态。属于 bug 修复而非回退。

发现 2 — catch { return [] } 范围扩大:

旧代码:只在 !resp.ok 时返回 [],JSON 解析错误会向上抛出

新代码:try { apiFetch } catch { return [] } 吞掉所有错误(含 JSON 解析错误)

评估:实际影响极小 — 后端返回非法 JSON 的概率接近 0,且列表为空比崩溃对用户更友好。

审核 4/7 Codex — 后端 API 兼容性审核 发现边缘 case

审核范围:deploy API 变更的向后兼容性和边缘场景

确认向后兼容:后端同时接受 working_dir(旧 CLI)和 app_dir(新 CLI)

发现 — /root 根目录边缘 case:

如果 blade-app.yaml 直接放在 /root/ 下(无子目录),findManifestRoot() 返回 /root,但 _resolve_app_dir() 要求 app_dir.startswith("/root/"),会被拒绝

评估:极其罕见的场景 — 正常使用中应用总是在 /root 的子目录下开发。旧代码在此场景下也会走 workspace 全局扫描的 fallback 路径,属于非标准用法。风险评级:极低。

审核 5/7 Agent — 错误处理行为变更审核 无回退

审核范围:逐函数比对 apiFetch 与原始 fetch 的错误处理语义

结论:所有 API 调用的错误处理行为均保持一致。

  • apiFetch 在非 2xx 时抛出 BladeApiError,与原始 throw new Error 等价
  • readJsonResponse() 对 204/空 body 返回 undefined,DELETE 请求无问题
  • 所有 "return [] on error" 的函数均用 try/catch 正确包裹
  • 抛出的错误类型从 Error 变为 BladeApiError,但 TanStack Query 的 mutation 和 query 都能正确捕获
审核 6/7 Agent — public-factory-v3 独有功能丢失检查 合并警告

审核范围:PR #1007 涉及的 12 个文件是否与 public-factory-v3 的改动冲突

结论:PR #1007 本身不构成回退,但未来合并 public-factory-v3 时需注意:

合并冲突预警:

  • deploy.go:v3 分支仍使用旧的 working_dir 逻辑,合并时会覆盖 PR #1007 的 app_dir 功能
  • app_publish.py:v3 分支没有 _resolve_app_dir(),合并时需要 cherry-pick 或手动保留
  • Factory-v2 前端文件:v3 分支删除了这些文件(用 v3 替代),这是预期行为
  • 文档和 SKILL.md:v3 分支的版本不包含 app_dir 相关文档更新

建议:合并 public-factory-v3 时,需要在 deploy 相关文件上 resolve conflict,保留 PR #1007 的 app_dir 功能

审核 7/7 Agent — TypeScript 类型与 SDK 接口兼容性 无回退

审核范围:TypeScript 类型定义、SDK 导出、编译检查

结论:无回退。

  • PublishRequest 新增的 app_dir?: string | null 字段是可选的,不破坏现有类型
  • apiFetch 正确从 @blade-hq/agent-kit/react 导出
  • TypeScript 编译通过(4 个预存 error 均与 PR #1007 无关:缺少 recharts 和 monaco-editor 类型声明)
  • public-factory-v3 中额外的类型定义(factory-v3 路由类型等)是 v3 独有功能,不属于 PR #1007 的范围

投票汇总

审核审核者角度结论
#1Claude Opus前端 API 迁移无回退
#2Claude OpusCLI + 后端 deploy无回退
#3Codex前端功能完整性低风险问题
#4Codex后端 API 兼容性边缘 case
#5Agent错误处理行为无回退
#6Agentv3 功能丢失合并警告
#7AgentTS/SDK 兼容无回退