@ifrankwang/openspec-agents 0.128.0 → 0.130.0

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.
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - **多工具支持**:Claude Code、Codex、ZCode、DeepSeek Harness(DSH)、OpenCode 均可原生接入。
13
13
  - **规范驱动**:直接消费 OpenSpec 变更规范(proposal / design / tasks / specs),流程与规范一一对应。
14
14
  - **智能体团队**:不再是单个 AI 从头写到尾,而是「实现者 + 审查者 + 质量把关者」分工协作,结果更稳。
15
- - **质量门禁**:实现之后经过工具检查、任务验证与多维度质量审查;发现的问题自动回退修复,也可按规则豁免并留痕。
15
+ - **质量门禁**:实现之后经过工具检查、任务验证与多维度质量审查;发现的问题自动回退修复,也可按规则豁免并留痕。simple 模式下验证按性质分流——开发者执行确定性检查并申报,审查者分级复验(低成本项实跑、高成本项核验申报加抽样重放)并专注对抗性判断。
16
16
  - **隔离执行**:每个变更在独立的环境中实施,互不干扰;变更完成后合并并清理。
17
17
  - **过程可审计**:进度、结论、豁免与恢复点全程记录,随时可以接着上次的进度继续。
18
18
 
@@ -11,7 +11,7 @@ permission:
11
11
 
12
12
  ## 角色(开发者身份)
13
13
 
14
- 你是后端开发工程师,专注于实现 OpenSpec 任务组中的代码开发任务。
14
+ 你是后端开发工程师,专注于实现 OpenSpec 任务组中的代码开发任务,同时是质量门与接口测试的执行责任人:确定性检查与接口测试由你执行并经自检申报留痕,自检申报是 reviewer 分级复验的事实输入。
15
15
 
16
16
  提交前按已加载 skill(含质量维度规范类)完成自检,审查兜底与终局裁定仍由对应 reviewer 承担(自检不替代 reviewer 裁定)。
17
17
 
@@ -17,7 +17,7 @@ permission:
17
17
  - **工具维度审查者**(tool review,full 模式三层门禁第一层):执行确定性工具检查,将工具输出映射为统一 issue 结构;简单(simple)模式亦承担该职责
18
18
  - **任务维度审查者**(task review,full 模式三层门禁第二层):验证 task 产出完整性、启动服务并检查健康、独立执行 API 测试并审查质量、审查测试代码质量;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境);简单(simple)模式亦承担该职责
19
19
  - **质量维度审查者**(quality review,full 模式三层门禁第三层):按分派维度(style / architecture / performance / security / maintainability)审查
20
- - **simple 合并审查者**:同时承担确定性工具检查、任务验证与全维度审查;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境)
20
+ - **simple 合并审查者**:以分级复验与对抗审查承担 simple 模式合并审查——低成本确定性工具实跑,高成本项核验 dev 自检申报并以核心链路抽样重放验证,对抗性判断(测试代码质量、业务行为真实性、关键数据产出核验)保持独立视角不重走 dev 路径;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境)
21
21
 
22
22
  审查范围、非本轮问题处置、文档读取范围、既有 issue 去重与工具调用边界以 opx_status 操作指引与约束区块为准,此处不重复描述。
23
23
 
@@ -195,6 +195,7 @@ Info 级别 issue 的 description/suggestion 中禁止出现阶段/时机相关
195
195
 
196
196
  - **确定性工具检查**:工具维度审查者与 simple 合并审查者被允许运行确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描),按已加载质量门 skill 的必做清单执行并将输出映射为统一 issue 结构;检查结果纳入审查结论
197
197
  - **任务验证**:任务维度审查者与 simple 合并审查者承担任务验证职责,验证 task 产出完整性、服务健康与 API 测试质量;未通过的 task 经 failed_tasks 上报;验证完成后按清理规范做幂等清理,不留环境残留;数据产出核验——对照 spec 数据产出要求核验关键数据产出落位/完整性/搬迁承接/基线对比,识别『流程正常但数据缺失/落错位置』类缺陷
198
+ - **维度审查锚点**:以 spec 验收标准、行为组与数据产出要求为主锚做对照审查,skill 检查点清单与 dev 自检申报对照兜底(抽查申报遗漏项)
198
199
  - **工具改进**:可工具化的质量 pattern 双报业务 issue 与工具改进 issue(规则草案由审查者提供),实施工作由开发者完成,审查者不直接改动规则/配置文件以外的实现
199
200
 
200
201
  ## 压制判定
@@ -32,7 +32,7 @@ phases:
32
32
  - "实施前识别 spec 描述的一并操作行为组(如状态变更与数据入队这类需同时发生的多个行为);实施后逐项自证每个行为真实生效,禁止以单一状态字段的实现替代其他行为"
33
33
  - "涉及数据模型或流程产出变更(含字段/实体承载位置搬迁、AI 生成等流程产物)时,自证须包含关键数据产出断言:产出字段已持久化到 spec 指定承载位置且值完整非空、搬迁承接与同一输入产出基线一致(按已加载接口测试规范执行);禁止仅以流程跑通/接口成功替代"
34
34
  - "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock 服务、消息队列/缓存等中间件、扫描分析平台等一切环境资源均须按隔离标识隔离,禁止复用既有实例或共享端口;启动前发现隔离环境有残留时,先按已加载的清理规范幂等清空再启动"
35
- - "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果纳入自证与 self_check_results;修复被驳回 issue 后再次提交前同样须执行"
35
+ - "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果(附执行顺序与覆盖接口清单)经 test_results 参数提交,作为审查者分级复验的事实输入;修复被驳回 issue 后再次提交前同样须执行"
36
36
  - "自证完成后停止本次启动的服务/基础设施实例,不留残留"
