sillyspec 3.29.3 → 3.29.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/asset-audit-2026-09-20/README.md +42 -0
  2. package/asset-audit-2026-09-20/asset-audit.cjs +253 -0
  3. package/asset-audit-2026-09-20/extract-candidates.cjs +37 -0
  4. package/asset-audit-2026-09-20/platform-archive.csv +294 -0
  5. package/asset-audit-2026-09-20/platform-fr.csv +12 -0
  6. package/asset-audit-2026-09-20/platform-gotchas.csv +6 -0
  7. package/asset-audit-2026-09-20/platform-knownissues.csv +23 -0
  8. package/asset-audit-2026-09-20/platform-modules.csv +222 -0
  9. package/asset-audit-2026-09-20/platform-quicklog.csv +1076 -0
  10. package/asset-audit-2026-09-20/platform-troubleshooting-candidates.csv +88 -0
  11. package/asset-audit-2026-09-20/platform-troubleshooting.csv +1 -0
  12. package/asset-audit-2026-09-20/sillyspec-archive.csv +108 -0
  13. package/asset-audit-2026-09-20/sillyspec-fr.csv +51 -0
  14. package/asset-audit-2026-09-20/sillyspec-gotchas.csv +4 -0
  15. package/asset-audit-2026-09-20/sillyspec-knownissues.csv +34 -0
  16. package/asset-audit-2026-09-20/sillyspec-modules.csv +30 -0
  17. package/asset-audit-2026-09-20/sillyspec-quicklog.csv +460 -0
  18. package/asset-audit-2026-09-20/sillyspec-troubleshooting.csv +69 -0
  19. package/asset-audit-2026-09-20/summary.json +241 -0
  20. package/assets/command-cards/run-archive.md +26 -0
  21. package/assets/command-cards/run-brainstorm.md +33 -0
  22. package/assets/command-cards/run-execute.md +29 -0
  23. package/assets/command-cards/run-plan.md +27 -0
  24. package/assets/command-cards/run-quick.md +34 -0
  25. package/assets/command-cards/run-verify.md +29 -0
  26. package/assets/command-cards/status.md +27 -0
  27. package/package.json +1 -1
  28. package/round4/account.mjs +85 -0
  29. package/round4/brief-autocompact.md +34 -0
  30. package/round4/brief-session-replay.md +50 -0
  31. package/round4/deep-read-synthesis.md +38 -0
  32. package/round4/extract-full.mjs +38 -0
  33. package/round4/extract-timeline.mjs +43 -0
  34. package/round4/find-sessions.mjs +13 -0
  35. package/round4/full-r4-l.md +4707 -0
  36. package/round4/full-r4-o-l.md +4300 -0
  37. package/round4/full-r4-os.md +1681 -0
  38. package/round4/full-r4-sf.md +4255 -0
  39. package/round4/full-r4-sq.md +1734 -0
  40. package/round4/gate-audit-relay-receipt.md +30 -0
  41. package/round4/gate-value-audit.md +52 -0
  42. package/round4/prereg.md +67 -0
  43. package/round4/prompt-R4-L.md +63 -0
  44. package/round4/prompt-R4-O-L.md +59 -0
  45. package/round4/prompt-R4-O-S.md +56 -0
  46. package/round4/prompt-R4-S-F.md +60 -0
  47. package/round4/prompt-R4-S-Q.md +66 -0
  48. package/round4/r4-os-timeline.txt +297 -0
  49. package/round4/r4-sf-timeline.txt +738 -0
  50. package/round4/r4-sq-timeline.txt +322 -0
  51. package/round4/r4l-timeline.txt +793 -0
  52. package/round4/r4ol-timeline.txt +729 -0
  53. package/round4/r4sf-timeline.txt +852 -0
  54. package/round4/result-S.md +171 -0
  55. package/round4/result-final.md +46 -0
  56. package/round4/result-quality.md +63 -0
  57. package/src/command-cards.js +73 -0
  58. package/src/contract-matrix.js +26 -5
  59. package/src/cross-repo-reconcile.js +232 -46
  60. package/src/diagnostic-codes.js +2 -1
  61. package/src/fr-index.js +58 -2
  62. package/src/index.js +35 -8
  63. package/src/init.js +25 -8
  64. package/src/machine-interface.js +88 -3
  65. package/src/module-impact.js +51 -22
  66. package/src/run/bg-sync.js +231 -0
  67. package/src/run/command.js +4 -0
  68. package/src/run/complete-handlers.js +244 -6
  69. package/src/run/complete.js +6 -3
  70. package/src/run/gate-snapshot.js +10 -4
  71. package/src/run/gates.js +124 -42
  72. package/src/run/prompt.js +1 -1
  73. package/src/run/quick-audit.js +28 -2
  74. package/src/run/shared.js +35 -1
  75. package/src/scope-audit.js +303 -20
  76. package/src/stages/execute.js +2 -2
  77. package/src/stages/plan-postcheck.js +33 -19
  78. package/src/stages/quick.js +2 -0
  79. package/src/sync.js +12 -0
  80. package/src/taskcard-frontmatter.js +57 -0
  81. package/src/verify-postcheck.js +68 -6
  82. package/src/verify-probes.js +45 -23
