# 试点与推广:自用仓库的落地实测(四个仓库 + 一组 AI 托管对照) 这份文档回答一个很具体的问题:**这套流程在真实项目里到底跑成什么样?** 不是 demo、不是设想 —— 是四个自用仓库的实测,外加一组「同一套流程、Gate 由 AI 托管」的对照。 - **数据时点**:2026-10-15(数字取自各仓库 `docs/process/**` 与 git 工作树;采集与复算方法见文末) - **脱敏口径**:仓库一律用代称(甲/乙/丙/丁),只保留技术形态,**不含仓库名、厂商名与业务字段名**;时间线里的需求语义也做了泛化;实例仓库是公开的,按实名写 - **一句话结论**:流程跑得通、也拦得住真问题;**时间几乎全花在「人什么时候来看 Gate」上**。而存量仓库里最薄的一环不是流程本身,是**留痕的结构化程度** —— 连「这个 Gate 是谁签的」都只能靠读自然语言。 ## 1. 五个落点各自走到哪一步 | 代称 | 技术形态 | 流程落点 | 走到哪一步 | 卡在哪 | | --- | --- | --- | --- | --- | | **甲** | 规则校验服务(Node + TypeScript,CLI + 测试) | 已跑真实包 | **FEAT-001 `done`(含 Gate4 收口,31 条 journal / 17.9h);FEAT-002 `frozen`(19 条 / 3.4h,等 Gate4)** | 没卡住;第二个包按「小步切片」推进 | | **乙** | 通知类命令行工具 | 已跑真实包 | 1 个包 `draft`,journal 9 条 / 1.7h,1 条批准记录 | 卡在**立项澄清**:Gate1 前的口径没定死,没人催就停在那 | | **丙** | UI 组件演示 | 只落骨架(`prd/` 只有模板) | 未立包 | 没拿真实需求试水 —— 骨架装上了,一直没开第一个包 | | **丁** | 平台类服务 | 立过包,产物已拆 | **无主件可读**:`prd/` 里只剩孤儿 `WKL-001.journal.jsonl.bak`(19 KB)+ `WKL-001.journal.jsonl.meta.json` | 仓库本身活跃(有近期提交)⇒ 不是项目停了,是**流程没被带进日常**,且产物被手工拆散了 | | **实例**(对照) | 电商 app(Node + 原生前端,运行时依赖 0) | 已跑真实包 | **FEAT-001 `done`(106 条 / 2.0h,四个 Gate 全 AI 托管);FEAT-002 `draft`(9 条,刚起步)** | 不适用 —— 它是验收装置,专门用来跑「无人值守」 | 三个可数的观察: - **落地 ≠ 用起来**:5 个落点都装了骨架(`docs/process/**` + `scripts/process/**` 齐全),但只有 3 个留下过可读的包记录。 - **停点会「无限期等待」**:乙的包停在等 Gate1,而 Gate1 只有人能签 —— 没有人来,它就一直停着(这不是 bug,是设计的代价,见 §2)。 - **产物会被手工改**:丁的包被拆成孤儿、多个仓库的 `prd/` 里混进了人工 `.bak`(见 §6)—— 骨架装上了,纪律不会自动跟着来。 ## 2. 一个包的全流程实录(甲 FEAT-001,四个 Gate 全人签) 需求:给一批数据按既有规则打标签并按约定格式输出(语义已泛化)。走 `full` 档。 | 相对时刻 | 环节 | 谁 | 事实 | | --- | --- | --- | --- | | +0.00h | intake | 主控 | 登记需求(含人给的初始裁定) | | **+1.24h** | **Gate0** | **人签** | 通过:两个待裁定问题当场定死(主键口径 / 记录方式) | | +1.24h | env | 主控 | 环境初始化 + 基线提交(git) | | +1.29h | pm 交件 | subagent:pm | PRD(AC-1~AC-12,输出格式逐字冻结)+ 契约 + 设计与说明(R-01~R-06 逐条对齐)+ UAT 清单 | | +1.30h | errata | 主控复核 | 勘误 ER-01:**追加结论列数 9→8**(产物实测与 PRD 不符) | | **+15.62h** | **Gate1** | **人签** | 通过并冻结契约 —— **距 pm 交件 14.3 小时** | | +15.83h | 策略裁定 | 人签 | 「先在有限需求里看产出,肯定会不断调整」⇒ 改为小步切片推进 | | +15.87h | test 写红 | subagent:test | 新增 10 文件 / 56 用例(绿 21 / 红 35) | | +15.92h | 口径收口 | subagent:pm | 处理写红波次提出的 8 条口径问题(勘误 / 锚定现状,**判据语义不变**) | | +16.01h | test 复跑 | subagent:test | 151 用例 115 绿 / 36 红(存量 94 全绿) | | **+16.04h** | **Gate2** | **人签** | 通过 —— **距 Gate1 仅 26 分钟** | | +16.24h | dev 交付 | subagent:dev | S1 实现:9 文件 `3307+/18-` | | +16.55h | UAT | subagent:uat | 黑盒 18 条 = 通过 14 / **不通过 4** / 存疑 1 | | +16.93h | UAT 复验 | subagent:uat | 针对不通过与存疑项定向复验 | | +17.88h | **Gate4** | **人签** | 签署收口(人原话:「我只看输出的最终表格」)⇒ `status: done` | 第二个包(FEAT-002)走的是切片式,同样是「人签」但**留痕不同**,这段很值得看: | 相对时刻 | 环节 | 留痕事实 | | --- | --- | --- | | +0.00h | pm 交件 | PRD / 契约 / 设计与说明 + UAT 清单齐备(R-01~R-08 复述核对件) | | **+0.03h** | **Gate1 签署** | journal 里 `actor` 是 **`orchestrator`**,而 note 写的是「Gate1 签署(**人原话「签」**)」 | | +1.98h | Gate2 签署 | 同样 `actor: orchestrator`,note 写「人原话『按照建议继续执行,放行 gate2』」 | | +2.69h | dev 交付 | `merge-annotated` 完成,并**回退了取巧改动** | | +2.93h | test 复跑 | `npm test` → 237 通过 / 6 未通过(共 243;本包 87 绿 / 0 红) | > **这就是「批准来源」必须结构化的理由**:这两次签署确实是人做的决定(note 里有原话),但**结构里只有 `actor: orchestrator`** —— 想知道「这个 Gate 是谁签的」,机器只能去读自然语言。0.5.0 引入的 `via: human | ai-hosted` 就是为了补这个洞(存量仓库 9 条批准记录里 **0 条**有 `via`,见 §7)。 **Gate 间隔实测耗时(整份文档里最有用的一组数)** | 段落 | 耗时 | 性质 | | --- | --- | --- | | pm 出 PRD + 契约 + 设计与说明 | **约 4 分钟** | 机器侧 | | test 写红(56 用例) | **约 5 分钟** | 机器侧 | | dev 交付一个切片 | **约 11 分钟** | 机器侧 | | UAT 黑盒一轮 18 条 | **约 1 分钟** | 机器侧 | | 交件 → **Gate1 人签** | **14.3 小时** | **人侧(占全链路 80%)** | | Gate1 → Gate2 人签 | **26 分钟** | 人侧(人在场时就很快) | 三条反直觉的结论: 1. **瓶颈不在 agent 干活,在「人什么时候来」**。机器侧每个环节都是分钟级;一次 14.3 小时的等待,就吃掉了全链路 17.9 小时里的 80%。 2. **人在场时 Gate 并不慢**。Gate2 只用了 26 分钟(写红 / 复跑 / 实现都已并行做完)。该压的是**人到的时机**,**不是去掉 Gate** —— 去掉 Gate 省下的是这 26 分钟,赔上的是整条链的质量归属。 3. **Gate 拦下的不是「agent 写错代码」,而是口径不清**。见 §5。 ## 3. 对照:同一套流程跑「AI 托管」(实例 FEAT-001) 把四个 Gate 交给 AI 自签(验收装置专用授权,`via: ai-hosted`),在一个全新空仓里只给一句话需求「做一个电商 app」: | 项 | 实测 | | --- | --- | | 全流程跨度 | **2.01 小时**(106 条 journal) | | 四个 Gate | Gate0 +0.00h、Gate1 +0.47h、Gate2 +0.83h、Gate4 +1.75h(全 `ai-hosted`) | | 交付物 | 5 个功能面:商品列表 / 详情 / 购物车 / 下单即假支付 / 订单列表 | | 交付物测试 | **53 / 53 通过**(我复跑过,纯 `node --test`,无浏览器依赖) | | 真机验收 | **45 张浏览器截图**(CDP 驱动真实浏览器点击取证) | | 流程产物 | 2091 行(PRD 474 · 设计与说明 200 · UI 规格 401 · 契约 344 · 台账 401 · UAT 清单 271) | **同一天、同一套流程:人在回路里 = 17.9 小时;AI 托管 = 2.01 小时。** > ⚠ 但这不是严格的效率对比:两者不是同一个项目,实例的规模也明确小于真实项目。这个对照能说明的只有一件事 —— **「等待人」这一段的量级差**,不是「AI 变快了」。 > > 更重要的边界:**AI 托管只能证明「装置能无人值守跑通」,不能证明「Gate 有效」**。Gate 的有效性只能由真实开发中人的裁定来证明。 ## 4. 规模量级(两种参照) | 项 | 甲 FEAT-001(中等需求) | 实例 FEAT-001(演示需求) | | --- | --- | --- | | PRD | 457 行(含 AC 与验收口径) | 474 行 | | 设计与说明 | 186 行(R-NN 逐条落地) | 200 行 | | 契约 | 438 行(第二个包 459 行) | 344 行 | | UI 规格 | 不适用 | 401 行 | | 台账 / UAT 清单 | 见 `docs/process/rules` | 401 / 271 行 | | 测试 | `tests/` 39 文件 / 9660 行;最新一轮复跑 243 用例(237 通过 / 6 未通过) | 9 文件 / 1640 行;53 用例全绿 | | 交付代码 | 源码 29 文件 / 7816 行 + 脚本 8 文件 / 3207 行 | server 699 + web 1418 行 | | journal | 31 条(FEAT-001)/ 19 条(FEAT-002) | 106 条(FEAT-001) | 对「单人 + AI」这个形态,这两个量级都合适:**PRD 与契约加起来不到 900 行,但把口径冻到了可判定** —— 后面 dev / test / uat 三个角色冲突时,回看的就是这几百行。 ## 5. 真实返工与装置缺陷(都留了痕) ### 5.1 返工全是「口径」,没有一条是「代码写错」 | 返工 | 性质 | 谁发现的 | | --- | --- | --- | | 勘误 ER-01:追加结论列数 9→8 | 产物实测与 PRD 不符 | 主控复核 pm 交付时 | | 写红波次提出 8 条口径问题 | 判据字面不严 / 需锚定现状 | test 写红时 | | 残余 4 条判据「字面冻死」 | 澄清 + **只收紧不放宽** | pm 收口 | | 条款张力 Q-P / 措辞 Q-Q | 消歧与一致性修正(`prdVersion` 保持不变) | pm 收口 | | UAT 18 条里 4 条不通过 + 1 条存疑 | 体验与预期不符 | uat 黑盒 | **没有一条是「agent 把代码写错了」** —— 全部是口径、字面、验收标准的对齐问题。这正是把角色边界放在提示词、把质量放在 Gate 人裁的理由:机器管可判定的那半,主观的与口径的留给人。 这也解释了为什么 **journal 必须逐条留痕**:上面每一条返工都能在 journal 里找到当时的判断依据(谁在什么环节、因为什么、改了什么)。事后再看,能分清「这是澄清」还是「这是放宽判据」—— 后者才是危险的。 ### 5.2 装置缺陷:真实数据挖出来的三个 bug | 缺陷 | 现象(实测) | 处置 | | --- | --- | --- | | **从件遮蔽主件** | 从件(`-design.md` 等)的 frontmatter 也带 `id`,而扫描原本「先到先得」;`-` 字典序在 `.` 之前 ⇒ **设计件顶替主件**:甲的两个包 `status=done` / `gate2=approved` 被报成 `confirmed` / `pending`。实例那边更严重:**状态工具直接返回 `value is not lossless JSON`**,续跑第一步就断 | **0.5.0 已修**(先按文件名排序、优先取 `.md`,退回从件时告警)。存量仓库**无需改动**,升级插件即恢复正确读数 | | **落点门禁提交后空放行** | 它判的是「未被忽略的**未跟踪**文件」。同一条命令:提交前 `受检 69 个(放行 69)`、提交后 `0 个(放行 0)`,**两次都 `exit 0`** ⇒ 当 CI 门禁用会得到「永远绿」,**已入库的越界文件永远发现不了** | 已写进 `docs/CONTRACT.md` 契约 4(有效读数固定在提交前 + 给出独立审计口径:按 `git ls-files` 全集比对属主表) | | **工具静默丢弃未声明字段** | 老版本工具只接受固定字段,多传的**不报错、不警告、直接丢** ⇒ 实例该包收口时的 35 条门禁执行记录里有 **4 条**缺命令与退出码(不是角色偷懒,是工具吃掉了;到本文时点仍是这 4 条) | 0.5.0 已支持 `gate` / `command` / `exitCode` / `via`;契约 2 写明「写不进去先看是不是老版本工具」 | > 三个 bug 有一个共同点:**判断依据不完整却照样给绿**。所以这套流程把「无法校验不是绿」当硬规则 —— 空转、旧格式、验不动,都必须如实显示成非绿。 ## 6. 现存不一致清单(择要) 诚实列出这批仓库里还没对齐的地方: 1. **旁挂 meta 全是旧格式**(四个自用仓库 + 实例都一样):只有 `lines` + `lastHash`,**没有 `chainHash`** ⇒ 这些 journal 目前**无法链式复算**,**改中间行查不出来**(读取侧会如实报「⚠旧格式」,不会误报篡改)。要拿到链式指纹,需在仓库里跑一次 `process_init({ upgrade: true })`。 2. **批准记录缺 `gate` 与 `via`**:四个仓库合计 9 条 `approve`,**0 条**有 `via`、**0 条**有 `gate` 字段 —— 只能靠 `actor`(`human` / `orchestrator`)与 `phase` 推断。甲 FEAT-002 那两次「人原话『签』」的批准,结构里就只写着 `actor: orchestrator`(见 §2)。**「谁签的」目前读不出来。** 3. **门禁证据偏薄**:四个仓库合计只有 **2 条** `action:"run"`,且**都没有结构化退出码** ⇒ 在这些仓库里,「跑过什么」**仍是自述**。这是升级到 0.5.0 之后最该补的一项。 4. **`gate0` 只记在核对件里**,PRD 的 frontmatter 不记 —— 扫描没问题,但人直接翻 PRD 时看不到 Gate0 是否签过。 5. **`bugs/` 是空的**:返工全靠 journal 的 `note` 记录 ⇒ 可追溯,但**不可机器统计**(想统计「这个包返工了几次」目前只能人读)。 6. **手工 `.bak` 混进流程产物目录**:四个仓库里共 **8 个** `*.journal.jsonl.bak`(甲 4 · 乙 2 · 丁 2)。实例那边后来把 `.bak` 移出了版本库 —— 值得照做。 7. **孤儿产物**:丁的 `prd/` 里留着 `WKL-001.journal.jsonl.bak`(19 KB)+ `.meta.json`,但**主件与非 `.bak` 的 journal 都不在了** ⇒ 审计会看到「有 meta 没有 journal」。这也说明丁**立过包**,只是被手工拆散了。 ## 7. 四个可数指标(都能机器核验) | 指标 | 怎么算 | 四个自用仓库 | 实例(AI 托管) | 它不衡量什么 | | --- | --- | --- | --- | --- | | **包收口率** | `status: done` 且 `gate4: approved` 的包 / 有主件可读的包 | **1 / 3 ≈ 33%** | **1 / 2**(第二个包刚起步) | 不衡量「做得好不好」,只衡量流程有没有走到底 | | **门禁证据密度** | journal 里带**非空 `exitCode`** 的 `run` 条数 / `approve` 条数 | **0 / 9 = 0** | **38 / 5 ≈ 7.6**(该仓库仍在推进,数字会涨) | 不衡量测试写得多不多;低就说明「跑过什么」还是自述 | | **批准来源可分辨** | 带 `via` 字段的 `approve` / 全部 `approve` | **0 / 9 = 0** | **5 / 5 = 100%** | 不衡量谁签得对;低就说明「谁签的」只能靠读自然语言 | | **人签等待占比** | Gate 从「交件」到「人签」的时长 / 全链路跨度 | **14.3h / 17.9h ≈ 80%** | 0(无人可等) | **不衡量 agent 快不快** —— 它只告诉你瓶颈在人什么时候来 | ## 8. 上马建议(按「最小代价跑通一次」排序) 1. **最小可用配置**:`PROJECT.md` 只需要 §1(产物清单)+ §2(命令槽)+ §3(产物属主表)。**§3 不填,落点门禁直接 `exit 1`** —— 这是新手第一个坎。§3 里**别忘给主控开状态位那一条**(否则「Gate 落状态位」这条规则无法满足,判据 ⑫ 还会把主控误判成越界)。 2. **先拿一个小而真的包试水**,别挑最大的需求。目标不是交付,是**走完一次 Gate0→Gate4**,把四个停点各体验一遍。 3. **开跑前做一次同版本自检**:`diff <插件包>/scaffold/README.md docs/process/README.md`。实测出现过差 120 行的骨架(流程口径互相矛盾);不一致就先 `process_init({ upgrade: true, dryRun: true })` 看会动哪些文件,再落地。门禁脚本是**项目自带副本**,插件升级不会自动改它们。 4. **每次 Gate 后顺手看一眼**状态位与 journal 尾部(`process_status` / `gate_summary`),别攒着看 —— 攒着就会像乙那样停在等 Gate1,而没人知道。 5. **门禁命令要记 `action:"run"` + 真实 `exitCode`**(0.5.0 起):Gate 摘要能自动列出「exit 0 ✓ / exit 非零 🚨」,发布前扫一眼就知道缺口在哪。用老版本工具写会被**静默丢弃**,别再踩。 6. **返工落 `bugs/`,别只写 journal note**(否则 §6.5 那种「统计不出来」会复现)。 7. **停自己起的实例别用宽匹配 `pkill -f`**:按 PID / 精确端口停。实测踩到过 —— 宽匹配命中了托管在固定端口的交付物本体(托管实例被 SIGTERM、exit 143),而「交付物还在不在」正是后续验收的前提。误杀了要如实上报,别自行重启掩盖。 ## 复算方法(都不需要装插件) ```bash # 一次算完 §7 的口径(纯 python3,无依赖)—— 在每个仓库里各跑一次;跨仓库合计见 §7 表 python3 - <<'EOF' import glob,json,os from datetime import datetime pkgs=[] for f in sorted(glob.glob('docs/process/prd/*.md')): n=os.path.basename(f) if n.startswith('_'): continue p=open(f,encoding='utf-8').read().split('---') if len(p)<3: continue d=dict(l.split(':',1) for l in p[1].split('\n') if ':' in l and not l.startswith((' ','\t'))) if (d.get('id') or '').strip()!=n[:-3]: continue # 主件 = 文件名词干等于 frontmatter id pkgs.append((n[:-3],{k:(d.get(k) or '').strip() for k in ('status','gate1','gate2','gate4','prdVersion')})) print('包:',pkgs or '(无)') runs=apps=ec=via=0; waits=[] for f in glob.glob('docs/process/prd/*.journal.jsonl'): last_w=None for l in open(f,encoding='utf-8'): if not l.strip(): continue e=json.loads(l) if e.get('action')=='write': last_w=e.get('at') if e.get('action')=='run': runs+=1; ec+= e.get('exitCode') is not None if e.get('action')=='approve': apps+=1; via+= bool(e.get('via')) if last_w: waits.append((datetime.fromisoformat(e['at'].replace('Z','+00:00'))-datetime.fromisoformat(last_w.replace('Z','+00:00'))).total_seconds()/3600) print(f'run {runs}(带退出码 {ec})· approve {apps}(带 via {via})') print('交件→批准的最大等待(小时):',round(max(waits),2) if waits else 'n/a') print('收口率:',sum(1 for _,d in pkgs if d.get('status')=='done' and d.get('gate4')=='approved'),'/',len(pkgs)) EOF ``` 契约字段与退出码口径见 [CONTRACT.md](./CONTRACT.md);一条完整链路的核验脚本见 [ACCEPTANCE.md](./ACCEPTANCE.md);实例侧的一次端到端验收记录见 [dsh-process-kit-example](https://github.com/SHADOW-LI0327/dsh-process-kit-example)。 > **这份快照会过期**:它是 2026-10-15 的实测,仓库在继续推进(甲的 FEAT-002 在等 Gate4、实例的 FEAT-002 刚起步)。看数字时请连同日期一起看;采集方法写在上面,可自行复算。