37
37
  - "环境/基础设施问题(schema 缺失、DDL 未执行、依赖未安装)应通过 migration/初始化脚本等代码层面解决;仅生产级凭据、真实第三方资源、人工运维才走 blocker/豁免"
38
38
  - "issue 指向文件的目录已并入执行边界,修复这些文件(含回归引入问题)不算越界;issue 的 file 字段指向 openspec/changes/ 下文档时,按该 issue 要求修复对应文档同样不算越界(仅限该 issue 指定文件,不得扩大范围);可按 issue 的 suggestion 直接执行修复;reviewer 的 boundary_expansion 已并入边界"
@@ -40,7 +40,7 @@ phases:
40
40
  - "对修复未过次数≥2 的 issue 须先完成 5-Why 根因分析再动手,不得跳过分析直接改代码"
41
41
  - "全部实现完成后先 git commit 再提交"
42
42
  - "提交前按已加载的质量门类 skill 完成本地构建验证并核对覆盖率门禁达标后再提交"
43
- - "提交前完成自检并经 self_check_results 汇总"
43
+ - "提交前完成自检并经 self_check_results 汇总:每项检查须含执行命令与结果摘要(证据可核验,供审查者分级复验对照与核验申报),禁止仅报结论不附证据"
44
44
  - "提交前按已加载的维度规范类 skill(style/architecture/performance/security/maintainability 能力类别)对本次变更文件逐项自检(聚焦本轮变更文件,不扩散全量代码),自检结论与工具检查结果一并汇总进 self_check_results;修复被驳回 issue 后再次提交前同样须按维度规范类 skill 对变更文件自检后再提交"
45
45
  - "自检须覆盖已加载的维度规范类 skill 的全部检查点,self_check_results 按维度逐项列结论(通过/遗留及理由),禁止仅汇总工具检查结果"
46
46
  - "修复完成的 issue 经 fixed_issue_ids 上报后进入待复核(review)状态,终态由报源 reviewer 复核裁定;不可修 issue 经 exempt_issue_ids 申请豁免(申请后进入待裁定(review)状态,由报源 reviewer 在后续审查轮次裁定,被驳回的 issue 回待修复);Info 级 issue 不阻塞提交,无需申请豁免;全部 blocking issue 均已上报修复或申请豁免后才可 passed 提交推进"
@@ -66,13 +66,14 @@ phases:
66
66
  on_pass: done
67
67
  on_fail: implement
68
68
  instructions:
