From 04c09e802a4046f3fed4c47d6e1b00727ec09653 Mon Sep 17 00:00:00 2001 From: oratis Date: Sat, 8 Aug 2026 23:39:11 +0800 Subject: [PATCH] docs: add the v0.3.0 delivery report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 中文交付报告:做了什么、拒绝了什么、与计划哪里不符、发布踩了哪五个坑。 三块是这份报告存在的理由: - §2 三个关键设计决定(单向取严、deny 不可被 bypassPermissions 豁免、 契约是策略不是边界)——决定了这层机制是"真的收紧"还是"看起来收紧"。 - §4 与计划不符的地方,含两条计划本身写错的判断。 - §6 发布五次失败的根因。v0.3.0 是本仓库第一个 tag,release.yml 从未跑过, 每修一个失败就往后推一步。其中 Node sidecar 哈希那条特别记了"修的是固定值 而不是放宽校验",以及"本地跑过脚本"恰恰是抓不到浅克隆 bug 的那种检查。 测试数按全量八个套件统计:1177 → 1415(+238)。此前 PR 描述里的 1414 少算了 根 scripts 套件。 Co-Authored-By: Claude Opus 5 --- README.md | 29 ++--- docs/V0.3.0_REPORT.md | 241 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 14 deletions(-) create mode 100644 docs/V0.3.0_REPORT.md diff --git a/README.md b/README.md index 6fb53c2..7bab230 100644 --- a/README.md +++ b/README.md @@ -60,20 +60,21 @@ Mac 客户端(v1 即将发布):拖入 Applications → 首启完成 onboar ### 设计文档 -| 文件 | 内容 | -| ---------------------------------------------------------------------------- | --------------------------------------------------- | -| [docs/CODEX_ALIGNMENT_PLAN.md](docs/CODEX_ALIGNMENT_PLAN.md) | 当前整体改造计划、审计证据、正反方审议与 PR 路线 | -| [docs/THREE_WAY_REVIEW.md](docs/THREE_WAY_REVIEW.md) | 与 Claude Code / Codex 的三方能力+界面对比与优先级 | -| [docs/FLOATBOAT_ADOPTION_PLAN.md](docs/FLOATBOAT_ADOPTION_PLAN.md) | 工作区治理层的采纳/拒绝决策记录与实施偏差 | -| [docs/research/floatboat.md](docs/research/floatboat.md) | Floatboat / Selfware 调研(带证据分级) | -| [docs/DEVELOPMENT_PLAN.md](docs/DEVELOPMENT_PLAN.md) | 整体开发方案 v0.5(1500+ 行 / §3 模块 / §6 里程碑) | -| [docs/VISUAL_DESIGN.html](docs/VISUAL_DESIGN.html) | 视觉设计 v0.4(11 屏 mockup) | -| [docs/security-model.md](docs/security-model.md) | 威胁模型 + 防御层 + 攻击向量测试 + 已知缺口 | -| [docs/design/session-format-v1.md](docs/design/session-format-v1.md) | 统一 session JSONL、旧格式迁移与 writer ownership | -| [docs/design/sandbox-plan-worktree.md](docs/design/sandbox-plan-worktree.md) | sandbox × plan mode × worktree 关系矩阵 | -| [docs/design/plugin-security.md](docs/design/plugin-security.md) | plugin 信任 ladder + sandbox 子进程 | -| [docs/design/effort-levels.md](docs/design/effort-levels.md) | 5 档 effort 到 DeepSeek API 参数映射 | -| [docs/m1-validation.md](docs/m1-validation.md) | M1 用真 DeepSeek API 验证记录 | +| 文件 | 内容 | +| ---------------------------------------------------------------------------- | ---------------------------------------------------- | +| [docs/CODEX_ALIGNMENT_PLAN.md](docs/CODEX_ALIGNMENT_PLAN.md) | 当前整体改造计划、审计证据、正反方审议与 PR 路线 | +| [docs/THREE_WAY_REVIEW.md](docs/THREE_WAY_REVIEW.md) | 与 Claude Code / Codex 的三方能力+界面对比与优先级 | +| [docs/FLOATBOAT_ADOPTION_PLAN.md](docs/FLOATBOAT_ADOPTION_PLAN.md) | 工作区治理层的采纳/拒绝决策记录与实施偏差 | +| [docs/V0.3.0_REPORT.md](docs/V0.3.0_REPORT.md) | 0.3.0 交付报告:做了什么、拒绝了什么、发布踩了什么坑 | +| [docs/research/floatboat.md](docs/research/floatboat.md) | Floatboat / Selfware 调研(带证据分级) | +| [docs/DEVELOPMENT_PLAN.md](docs/DEVELOPMENT_PLAN.md) | 整体开发方案 v0.5(1500+ 行 / §3 模块 / §6 里程碑) | +| [docs/VISUAL_DESIGN.html](docs/VISUAL_DESIGN.html) | 视觉设计 v0.4(11 屏 mockup) | +| [docs/security-model.md](docs/security-model.md) | 威胁模型 + 防御层 + 攻击向量测试 + 已知缺口 | +| [docs/design/session-format-v1.md](docs/design/session-format-v1.md) | 统一 session JSONL、旧格式迁移与 writer ownership | +| [docs/design/sandbox-plan-worktree.md](docs/design/sandbox-plan-worktree.md) | sandbox × plan mode × worktree 关系矩阵 | +| [docs/design/plugin-security.md](docs/design/plugin-security.md) | plugin 信任 ladder + sandbox 子进程 | +| [docs/design/effort-levels.md](docs/design/effort-levels.md) | 5 档 effort 到 DeepSeek API 参数映射 | +| [docs/m1-validation.md](docs/m1-validation.md) | M1 用真 DeepSeek API 验证记录 | ## 项目结构 diff --git a/docs/V0.3.0_REPORT.md b/docs/V0.3.0_REPORT.md new file mode 100644 index 0000000..67cf1b9 --- /dev/null +++ b/docs/V0.3.0_REPORT.md @@ -0,0 +1,241 @@ +# v0.3.0 交付报告 —— 工作区治理层 + +> 日期:2026-08-08 · 版本 [`v0.3.0`](https://github.com/oratis/deepcode/releases/tag/v0.3.0) · 基线 `main@a8274ef` +> 起点:`main@ec94748`(0.2.0 之后) +> 相关文档:[调研](research/floatboat.md) · [方案与决策记录](FLOATBOAT_ADOPTION_PLAN.md) · [CHANGELOG](../CHANGELOG.md) + +--- + +## 0. 结论先行 + +本轮交付了一层 **工作区治理(workspace governance)**:_agent 能碰什么、改了什么、怎么撤销_。 + +来源是对 Floatboat 开源的 **Selfware 协议**的一手调研 —— 克隆规范仓库通读,而不是读发布稿。结论是: +**值得抄的只有它的治理声明,不值得抄的是它的分发模型。** + +| 项目 | 数字 | +| ------------ | ------------------------------------------------- | +| 合并 PR | **16 个**(#235–#250) | +| 测试 | 1177 → **1415 passed**(+238),16 skipped | +| 新增用户文档 | 3 份(file-contract / change-ledger / combo) | +| 发布产物 | GitHub Release + VSIX(DMG 与 npm 待凭证,见 §6) | + +三件 0.2.0 时**表达不出来**的事,现在能表达了: + +| 说不出的话 | 之前为什么说不出 | 现在 | +| --------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | +| "`.env` 永远不许读" | 权限规则是**工具维度**的,路径只做前缀比对,而 `file_path` 通常是绝对路径 —— `Read(.env*)` 匹配不到任何真实调用 | **File Contract**:glob × 读/写/执行 × allow/ask/deny | +| "上一轮 agent 改了什么、怎么撤销" | session 是**消息流**不是变更账本;snapshot 可寻址但不带意图 | **Change Ledger** + `ledger rollback` | +| "这个 runtime 能写哪里、哪些动作要确认" | `initialize()` 只声明**协议特性**,不声明权限与写边界 | **`runtime/capabilities`** | + +--- + +## 1. 交付清单 + +### 1.1 调研与方案(2) + +| PR | 内容 | +| --------------------------------------------------- | ---------------------------------------------------- | +| [#235](https://github.com/oratis/deepcode/pull/235) | Floatboat / Selfware 调研报告,**带 A/B/C 证据分级** | +| [#236](https://github.com/oratis/deepcode/pull/236) | 采纳方案与拒绝清单 | + +调研的关键做法:**一手克隆 `floatboatai/selfware.md`@`4c4fddd`(62 个文件)通读规范与参考实现**, +而不是依赖转述。凡第三方转述的数字("减少 60–70% 复制粘贴"、"被动感知 80% 操作"、"10,000+ 用户") +一律标 C 级,**明确规定不得作为设计依据**。 + +同时记录了对方的不利事实:规范版本号自相矛盾(README 写 `v0.1.0`、正文写 `0.2.0`); +5 个文件含不可恢复的 U+FFFD 替换字符、4 个文件 `iconv -f UTF-8` 直接失败(**其中包括中文版协议权威文件本身**); +`signature_required: false`,制品信任比 DeepCode 现有的 ed25519 强制校验还弱。 + +### 1.2 实现(9) + +| PR | 内容 | 标签 | +| --------------------------------------------------- | ------------------------------------------------------------ | ------------ | +| [#237](https://github.com/oratis/deepcode/pull/237) | 无人值守运行的显式审批策略(`onApprovalRequired`、退出码 6) | feature | +| [#238](https://github.com/oratis/deepcode/pull/238) | File Contract 解析器与**纯函数**裁决器(不接线) | internal | +| [#239](https://github.com/oratis/deepcode/pull/239) | File Contract 接入中央门禁 `dispatchToolCall` | feature | +| [#240](https://github.com/oratis/deepcode/pull/240) | Change Ledger 写入与 `deepcode ledger` | feature | +| [#241](https://github.com/oratis/deepcode/pull/241) | No Silent Apply 仪式 + `ledger rollback` | feature | +| [#242](https://github.com/oratis/deepcode/pull/242) | `runtime/capabilities` 协议方法 | feature | +| [#243](https://github.com/oratis/deepcode/pull/243) | `/combo` —— thread 蒸馏为 SKILL.md | feature | +| [#244](https://github.com/oratis/deepcode/pull/244) | Trigger Profile:每个定时任务自带权限档位 | **breaking** | +| [#245](https://github.com/oratis/deepcode/pull/245) | 威胁模型更新、方案收尾、版本号 0.3.0 | internal | + +### 1.3 发布管线修复(5) + +见 §6 —— 这部分不在原计划里,是发布过程中暴露出来的。 + +--- + +## 2. 三个关键设计决定 + +这三条是评审时最值得看的部分,因为它们决定了这层机制是"真的收紧"还是"看起来收紧"。 + +### 2.1 单向取严:新机制不可能降低现有安全性 + +``` +final = mostRestrictive(toolVerdict, pathVerdict) deny > ask > allow +``` + +`no-match` 表示"无意见",永不获胜。所以**没有契约文件时结果精确等于改造前**, +不是"约等于"。16 格合成表在测试中被逐格枚举,而不是抽样。 + +同样的单向性也用在 Trigger Profile 上:deny/ask 取并集、allow 取交集、sandbox 取更严者。 +**无论 profile 作者写什么,结果都不会比设置本身更宽。** + +### 2.2 契约的 `deny` 不能被 `bypassPermissions` 豁免 + +这是本轮唯一一处刻意的不对称,也是最值得争论的一处。 + +`deny` 陈述的是**关于路径的常驻事实**("永远不读 `.env`"),不是逐次提示。 +`bypassPermissions` 存在的意义是跳过提示。如果它也能清掉 deny, +**契约最强的一句话同时就是最容易被关掉的一句话。** + +契约的 `ask` 则是普通审批,照常受 mode 和 hook 链管辖。 + +### 2.3 诚实的能力边界:契约是策略,不是边界 + +**Bash 明确不在契约的静态裁决范围内。** `cat .env` 是一个字符串, +静态解析 shell 去猜是"把猜测包装成执行保证",比不做更危险。 + +因此代码里做了三件事,而不只是在文档里写一句: + +1. 契约含 `read: deny` 而沙箱解析为 `danger-full-access` 时,**REPL 启动、headless 运行、 + `contract show`、`doctor` 四处都告警**; +2. 只有写权限的契约**保持沉默** —— 那里没有虚假执行感的风险,没必要的告警只会训练用户忽略告警; +3. [`security-model.md`](security-model.md) 新增残余风险小节,写明路径归一化是字符串运算、 + 不调 `realpath`,**并明确要求维护者不要在任何面向用户的文案里把它宣传成"秘密防护"**。 + +--- + +## 3. 明确拒绝的部分 + +写下拒绝理由和采纳理由同等重要,否则半年后会有人重新提。 + +| 机制 | 拒绝理由 | +| ----------------------------- | -------------------------------------------------------------------------------------------------------- | +| `.self` 自执行文件分发 | "文件即应用"意味着分发单元携带可执行逻辑。对办公场景是便利,对 coding agent 是**教科书式的供应链攻击面** | +| Tacit Engine 式被动全局观察 | 跨文件/浏览器/系统应用采集操作习惯,是隐私红线;而且 `/combo` 在**显式触发**下能 100% 拿到同样的价值 | +| FloatIM 跨组织 agent 网络 | 等于让**未经审计的第三方 agent 触达源码** | +| loopback HTTP runtime API | 与既有 app-server 重复,正是 alignment plan 在消灭的那类分叉 | +| 日历接入 / Rhythm Recognition | 产品方向不同 | + +**暂缓**:IACT 内嵌可点击动作。方向对,但必须先回答"按钮触发的动作走不走审批" —— +不走就是一条绕过 dispatcher 的执行路径,直接违反 `AGENTS.md` 第一条约束。 + +--- + +## 4. 与计划不符的地方 + +比宣称"照计划完成"有用。完整六条见 +[`FLOATBOAT_ADOPTION_PLAN.md`](FLOATBOAT_ADOPTION_PLAN.md) §4.1,其中两条是**计划本身写错了**: + +| 项 | 计划 | 实际 | +| ------------------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| PR 0 的问题陈述 | 称无人值守可能"静默放行" | **错的**。`ask` 路径本来就 fail-closed(`runHeadless` 传 `approval: async () => false`)。真正缺的是"停下来"的能力和可见性,#237 按事实重写了自己的范围 | +| 四客户端一致性测试 | 要求 4 个客户端逐字段相等 | 实际只有 CLI 与 app-server **独立解析**策略;VS Code / LSP 是协议瘦客户端,逐字节消费 server 的答复。测试断言前两者并说明后两者的理由,**不宣称验证了 4 条独立路径** | + +**未做的(诚实列出)**:Grep/Glob 命中结果的二次过滤(当前只裁决搜索根)、 +制品 `provenance` 派生链、触发源抽象(ICS / file-watch)。 + +--- + +## 5. 顺手修掉的既有问题 + +都不是本轮引入的: + +- **`docs/cli-flags.md` 的退出码表与实现矛盾** —— 表里写 `3` 是 "Tool denied"、`5` 是 "API key invalid", + 而代码与 `quickstart.md` 一直是 `3` api/provider、`4` max-turns、`5` aborted。按 `headless.ts` 更正(#237)。 +- **中断批次时 `tool_use` 无应答** —— provider 在 resume 时会拒绝这种消息序列。现在统一补"未执行"结果(#237)。 +- **plugin capability bridge 绕过路径规则** —— `apps/server` 的 bridge 直接调 `dispatchToolCall` 却没传契约, + 等于给 plugin 子进程留了后门(#239)。 +- **`RELEASING.md` 的版本清单漏了两处** —— 仓库自带的 `version-consistency.test.ts` 抓到 `Cargo.lock` 仍是 0.2.0。 + 实际需要同步 **6 处**,文档只列了 4 处(#245)。 + +--- + +## 6. 发布过程:五次失败的根因 + +`v0.3.0` 是本仓库**有史以来第一个 tag**,因此 `release.yml` 从未真正跑过。 +每修一个,失败就往后推进一步 —— 这是一条从未执行过的管线该有的样子。 + +| # | PR | 根因 | +| --- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | [#246](https://github.com/oratis/deepcode/pull/246) | validate 在裸 `ubuntu-latest` 上跑测试,而 `ci.yml` 会先装 bubblewrap。deny-all-net 回退测试要 spawn `bwrap` → ENOENT。**发布门禁比 CI 弱,等于让"CI 绿"不再预测"发布绿"** | +| 2 | [#247](https://github.com/oratis/deepcode/pull/247) | `npm version` 在 pnpm workspace 里会 reify lockfile 并拒绝 `workspace:*`(EUNSUPPORTEDPROTOCOL)。`publish-cli` 有同样的潜伏 bug | +| 3 | [#247](https://github.com/oratis/deepcode/pull/247) | **Node sidecar 的固定 SHA256 是错的** —— `ef28d8fa…` 不匹配任何已发布的包。这条完整性校验**一次都没通过过** | +| 4 | [#248](https://github.com/oratis/deepcode/pull/248) | `build-vscode` 把 VERSION 打进 core 源码后直接打包,没跑根 `pnpm build`,导致 esbuild 解析不到 `@deepcode/core/*` 的 `dist/` 导出 | +| 5 | [#250](https://github.com/oratis/deepcode/pull/250) | `actions/checkout` 默认浅克隆 → `git rev-list --max-parents=0 HEAD` 返回 HEAD 自己 → release body 显示 **"0 commits."** | + +第 3 条值得单独说:**修的是固定值,不是放宽校验。** +正确哈希经两条独立途径确认 —— nodejs.org 的 `SHASUMS256.txt`,以及本地下载 24.7 MB 实包重新计算。 +committed 哈希能防住"nodejs.org 被攻陷",构建时抓 `SHASUMS256.txt` 防不住 —— 但前提是哈希得是对的。 + +第 5 条也值得记:**发布前我在本地跑过 `gen-release-notes.ts`,输出完全正常** —— +因为本地克隆有完整历史。"我测过这个脚本"恰恰是抓不到这个 bug 的那种检查。 + +--- + +## 7. 两个需要你决定并已执行的事项 + +### 7.1 npm 包名改为 `@deepcode/cli`(breaking) + +未加 scope 的 `deepcode-cli` 在 npm 上**属于另一个无关项目** +(`guocong199708`,`guocong-bincai/deepcode-cli`,当前 1.3.2,一个基于豆包的 CLI)。 +`apps/cli/package.json` 声称的正是这个名字,`pnpm publish` 会 403 —— 这个名字从来就不是我们的。 + +安装命令改为 `npm i -g @deepcode/cli`,二进制仍是 `deepcode`,行为无变化。 +历史快照文档(MORNING_REPORT / DEVELOPMENT_PLAN / HANDOFF / BEHAVIOR_PARITY)保留旧名, +它们记录的是写下时为真的事。 + +> typecheck 抓到一个真问题:`/npm i -g @deepcode/cli@latest/` 里 scope 的 `/` 会提前终结正则字面量。 +> 已改为 `toContain`。带 scope 的重命名撞上正则,正是全局替换会漏掉的那类。 + +### 7.2 缺凭证时也能发布 + +`validate` 现在探测哪些 secret 存在,跳过跑不了的环节: + +| 缺失 | 效果 | +| ------------------ | --------------------------------------- | +| Apple 签名 secrets | `build-mac` **跳过** —— 无 DMG | +| `NPM_TOKEN` | `publish-cli` **跳过** —— 不发 npm | +| 都缺 | GitHub Release 照常发布,带 VSIX 与源码 | + +**是跳过,不是失败。** 因为缺凭证而红的发布,只会训练大家忽略红色发布。 +真正**失败**的任务仍然阻断发布 —— 守卫写的是 `!= 'failure'` 而不是 `== 'success'`。 +"不发部分制品"的原则也保留:npm 发布仍然等两个可安装制品都构建成功。 + +并且 release body 会**写明缺了什么、为什么缺**。否则一个没有 DMG 的发布页 +读起来像"这个项目没有 Mac 版",而不是"这次没产出"。 + +--- + +## 8. 当前状态与遗留事项 + +### 已完成 + +- `main@a8274ef`,CI 全绿,1415 passed / 16 skipped +- [`v0.3.0`](https://github.com/oratis/deepcode/releases/tag/v0.3.0) 已发布,附 `deepcode-0.3.0.vsix` +- Release body 已用 CHANGELOG 的 0.3.0 条目重新生成(原先因浅克隆显示 "0 commits.") + +### 需要你操作 + +| 事项 | 说明 | +| ------------------------- | ------------------------------------------------------------------------------------------------------------ | +| 创建 npm `@deepcode` 组织 | 首次发布前必须存在;workflow 已带 `--access public`(scoped 包不加会默认私有) | +| 配置 6 个 Actions secret | 5 个 Apple + `NPM_TOKEN`,见 [`RELEASING.md`](RELEASING.md) §One-time setup。配好后重新打 tag 即可跑完整管线 | + +### 建议的后续(P2,均未做) + +- Grep/Glob 命中结果的二次过滤 +- 制品 `provenance` 派生链(Selfware §11.1) +- 触发源抽象:ICS / file-watch(**不内置任何日历厂商 SDK**,只接受标准 ICS 输入) +- 发布说明策略:当前 `gen-release-notes.ts` 在无前序 tag 时回退到根提交,会列出整个项目历史; + 从 CHANGELOG 取当期条目更合适 + +--- + +## 附:一句话总结 + +> **DeepCode 在"执行的安全性"上本来就强于 Selfware(真 OS 沙箱、ed25519 强制签名、吊销列表、凭证边界); +> 这一轮补的是"治理的可读性与可审计性"—— 路径级契约、变更账本、能力自声明。两者几乎正交。**