@@ -0,0 +1,171 @@
1
+ # R4 小任务对撞结果:R4-S-Q(sillyspec quick 3.29.4)vs R4-O-S(OpenSpec 1.13.1)
2
+
3
+ > 同任务(claude autocompact 三键)、同基线 50736b6ef、同机同模型、全新本地 zcode 会话、零子代理。
4
+ > 会话:R4-S-Q = sess_3c71e652(标题「R4 对照实验:autocompact 小任务 sillyspec quick 通道」,用户手起标题 `R4 ` 带空格致 `R4-` LIKE 漏配,按 id 补归);R4-O-S = sess_b818b681。
5
+
6
+ ## 硬账(zcode db,epoch-ms 数值比较)
7
+
8
+ | 指标 | R4-S-Q sillyspec quick | R4-O-S OpenSpec | 比 |
9
+ |---|---|---|---|
10
+ | 墙钟(创建→最后活动) | **41.2min** | **21.5min** | 1.92× |
11
+ | 请求 数 | 87 | 85 | ≈平 |
12
+ | tokens(computed_total) | **8.97M** | 9.33M | sillyspec 略优 |
13
+ | model-time(Σduration) | 13.3min | 13.1min | 平 |
14
+ | 子代理 | 0 | 0 | 平 |
15
+ | 模型利用率(model-time/墙钟) | 32% | 61% | 差在空闲 |
16
+
17
+ **墙钟差 19.7min ≈ 非模型时间差**(27.9 vs 8.4min)——模型算力完全同量级,差距全在本地命令等待。
18
+
19
+ ## 非模型时间去向(R4-S-Q 账面证据)
20
+
21
+ 1. quick --done 门禁**隔离快照全量测试 545.5s(9.1min)**(quicklog 结果段自述 + 提交信息双证)
22
+ 2. 全仓 lint 门(ruff check/format 1288 文件 + mypy 963 文件)——且因全仓口径被存量 format 债卡住,agent 被迫**顺手清偿两文件范围外 ruff 债**才过门
23
+ 3. 定向测试(daemon 31/31 + 相邻 93/93、frontend 35/35 + 相邻 46/46)+ 新工作树依赖安装
24
+
25
+ ## 预注册判定(prereg.md H4/H6)
26
+
27
+ - H6 墙钟 ≤20min:**FAIL**(41.2min)
28
+ - H6 --done 一次过零返工:**PASS**(steps 零 wait_round、门禁双 PASS 一次过)
29
+ - H4 quick 资产尾:**FAIL——CLI 缺陷,非 agent 违令**(细读更正:db 原始命令实证两次 `--done` 均带 `--linked-changes 2026-09-20-r4-linked-parent`)。两个独立缺陷:①②见「细读补正」节。
30
+
31
+ ## 意外发现:第 3 轮 OpenSpec 参照值是 fork 污染值
32
+
33
+ OpenSpec 全新会话实测 **9.33M**,第 3 轮参照「33.3M」是 **fork 继承胖上下文**(该跑 db 标题「Fork of …」实证)——**3.6× 虚高**。真实对比下两边 token 成本几乎相同;此前「OpenSpec 小任务更费 token」的印象不成立。sillyspec quick 8.97M 也只有第 3 轮 sillyspec 全流程 17.2M 的一半。
34
+
35
+ ## 质量面(非对称交付)
36
+
37
+ - sillyspec:隔离快照全量 + 定向 31/35 + 相邻 139 例 + 双侧 tsc + lint 全绿;资产落盘(quicklog 四参数结构化条目 + patch 双件 + 模块文档增量段 + 范围快照 sha256 锚定)
38
+ - OpenSpec:自愿跑测试 27/27 + 32/32(无门禁强制);规格库合入 5 requirement + archive
39
+
40
+ ## 结论与下一刀
41
+
42
+ 轻通道的「省 token」目标已达成(与 OpenSpec 持平且略优、较自家全流程减半);剩余墙钟差距是**机制级可修的**:quick --done 门禁的测试/lint 范围化(按 touched-files 定范围或信任 agent 定向实测 + 差量校验),预计可砍 10–15min 墙钟——这是 3.29.5 的明确候选工作项。
43
+
44
+ ## 细读补正(2026-09-21,逐条从会话正文/原始命令核出)
45
+
46
+ ### 更正记录
47
+
48
+ 前版「agent 未按提示词声明 --linked-changes」为**误判**:db 原始 Bash 命令显示两次 --done(首跑 22:29 与 lint 债修复后重跑 22:35)均带 `--linked-changes 2026-09-20-r4-linked-parent`。agent 行为完全合规。
49
+
50
+ ### 新发现的 CLI 缺陷(3.29.4,均 R4-S-Q 实证)
51
+
52
+ **缺陷 A(② changelog 边车死路)**:会话控制台实录 `⚠️ [资产尾] changelog 追加异常(fail-open):loadQuickModuleIndex is not a function`。源码定位:`src/run/shared.js:1294` 的 `loadQuickModuleIndex` 是内部函数**缺 `export`**,`complete-handlers.js:1430` 动态 import 解构得 undefined → 调用即 TypeError → fail-open 吞掉。§7 单测没抓到是因为直接模拟 join 语义、没走真实 import。
53
+
54
+ **缺陷 B(① 蒸馏尾未触发 + quicklog「关联变更:(无)」同根)**:tail 块读 `mergedGuard?.linkedChanges`,但 `--linked-changes` 在 --done 时解析后未并入该结构(manualLinked 空列表 → distill 干净跳过、零警告);quicklog 条目的关联变更字段渲染源同链。flag→guard 的接线断点需在修复任务中定位(command.js:645-666 解析后进入完成路径的通道缺失)。
55
+
56
+ ### 墙钟 41.2min 的精确分解(时间线实测)
57
+
58
+ | 阶段 | 时间 | 内容 |
59
+ |---|---|---|
60
+ | 0–1.6m | 1.6min | 引导+身份+CLAUDE.md;**worktree 守卫摩擦 3 次失败**后才用 `--allow-worktree-cwd --spec-dir` 放行 |
61
+ | 1.6–6.3m | 4.7min | Step1 理解:读码 + **5 次联网核键名**(precomputeCompactionEnabled 官方文档实证,任务简报未给键名) |
62
+ | 7.2–16.2m | 9.0min | 实现+定向测试全绿(daemon 31/31+相邻 93/93、前端 35/35+相邻 46/46、双侧 tsc、lint 基线对照)+ 依赖安装 + 模块文档增量 |
63
+ | 16.2–26.1m | 9.9min | **--done #1**:隔离快照全量测试 545.5s + lint → **被 2 个未触碰的存量 ruff format 债文件拦下** |
64
+ | 26.1–28.3m | 2.2min | agent 清偿范围外存量债 + 边界重声明 |
65
+ | 28.3–39.0m | 10.7min | **--done #2**:门禁全量重跑(test 539.3s + lint 62.7s)→ PASS |
66
+ | 39.0–41.2m | 2.2min | quicklog 核对 + 显式 pathspec 提交 + 报告 |
67
+
68
+ **门禁双跑 ≈ 20.7min,占墙钟一半**。其中第二跑对纯 lint 修复重跑全部测试是纯浪费(~9min);首跑被存量债拦截是 lint 全仓口径的结构问题。CLAUDE.md 规则 0(禁全量测试、留给 CI)与门禁的模块全量口径直接矛盾——工具门禁违反了仓规。
69
+
70
+ ### OpenSpec 侧行为细读(21.5min 分解)
71
+
72
+ - 0–3.5m 引导:init 即生成 `.zcode/commands/opsx/*` 流程说明书(propose/apply/archive),agent 读模板即上手——**工具自带教学**;
73
+ - 3.5–7.0m 只读探索(与 sillyspec 同量);
74
+ - 7.3–9.8m proposal 阶段:CLI 脚手架+instructions 模板引导,agent 写四件套(proposal/specs delta/design/tasks 8 任务),strict 校验过;
75
+ - 10.1–19.7m apply:8 任务推进,**前端依赖后台安装与表单编辑并行**(墙钟并行度);测试 3 轮修复迭代(2 处 esbuild 语法 + 1 处选择器逻辑);daemon 27/27 + 前端 32/32 定向绿;
76
+ - 20.0–21.1m archive:CLI 把 delta 合入活规格(5 requirement)+ 提交。
77
+ - **零强制门禁**:agent 自选验证深度(比 sillyspec 少 7 个新测试用例、不跑 lint、不清存量债、不跑全量回归);键名**未联网核验**(凭先验写 precomputeCompactionEnabled,碰巧对——sillyspec 花了 2.5min 实证)。
78
+
79
+ ### 质量不对称的本质
80
+
81
+ sillyspec 的 20.7min 门禁买到:模块级全量回归×2、全仓 lint、强制清偿存量债、22 个新测试。OpenSpec 买到:15 个新测试 + 自愿 typecheck。差距不是「sillyspec 浪费」而是**质量执行深度 2× 于对手**——但当前实现里约 11min(第二跑全量测试 + 存量债拦截处理)是可消除的纯损耗,且模块全量口径违反仓规(规则 0)。
82
+
83
+ ### 3.29.5 候选工作项(按 ROI 排序)
84
+
85
+ 1. **门禁增量复用**:纯 lint 失败重试时跳过测试重跑(按树 hash 缓存测试结论)——省 ~9min;
86
+ 2. **lint 范围化**:quick 门禁 lint 限 touched-files(或存量债基线快照豁免)——消除范围外拦截与「顺手清债」连带;
87
+ 3. **缺陷 A 修复**:shared.js:1294 补 export + 用真实 import 的回归测试;
88
+ 4. **缺陷 B 修复**:--linked-changes → mergedGuard.linkedChanges 接线 + quicklog 关联变更字段同修;
89
+ 5. 测试口径与 CLAUDE.md 规则 0 对齐(模块全量→touched 模块,全量留 CI)。
90
+
91
+ # R4 大任务+小任务全流程结果(2026-09-21 终态核算)
92
+
93
+ ## 硬账总表(五跑全终态,zcode db epoch-ms 口径)
94
+
95
+ | 跑 | 墙钟 | 请求 | tokens | 子代理 | 终态 |
96
+ |---|---|---|---|---|---|
97
+ | R4-L sillyspec 大·全流程 | 184.5min | 767 | 99.07M | 19 | 归档 01:14 verify PASS |
98
+ | R4-O-L OpenSpec 大 | 79.8min | 251 | 52.00M | 0 | archive 23:53(17 Requirement) |
99
+ | R4-S-F sillyspec 小·全流程 | 170.2min | 298 | 53.64M | 2 | 归档 01:00 |
100
+ | R4-S-Q sillyspec 小·quick | 41.2min | 87 | 8.97M | 0 | 已析(前节) |
101
+ | R4-O-S OpenSpec 小 | 21.3min | 85 | 9.33M | 0 | 已析(前节) |
102
+
103
+ 对照臂:大任务旧 sillyspec 重做 269min/681req/104.13M/12 子代(Fork 续跑);OpenSpec 旧跑 177.8min/288req/80.03M(同为 Fork)——**fork 污染双向坐实:OpenSpec 全新会话 79.8min/52M,比它自己的 fork 跑快 2.2×、省 35% token**。
104
+
105
+ ## 预注册判定(prereg.md)
106
+
107
+ - **H1 大任务墙钟 ≤150min:FAIL**(184.5min;较对照臂 269min 降 31%;vs OpenSpec 同条件 2.3×)
108
+ - **H2 机制五点:5/5 全中 → PASS**
109
+ - a 波次并发:15:22 双并发、15:34 **四并发**实证(对照第 3 轮全串行——拓扑守卫生效)
110
+ - b 无假红循环:无「同 gate 无变化重试」旧病(PASS);但见「新病」——隔离快照 lint 环境差异无诊断线索(见新发现)
111
+ - c verify 批量补完:batch completion 生效(R4-S-F 61.4m 实录"batch completion kicked in")
112
+ - d 审查请求钳(四律):设计 11/12 ✓、计划 6/10 ✓、QA 6/15 ✓——**三阶段全达标**
113
+ - e plan 零卡片填充子代理:19 个子代全是调研/取证/审查/实现,无 TaskCard 生成器 ✓
114
+ - **H3 提示词级可靠性:PASS**——四律请求钳本次被遵守(单样本,不可外推为「已解决」)
115
+ - **H5 小任务全流程 ≤30min:FAIL**(170.2min;分解见下)
116
+
117
+ ## R4-S-F 170min 去向(时间线分解)
118
+
119
+ 1. 0–61min:brainstorm+plan+execute 五任务(两个 batch 子代理,实现与测试全绿)——**净仪式+实现成本约 60min**
120
+ 2. 67.5–97.3min:**额度中断 ~30min**(会话被限额卡停,用户"继续,额度已恢复")
121
+ 3. 69–141min:**verify 隔离快照 lint 法证 ~70min**——CLI 实测隔离快照根在临时目录:mypy/ruff 缓存全冷(每次 --done 全速重跑 ~7min)+ known_failures 豁免环境差异 → agent 侧复现恒绿、门禁恒红,agent 被迫做缓存 mtime 考古 + WAL db 探测定位(131.2m "FOUND IT")
122
+ 4. 141–170min:module-impact 死信回填 + 槽格式学习 + archive
123
+
124
+ **剔除额度中断与快照法证后净成本 ~60-70min**——仍超 39.5min 旧臂(服务器侧条件不可比),但数量级合理。
125
+
126
+ ## 新发现(本轮最大 actionable)
127
+
128
+ **verify 隔离快照的 lint 环境差**:快照根(%TEMP%)无 mypy/ruff 缓存、known_failures 豁免随行性存疑 → 门禁失败无诊断线索,fresh agent 花 70min 法证。修法候选:①快照 lint 失败输出一行诊断(快照根路径+「与工作区差异可能原因:缓存冷/豁免不随行」);②快照复用工作区 lint 缓存目录;③lint 结论按树 hash 缓存(ROADMAP 已登记的 parity 增量缓存同族)。
129
+
130
+ ## 结论
131
+
132
+ - **结构性修复全部生效**(波次并发/审查钳/批量补完/零填卡/无假红——H2 5/5),token 效率大任务 99M vs 旧 104M(fork 臂不可比,OpenSpec fresh 52M 仍是 1.9×——子代理架构的固有税)
133
+ - **剩余墙钟差距的三块**:①额度中断(环境非工具);②隔离快照 lint 法证(工具缺陷,可修);③严格档槽格式学习曲线(fresh agent 每次重付——流程命令卡的 verify 卡应预载槽格式要点,2026-09-21-flow-command-cards 的 run-verify 卡已有此意,可强化)
134
+ - 产品级判断:小任务路由 quick(41min)正确;全流程通道的修复方向已从「结构」转移到「门禁环境差诊断」与「槽格式先验」
135
+
136
+ ## 五会话细读分析(2026-09-21 补)
137
+
138
+ ### 交付物对照(大任务,分支内 diff,排除 spec 产物)
139
+
140
+ | | R4-L sillyspec | R4-O-L OpenSpec |
141
+ |---|---|---|
142
+ | 代码文件/插入 | 24 文件 / 7241 行 | 25 文件 / 3396 行 |
143
+ | 其中测试 | 2909 行(40%) | 1193 行(35%) |
144
+ | 提交数 | 15 | 5 |
145
+ | 审查面 | 13 task review.json + 3 阶段独立审查 | schema-only strict validate |
146
+
147
+ ### 关键出入(可比性)
148
+
149
+ **三个大跑撞了同一个 5h 额度墙**:R4-O-L 74.5m、R4-S-F 97.3m、R4-L 97.5m 各有一次「继续,额度已恢复」——恢复时延取决于用户何时看到(O-L 仅 ~3.5min,S-F ~30min,L 未知)。**所有墙钟绝对值被污染,趋势方向可信**。
150
+
151
+ ### OpenSpec 快的解剖(79.8min)
152
+
153
+ 0–19m 探查(含 4 个真实数据探针脚本:zcode sqlite part.data/cursor transcript ×3,96 份样本实证格式)→ 19–22m proposal 四件套+strict validate+提交(3min)→ 22–43m daemon(自测 129 绿,6 轮小修)→ 43–57m backend(20 绿+gen:types)→ 57–71m 前端+测试 → 74–79 archive。**单上下文 251 请求零子代理、零外部门禁、所有验证自跑即时反馈(vitest 13s/pytest 17s)、archive 1min 机械合并**。
154
+
155
+ ### sillyspec 慢的解剖(184.5min,含额度中断)
156
+
157
+ 0–14m 三调研子代理并发 → 14:30 取证 → 14:50–15:07 设计+计划审查串行(11+6 req,均达标)→ 15:22–16:52 execute 五波(2/4/2/2/1 并发,编排者波间 TaskOutput 阻塞)→ 其余为 verify/archive 的槽格式学习(module-impact 缺失重建、step --done 不推进 ×2、结论枚举/探针 7 矩阵/死信回填)。
158
+
159
+ ### 慢的归因排序(可修性)
160
+
161
+ 1. **子代理重序列化税**(token 1.9× 主因)——架构固有,缩法:execute 子代理 prompt 瘦身(只给 task 卡+模块摘要不给全量上下文)
162
+ 2. **隔离快照 lint 冷缓存法证**(S-F 70min)——可修(诊断行/缓存随行)
163
+ 3. **槽格式学习曲线**(每 fresh agent 重付 ~20min)——可修(run-verify 卡强化)
164
+ 4. **编排者波间空闲**(execute 90min 中编排者大多在等)——可修(波间做 verify 前置准备)
165
+ 5. 审查串行 ~17min——已钳住,量小
166
+
167
+ ### 别的问题
168
+
169
+ - TodoWrite reminder 噪声:R4-O-L 26 条系统提醒纯 token 浪费(harness 层,非工具账)
170
+ - OpenSpec 质量下限依赖 agent 自觉:本跑 agent 勤奋(真实探针+129 测试)但无独立审查面——若遇懒 agent 无兜底
171
+ - R4-S-F 的 brainstorm+plan 仪式(0–38m)与其实现(38–61m)等长——小任务走全流程的仪式/实现比 ≈1:1,路由 quick 正确
@@ -0,0 +1,46 @@
1
+ # R4 对照实验·终局核算(2026-09-21,五跑全终态)
2
+
3
+ ## 终表(全部本地 zcode 新会话、同机同模型)
4
+
5
+ | 跑 | 工具/通道 | 墙钟 | 合计请求 | 合计 tokens | 子代理 | 终态 |
6
+ |---|---|---|---|---|---|---|
7
+ | R4-L | sillyspec 3.29.4 大任务全流程 | **185min** | 767 | 99.1M | 19 | verify PASS + archived |
8
+ | R4-O-L | OpenSpec 1.13.1 大任务 | **80min** | 251 | 52.0M | 0 | archived |
9
+ | R4-S-F | sillyspec 全流程(小任务) | **171min** | 298 | 53.6M | 2 | archived |
10
+ | R4-S-Q | sillyspec quick(小任务) | 41.2min | 87 | 8.97M | 0 | --done 落账 |
11
+ | R4-O-S | OpenSpec(小任务) | 21.5min | 85 | 9.33M | 0 | archived |
12
+
13
+ ## 预注册判定(H1–H6 收口)
14
+
15
+ | # | 假设 | 判定 | 证据 |
16
+ |---|---|---|---|
17
+ | H1 | 大任务墙钟 ≤150min | **FAIL** | 185min(vs 老版 269min 降 31%,但超线 23%) |
18
+ | H2 | 机制 ≥3/5 生效 | **PASS(4/5 确认)** | 见下 |
19
+ | H3 | 提示词级四律可靠 | **PASS(本跑)** | 审查钳 3/3 阶段达标:Design Grill 11req(≤12)/ plan 6req(≤10)/ QA 6req(≤15)——四律首次实证能被遵守 |
20
+ | H4 | quick 资产尾 | **FAIL** | CLI 缺陷 A(export 缺失)+ B(--linked-changes 管道断),已列修 |
21
+ | H5 | 小任务全流程 ≤30min | **FAIL** | 171min,其中 ≥3 轮全量门禁循环(存量债→advisory→死信逐层暴露) |
22
+ | H6 | 小任务 quick ≤20min | 墙钟 **FAIL**(41.2)/ 一次过 **PASS** | 零等待轮零返工 |
23
+
24
+ ## H2 机制点明细(R4-L 19 个子会话时间窗实证)
25
+
26
+ - **波次并发 ✅**:Wave1 两个实现子代理 72~81min 并行;Wave2 四个实现子代理 85~95min 并行(3.29.3 拓扑守卫生效的直接证据)
27
+ - **无假红循环 ✅**:工作树 friction-tally 零 gate_rollback、verify 一次过(review_rejected×3 属 S2 审查正常否决)
28
+ - **审查请求钳 ✅**:三阶段 11/6/6,全部在 12/10/15 帽内
29
+ - **零卡片填充子代理 ✅**:19 子 = 3 只读调研 + 1 取证 + 2 审查 + 12 实现 + 1 QA,无 TaskCard 生成器(第 3 轮的老病灶消失)
30
+ - 批量补完:未单独确认(verify 163~185min 含门禁,一次通过)
31
+
32
+ ## R4-L 的 185min 分解(子会话窗口)
33
+
34
+ 引导+brainstorm 调研 0–20(3 调研代理并发)→ 四件套+原型 20–40 → 设计审查+计划审查 40–57(合计仅 17min,四律生效)→ 计划定稿 57–72 → **execute 72–162(90min,6 波,波内并发)** → verify+归档 163–185。
35
+
36
+ ## 三层对比结论
37
+
38
+ 1. **纵向**(修复前后):大任务 269→185min(-31%)、tokens 104→99M(平);小任务全流程表面 39.5→171 恶化,但 39.5 是服务器侧+fork 条件不可比,171 是门禁病理特异值(非正常流)。
39
+ 2. **横向**(同条件对撞):大任务 sillyspec/OpenSpec = 墙钟 2.3×、tokens 1.9×、请求 3.1×;小任务 = 墙钟 1.9×、tokens 0.96×(持平)。**fork 混杂再次证实**:OpenSpec 大任务全新会话 80min/52M vs 第 3 轮 fork 跑 177.8min/80M(fork 虚高 ~2×)。
40
+ 3. **机制层**:全部主要结构修复在真实运行中生效(串行波→并发、审查失控→钳内、填卡子代理→零、假红→零)。**墙钟未同比例改善的原因**:(a) 子代理扇出的固有成本——19 个子会话重读上下文吃掉 42.3M/522req(占总 tokens 43%/总请求 68%);(b) 门禁病理(R4-S-F 171min 几乎全是门禁循环);(c) ceremony 总厚度。
41
+
42
+ ## 后续(已在办)
43
+
44
+ - 门禁三件套 + 缺陷 A/B + 模块粒度范围化(已安排,gate-value-audit.md 拍板 touched-modules 粒度)
45
+ - 3.29.5 发版后 R5 小任务 ×2 重放验收(同基线、2 跑取分布)
46
+ - 子代理扇出的 token 倍增是产品定位问题(质量换成本),不是缺陷——是否优化(如实现子代理共享预载上下文)待单独立项评估
@@ -0,0 +1,63 @@
1
+ # R4 代码质量与项目资产对比(2026-09-21)
2
+
3
+ ## 一、小任务(autocompact):一个决定性的质量分野
4
+
5
+ 两侧 daemon 白名单实现**工艺等价**(同构值守护:window 正整数 + 开关布尔、坏键不拖累同批、非法静默跳过;注释都引了各自的设计决策号)。分歧在**域事实**:
6
+
7
+ | | sillyspec(R4-S-Q) | OpenSpec(R4-O-S) |
8
+ |---|---|---|
9
+ | 第三键名 | `precomputeCompactionEnabled` | `autoCompactPreCompute` |
10
+ | 依据 | 5 次联网核验官方文档(settings reference + /config) | 凭先验,零核验 |
11
+ | 交叉验证 | 与第 3 轮主仓独立实现(c1ce37e9e,同样经文档核验)一致 | 与两轮独立核验**都不一致** |
12
+
13
+ **OpenSpec 侧是错键:第三个开关(预计算)在生产是 no-op。** 其 27/27 测试全绿(断言的是自己写的错键)、干净归档——单测验证的是实现自洽,不能发现域事实错误;无任何门禁对外部真值复核。sillyspec 多花的 2.5 分钟联网核验,就是这道防线。
14
+
15
+ 前端行为差异(都合理):sillyspec 坏值静默不进提交体;OpenSpec 即时校验 + alert 拦提交。
16
+
17
+ ## 二、大任务(session-replay):范围对齐、测试体量 2.4×
18
+
19
+ - 范围:两侧都交付解析器矩阵(claude-code / cursor-agent / zcode model-io / zcode-sqlite)+ AgentReplayBody 回放主体,提案成功标准覆盖对齐。
20
+ - 测试:sillyspec 2,909 行 vs OpenSpec 1,193 行(回放主体 806 vs 380 行测试)。
21
+ - 行数差(18,126 vs 3,999)主要来自生成物(api-types/gen)与文档,**不作为质量依据**。
22
+
23
+ ## 三、项目资产盘点(大任务终态实录)
24
+
25
+ **sillyspec**(归档提交触达):
26
+ - 变更归档 15 件(四件套 + plan/tasks + decisions + module/symbol-impact + verify-facts/result + scope-audit + 原型)
27
+ - **决策提炼 4 条**入 `knowledge/decisions/unmapped.md`(+36 行)
28
+ - **FR 索引 7 条**入 `knowledge/fr/host-fs-handler.md`(+73 行)+ INDEX
29
+ - **ROADMAP 里程碑** + 模块文档增量(daemon.md / platform_sync.md)
30
+
31
+ **OpenSpec**:
32
+ - 归档变更夹 + **活规格库 3 个 capability**(agent-log-messages-schema / parsers / session-replay,215 行 WHEN/SHALL 契约)
33
+
34
+ 两种资产形态不同但都是真可检索资产:sillyspec 是「决策 + FR + 路线图」(按域索引的特性真相),OpenSpec 是「活规格」(按能力组织的行为契约,后续变更以 delta 修改)。
35
+
36
+ **资产的正确性风险不对称**:OpenSpec 小任务的活规格把**错键写进了 5 条 requirement**——错误被典藏为权威事实,后续变更信任并传播它。sillyspec 的 FR 来自文档核验后的 requirements。
37
+
38
+ ## 四、结论
39
+
40
+ 1. 工艺层面(代码风格/守护逻辑/测试写法)两侧**无可观差距**——LLM 同源,写代码不是分歧点。
41
+ 2. 分歧点在**认识论**:域事实要不要对外部真值核验。本轮唯一一个硬缺陷(错键 no-op)恰好出在无核验侧,且被其全绿测试和干净归档完美掩盖。
42
+ 3. sillyspec 的结构价值在这轮得到具体化:联网核验习惯(agent 行为,部分归功流程提示词的「实证」文化)+ 门禁对外部口径的复核对这类缺陷是防线;OpenSpec 的「赋能不门禁」在域事实类错误上无防线。
43
+ 4. 局限:错键是 n=1 的硬案例;「sillyspec 的流程必然导致核验」不成立(R4-O-S 侧的核验缺失是 agent 行为方差,第 3 轮 OpenSpec 跑也可能核验)。可防御的表述是:**门禁+实证文化提供的是概率性防线,OpenSpec 连概率都不提供**。
44
+
45
+ ## 五、补遗(2026-09-21):R4-L 审查链实际拦下的东西(非随机实例)
46
+
47
+ - **Design Grill 首轮 REJECT(阻断项 B1)**:初版设计把 cursor-agent-store 读取器注册进 registry——审查员独立核了源码事实(registry 契约为 content 字符串,registry.ts:53-56;zcode SQLite 恰是绕过 registry 的 handler 专用分支先例),判定设计自相矛盾,强制改为专用分发分支 + `~/.cursor/chats/` 目录门(design.md:49-50 落地)。**这是代码写出来之前拦下的集成级缺陷**——不拦的话 cursor-agent 解析链路接错调度面,集成期才爆,返工一轮。
48
+ - G1(三态枚举补 409,对照 router.py 真实行为)、G2(命名口径统一)两条非阻断同轮闭合。
49
+ - **QA 终审独立复跑全部测试**(daemon 165/165 + backend 247 + frontend 46/46,6 个请求内完成)并做了四跳字段契约核对(daemon→RPC→backend→api-types→前端逐层比对)。
50
+ - 对照组:OpenSpec 全流程无任何独立审查环节,B1 类设计-源码矛盾无人核。
51
+
52
+ ## 六、质量差距的诚实总结(回应「是不是就一个小概率事件」)
53
+
54
+ 四条防线、每条都有本周实证,全部属于「没有该机制就必然带病落盘」类别:
55
+
56
+ | 防线 | 机制 | 本周实例 | OpenSpec 对应物 |
57
+ |---|---|---|---|
58
+ | 域事实核验 | 实证文化+流程提示词 | 错键(R4-O-S 生产 no-op) | **无**(n=1 但防线是结构性的:流程里没有任何核验步骤) |
59
+ | 设计-源码一致性 | 独立 Design Grill | B1(R4-L,改设计于写码前) | 无 |
60
+ | 声明-现实对账 | 测试门禁 | 主仓 2 个月 12 次真拦(gate-value-audit) | 无(pre-commit 只查格式) |
61
+ | 资产正典正确性 | 文档同步义务+FR 实证来源 | 规格库典藏错键(对照侧) vs sillyspec FR 经核验 | 无 |
62
+
63
+ 同时如实记录防线的漏检面:sillyspec 自己的缺陷 A/B(export 缺失/管道断)25 个单测+S2 审查都没拦住,是靠 R4 实测暴露的——**仪式是概率盾,本样本内拦 3 漏 2**。
@@ -0,0 +1,73 @@
1
+ // 流程命令卡注入器(2026-09-21-flow-command-cards)——init 按 --tools 把包内
2
+ // assets/command-cards/*.md 落到工具命令目录(zcode/claude),尾部锚行三态幂等。
3
+ // 基准(Grill P1-3 修订):锚行记录「剥离锚行后的落盘正文 sha」,重跑剥离重算比对
4
+ // ——检测的是用户手改正文;「锚行 vs 包资产」字面比对检测不到正文手改(已否决)。
5
+ import { readdirSync, readFileSync, mkdirSync } from 'fs'
6
+ import { join } from 'path'
7
+ import { fileURLToPath } from 'url'
8
+ import { createHash } from 'crypto'
9
+ import { writeAtomicSync } from './fs-atomic.js'
10
+
11
+ export const COMMAND_CARD_TARGETS = { zcode: '.zcode/commands/sillyspec', claude: '.claude/commands/sillyspec' }
12
+ export const COMMAND_CARD_NAMES = ['run-brainstorm', 'run-plan', 'run-execute', 'run-verify', 'run-archive', 'run-quick', 'status']
13
+
14
+ const ANCHOR_TAIL_RE = /\n?<!-- sillyspec-card: v(\S+) sha256=([0-9a-f]{64}) -->\s*$/
15
+ const sha256 = (s) => createHash('sha256').update(s, 'utf8').digest('hex')
16
+ // 尾换行对称归一(首版 bug 实证:锚行正则 \n? 吞掉正文末换行,重算侧 replace(/\s+$/,'\n')
17
+ // 对无尾随空白的串是 no-op 换行补不回 → 完好文件恒判「手改」。先全剥尾随空白再统一补单个 \n,
18
+ // 两侧(资产读取/落盘重解析)同函数 → 对称。
19
+ const canonical = (raw) => raw.replace(/\r\n/g, '\n').replace(/\s+$/, '') + '\n'
20
+
21
+ /** 读包内卡资产(import.meta.url 相对——npm 全局安装/本地 checkout 双形态同源)。 */
22
+ export function readCardAssets() {
23
+ const dir = fileURLToPath(new URL('../assets/command-cards/', import.meta.url))
24
+ const assets = new Map()
25
+ for (const f of readdirSync(dir).filter((x) => x.endsWith('.md')).sort()) {
26
+ assets.set(f.replace(/\.md$/, ''), canonical(readFileSync(join(dir, f), 'utf8')))
27
+ }
28
+ return assets
29
+ }
30
+
31
+ /**
32
+ * 三态四分支注入(判据源唯一=尾部锚行;frontmatter 不承载管理面):
33
+ * 1 目标不存在 → 写(正文+锚行)
34
+ * 2 锚行在且剥离重算正文 sha 一致(完好):与包资产一致 → no-op(mtime 不动);不一致(CLI 更新)→ 覆盖
35
+ * 3 锚行缺失(外来同名文件)或重算 sha 不符(用户手改正文)→ warn 跳过,force 才覆盖
36
+ * @returns {Promise<{written:string[], updated:string[], skipped:string[], warnings:string[]}>}(元素为相对目标目录的卡名)
37
+ */
38
+ export async function injectCommandCards(projectDir, { tools = [], force = false, version = '' } = {}) {
39
+ const written = [], updated = [], skipped = [], warnings = []
40
+ const assets = readCardAssets()
41
+ if (assets.size === 0) {
42
+ warnings.push('包内 assets/command-cards/ 为空——npm 发布是否漏 assets/(白屏防线:npm pack --dry-run | grep assets/command-cards)')
43
+ return { written, updated, skipped, warnings }
44
+ }
45
+ for (const name of COMMAND_CARD_NAMES) {
46
+ if (!assets.has(name)) warnings.push(`资产缺失:${name}.md 不在包内 assets/command-cards/`)
47
+ }
48
+ for (const tool of [...new Set(tools)].filter((t) => COMMAND_CARD_TARGETS[t])) {
49
+ const dir = join(projectDir, COMMAND_CARD_TARGETS[tool])
50
+ mkdirSync(dir, { recursive: true })
51
+ for (const [name, body] of assets) {
52
+ const file = join(dir, `${name}.md`)
53
+ const out = `${body}<!-- sillyspec-card: v${version} sha256=${sha256(body)} -->\n`
54
+ let landed = null
55
+ try { landed = readFileSync(file, 'utf8') } catch { /* 不存在走分支 1 */ }
56
+ if (landed === null) { writeAtomicSync(file, out); written.push(name); continue }
57
+ const m = landed.match(ANCHOR_TAIL_RE)
58
+ if (!m) {
59
+ if (force) { writeAtomicSync(file, out); updated.push(name); warnings.push(`${tool}/${name}:外来同名文件被 --force 覆盖`) }
60
+ else { skipped.push(name); warnings.push(`${tool}/${name}:无锚行(外来同名文件),跳过——确认后删它重跑 init 或 --force`) }
61
+ continue
62
+ }
63
+ const bodyNow = canonical(landed.slice(0, m.index))
64
+ if (sha256(bodyNow) === m[2]) {
65
+ if (bodyNow === body) { skipped.push(name); continue } // 完好且同资产:no-op(mtime 不动)
66
+ writeAtomicSync(file, out); updated.push(name); continue // 完好且新资产:版本更新
67
+ }
68
+ if (force) { writeAtomicSync(file, out); updated.push(name); warnings.push(`${tool}/${name}:手改正文被 --force 覆盖(原改动已丢)`) }
69
+ else { skipped.push(name); warnings.push(`${tool}/${name}:正文与锚行记录不符(用户手改),跳过——保留改动;--force 可覆盖`) }
70
+ }
71
+ }
72
+ return { written, updated, skipped, warnings }
73
+ }
@@ -542,11 +542,16 @@ export function verifyApiParity(specBase, scanRoot, runtimeRoot, changeName = nu
542
542
  // worktree,scanRoot(主仓 cwd)里是旧版本——读旧版会漏新调用/多已删调用。
543
543
  let frontendCalls = []
544
544
  let frontendScope = 'full-repo'
545
+ // 变更文件面一次解析两用(quick-C,2026-09-20 报告问题 C):前端调用收窄 + unused 分层的
546
+ // change-relevant 判定共消费;解析失败 → null(前端回退全仓、分层回退 artifact 口径)
547
+ const parityChanged = changeName
548
+ ? (() => { try { return _resolveDiffFilesForParity(specBase, scanRoot, changeName, runtimeRoot) } catch { return null } })()
549
+ : null
545
550
  const frontendRoot = (wt && wt.gitDir !== scanRoot) ? wt.gitDir : scanRoot
546
551
  const frontendRootLabel = frontendRoot === scanRoot ? 'scan-root' : 'worktree'
547
552
  if (changeName) {
548
553
  try {
549
- const changed = _resolveDiffFilesForParity(specBase, scanRoot, changeName, runtimeRoot)
554
+ const changed = parityChanged
550
555
  if (changed && changed.length > 0) {
551
556
  const changedSet = new Set(changed.map(f => f.replace(/\\/g, '/')))
552
557
  frontendCalls = scanFrontendApiCalls(frontendRoot).filter(c => {
@@ -647,12 +652,28 @@ export function verifyApiParity(specBase, scanRoot, runtimeRoot, changeName = nu
647
652
  return liveKeys.has(key) || liveEndpoints.length === 0
648
653
  })
649
654
  // unused 分层(坑 probe5-unused-stock-noise,2026-09-15 EHS 生产实证:490 个 unused 全是
650
- // urgent 等他模块存量端点——全仓 live 扫描 × 本变更对账的口径噪音刷屏)。本变更相关 =
651
- // contract artifact 端点集内(本变更换的端点漏配才是真信号);存量其余折叠计数。无
652
- // artifact(非契约流)回退全列零回归。
655
+ // urgent 等他模块存量端点——全仓 live 扫描 × 本变更对账的口径噪音刷屏)。本变更相关判定
656
+ // 两级(quick-C,2026-09-20 报告问题 C:artifact 集口径被整仓 baseline 击穿——execute 起点
657
+ // 拍的全仓端点基线让 artifactKeys ⊇ 全仓、418 存量端点全误标「本变更端点前端未调用」):
658
+ // ①有变更文件面(_resolveDiffFilesForParity 同款链,前端收窄复用同一次解析)→ 判「端点定义
659
+ // 源文件 ∈ 本变更 diff 面」(源串反斜杠归一 + artifact 任务目录前缀形态,双向 endsWith——
660
+ // 与前端调用收窄同款匹配);
661
+ // ②面不可得(CLI contractScan 无 changeName / diff 兜底链全空)→ 回退 artifact 端点集口径;
662
+ // ③无 artifact(非契约流)→ 回退全列零回归。
653
663
  const artifactKeys = new Set(allProviderEndpoints.map(e => `${e.method} ${e.path}`))
654
664
  const hasArtifacts = allProviderEndpoints.length > 0
655
- const unusedChangeRelevant = hasArtifacts ? narrowedUnused.filter(u => artifactKeys.has(`${u.method} ${u.path}`)) : narrowedUnused
665
+ const unusedChangeRelevant = parityChanged && parityChanged.length > 0
666
+ ? narrowedUnused.filter(u => {
667
+ // diffApiParity 的 unused 项定义源字段是 providerFile(endpoint-extractor.js:492),
668
+ // 兼容直调方可能给的 source 形态
669
+ const src = String(u.providerFile || u.source || '').replace(/\\/g, '/')
670
+ if (!src) return false
671
+ return parityChanged.some(cf => {
672
+ const c = String(cf).replace(/\\/g, '/')
673
+ return src === c || src.endsWith('/' + c) || c.endsWith('/' + src) || src.endsWith(c) || c.endsWith(src)
674
+ })
675
+ })
676
+ : (hasArtifacts ? narrowedUnused.filter(u => artifactKeys.has(`${u.method} ${u.path}`)) : narrowedUnused)
656
677
  const unusedStockCount = narrowedUnused.length - unusedChangeRelevant.length
657
678
 
658
679
  const ok = missingBackend.length === 0