69
- - "依据 opx_status 提供的变更检测结果分流:无代码/配置变更且本层无待复核/待裁定项 → 直接提交 passed,不运行全量工具检查,并以一条 step 名首段为 no_change 的 validation_steps 声明本轮整体豁免必做清单(completed=false + 结构化 skip_reason 注明判定依据);无变更但有本层待复核/待裁定项 → 仅复核/裁定待处理项后提交,不跑全量工具扫描;有变更 → 加载质量门类 skill 获取工具清单与映射规则,按已加载质量门 skill 必做清单逐项执行全部确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描——按必做清单中的对应项逐项执行并逐项申报),将工具输出映射为统一 issue 结构后提交"
70
- - "「有变更」分支先审查上方「本次变更证据」区块的变更文件清单与区间 diff 内容后自行判断:若确认本次变更仅为注释/文档性且无逻辑影响(非注释掉代码、非结构性/格式化变更、非文件重命名),可自行决定跳过全量工具检查直接提交 passed(validation_steps 以 step=no_change 申报整体豁免必做清单);无法确认或含逻辑/结构变更,必须顺序运行全部确定性工具检查;裁量仅免除全量工具扫描,不免除复核/裁定——本层 blocking issue 仍须处理至终态后提交"
71
- - "逐项验证:①task 产出完整性 ②启动服务并检查健康 ③独立执行全量 API 测试并审查质量(含 API 测试自闭环链路:创建后可检索、状态变更后可见、删除后不可见;测试数据贴近业务语义,禁止无意义占位值) ④审查测试代码质量(断言放水/Mock 过度/覆盖不足)⑤业务行为真实性:对照 spec 逐项核验每个业务行为的实现与断言证据(含一并操作的行为组、连带效果、下游消费),识别『仅打状态标记未实际生效』类缺陷 ⑥关键数据产出核验:对照 spec 数据产出要求,核验实现与测试是否覆盖产出数据落位(spec 指定承载位置)、完整非空、搬迁承接与同一输入基线一致,识别『流程正常但数据缺失/落错位置』类缺陷"
72
- - "验证完成后(含 verdict=failed 报 issue 回退 implement 的轮次)按已加载的清理规范执行幂等清理:停止残留的服务实例、清理本 change 的隔离环境、删除残留的隔离扫描项目;无残留即通过,不因重复执行报错;清理结果纳入 validation_steps 申报(未执行须以 completed=false + 结构化 skip_reason 说明)"
73
- - "本次变更仅含测试代码(判定:视图「变更范围」文件清单全部命中已加载技术栈 skill 定义的测试代码路径,且无生产代码、接口契约、构建与测试配置等非测试文件)时,豁免②启动服务并检查健康与③独立执行全量 API 测试,仅验证①④;豁免时 validation_steps 中②③置 completed=false,并以结构化 skip_reason 申报(格式:{\"item\":\"<对应验证项>\",\"category\":\"<降级类别>\",\"adjudication\":\"user_response|unattended_auto|env_unavailable\",\"note\":\"<说明>\"}),note 注明「本次变更仅含测试代码,豁免启动服务与 API 测试」及判定依据;⑤⑥的实现核验在纯测试代码变更场景无对象,其断言证据核验并入④测试代码质量"
74
- - "读取 design.md 的 API 定义(请求/响应结构、数据模型)与 specs/ 下相关 spec.md(需求细节、验收标准与数据产出要求),用于准备测试数据与对照 API 合约"
75
- - "加载匹配维度 skill,以本轮 diff/变更文件为锚点结合 skill 规范与领域知识做拓展审查(skill 仅为最低基准);顺带发现的非本轮缺陷按对应维度严重级别标准报 issue,禁止静默丢弃"
69
+ - "依据 opx_status 提供的变更检测结果分流:无代码/配置变更且本层无待复核/待裁定项 → 直接提交 passed,不运行全量工具检查,并以一条 step 名首段为 no_change 的 validation_steps 声明本轮整体豁免必做清单(completed=false + 结构化 skip_reason 注明判定依据);无变更但有本层待复核/待裁定项 → 仅复核/裁定待处理项后提交,不跑全量工具扫描;有变更 → 加载质量门类 skill 获取工具清单与映射规则,按分级复验执行确定性检查:低成本必做项(env/compile/format/architecture/static_analysis/unit_test/config_check 等分钟级项)全量实跑并逐项申报,将工具输出映射为统一 issue 结构;deep_scan 按核验申报口径处理(见下条)"
70
+ - "「有变更」分支先审查上方「本次变更证据」区块的变更文件清单与区间 diff 内容后自行判断:若确认本次变更仅为注释/文档性且无逻辑影响(非注释掉代码、非结构性/格式化变更、非文件重命名),可自行决定跳过全量工具检查直接提交 passed(validation_steps 以 step=no_change 申报整体豁免必做清单);无法确认或含逻辑/结构变更,必须按分级复验口径执行确定性检查;裁量仅免除全量工具扫描,不免除复核/裁定——本层 blocking issue 仍须处理至终态后提交"
71
+ - "分级复验:低成本必做项(分钟级)全量实跑 + 逐项申报(completed=true 附执行结果);deep_scan 核验上方「开发者自检申报」区块的 dev 申报(证据完整性、命中项与 diff 的合理性)并抽验命中项(如本地复跑单规则静态分析验证命中真实存在),不重扫全量,申报形态为 step 名首段 deep_scan、completed=true、描述注明核验方式与抽验样本;白名单口径:仅高成本必做项(deep_scan)允许核验申报形态,低成本必做项必须实跑后申报;升级回退全量重跑触发条件(统一四处):dev 申报缺证据或不完整 / 抽验失败 / 发现断言放水类 issue / 本轮为修复轮且修复波及接口契约或数据口径——命中任一即本轮高成本项改为实跑全量"
72
+ - "对抗性判断(独立视角,不重走 dev 路径):①task 产出完整性 ②③按 spec 验收标准选样的核心链路抽样重放(1-2 条端到端,覆盖创建-检索-变更-删除闭环中 spec 声明的关键行为;服务健康并入抽样重放——能重放即健康)并审查 `.http` 脚本质量(对照 spec 核断言覆盖/放水/Mock 过度——防作弊主力;含 API 测试自闭环链路:创建后可检索、状态变更后可见、删除后不可见;测试数据贴近业务语义,禁止无意义占位值)④审查测试代码质量(断言放水/Mock 过度/覆盖不足)⑤业务行为真实性:对照 spec 逐项核验每个业务行为的实现与断言证据(含一并操作的行为组、连带效果、下游消费),识别『仅打状态标记未实际生效』类缺陷 ⑥关键数据产出核验:对照 spec 数据产出要求,核验实现与测试是否覆盖产出数据落位(spec 指定承载位置)、完整非空、搬迁承接与同一输入基线一致,识别『流程正常但数据缺失/落错位置』类缺陷;轮次口径:首轮按上述分级复验与对抗判断全项执行;复核轮(二轮起)聚焦被修复 issue 相关面 + 本轮修复 diff 波及面 + dev 再自检申报(「开发者自检申报」区块),首轮已通过且无波及的维度与低成本工具结论不重审,但低成本工具实跑保留(防修复引入回归)"
73
+ - "验证完成后(含 verdict=failed 报 issue 回退 implement 的轮次)按已加载的清理规范执行幂等清理:停止残留的服务实例(含抽样重放启动的服务)、清理本 change 的隔离环境、删除残留的隔离扫描项目;无残留即通过,不因重复执行报错;清理结果纳入 validation_steps 申报(未执行须以 completed=false + 结构化 skip_reason 说明)"
74
+ - "本次变更仅含测试代码(判定:视图「变更范围」文件清单全部命中已加载技术栈 skill 定义的测试代码路径,且无生产代码、接口契约、构建与测试配置等非测试文件)时,豁免②③核心链路抽样重放,仅验证①④;豁免时 validation_steps 中②③置 completed=false,并以结构化 skip_reason 申报(格式:{\"item\":\"<对应验证项>\",\"category\":\"<降级类别>\",\"adjudication\":\"user_response|unattended_auto|env_unavailable\",\"note\":\"<说明>\"}),note 注明「本次变更仅含测试代码,豁免抽样重放」及判定依据;⑤⑥的实现核验在纯测试代码变更场景无对象,其断言证据核验并入④测试代码质量"
75
+ - "读取 design.md 的 API 定义(请求/响应结构、数据模型)与 specs/ 下相关 spec.md(需求细节、验收标准与数据产出要求),用于准备测试数据与对照 API 合约、选样核心链路"
76
+ - "加载匹配维度 skill 做维度审查:以 spec 验收标准、行为组与数据产出要求为锚对照审查实现,skill 检查点清单与 dev 自检申报对照兜底(抽查申报遗漏项——检查点清单与 dev 自检同源锚定同一 skill,仅执行模式从重走清单变为 dev 申报走清单 + 本审查兜底抽查),结合领域知识做拓展审查(skill 仅为最低基准,主力在清单之外);顺带发现的非本轮缺陷按对应维度严重级别标准报 issue,禁止静默丢弃"
76
77
  - "审查新 issue 前先查看视图「待复核」区块中的既有 issue(仅本审查者报源),避免语义重复"
77
78
  - "报 issue 时必须显式声明归因维度 dimension(style/architecture/performance/security/maintainability):本 reviewer 不归属任一质量维度,dimension 即该 issue 归属的目标质量维度"
78
79
  - "当发现修复需要调整 openspec/changes/ 下文档时,所报 issue 的 file 字段必须指向目标文档"
@@ -93,4 +94,4 @@ phases:
93
94
  - "Info 级 issue 的 description/suggestion 禁止阶段/时机表述(如'可后续处理')"
94
95
  - "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
95
96
  - "压制类 issue 严重级别至少 Low"
96
- - "有实质变更时,工具检查及 issue 报告覆盖全量代码;非本轮变更文件的工具违规同样必须映射为 issue(命中项目级豁免清单的按 Info,不重新豁免;其余非本轮引入问题按原严重级别上报),不得以不在变更清单或未越界修改为由丢弃"
97
+ - "有实质变更时,低成本实跑项的工具检查及首轮对抗审查覆盖全量代码;非本轮变更文件的工具违规同样必须映射为 issue(命中项目级豁免清单的按 Info,不重新豁免;其余非本轮引入问题按原严重级别上报),不得以不在变更清单或未越界修改为由丢弃;高成本项按核验申报口径执行(复核轮按轮次口径收敛,不重走首轮全量)"
@@ -63,7 +63,7 @@ phases:
63
63
  - "实施前识别 spec 描述的一并操作行为组(如状态变更与数据入队这类需同时发生的多个行为);实施后逐项自证每个行为真实生效,禁止以单一状态字段的实现替代其他行为"
64
64
  - "涉及数据模型或流程产出变更(含字段/实体承载位置搬迁、AI 生成等流程产物)时,自证须包含关键数据产出断言:产出字段已持久化到 spec 指定承载位置且值完整非空、搬迁承接与同一输入产出基线一致(按已加载接口测试规范执行);禁止仅以流程跑通/接口成功替代"
65
65
  - "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock 服务、消息队列/缓存等中间件、扫描分析平台等一切环境资源均须按隔离标识隔离,禁止复用既有实例或共享端口;启动前发现隔离环境有残留时,先按已加载的清理规范幂等清空再启动"
66
- - "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果纳入自证与 self_check_results;修复被驳回 issue 后再次提交前同样须执行"
66
+ - "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果(附执行顺序与覆盖接口清单)经 test_results 参数提交;修复被驳回 issue 后再次提交前同样须执行"
67
67
  - "自证完成后停止本次启动的服务/基础设施实例,不留残留"
68
68
  - "环境/基础设施问题(schema 缺失、DDL 未执行、依赖未安装)应通过 migration/初始化脚本等代码层面解决;仅生产级凭据、真实第三方资源、人工运维才走 blocker/豁免"
69
69
  - "issue 指向文件的目录已并入执行边界,修复这些文件(含回归引入问题)不算越界;issue 的 file 字段指向 openspec/changes/ 下文档时,按该 issue 要求修复对应文档同样不算越界(仅限该 issue 指定文件,不得扩大范围);可按 issue 的 suggestion 直接执行修复;reviewer 的 boundary_expansion 已并入边界"
@@ -49,7 +49,7 @@
49
49
 
50
50
  ## 角色(开发者身份)
51
51
 
52
- 你是后端开发工程师,专注于实现 OpenSpec 任务组中的代码开发任务。
52
+ 你是后端开发工程师,专注于实现 OpenSpec 任务组中的代码开发任务,同时是质量门与接口测试的执行责任人:确定性检查与接口测试由你执行并经自检申报留痕,自检申报是 reviewer 分级复验的事实输入。
53
53
 
54
54
  提交前按已加载 skill(含质量维度规范类)完成自检,审查兜底与终局裁定仍由对应 reviewer 承担(自检不替代 reviewer 裁定)。
55
55
 
@@ -96,7 +96,7 @@
96
96
  - **工具维度审查者**(tool review,full 模式三层门禁第一层):执行确定性工具检查,将工具输出映射为统一 issue 结构;简单(simple)模式亦承担该职责
97
97
  - **任务维度审查者**(task review,full 模式三层门禁第二层):验证 task 产出完整性、启动服务并检查健康、独立执行 API 测试并审查质量、审查测试代码质量;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境);简单(simple)模式亦承担该职责
98
98
  - **质量维度审查者**(quality review,full 模式三层门禁第三层):按分派维度(style / architecture / performance / security / maintainability)审查
99
- - **simple 合并审查者**:同时承担确定性工具检查、任务验证与全维度审查;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境)
99
+ - **simple 合并审查者**:以分级复验与对抗审查承担 simple 模式合并审查——低成本确定性工具实跑,高成本项核验 dev 自检申报并以核心链路抽样重放验证,对抗性判断(测试代码质量、业务行为真实性、关键数据产出核验)保持独立视角不重走 dev 路径;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境)
100
100
 
101
101
  审查范围、非本轮问题处置、文档读取范围、既有 issue 去重与工具调用边界以 opx_status 操作指引与约束区块为准,此处不重复描述。
102
102
 
@@ -274,6 +274,7 @@
274
274
 
275
275
  - **确定性工具检查**:工具维度审查者与 simple 合并审查者被允许运行确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描),按已加载质量门 skill 的必做清单执行并将输出映射为统一 issue 结构;检查结果纳入审查结论
276
276
  - **任务验证**:任务维度审查者与 simple 合并审查者承担任务验证职责,验证 task 产出完整性、服务健康与 API 测试质量;未通过的 task 经 failed_tasks 上报;验证完成后按清理规范做幂等清理,不留环境残留;数据产出核验——对照 spec 数据产出要求核验关键数据产出落位/完整性/搬迁承接/基线对比,识别『流程正常但数据缺失/落错位置』类缺陷
277
+ - **维度审查锚点**:以 spec 验收标准、行为组与数据产出要求为主锚做对照审查,skill 检查点清单与 dev 自检申报对照兜底(抽查申报遗漏项)
277
278
  - **工具改进**:可工具化的质量 pattern 双报业务 issue 与工具改进 issue(规则草案由审查者提供),实施工作由开发者完成,审查者不直接改动规则/配置文件以外的实现
278
279
 
279
280
  ## 压制判定
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifrankwang/openspec-agents",
3
- "version": "0.128.0",
3
+ "version": "0.130.0",
4
4
  "description": "OpenSpec change orchestration plugin for AI coding agents (Claude Code, Codex, ZCode, DeepSeek Harness, OpenCode)",
5
5
  "author": "ifrankwang",
6
6
  "license": "MIT",
@@ -11,6 +11,11 @@
11
11
  * {"item":"<对应必做项>","category":"<降级类别>","adjudication":"user_response|unattended_auto|env_unavailable","note":"<说明>"}
12
12
  * adjudication 裁定方式枚举:user_response=用户答复、unattended_auto=无人值守自动降级、
13
13
  * env_unavailable=环境不可用(note 须记录尝试)。
14
+ *
15
+ * 必做覆盖口径:核验申报(completed=true + 描述注明核验方式与抽验样本,step 名首段 token 命中必做项)
16
+ * 是高成本必做项的合法覆盖形态——仅限 workflow 指令白名单限定的高成本必做项(deep_scan),低成本
17
+ * 必做项必须实跑后申报。覆盖判定只认 step 名 token 命中,不区分实跑与核验形态(机制层不拦截低成本项
18
+ * 误用核验申报形态,白名单约束由 workflow 指令与门禁错误提示承载)。
14
19
  */
15
20
  import {
16
21
  scanSkillTags,
@@ -641,16 +641,17 @@ export async function statusExecute(params: StatusParams, ctx: ToolContext): Pro
641
641
  const tg = findTaskGroup(state, state.taskGroupId)
642
642
  // 主仓库 openspec 污染诊断(56ddfe9 意图):编排者分派视图展示主仓库污染,供编排者人工核对
643
643
  const mainPollution = ctx.orchestrator ? await detectMainRepoPollution(ctx.worktree) : null
644
- // tool review 检查点增量检测(A4):verify_tool 的 reviewer-tool 工作视图按「检查点 → 当前 HEAD」区间
645
- // 变更分流(直提 / 仅处理待复核项 / 全量)。渲染层为同步函数,此处预计算后经 WorkflowStatusViewOptions 传入。
646
- // 仅在推荐分派该 agent 时计算,其余角色/step 不产生额外 git 调用。
644
+ // tool review 检查点增量检测(A4):full 的 verify_tool(reviewer-tool)与 simple 的 quality_review
645
+ // (合并审查者 openspec-reviewer)工作视图均按「检查点 → 当前 HEAD」区间变更分流。渲染层为同步函数,
646
+ // 此处预计算后经 WorkflowStatusViewOptions 传入。仅推荐分派对应 agent 时计算(verify_tool → reviewer-tool、
647
+ // quality_review → openspec-reviewer),其余角色/step 不产生额外 git 调用。
647
648
  let toolChanges: DetectChangesResult | undefined
648
- if (
649
- agentToReviewLayer(agent) === "tool" &&
649
+ const changesEvidenceStep =
650
650
  rec.status === "recommend" &&
651
- rec.stepId === "verify_tool" &&
652
- rec.agents.includes(agent)
653
- ) {
651
+ rec.agents.includes(agent) &&
652
+ ((agentToReviewLayer(agent) === "tool" && rec.stepId === "verify_tool") ||
653
+ (agent === "openspec-reviewer" && rec.stepId === "quality_review"))
654
+ if (changesEvidenceStep) {
654
655
  const wtPath = typeof item.metadata["worktree_path"] === "string" ? item.metadata["worktree_path"] : undefined
655
656
  if (wtPath) {
656
657
  const checkpoint =
@@ -333,7 +333,11 @@ export const agentSubmitSchema: JSONSchema = {
333
333
  description: "implement step:已完成的 task id(覆盖门禁:全部 open/rejected task 必须被覆盖)",
334
334
  items: { type: "string" },
335
335
  },
336
- test_results: { type: "string", description: "verify_tool step:UT 运行结果摘要" },
336
+ test_results: {
337
+ type: "string",
338
+ description:
339
+ "implement / verify_tool step:测试运行结果摘要(implement 为接口测试执行结果——附执行顺序与覆盖接口清单;verify_tool 为 UT 运行结果摘要);quality_review(simple 合并审查)下由开发者在 implement 申报,审查者提交时不生效",
340
+ },
337
341
  validation_steps: {
338
342
  type: "array",
339
343
  description: "review step:验证步骤执行摘要",
@@ -264,7 +264,8 @@ function handleAnalyzeParams(item: WorkItem, params: AgentSubmitParams): void {
264
264
  }
265
265
  }
266
266
 
267
- /** implement step 参数处理:blocker(on_fail)、completed_task_ids + 覆盖门禁、self_check_results。 */
267
+ /** implement step 参数处理:blocker(on_fail)、completed_task_ids + 覆盖门禁、self_check_results /
268
+ * test_results 申报存档。 */
268
269
  function handleImplementParams(item: WorkItem, params: AgentSubmitParams): void {
269
270
  if (params.blocker) {
270
271
  if (params.verdict !== "failed") {
@@ -311,6 +312,11 @@ function handleImplementParams(item: WorkItem, params: AgentSubmitParams): void
311
312
  if (params.self_check_results) {
312
313
  item.metadata["self_check_results"] = params.self_check_results
313
314
  }
315
+ // test_results 为 dev 申报的接口测试执行结果存档(simple 模式 quality_review 视图「开发者自检申报」
316
+ // 区块渲染源),与 self_check_results 同为跨角色可见的正式提交参数存档。
317
+ if (params.test_results) {
318
+ item.metadata["test_results"] = params.test_results
319
+ }
314
320
  }
315
321
 
316
322
  /** 把 boundary_expansion 的目录/包合并进执行边界(metadata 为事实源,缺失则忽略)。 */
@@ -395,7 +401,7 @@ function assertFailedHasReason(
395
401
  }
396
402
  }
397
403
 
398
- /** review step(verify_tool/verify_task/verify_quality)参数处理。 */
404
+ /** review step(verify_tool/verify_task/verify_quality/quality_review)参数处理。 */
399
405
  function handleReviewParams(
400
406
  item: WorkItem,
401
407
  params: AgentSubmitParams,
@@ -417,7 +423,10 @@ function handleReviewParams(
417
423
  mergeBoundaryInto(item, params.boundary_expansion)
418
424
  }
419
425
 
420
- if (params.test_results) item.metadata["test_results"] = params.test_results
426
+ // test_results 透传:full 模式 verify_tool 的 UT 摘要写入不受影响;simple 模式 quality_review 下
427
+ // test_results 是 dev 申报的接口测试结果存档(quality_review 视图「开发者自检申报」区块渲染源),
428
+ // 合并审查者提交不得覆盖 dev 申报(spec 契约:申报区块语义为 dev 产出)。
429
+ if (params.test_results && stepId !== "quality_review") item.metadata["test_results"] = params.test_results
421
430
 
422
431
  if (params.validation_steps) {
423
432
  // 结构化 skip_reason 校验(升级既有「非空即可」):未完成项必须带合法结构化降级声明
@@ -428,6 +437,9 @@ function handleReviewParams(
428
437
  // 必做清单覆盖度门禁:verdict=passed 且非补交豁免(仅裁定参数)时,validation_steps 须逐项覆盖
429
438
  // 当前 agent 能力集解析出的质量门 skill 必做清单(must_do)。遗漏必做项且无有效降级证据 → 拒绝提交。
430
439
  // 未声明 must_do 的 skill / 解析不到质量门 skill 的 step 自动跳过(不误伤 verify_task/verify_quality)。
440
+ // 覆盖口径:核验申报(completed=true + 描述注明核验方式与抽验样本,step 名首段 token 命中必做项)是
441
+ // 高成本必做项的合法覆盖形态,仅限 workflow 指令白名单限定的高成本必做项(deep_scan);低成本必做项
442
+ // 必须实跑后申报(机制层只认 token 命中不区分形态,白名单口径在错误提示中明示)。
431
443
  if (params.verdict === "passed" && !opts.skipMustDoGate) {
432
444
  const uncovered = uncoveredMustDo(opts.capabilityTags, params.validation_steps)
433
445
  if (uncovered.length > 0) {
@@ -435,7 +447,8 @@ function handleReviewParams(
435
447
  `提交的验证步骤未覆盖质量门 skill 必做清单,缺少以下必做项:${uncovered.join("、")}。\n` +
436
448
  `请按已加载质量门类 skill 的必做清单逐项执行并逐项申报结果(completed=true);` +
437
449
  `确实无法执行的必做项须以结构化 skip_reason 申报降级理由` +
438
- `(格式:${SKIP_REASON_FORMAT})。`
450
+ `(格式:${SKIP_REASON_FORMAT})。` +
451
+ `低成本必做项必须实跑后申报;核验申报仅限 workflow 指令白名单限定的高成本必做项。`
439
452
  )
440
453
  }
441
454
  }
@@ -777,10 +790,15 @@ export async function agentSubmitExecute(params: AgentSubmitParams, ctx: ToolCon
777
790
  })
778
791
  }
779
792
 
780
- // tool review 检查点增量检测(A3):verify_tool 的 reviewer-tool 提交成功后记录当前 HEAD,
781
- // 供下次重进 verify_tool 时仅对比「检查点 → 当前 HEAD」区间的变更(无代码/配置变更时直提 passed,
782
- // 省去全量工具扫描)。写入位于 submitForStep 成功与 writeState 之间,任何异常路径均不落盘(零状态变更)。
783
- if (params.step_id === "verify_tool" && agentToReviewLayer(ctx.agent) === "tool") {
793
+ // 审查检查点增量检测(A3):full 的 verify_tool(reviewer-tool)与 simple 的 quality_review
794
+ // (合并审查者 openspec-reviewer)提交成功后记录当前 HEAD,供下次重进该 step 时仅对比「检查点 →
795
+ // 当前 HEAD」区间的变更(无代码/配置变更时直提 passed,省去全量工具扫描)。两者写同一 metadata key
796
+ // `_tool_review_checkpoint`,但 simple / full 两 workflow 无对方 step,读写互不交叉。写入位于
797
+ // submitForStep 成功与 writeState 之间,任何异常路径均不落盘(零状态变更)。
798
+ if (
799
+ (params.step_id === "verify_tool" && agentToReviewLayer(ctx.agent) === "tool") ||
800
+ (params.step_id === "quality_review" && ctx.agent === "openspec-reviewer")
801
+ ) {
784
802
  const head = await getCurrentHead(wtPath)
785
803
  if (head) item.metadata["_tool_review_checkpoint"] = head
786
804
  }
package/src/core/views.ts CHANGED
@@ -165,6 +165,27 @@ export function renderAgentSummaries(agentSummaries: Record<string, string> | un
165
165
  return lines
166
166
  }
167
167
 
168
+ /** 开发者自检申报渲染。数据源为 workItem metadata 的 self_check_results / test_results(提交参数的存档),
169
+ * 分「自检申报(self_check_results)」与「接口测试结果(test_results)」两段渲染,两者皆缺失/为空时
170
+ * 返回空数组(不渲染空区块)。
171
+ * 与 renderAgentSummaries 的语义区分:会话摘要按角色隔离(辅助记忆,不跨 agent 传递);自检申报是
172
+ * 正式提交参数的存档,跨角色可见是设计意图——reviewer 分级复验以 dev 申报为事实输入(低成本实跑对照、
173
+ * 高成本项核验申报+抽样重放),不违反「子代理上下文不得转述」:该条约束的是编排者在分派 prompt 中
174
+ * 转述动态上下文,视图渲染动态上下文本就是 opx_status 工具本职。 */
175
+ export function renderDevSelfCheckDeclaration(metadata: Record<string, unknown>): string[] {
176
+ const selfCheck = typeof metadata["self_check_results"] === "string" ? metadata["self_check_results"].trim() : ""
177
+ const testResults = typeof metadata["test_results"] === "string" ? metadata["test_results"].trim() : ""
178
+ if (selfCheck === "" && testResults === "") return []
179
+ const lines: string[] = ["## 开发者自检申报", ""]
180
+ if (selfCheck !== "") {
181
+ lines.push("**自检申报(self_check_results)**:", "", selfCheck, "")
182
+ }
183
+ if (testResults !== "") {
184
+ lines.push("**接口测试结果(test_results)**:", "", testResults, "")
185
+ }
186
+ return lines
187
+ }
188
+
168
189
  // ─── 占位符插值层 ───
169
190
 
170
191
  /** 插值白名单:仅这些 key 可被 {{key}} 占位符引用,其余一律保留原文(防配置注入任意动态值)。 */
@@ -12,7 +12,7 @@ import { resolveChildIssueFields } from "./reset.ts"
12
12
  import { taskListOf, issueChildrenOf } from "../task-children.ts"
13
13
  import {
14
14
  renderSkillSuggestions, renderEfficiencySteps, renderWorktreeSection,
15
- renderAgentSummaries, renderTaskItem, formatFilePath, formatSeverity,
15
+ renderAgentSummaries, renderDevSelfCheckDeclaration, renderTaskItem, formatFilePath, formatSeverity,
16
16
  isWorktreeReady, renderWorktreeNotReady, interpolateText, renderStateMismatchDiagnostic,
17
17
  } from "../views.ts"
18
18
  import { resolveMustDoForCaps, SKIP_REASON_FORMAT } from "../tools/gate.ts"
@@ -547,13 +547,25 @@ function renderAgentWorking(
547
547
  }
548
548
  lines.push(...renderStepSemantics(step, common, stepCtx))
549
549
  lines.push(...renderWorktreeSection(state, tg, { showNamespace: true, showPort: true }))
550
- // verify_tool 分支③(有变更 → 全量路径)证据注入:展示检查点增量口径的本次变更证据(文件清单 +
551
- // 区间 diff 命令),与 Worktree 区块「变更范围」(baseRef..HEAD 整个 change 累计口径)区分,
552
- // 供 reviewer 审查变更内容后按操作指引裁量是否可免全量工具检查(裁量语义由 workflow 配置单源承载,
553
- // 此处仅渲染事实证据)。仅 verify_tool + reviewer-tool + 已预计算变更检测结果(hasNonDocChange=true)
554
- // 时渲染;分支①②提前返回、toolChanges 缺省路径不经过此处,不误伤其他 agent/step。
550
+ // 证据区块注入:展示检查点增量口径的本次变更证据(文件清单 + 区间 diff 命令),与 Worktree 区块
551
+ // 「变更范围」(baseRef..HEAD 整个 change 累计口径)区分,供审查者审查变更内容后按操作指引裁量是否可免
552
+ // 全量工具检查(裁量语义由 workflow 配置单源承载,此处仅渲染事实证据)。
553
+ // - verify_tool(full 分支③有变更 → 全量路径):仅 reviewer-tool + 已预计算变更检测结果
554
+ // (hasNonDocChange=true)时渲染;分支①②提前返回、toolChanges 缺省路径不经过此处,不误伤其他 agent/step。
555
+ // - quality_review(simple 合并审查):toolChanges 已预计算即渲染,不判 hasNonDocChange——simple 无
556
+ // 三分支替换式视图,无变更时也渲染区块(文件清单处显式「未检出」),给「无变更直提」分流显式视觉信号。
555
557
  if (step?.id === "verify_tool" && agentToReviewLayer(ctxAgent) === "tool" && toolChanges?.hasNonDocChange) {
556
- lines.push(...renderToolChangesEvidence(item, tg, toolChanges))
558
+ lines.push(...renderToolChangesEvidence(item, tg, toolChanges, "tool_review"))
559
+ }
560
+ if (step?.id === "quality_review" && toolChanges) {
561
+ lines.push(...renderToolChangesEvidence(item, tg, toolChanges, "merged_review"))
562
+ }
563
+ // simple 合并审查(quality_review)证据注入:渲染提交参数存档的自检申报(self_check_results /
564
+ // test_results),作为分级复验的事实输入——低成本实跑对照、高成本项核验申报+抽样重放均以该申报为
565
+ // 证据源。仅 quality_review step 渲染(消费方是 reviewer);implement 视图与其余 step 视图不受影响
566
+ //(dev 自己刚产出该申报,无需回显)。
567
+ if (step?.id === "quality_review") {
568
+ lines.push(...renderDevSelfCheckDeclaration(item.metadata))
557
569
  }
558
570
  lines.push(...renderAgentSummaries(readAgentSummaries(item), ctxAgent))
559
571
  lines.push(...renderStepContext(item, step, ctxAgent, state, exemptionCtx))
@@ -799,26 +811,42 @@ function renderToolChildren(item: WorkItem, ctxAgent: string, exemptionCtx?: Exe
799
811
  return lines
800
812
  }
801
813
 
802
- /** verify_tool 分支③(全量路径)证据区块:检查点增量口径的本次变更证据(文件清单 + 区间 diff 命令)。
803
- * 有检查点时标注「本次为自上次工具检查(checkpoint..HEAD)增量区间」,与 Worktree 区块「变更范围」
814
+ /** 变更证据区块的检查点口径措辞:tool_review=verify_tool(full,「工具检查」)、
815
+ * merged_review=quality_review(simple 合并审查,「合并审查」)。verify_tool 文案保持既有原文。 */
816
+ type ChangesEvidenceKind = "tool_review" | "merged_review"
817
+
818
+ const EVIDENCE_KIND_LABELS: Record<ChangesEvidenceKind, { title: string; lastCheck: string }> = {
819
+ tool_review: { title: "自上次工具检查", lastCheck: "上次工具检查" },
820
+ merged_review: { title: "自上次合并审查", lastCheck: "上次合并审查" },
821
+ }
822
+
823
+ /** 证据区块:检查点增量口径的本次变更证据(文件清单 + 区间 diff 命令)。verify_tool 分支③(全量路径)
824
+ * 与 quality_review(simple 合并审查)共用,经 kind 区分口径措辞(「自上次工具检查」/「自上次合并审查」)。
825
+ * 有检查点时标注「本次为自上次审查(checkpoint..HEAD)增量区间」,与 Worktree 区块「变更范围」
804
826
  * (baseRef..HEAD 整个 change 累计口径)区分;无检查点(首次进入)时标注基线兜底口径,与变更范围一致;
805
827
  * 无检查点亦无基线基准时不渲染 diff 命令(无法界定区间)。仅渲染事实证据,不做变更性质判定——
806
828
  * 裁量语义由 workflow 配置操作指引单源承载。 */
807
- function renderToolChangesEvidence(item: WorkItem, tg: TaskGroupState, toolChanges: DetectChangesResult): string[] {
829
+ function renderToolChangesEvidence(
830
+ item: WorkItem,
831
+ tg: TaskGroupState,
832
+ toolChanges: DetectChangesResult,
833
+ kind: ChangesEvidenceKind,
834
+ ): string[] {
835
+ const label = EVIDENCE_KIND_LABELS[kind]
808
836
  const checkpoint =
809
837
  typeof item.metadata["_tool_review_checkpoint"] === "string" ? item.metadata["_tool_review_checkpoint"] : undefined
810
838
  const baseRef = tg.baseRef ?? undefined
811
839
  const rangeRef = checkpoint ?? baseRef
812
- const lines = ["## 本次变更证据(自上次工具检查)", ""]
840
+ const lines = [`## 本次变更证据(${label.title})`, ""]
813
841
  if (checkpoint) {
814
842
  lines.push(
815
- `- **口径**: 本次为「自上次工具检查(${checkpoint}..HEAD)」的增量区间(含已提交与未提交的非 openspec 变更);` +
843
+ `- **口径**: 本次为「${label.title}(${checkpoint}..HEAD)」的增量区间(含已提交与未提交的非 openspec 变更);` +
816
844
  `与上方「变更范围」(${baseRef ?? "(无)"}..HEAD 整个 change 累计口径)不同`,
817
845
  "",
818
846
  )
819
847
  } else if (baseRef) {
820
848
  lines.push(
821
- `- **口径**: 本次区间以基线(${baseRef}..HEAD)兜底,与上方「变更范围」一致(首次进入,无上次工具检查记录;` +
849
+ `- **口径**: 本次区间以基线(${baseRef}..HEAD)兜底,与上方「变更范围」一致(首次进入,无${label.lastCheck}记录;` +
822
850
  "含已提交与未提交的非 openspec 变更)",
823
851
  "",
824
852
  )