From 8a3ac8e818e43d8da224b5e12571d1f9cbaa29e7 Mon Sep 17 00:00:00 2001 From: Jay Shen Date: Mon, 31 Aug 2026 18:57:47 +0800 Subject: [PATCH] docs: tighten closure recovery and evidence contracts --- .../luowang-v07-production-closure/intent.md | 10 +- .../luowang-v07-production-closure/plan.md | 109 +++++++++------- .../luowang-v07-production-closure/spec.md | 120 +++++++++++++----- 3 files changed, 159 insertions(+), 80 deletions(-) diff --git a/docs/changes/luowang-v07-production-closure/intent.md b/docs/changes/luowang-v07-production-closure/intent.md index 9a1d1c6..bff34ff 100644 --- a/docs/changes/luowang-v07-production-closure/intent.md +++ b/docs/changes/luowang-v07-production-closure/intent.md @@ -1,6 +1,6 @@ # 罗网 v0.7 生产闭环补齐 Intent -- 状态:Approved v0.2 +- 状态:Approved v0.3 - 关联规格:[spec.md](./spec.md) - 实现计划:[plan.md](./plan.md) - 上游基线:[罗网 Harness MVP](../luowang-harness-mvp/intent.md) @@ -28,10 +28,10 @@ 1. Main · 规划、Runner、Reviewer、Main · 最终汇总和初始化方法成为罗网自身版本化的 Built-in Role Instructions(内置角色指令),由应用按 Session 确定性加载并完整注入;它们是发布物中的固定 Markdown 资源,不是 Pi Skills;目标仓库、宿主机和用户目录中的 Skills 仍不会被发现或执行; 2. 固定方法、安全边界、动态 Run 上下文和本次请求分层传递,不再重复注入同一长提示词;不同角色只看到自己需要的动态事实; -3. 人工 merge 请求进入现有 SQLite FIFO,在轮到它时完成 `merge --no-ff → non-force push → 固定新的 scenario-testing HEAD → Run`;普通人工测试不能直接绕开场景测试分支; -4. Runner 可以登记测试数据并通过 UI/API 删除,但 Runner 的清理声明不能直接变成完成事实;只有受控 adapter 独立核验,或 Reviewer 读取 Harness 管理的清理证据后确认,数据才视为已清理,任何未确认残留仍可靠地使结果 blocked; +3. 人工 merge 请求进入现有 SQLite FIFO,在轮到它时生成可跨重启恢复的 prepared merge,完成 `non-force push → 固定 resolved target → Run`;prepared commit 在本地持久 Git 仓库中保持可达,普通人工测试不能直接绕开场景测试分支; +4. Runner 可以登记测试数据并通过 UI/API 删除,但 Runner 的清理声明或自填文本不能直接变成完成事实;只有受控 adapter 独立核验,或 Reviewer 读取由 Harness 直接捕获的工具/adapter 输出或 Playwright 截图后确认,数据才视为已清理,任何未确认残留仍可靠地使结果 blocked; 5. 网站在真实执行中显示总场景数、已完成数、当前场景和脱敏活动,而不是只依赖 UI fixture; -6. Main · 规划可以按需查询有限、只读、相关的历史 Run 摘要;Main · 最终汇总只获得本次 confirmed Bugs 的 Issue create/link 所需摘要;Runner 和 Reviewer 均不获得历史查询工具; +6. Main · 规划可以按需查询有限、只读、相关的历史 Run 摘要;Main · 最终汇总先从本次 `draft-report.md` 和 `review.md` 形成 Bug 候选,再通过受限只读工具查询可能相同的历史 Issue/Run 并决定 create/link;Runner 和 Reviewer 均不获得历史查询工具; 7. 本地自动化验收与真实外部联合验收明确分层:本地通过不能冒充 live 通过,发布验收在任何必需外部证明 blocked 时必须失败; 8. 使用独立、可信、非生产测试项目完成真实 Provider、Pi Agent、Playwright MCP、OSS、GitHub、数据清理、归档、Issue 和进度闭环; 9. README 准确说明已实现、已本地验证、尚未 live 验证和本地构建前置条件; @@ -105,7 +105,7 @@ 本变更成功不以“新增了多少文件或测试”为标准,而以以下事实同时成立为准: - 已知生产路径缺口均有用户可观察的修复和自动回归; -- 实际 Pi SDK Session 而非 FixtureSessionFactory 分别证明正常四 Session Run 和陌生项目初始化流程,覆盖模型消息、受控工具循环、Session 隔离与 dispose; +- 实际 Pi SDK Session 而非 FixtureSessionFactory 分别证明正常四 Session Run、初始化直接新增场景的六 Session 流程,以及需要场景 PR 时立即结束的三 Session 特殊 blocked 流程,覆盖模型消息、受控工具循环、Session 隔离与 dispose; - 真实联合 Run 在独立非生产项目上完成并可由 Run、commit、报告、截图、OSS object、PR/Issues 和清理结果复核; - 本地与 live 结果被准确区分,缺少任何 live 前置条件时明确 blocked 且不能发布; - 没有通过补复杂状态机、放宽安全边界或增加未来架构来“解决”问题。 diff --git a/docs/changes/luowang-v07-production-closure/plan.md b/docs/changes/luowang-v07-production-closure/plan.md index a49e54f..40b1c73 100644 --- a/docs/changes/luowang-v07-production-closure/plan.md +++ b/docs/changes/luowang-v07-production-closure/plan.md @@ -1,6 +1,6 @@ # 罗网 v0.7 生产闭环补齐实施计划 -- 状态:Implementation Plan v0.2 +- 状态:Implementation Plan v0.3 - 关联 Intent:[intent.md](./intent.md) - 关联 Spec:[spec.md](./spec.md) - 上游计划:[罗网 Harness MVP Plan](../luowang-harness-mvp/plan.md) @@ -142,7 +142,7 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET | Closure 2 | `fix/closure-merge-test-queue` | branch/tag/SHA 经同一 FIFO 合并并测试固定分支 HEAD | MERGE-01/02、TARGET-01 | | Closure 3 | `fix/closure-test-data` | Runner 能确认实际清理,残留可靠 blocked | DATA-01/02 | | Closure 4 | `fix/closure-live-progress` | 真实 Run 上报当前场景、总数和完成数 | ACTIVE-01 | -| Closure 5 | `feat/closure-run-history` | Main · 规划可查询相关历史,Main · 最终汇总只获本次 bug 摘要 | HISTORY-01 | +| Closure 5 | `feat/closure-run-history` | Main · 规划查询 Run 历史;Main · 最终汇总按本次 Bug 候选受限查询 Issue/Run | HISTORY-01 | | Closure 6 | `feat/closure-production-acceptance` | local 验收真实经过 Pi SDK,local/live/release 分层 | PI-01、ACCEPT-01/02 | | Closure 7 | `feat/closure-live-acceptance-release` | 使用人类提供资源完成 live 联合验收并发布 | LIVE-01/02、SECRET-01、RELEASE-01 | @@ -237,23 +237,27 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET - queued/running-without-run manual/api 且旧 target 非空时明确 failed,不把旧 target 猜成 sourceRef 或 merge 授权; - 旧 `target_ref` 只作历史兼容读取,新调度不使用; 2. 在 Queue/Automation owner 中实现 Spec §4 三类请求;自动请求仍只合并 queued automatic,人工请求永不合并; -3. 调度 `manual-merge-source` 时严格执行: +3. 在 Repository/Queue owner 中以持久目标仓库 object store 管理确定性本地 ref `refs/luowang/merge-requests/`;该 ref 不进入 push refspec、不推送到目标仓库,也不作为业务分支展示; +4. 调度 `manual-merge-source` 时严格执行: - fetch 并解析 source ref; - 基于当时远端 `scenario-testing` HEAD 生成本地 `merge --no-ff` commit; - - push 前持久化 `prepared_merge_commit`; + - 先创建 internal ref 指向该 commit,确保 object 可达; + - 再持久化同值的 `prepared_merge_commit`; - non-force push 同一 prepared commit; - push 成功后持久化同值的 `resolved_target_commit`; - 只使用 `resolved_target_commit` 创建或关联唯一 Run; -4. 恢复逻辑按已持久化事实分支: - - 只有 prepared:远端已包含则补写 resolved;未包含则只尝试 push 同一 commit,远端竞争时失败,不重做 merge; +5. 恢复逻辑按 Git ref 和 SQLite 事实共同判断: + - 只有 prepared:internal ref 必须指向同一 SHA;远端已包含则补写 resolved,否则只 push 该 ref 的 commit;ref 缺失/不匹配且远端未包含时失败,不重做 merge; - 已有 resolved:校验它位于远端场景分支历史,忽略后来新增 HEAD,创建或关联唯一 Run; + - internal ref 已有但 prepared 为空:视为 ref/DB 间崩溃,明确失败并清理,不猜测 prepared; - 已有关联 Run:不再创建第二个; -5. 来源已是祖先时不生成 merge commit,把当时远端 HEAD 持久化为 prepared/resolved 后创建 Run; -6. 改造 `/api/repository/merge` 和网站合并入口为异步入队,返回 queue/request ID; -7. 普通 `/api/runs` 和网站 Run 表单移除任意 target 输入;非空旧字段明确 `400`; -8. 重测入口复用原请求说明但在调度时读取当前场景测试分支 HEAD; -9. Orchestrator 只接收调度层持久化且已证明发布到场景测试分支的 `resolved_target_commit`;保留 checkout 后 SHA 一致性检查; -10. 更新 API/UI 文案,明确“已排队”而不是“已经合并”。 +6. 来源已是祖先时不生成 merge commit;internal ref 指向当时远端 HEAD,再持久化 prepared/resolved 后创建 Run; +7. 请求在 queued/running/waiting_archive 期间保留 internal ref,不受普通 workspace cleanup、fetch/prune 或 Git GC 影响;completed/failed/interrupted 后幂等清理,启动时清理无队列行的孤儿 ref; +8. 改造 `/api/repository/merge` 和网站合并入口为异步入队,返回 queue/request ID; +9. 普通 `/api/runs` 和网站 Run 表单移除任意 target 输入;非空旧字段明确 `400`; +10. 重测入口复用原请求说明但在调度时读取当前场景测试分支 HEAD; +11. Orchestrator 只接收调度层持久化且已证明发布到场景测试分支的 `resolved_target_commit`;保留 checkout 后 SHA 一致性检查; +12. 更新 API/UI 文案,明确“已排队”而不是“已经合并”。 ### 专项验证 @@ -264,14 +268,15 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET - 旧 manual/api 非空 target 不会写入 `source_ref`、不会 merge、不会创建 Run,错误提示要求通过 merge-source 重新提交; - 旧 automatic 的 `target_ref` 不作为新 target,轮到时固定当时场景分支 HEAD;有关联旧 Run 的 resolved 只从已存 Run/Recovery target 回填; - 排队两个普通人工请求和一个 merge-source,按 FIFO 执行且不丢失; -- merge-source 产生 `--no-ff` merge commit,且在 push 前数据库已有 `prepared_merge_commit`; -- push 成功后 `resolved_target_commit == prepared_merge_commit`,Run target 严格等于 resolved; -- 在 prepared 持久化后、push 前退出:恢复只 push 同一 prepared commit,不重新生成 merge; -- 在 push 后、resolved 持久化前退出:恢复从远端包含关系补写同一 resolved,不重复 merge; +- merge-source 产生 `--no-ff` merge commit,先创建 `refs/luowang/merge-requests/`,再写 `prepared_merge_commit`;ref、prepared 和 commit SHA 完全一致; +- 检查远端 refs,internal ref 从未被 push;push 成功后 `resolved_target_commit == prepared_merge_commit`,Run target 严格等于 resolved; +- 在 prepared 持久化后、push 前退出:删除临时工作树/clone、重启进程并执行 `git gc`,commit 仍可由 persistent internal ref 读取,恢复只 push 同一 SHA,不重新生成 merge; +- 在 internal ref 创建后、prepared 写入前退出:请求明确 failed、ref 被清理且不创建 Run;prepared 存在但 ref 缺失/不匹配且远端不含该 commit 时同样 failed; +- 在 push 后、resolved 持久化前退出:即使 internal ref 异常缺失,也能从远端包含关系补写同一 resolved,不重复 merge; - resolved 后、Run 创建前让场景分支再前进:恢复仍创建一个以旧 resolved 为 target 的 Run; -- Run 关联后重启:不创建第二个 Run; -- 来源已是祖先时不重复 merge,但持久化当时 HEAD 并创建新的人工 Run; -- merge 冲突、来源不存在、prepared 后远端竞争时无 Run、无推进、工作树清理; +- Run 关联后重启:不创建第二个 Run;请求 terminal 后 internal ref 被幂等清理,重复清理安全;无队列行的孤儿 ref 在启动对账后删除; +- 来源已是祖先时不重复 merge,internal ref/ prepared/resolved 指向当时 HEAD 并创建新的人工 Run; +- merge 冲突、来源不存在、prepared 后远端竞争时无 Run、无推进、工作树和 internal ref 清理; - `/api/runs` 任意 SHA/ref 返回 `400`;普通人工和重测 target 为调度时远端场景分支 HEAD; - 自动合批行为和 last completed target 计算不回归。 @@ -289,13 +294,18 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET 1. 扩展现有 TestDataManager,维护当前 Run 的 registered、cleanup claim、verified-cleaned 和 pending 查询; 2. 增加 Runner 的 `submit_test_data_cleanup_claim`、`list_pending_test_data` custom tools:claim 必须引用当前 Run Evidence Store 中真实存在的证据 ID,只能进入待核验状态; -3. 为脱敏删除后 API 查询结果增加受控文本 evidence 保存/读取;沿用当前 Run 路径、大小、类型和 Secret 校验; +3. 为删除后核验增加 Harness-side evidence capture,而不是接受 Agent 任意文本: + - 清理 adapter 查询、受控 API 查询和与已登记 data ID 绑定的只读命令返回时,由工具 wrapper 直接捕获真实响应/输出; + - Runner 只能选择登记 ID 和 allowlist 内查询操作/参数,不能提交 evidence 正文、状态码、退出码、摘要或 hash; + - 禁止把 `echo`/`printf`、自由文本命令或复述结论当作清理证据; + - 每条记录来源工具/adapter ID、Run ID、data ID、查询时间、状态码/退出码、脱敏后内容摘要和 SHA-256;沿用当前 Run 路径、大小、类型、Secret 脱敏和 allowlist; + - Playwright MCP 直接产生的删除后截图继续作为受控图像 evidence; 4. 增加 Reviewer 的 `verify_test_data_cleanup`:只有 Reviewer 已实际读取 claim 对应 evidence 后才能确认或拒绝,不能执行目标环境命令或访问账号; 5. 更新 Runner/Reviewer 内置角色指令: - 创建前取得 run-id prefix; - 创建后立即登记; - 场景结束通过 UI/API 删除; - - 保存“删除后不存在”的脱敏截图/查询证据并提交 claim; + - 触发删除后受控查询,让 Harness 捕获真实输出,或保存 Playwright MCP 直接生成的删除后截图,再引用其 evidence ID 提交 claim; - Reviewer 先读证据,再结构化确认或拒绝; 6. 调整 Run 收尾顺序:Runner 后 adapter 可先核验 pending,Reviewer 后做最终检查,再把未确认项作为 blocking reason 交给 Main · 最终汇总; 7. 无数据或全部 verified-cleaned → 正常;纯声明、未受控/未读取证据、Reviewer 拒绝、pending 或 adapter 失败 → blocking reason + execution/report 残留清单; @@ -304,8 +314,9 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET ### 专项验证 -- 默认生产 manager:登记 → UI/API fixture 删除 → 保存删除后证据 → claim → Reviewer 读取并确认 → Run 不因缺 adapter blocked; -- Runner 只 claim、不提供证据、引用任意路径/URL、Reviewer 未读取证据或拒绝 → 不能 verified,Run blocked; +- 默认生产 manager:登记 → UI/API fixture 删除 → 受控 API/查询命令实际返回“不存在” → Harness 捕获并生成 evidence → claim → Reviewer 读取并确认 → Run 不因缺 adapter blocked; +- adapter、API、只读命令三种文本来源分别生成完整 provenance;Playwright MCP 删除后截图保持可读取; +- Agent 尝试提交自填 evidence 正文/状态码/摘要、`echo`/`printf` 输出、任意路径/URL,或 Runner 只 claim、Reviewer 未读取/拒绝 → 不能生成合格 evidence 或 verified,Run blocked; - claim 未登记 ID、其他 Run ID、重复确认被拒绝或明确幂等; - 受控 adapter 删除并独立查询不存在,可直接产生 verified receipt;adapter 部分失败仍 blocked; - 多场景数据分别核验,pending 数量正确; @@ -345,30 +356,39 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET `AC-CLOSURE-ACTIVE-01` 和上游 `AC-ACTIVE-VIEW-01` 通过。 -## 11. Closure Phase 5:Main Planning 相关历史 Run +## 11. Closure Phase 5:Main 的受限历史查询 ### 目标 -Main · 规划能使用 SQLite/Recovery 中未写入正式 Git 报告的历史事实;Main · 最终汇总只得到本次 confirmed Bugs 的 Issue create/link 所需摘要,同时保持查询有限、脱敏和角色隔离。 +Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总不等待尚未生成的 `confirmed_bugs`,而是在读取本次草稿和审核后,用受限只读工具查询可能相同的历史 Issue/Run,再决定 create/link。两类查询保持有限、脱敏和角色隔离。 ### 修改范围 -1. 扩展 RunStore/Recovery owner,提供 Spec §7 的摘要查询;复用已有表,不复制历史; -2. 支持 recent、commit、scenario、bug/Issue 过滤和 20/100 限制; -3. 增加 Main Planning 专用 `query_run_history` custom tool;Main · 最终汇总不获得该工具,只由 Harness 注入本次 confirmed Bugs 的 Issue create/link 所需有限摘要; -4. Runner、Reviewer 工具集中不存在该工具; -5. 返回正常 completed、特殊 blocked、interrupted、场景 PR、归档失败和多个 Issue 摘要; -6. 查询失败显式 unavailable,成功空结果显式 empty; -7. 更新 Main · 规划和 Main · 最终汇总的内置角色指令,前者按相关性查询,后者只使用 Harness 提供的本次 bug 摘要,不把全部历史塞进 prompt。 +1. 扩展现有 RunStore/Recovery/Issue 查询 owner,复用已有表和 GitHub Issue 读取边界,不复制历史、不增加中间状态文件; +2. 为 Main Planning 提供 `query_run_history`:支持 recent、commit、scenario、bug/Issue 过滤,默认 20、硬上限 100; +3. 为 Main Finalization 提供独立 `query_issue_candidates({ title?, keywords?, bug_key?, limit? })`: + - title/keywords/bug key 至少一个;实现 Spec §7 的长度、类型、NFKC/大小写/空白归一化; + - 按 exact bug key、exact/包含 title、关键词命中数匹配,按 Spec 固定顺序排序和去重; + - 返回固定 `ok | empty | unavailable` 结构,只包含候选 Issue、匹配原因及相关 Run 摘要; + - 默认 20、硬上限 100;一个 Finalization Session 最多 10 次调用,同一 unavailable 查询最多重试一次,禁止重复 ok/empty 查询; + - 只读,不能创建、修改、关闭或评论 Issue; + - 不返回完整工件、测试账号、Secret 或未脱敏工具参数; +4. 更新 Main · 最终汇总内置角色指令和工具顺序:先读 `draft-report.md`、`review.md` 形成 Bug 候选,再调用 `query_issue_candidates`,最后在 `report.md` 决定 confirmed Bug 的 create/link;不预先注入依赖 `confirmed_bugs` 的摘要; +5. Main · 规划只有 `query_run_history`,Main · 最终汇总只有 `query_issue_candidates`;Runner、Reviewer 两者都没有; +6. Run 查询返回正常 completed、特殊 blocked、interrupted、场景 PR、归档失败摘要;Issue 候选查询返回 number/title/url/state、匹配原因/bug key 和关联 Run 的有限字段; +7. 两类查询失败都显式 unavailable,成功空结果显式 empty;第二次 unavailable 或调用预算耗尽后记录覆盖缺口并继续,不循环;不增加 Reviewer 结构化 Bug 结果或新的事实源。 ### 专项验证 - 构造正常 passed、failed、多 Issue、特殊 blocked + PR、interrupted、archive failed; -- Main · 规划按场景/commit/Issue 查到正确摘要和稳定顺序;Main · 最终汇总只能看到本次 confirmed Bugs 的有限摘要,不能主动扩大查询; -- limit 边界、无结果和数据库失败区分; -- 摘要不含完整工件、测试账号、Secret 和未经脱敏错误; -- Runner/Reviewer 调不到历史工具; -- Main · 规划产出的计划真实引用相关历史,不回写旧 Run。 +- Main · 规划按场景/commit/Issue 查到正确摘要和稳定顺序; +- Main · 最终汇总在读取 draft/review 前调用候选工具被流程测试判为错误;读取后可分别按 title/keywords/bug key 查询相似 Issue 和相关 Run,最终正确选择 create 或 link; +- `query_issue_candidates` 无需预先存在 `confirmed_bugs`,不修改任何 Issue;缺少全部检索条件、错误 keywords 类型/数量/长度、控制字符和越界 limit 均被拒绝; +- 构造大小写、Unicode/空白、exact bug key、exact/包含 title、多关键词命中和相同时间数据,断言去重和稳定排序与 Spec 一致; +- `ok` 非空、`empty` 成功空、`unavailable` 依赖失败严格区分;同一 unavailable 只重试一次,ok/empty 不重复,总调用超过 10 被拒绝并形成覆盖缺口; +- 两类摘要都不含完整工件、测试账号、Secret 和未经脱敏错误; +- Main · 规划调不到 Issue 候选工具,Main · 最终汇总调不到通用 Run 历史工具,Runner/Reviewer 两者都调不到; +- Main · 规划产出的计划真实引用相关历史;Main · 最终汇总只把最终 confirmed Bugs 写入 `report.md`,不产生新中间状态文件、不回写旧 Run。 ### 退出条件 @@ -393,10 +413,10 @@ Main · 规划能使用 SQLite/Recovery 中未写入正式 Git 报告的历史 - Main Finalization Session:最终汇总; 4. 初始化验收必须形成三个独立用例: - 直接新增场景:执行完整六 Session 序列,由候选验证 Runner 真实执行后再进入 Reviewer 和 Main Finalization; - - 需要场景 PR:执行 Main Planning 静态勘察 → Runner 运行时侦察 → 新 Main Planning 候选综合 → Reviewer → Main Finalization 五个 Session;跳过候选验证 Runner,不执行未审核场景,仍写齐五个 Markdown 工件和受限 patch,以 blocked 归档并创建场景 PR; - - 最终修订未重跑:在已经完成候选验证的初始化用例中,Main · 最终汇总按 Reviewer 意见修订尚未发布 patch 后,不创建新的 Runner Session,因此结果保持 blocked; + - 需要场景 PR:只执行 Main Planning 静态勘察 → Runner 运行时侦察 → 新 Main Planning 候选综合三个 Session;策略判断需要人工审核后立即 blocked,不创建候选验证 Runner、Reviewer、Main Finalization,不等待人类;Harness 生成特殊 blocked report;special finalize 按 patch/report allowlist 选择性完成,不能原样 rename 含临时 Markdown 的 running 目录;Archiver 再创建场景 PR; + - 最终修订未重跑:只在已经完成候选验证并进入 Reviewer/Main Finalization 的直接新增用例中验证;Main · 最终汇总修订尚未发布 patch 后,不创建新的 Runner Session,因此结果保持 blocked; 5. 记录并断言每次 Session 的唯一 ID、Agent 配置来源、内置角色指令 ID/hash、工具集合、输入工件、输出工件和 dispose;多个 Main Planning Session、多个 Runner Session 均不得共享完整对话; -6. 把确定性故障证明纳入 local:使用真实生产代码和本地 Git、HTTP、S3-compatible 服务验证 merge 冲突、归档失败重试、Indexer 暂时不可用、进程重启、队列恢复及 prepared/resolved merge 恢复; +6. 把确定性故障证明纳入 local:使用真实生产代码和本地 Git、HTTP、S3-compatible 服务验证 merge 冲突、归档失败重试、Indexer 暂时不可用、进程重启、队列恢复,以及 internal ref + prepared/resolved merge 恢复; 7. 保留 FixtureSessionFactory 用于细粒度确定性单测,但普通/初始化 Pi 路径和上述生产恢复不得以 FixtureSessionFactory 作为 AC 证据; 8. 重构 acceptance AC 映射,每个 AC 运行或引用能证明自身行为的检查,不按粗粒度 proof 批量赋值; 9. 增加 `test:acceptance:local`、`test:acceptance:live`、`test:acceptance:release`;兼容 `test:acceptance` 只能别名 local; @@ -410,11 +430,12 @@ Main · 规划能使用 SQLite/Recovery 中未写入正式 Git 报告的历史 - 普通 Run 创建四个不同 Session ID,显示 Main · 规划 → Runner → Reviewer → Main · 最终汇总;两个 Main Session 使用同一 Main 模型/thinking 配置但 Prompt、工具和对话隔离; - 普通 Run 真实经过 Pi 模型消息和 custom tool 循环,写出 `plan.md`、`execution.md`、`draft-report.md`、`review.md`、`report.md` 并 dispose 全部 Session; - 初始化直接新增场景用例真实经过六个新 Session;两个 Main Planning Session 互不共享对话,两个 Runner Session 互不共享对话,每次只获得本阶段内置角色指令和工具; -- 初始化场景 PR 用例严格创建 Main Planning/Runner/Main Planning/Reviewer/Main Finalization 五个 Session,明确没有候选验证 Runner;`plan.md`、`execution.md`、`draft-report.md`、`review.md`、`report.md` 和受限 patch 齐全,结果 blocked 后才由归档创建场景 PR;不把未审核场景写成已验证; +- 初始化场景 PR 用例严格只创建 Main Planning/Runner/新 Main Planning 三个 Session 并全部 dispose;策略判断后立即 blocked,断言没有候选验证 Runner、Reviewer、Main Finalization; +- 在 running workspace 先制造三个 Session 的临时 plan/execution/draft,再执行 special finalize;completed artifact list 必须严格等于 `scenario-changes.patch`、Harness 生成的 `report.md`,四个普通工件均不存在;`isSpecialScenarioReviewRun()` 按两文件契约识别,Archiver 创建场景 PR 且不把它当普通 Run; - 初始化最终汇总修订 patch 用例没有重新 Runner 执行,因此最终仍 blocked; - 配置和 connectivity checks 仍只有 Main、Runner、Reviewer 三组,不出现 Planner/Finalizer 字段或第四个 Provider 检查; - 模型协议返回非法工具、漏写文件、越权工具时生产校验拒绝; -- 本地真实 Queue/Repository/Archiver/Indexer 生产代码通过 merge conflict、prepared/push/resolved 各退出点、归档失败重试、Indexer 故障恢复、进程重启和队列恢复; +- 本地真实 Queue/Repository/Archiver/Indexer 生产代码通过 merge conflict、internal-ref/prepared/push/resolved 各退出点、临时工作区删除与 Git GC、terminal ref 清理、归档失败重试、Indexer 故障恢复、进程重启和队列恢复; - `test:acceptance:local` 在无外部变量环境通过且不称 release passed; - `test:acceptance:live` 缺任一字段列出完整 missing 集合并非零;构造 live failed/blocked 时 release 非零;全部 test double 只能使 local passed; - 每个受影响 AC 报告自己的 evidence;报告与 CI 日志中注入 canary Secret,扫描阴性。 @@ -457,10 +478,10 @@ Main · 规划能使用 SQLite/Recovery 中未写入正式 Git 报告的历史 2. 通过网站/API 配置真实测试仓库、环境、Provider、Main/Runner/Reviewer 三个模型、Playwright MCP、私有 OSS 和账号;不得出现 Planner/Finalizer 独立配置或第四个模型检查; 3. 运行所有 connectivity checks,保存脱敏结果; 4. 使用 merge-source 请求把可控产品/需求变化纳入 `scenario-testing`,验证 FIFO、prepared/resolved 持久化事实和固定 `resolved_target_commit`; -5. 完成一个真实 passed UI Run:真实 Pi 创建 Main · 规划、Runner、Reviewer、Main · 最终汇总四个隔离 Session,执行 Playwright MCP 操作、截图、OSS 上传和 Reviewer 看图;创建并删除测试数据,提交清理 claim 后由 adapter 独立核验或 Reviewer 实际读取 Harness 证据确认;写五个工件、Git 正式报告,完成 Indexer 回读和实时 0/N→N/N; +5. 完成一个真实 passed UI Run:真实 Pi 创建 Main · 规划、Runner、Reviewer、Main · 最终汇总四个隔离 Session,执行 Playwright MCP 操作、截图、OSS 上传和 Reviewer 看图;创建并删除测试数据,提交清理 claim 后由 adapter 独立核验,或由 Reviewer 实际读取 Harness 直接捕获的受控查询输出/Playwright 截图并确认;写五个工件、Git 正式报告,完成 Indexer 回读和实时 0/N→N/N; 6. 使用人类预先给出的两个独立、可逆失败条件完成一个真实 failed Run,确认至少两个不同 Bugs,幂等创建/关联多个 Issues,报告及 Issues 完成后才推进; 7. 完成一个真实 blocked Run:保留已确认 Bug(如有)但不推进;阻塞来源使用可控非生产依赖,不破坏环境; -8. 验证场景 PR、PR 合并后旧 Run 不变、当前 HEAD 人工重测; +8. 验证真实场景 PR 特殊 Run 只创建三个 Agent Session 并仅持久化 patch + Harness report;PR 合并后旧 Run 不变,当前 HEAD 人工重测创建新 Run; 9. 验证场景/报告 allowlist、历史报告 blob SHA 不变、罗网仓库无测试资产; 10. 验证所有测试数据和 OSS 临时探测对象按策略清理;被正式 Git 报告引用的证据对象保留到项目负责人明确执行后续保留/删除决定,不得在验收收尾时误删; 11. 运行 `npm run test:acceptance:release`;它必须复用 Phase 6 的 local 确定性故障证据并执行本 Phase live 联合证明,保存分层 JSON/Markdown 结果;不在真实 GitHub/官网环境重复制造 merge 冲突、归档、Indexer、重启或队列故障; diff --git a/docs/changes/luowang-v07-production-closure/spec.md b/docs/changes/luowang-v07-production-closure/spec.md index 99f35d1..ce75d3f 100644 --- a/docs/changes/luowang-v07-production-closure/spec.md +++ b/docs/changes/luowang-v07-production-closure/spec.md @@ -1,6 +1,6 @@ # 罗网 v0.7 生产闭环补齐 Spec -- 状态:Implementation Baseline v0.2 +- 状态:Implementation Baseline v0.3 - 关联 Intent:[intent.md](./intent.md) - 实现计划:[plan.md](./plan.md) - 上游规格:[罗网 Harness MVP Spec](../luowang-harness-mvp/spec.md) @@ -102,7 +102,7 @@ Main Planning Session 和 Main Finalization Session 共同使用 `agents.main` | Main · 规划 | `common.md` + `main-planning.md` | `scenario-initialization.md` | 理解请求、需求和累计 diff;阅读项目理解、场景和相关历史;维护或选择场景;形成 `plan.md`;必要时生成受限场景 patch;不执行测试 | | Runner | `common.md` + `runner-execution.md` | 无 | 顺序执行计划;使用受控命令、Playwright MCP 和测试账号;创建、登记、清理测试数据;保存证据;写 `execution.md` 和 `draft-report.md` | | Reviewer | `common.md` + `reviewer-audit.md` | 无 | 独立读取本次工件和受控证据;审核截图和清理证据;判断 Bug、blocked 和零场景结论;写 `review.md`;不执行命令、不获取测试账号 | -| Main · 最终汇总 | `common.md` + `main-finalization.md` | `scenario-initialization.md` | 读取前置工件和 Reviewer 结论;按 `blocked > failed > passed` 聚合;处理 confirmed Bugs 的 Issue create/link;写 `report.md`;初始化 Run 可按 Reviewer 意见修订尚未发布的场景 patch,但修订后未重新执行必须保持 blocked | +| Main · 最终汇总 | `common.md` + `main-finalization.md` | `scenario-initialization.md` | 读取前置工件和 Reviewer 结论;从本次草稿形成 Bug 候选并受限查询相似历史 Issue/Run;按 `blocked > failed > passed` 聚合;决定 confirmed Bugs 的 Issue create/link;写 `report.md`;初始化 Run 可按 Reviewer 意见修订尚未发布的场景 patch,但修订后未重新执行必须保持 blocked | 初始化中的“静态勘察”和“候选综合”都是 Main Planning Session;“运行时侦察”和“候选验证”都是 Runner Session。职责相同的多次 Session 仍不能共享完整对话,只能读取当时允许的落盘工件和角色裁剪上下文。 @@ -134,7 +134,7 @@ User Message - **Main · 规划**:请求、trigger、base/target/included commits、场景模式、初始化标记、已索引场景摘要,以及有限的历史报告/Run/Issue 查询能力; - **Runner**:run-id、固定 target、计划、工作场景、非生产环境工具和 Harness 已确认阻塞原因;不直接注入历史 Issues 或 Git Token; - **Reviewer**:run-id、固定 target、本次工件、证据引用和 Harness 阻塞原因;可以对已经读取的当前 Run 清理证据作结构化确认,但不获得目标环境命令、历史 Issue 列表、测试账号或任意仓库写入能力; -- **Main · 最终汇总**:固定 Run 范围、本次四个前置工件、Reviewer 结论,以及只与本次 confirmed Bugs 的 Issue create/link 相关的历史 Issue/Run 摘要;不获得通用历史查询、目标仓库通用读取或命令能力。 +- **Main · 最终汇总**:固定 Run 范围、本次四个前置工件、Reviewer 结论和受限的 `query_issue_candidates`;它先从 `draft-report.md`、`review.md` 形成 Bug 候选,再按标题/关键词/bug key 查询可能相同的 Issue/Run;不预先依赖尚未生成的 `confirmed_bugs`,也不获得通用历史查询、目标仓库通用读取或命令能力。 ### 3.6 内置角色指令内容规则 @@ -184,27 +184,40 @@ User Message - 初始化请求同样只能针对当前场景测试分支 HEAD,或先通过 merge-source/首次建分支把来源纳入固定分支; - API 响应和网站显示 queued、merge/running、waiting archive、completed/failed/interrupted 等现有事实,不增加跨 Run checkpoint。 -### 4.3 固定 merge 结果与恢复幂等 +### 4.3 固定 merge 结果、Git 可达性与恢复幂等 -`manual-merge-source` 必须按以下顺序执行: +`manual-merge-source` 在罗网的**本地持久 Git 仓库**中为每个队列请求使用确定性 internal ref: + +```text +refs/luowang/merge-requests/ +``` + +该 ref 不是业务分支,只用于让 prepared commit object 在进程重启、临时工作区清理和本地 Git GC 后仍可达;它不得被 push 到目标仓库,也不得加入任何默认 push refspec。 + +执行顺序固定为: ```text 解析 source ref → 基于当时远端 scenario-testing HEAD 生成本地 merge commit +→ 创建本地 internal ref 指向该 commit → 持久化 prepared_merge_commit -→ non-force push +→ non-force push prepared commit 到远端 scenario-testing → 持久化 resolved_target_commit → 使用 resolved_target_commit 创建且只创建一个 Run +→ 请求 completed 或明确 failed/interrupted 后清理 internal ref ``` 具体规则: -- `prepared_merge_commit` 必须在 push 前提交到 SQLite;成功 push 后,`resolved_target_commit` 固定为已经发布到场景测试分支的同一 commit;Orchestrator 只能接收该字段,不能重新读取移动中的 HEAD 替换 target; -- 来源已经是场景测试分支祖先时不创建重复 merge commit;把当时远端 HEAD 作为本请求的 prepared/resolved commit,仍可创建本次人工 Run; +- `prepared_merge_commit` 必须在 push 前提交到 SQLite,且此时 internal ref 必须存在并指向同一 SHA;成功 push 后,`resolved_target_commit` 固定为已经发布到场景测试分支的同一 commit;Orchestrator 只能接收该字段,不能重新读取移动中的 HEAD 替换 target; +- 来源已经是场景测试分支祖先时不创建重复 merge commit;internal ref 指向当时远端 HEAD,再把该 SHA 持久化为 prepared/resolved,仍可创建本次人工 Run; +- 进程在 prepared 后、push 前退出时,恢复逻辑必须从 internal ref 读取并校验同一 object,再 non-force push 同一 commit;临时 clone、merge 工作树或进程内对象都不能成为唯一来源; +- prepared 存在但 internal ref 缺失/指向其他 SHA,且远端也不包含 prepared commit 时,请求明确失败,不重新生成 merge;如果远端已包含 prepared,则按已成功 push 恢复并持久化同一 resolved; - 进程在 push 后、写入 resolved 前退出时,恢复逻辑 fetch 远端并检查是否已包含 `prepared_merge_commit`;已包含则持久化同一 `resolved_target_commit`,不得重复 merge 或改用更新后的 HEAD; -- 进程在 prepared 后、push 前退出时,只能尝试把同一 prepared commit non-force push;若远端已经竞争性前进且不包含 prepared commit,则请求明确失败,不重新生成指向新 HEAD 的 merge; - `resolved_target_commit` 已存在时,恢复逻辑只校验该 commit 已发布在远端场景测试分支历史中,然后创建或关联唯一 Run;即使场景分支后来又有新 commit,本请求 target 也不改变; -- `sourceRef` 无法解析、merge 冲突、远端竞争或 push 失败时,请求以明确失败结束,不创建 Agent Run、不修改产品代码、不推进 target; +- internal ref 已创建但 SQLite 尚无 prepared(进程恰在两步之间退出)时,不猜测或重做 merge:当前请求明确失败并清理该 ref;没有对应队列行的孤儿 ref 也在启动对账后清理; +- internal ref 在 `queued`、`running`、`waiting_archive` 期间不得被普通 workspace cleanup、fetch/prune 或 GC 删除;只在请求进入 terminal 状态后幂等清理;清理失败记录脱敏运维错误但不得改变已经固定的 Run target; +- `sourceRef` 无法解析、merge 冲突、远端竞争或 push 失败时,请求以明确失败结束,不创建 Agent Run、不修改产品代码、不推进 target,并清理 internal ref; - 人工 merge 请求不参与自动请求合批;远端写入继续禁止 force-push。 ### 4.4 `v0.1.0` 旧队列行迁移 @@ -240,9 +253,9 @@ registered → cleanup-claimed → verified-cleaned `cleanup-claimed` 只是 Runner 声明,不能让 Run 通过;只有以下任一方式能产生 `verified-cleaned`: 1. 受控清理 adapter 对该 ID 执行删除并独立查询确认不存在,返回 Harness 生成的核验 receipt; -2. Runner 使用受控 UI/API/命令工具删除并把“删除后不存在”的脱敏截图或查询结果保存到当前 Run evidence,Reviewer 实际读取该证据后,通过专用确认工具判定足以证明清理。 +2. Runner 使用受控 UI/API/命令工具删除后,由 Harness 直接捕获删除后查询的真实响应/输出,或接收 Playwright MCP 直接生成的删除后截图;Reviewer 实际读取该证据后,通过专用确认工具判定足以证明清理。 -Markdown、自填字符串、任意 URL、没有被 Harness Evidence Store 管理的路径,或 Runner 单独调用“已清理”工具,都不能成为 `verified-cleaned`。 +Markdown、自填字符串、任意 URL、没有被 Harness Evidence Store 管理的路径,或 Runner 单独调用“已清理”工具,都不能成为 `verified-cleaned`。Agent 不能提交 evidence 正文、状态码、退出码或内容摘要来伪装工具结果。 ### 5.2 Runner 和 Reviewer 工具 @@ -255,7 +268,15 @@ Runner 获得: Reviewer 获得 `verify_test_data_cleanup`:只能处理当前 Run 的 cleanup claim;对应 evidence 必须存在,并且 Reviewer 已通过受控 evidence reader 实际读取。Reviewer 可以确认或拒绝,不能执行删除、访问测试账号或提供任意证据路径。 -需要支持脱敏文本查询结果时,Evidence Store 增加受限的文本 evidence 保存/读取能力;文件名、类型、大小和路径继续受当前 Run 目录 allowlist 约束。`cleanup_test_data` 不再在没有真实 adapter 时假称统一删除。 +需要文本清理证据时,不提供接受 Agent 任意 `content` 的保存工具。Evidence Store 只能从以下受控执行结果直接生成记录: + +- 清理 adapter 的删除后查询响应; +- 受控 API 查询工具的真实响应; +- 受控、只读、与已登记测试数据 ID 绑定的查询命令实际输出。 + +任意 `echo`/`printf`、自由文本命令或仅复述结论的输出不能成为合格清理证据。Runner 可以选择已登记数据 ID 和 allowlist 内的查询操作/参数,但不能提供响应正文。Harness 在工具/adapter 返回时捕获真实 payload,完成 Secret 脱敏后把可审核内容及其 metadata 写入 evidence;每条至少记录:来源工具/adapter ID、当前 Run ID、测试数据 ID、查询时间、HTTP 状态码或进程退出码、脱敏后内容摘要和 SHA-256。文件名、类型、大小、路径和响应脱敏继续受当前 Run Evidence Store allowlist 约束。Playwright MCP 直接产生的删除后截图仍可作为图像证据。 + +`submit_test_data_cleanup_claim` 只能引用上述 Harness 生成的 evidence ID 或受控 Playwright 截图 ID;`cleanup_test_data` 不再在没有真实 adapter 时假称统一删除。 ### 5.3 场景结束和 Run 结束 @@ -302,12 +323,46 @@ finish_scenario(scenario_id) - report/scenario/archive 状态和脱敏错误; - initialization、special blocked、interrupted 标记。 -支持按当前 commit 范围、场景 ID、Issue/bug key 和最近数量筛选;默认上限 20,硬上限 100。默认不返回完整工件、模型对话、Secret、测试账号或未脱敏工具参数。 +Main Planning 的 `query_run_history` 支持按当前 commit 范围、场景 ID、Issue/bug key 和最近数量筛选;默认上限 20,硬上限 100。 + +Main Finalization 不依赖尚未生成的 `confirmed_bugs` 预注入摘要,而获得独立的受限只读工具: + +```text +query_issue_candidates({ + title?: string, + keywords?: string[], + bug_key?: string, + limit?: number +}) +``` + +输入契约: + +- `title`、非空 `keywords`、`bug_key` 至少提供一个;全部 trim 后校验,不接受控制字符; +- `title` 最长 200 字符;`bug_key` 最长 128 字符;`keywords` 为 1–8 个去重字符串,每项 2–64 字符; +- `limit` 是 1–100 的整数,默认 20; +- 匹配前统一 Unicode NFKC、转小写并折叠空白;bug key 精确匹配优先,其次是规范化标题精确/互相包含,再按关键词在 Issue title、StoredRunIssue title/bug key 中的命中数匹配; +- 去重后稳定排序:exact bug key、exact title、关键词命中数降序、Issue `updatedAt` 降序、Issue number 降序;相关 Run 按 finishedAt 降序、run-id 降序。 + +结构化返回固定为: + +```text +{ status: "ok", candidates: [...] } +{ status: "empty", candidates: [] } +{ status: "unavailable", candidates: [], message: "脱敏原因" } +``` + +`ok` 只能用于非空结果;`empty` 只表示查询成功但无匹配;依赖失败必须是 `unavailable`。candidate 可以包含 Issue number/title/url/state、匹配原因/bug key,以及关联 Run 的 run-id/result/scenario IDs/target commit;不返回完整工件、模型对话、测试账号、Secret 或未脱敏工具参数。 + +使用顺序和反循环边界: + +1. Main · 最终汇总先读取本次 `draft-report.md`、`review.md` 和其他允许工件,自行形成一个或多个 Bug 候选; +2. 再按每个候选调用工具;一个 Main Finalization Session 最多调用 10 次;同一规范化查询只有首次结果为 `unavailable` 时可以重试一次,`ok`/`empty` 不得原样重复查询; +3. 第二次 unavailable 或总预算耗尽后记录覆盖缺口并继续最终汇总,不能循环调用,也不能把 unavailable 当 empty; +4. 工具只读,不能创建、修改、关闭或评论 Issue;最终 create/link 决定仍由 Main · 最终汇总写入 `report.md`,后续受控 Issue owner 执行; +5. 不增加 Reviewer 结构化 Bug 输出、中间状态文件或新的长期事实源。 -- Main · 规划可以按需调用 `query_run_history`,用于影响判断和场景选择; -- Main · 最终汇总不获得通用历史查询工具,只由 Harness 提供与本次 confirmed Bugs 的 Issue create/link 相关的有限历史 Issue/Run 摘要; -- Runner 和 Reviewer 不获得历史查询工具; -- SQLite 查询失败与“成功但无历史”必须区分,失败时 Main · 规划记录覆盖缺口,不能当作空历史。 +Main · 规划只获得 `query_run_history`;Main · 最终汇总只获得 `query_issue_candidates`;Runner 和 Reviewer 两者都没有。SQLite/GitHub 查询失败与“成功但无候选”必须区分,失败时对应 Main 记录覆盖缺口,不能当作空结果。 ## 8. 验收分层和命令语义 @@ -329,10 +384,11 @@ local 至少证明两类生产流程: 初始化还必须分别覆盖: - **直接新增并验证**:执行上述完整六 Session 序列,候选综合产生可直接应用的新场景,新的 Runner Session 执行候选验证,之后 Reviewer 和 Main Finalization 均运行; -- **需要场景 PR 时提前 blocked**:固定执行 Main Planning 静态勘察 → Runner 运行时侦察 → 新 Main Planning 候选综合 → Reviewer → Main Finalization,共五个 Session;由于候选 patch 必须人工审核,**不创建候选验证 Runner Session、不执行未审核场景**,但 Reviewer 仍审核已有侦察/patch 并写 `review.md`,Main Finalization 写 blocked `report.md`;与普通 Run 相同的五个 Markdown 工件必须齐全,另保留受限场景 patch 供归档创建 PR; -- **最终修订未重跑**:在已完成候选验证的初始化用例中,Main · 最终汇总按 Reviewer 意见修订尚未发布 patch 后,因修订内容没有新的 Runner Session 重新执行,结果必须保持 blocked。 +- **需要场景 PR 时立即 blocked**:固定执行 Main Planning 静态勘察 → Runner 运行时侦察 → **新的** Main Planning 候选综合,共三个真实 Agent Session;策略判断候选 patch 需要人工审核后立即结束,不创建候选验证 Runner、Reviewer 或 Main Finalization Session,不执行未审核场景,也不等待人类;Harness 确定性生成特殊 blocked `report.md`,Archiver 随后创建场景 PR; +- **特殊 Run 工件**:最终持久化工件严格只有 `scenario-changes.patch` 和 `report.md`;`plan.md`、`execution.md`、`draft-report.md`、`review.md` 对该特殊 Run 标记为不适用。三个 Session 在 running workspace 产生的临时交接文件可以用于当次流程,但 `RunWorkspace.finalize({ specialScenarioReview: true })` 必须按两文件 allowlist 选择性完成,不能把整个 running 目录原样 rename 后让额外 Markdown 残留;completed artifact list 必须精确等于 patch + report,`isSpecialScenarioReviewRun()` 的两文件识别契约保持; +- **最终修订未重跑**:只适用于已经进入 Reviewer/Main Finalization 的直接新增验证路径;Main · 最终汇总按 Reviewer 意见修订尚未发布 patch 后,因修订内容没有新的 Runner Session 重新执行,结果必须保持 blocked。 -多个 Main Planning Session 和多个 Runner Session 不共享完整对话,每个 Session 只获得自己的内置角色指令和受控工具;上述每条路径创建的全部 Session 都必须 dispose。 +直接新增路径中的多个 Main Planning Session 和多个 Runner Session 不共享完整对话,每个 Session 只获得自己的内置角色指令和受控工具;所有实际创建的 Session 都必须 dispose。 merge 冲突、归档失败重试、Indexer 暂时不可用、进程重启和队列恢复属于确定性本地验收:使用真实生产代码和本地 Git、HTTP、S3-compatible 服务完成,不要求在 live GitHub 或官网环境制造故障。 @@ -460,10 +516,11 @@ thinking level、环境说明、额外账号和外部 allowlist 可以使用非 |---|---| | 内置角色指令缺失/错误 | Session 不启动,Run 明确失败或 blocked;不退回 Pi Skills 或 ambient 资源 | | 普通 Run 指定任意 target | `400` 拒绝并提示固定分支入口 | -| merge conflict/远端竞争 | 队列请求失败,不创建 Run、不推进、不自动改代码 | -| 数据只有 Runner 清理声明、证据未受控/未读取、Reviewer 拒绝或 adapter 未确认 | Run blocked,列脱敏残留和核验状态 | +| merge conflict/远端竞争 | 队列请求失败,不创建 Run、不推进、不自动改代码,清理本地 internal ref | +| prepared 未发布且 internal ref 缺失/不匹配 | 请求失败,不重做 merge、不改变 target;若远端已包含 prepared 则按成功 push 恢复 | +| 数据只有 Runner 清理声明、Agent 自填文本、证据未受控/未读取、Reviewer 拒绝或 adapter 未确认 | Run blocked,列脱敏残留和核验状态 | | Runner 没有场景 | 显示 `0/0`;是否 passed 仍执行既有零场景审核规则 | -| 历史 Run 查询失败 | 标记 unavailable,不伪装空历史 | +| Run 历史或 Issue 候选查询失败 | 标记 unavailable,不伪装空历史/空候选 | | local 通过、live 未配置 | local=passed、live=blocked、release=blocked,release 命令非零 | | Provider/MCP/OSS/GitHub 任一 live 检查失败 | live failed/blocked,不发布 | | 清理失败 | 保留证据和残留清单,不把 Run 或 release 写成 passed | @@ -472,7 +529,8 @@ thinking level、环境说明、额外账号和外部 allowlist 可以使用非 - SQLite schema 变更使用版本化、可重复执行 migration;现有队列、Run 和归档数据必须前向升级; - API 删除或拒绝 `targetCommit` 时更新网站和测试;如保留过渡字段,只能明确报错,不能继续执行旧的不安全语义; -- 已有 completed/、报告、Issues、场景 PR、last completed target 和 `v0.1.0` tag 不修改; +- 已有 completed/、报告、Issues、场景 PR、last completed target 和 `v0.1.0` tag 不修改;特殊场景审核 Run 继续只以 patch + report 识别; +- `refs/luowang/merge-requests/*` 只存在于罗网本地持久 Git 仓库,不迁移为目标仓库分支、不写入远端;升级启动时只对账和清理没有对应请求的孤儿 ref; - 内置角色指令资源属于罗网发布物,不是 Pi Skills,不写目标仓库; - 本地 acceptance 结果命名变化要提供 README 迁移说明; - 原生 `better-sqlite3` 在没有匹配预编译包时需要 `python3`、`make`、`g++`,README 优先推荐 Docker 并说明本地依赖。 @@ -491,14 +549,14 @@ thinking level、环境说明、额外账号和外部 allowlist 可以使用非 1. **AC-CLOSURE-INSTR-01**:Main Planning、Runner、Reviewer、Main Finalization 四类 Session 只装载对应的罗网 Built-in Role Instructions;ambient Skills、Prompt、Context 和用户/宿主机/目标仓库资源不会进入 Session;配置仍只有 Main、Runner、Reviewer 三组; 2. **AC-CLOSURE-INSTR-02**:固定角色指令只进入 system prompt 一次,user message 只包含当前任务和角色裁剪的动态上下文;角色工具权限与上游安全边界不变; 3. **AC-CLOSURE-INSTR-03**:Role Instructions 内容包含证据优先级、代码不得反推期望、独立审核、清理、偏差和反模式,但没有引入 suite/catalog/checkpoint/新结果状态/发布 gate; -4. **AC-CLOSURE-MERGE-01**:人工 branch/tag/SHA 请求进入 FIFO,按顺序生成 `merge --no-ff` commit、持久化 `prepared_merge_commit`、non-force push、持久化 `resolved_target_commit`,并只测试该已发布的不可变 commit;已包含来源不会重复 merge; +4. **AC-CLOSURE-MERGE-01**:人工 branch/tag/SHA 请求进入 FIFO,按顺序生成 `merge --no-ff` commit、创建本地 `refs/luowang/merge-requests/`、持久化 `prepared_merge_commit`、non-force push、持久化 `resolved_target_commit`,并只测试该已发布的不可变 commit;internal ref 从不推送,已包含来源不会重复 merge; 5. **AC-CLOSURE-TARGET-01**:普通人工/API Run 不能直接指定任意 target;自动、人工和初始化 Run 的 target 都是远端场景测试分支历史上的不可变 commit; -6. **AC-CLOSURE-MERGE-02**:`prepared_merge_commit`、`resolved_target_commit` 和唯一 Run 关联使 merge 冲突、远端竞争、push 前后重启恢复不修改产品代码、不重复 merge、不改变本次 target、不创建错误 Run、不推进; -7. **AC-CLOSURE-DATA-01**:Runner 可以登记并实际删除测试数据,但只有受控 adapter 独立核验,或 Reviewer 读取 Harness 管理的删除后证据并确认,才能成为 `verified-cleaned`;无 adapter 时全部经 Reviewer 确认的生产 Run 可以完成; -8. **AC-CLOSURE-DATA-02**:纯 Runner 声明、未受控/未读取证据、Reviewer 拒绝、pending 或兜底核验失败都使 Run blocked,报告显示脱敏残留和核验状态且 Secret 不泄漏; +6. **AC-CLOSURE-MERGE-02**:internal ref 保证 prepared object 经重启、临时工作区清理和 Git GC 后仍可达;结合 `prepared_merge_commit`、`resolved_target_commit` 和唯一 Run 关联,使 merge 冲突、远端竞争、push 前后重启恢复不重复 merge、不改变本次 target、不创建错误 Run;请求 terminal 后幂等清理 internal ref; +7. **AC-CLOSURE-DATA-01**:Runner 可以登记并实际删除测试数据,但只有受控 adapter 独立核验,或 Reviewer 读取 Harness 直接捕获的 adapter/API/只读查询输出或 Playwright 截图并确认,才能成为 `verified-cleaned`;无 adapter 时全部经 Reviewer 确认的生产 Run 可以完成; +8. **AC-CLOSURE-DATA-02**:Agent 自填 evidence 正文/状态/摘要、纯 Runner 声明、未受控/未读取证据、Reviewer 拒绝、pending 或兜底核验失败都使 Run blocked;合格文本证据记录来源、Run/data ID、时间、状态码/退出码和脱敏摘要/hash,且 Secret 不泄漏; 9. **AC-CLOSURE-ACTIVE-01**:真实 Runner Run 在网站依次显示总数、当前场景、已完成数和脱敏活动;零场景、Agent 异常和初始化侦察显示正确; -10. **AC-CLOSURE-HISTORY-01**:Main Planning 可以按需查询有限的正常、特殊 blocked、interrupted、场景 PR 和归档失败历史 Run,并区分空历史与查询失败;Main Finalization 只获得本次 confirmed Bugs 所需的有限历史 Issue/Run 摘要;Runner 和 Reviewer 不获得历史查询工具; -11. **AC-CLOSURE-PI-01**:本地生产路径集成用真实 `createAgentSession()` 分别完成普通 Main Planning → Runner → Reviewer → Main Finalization 四 Session Run,以及完整陌生项目初始化流程;覆盖 Pi 模型消息、内置角色指令、custom tool 循环、多个同角色 Session 的对话隔离、每个已创建 Session 的 dispose 和五个 Markdown 工件;初始化同时证明:直接新增并验证走完整六 Session;场景 PR 路径跳过候选验证 Runner、仍走 Reviewer/Main Finalization 并写齐五工件后提前 blocked;最终汇总修订未发布 patch 但未重跑时仍 blocked;FixtureSessionFactory 不能作为本 AC 证据; +10. **AC-CLOSURE-HISTORY-01**:Main Planning 可通过 `query_run_history` 查询有限历史 Run;Main Finalization 先读本次草稿形成 Bug 候选,再通过只读 `query_issue_candidates` 的受限 schema、稳定匹配/排序和 20/100 结果限制查询 Issue/相关 Run 并决定 create/link;返回严格区分 ok/empty/unavailable,同一 unavailable 最多重试一次且 Session 总调用不超过 10;Runner 和 Reviewer 无历史查询工具; +11. **AC-CLOSURE-PI-01**:本地生产路径集成用真实 `createAgentSession()` 分别完成普通四 Session Run 和陌生项目初始化;覆盖 Pi 模型消息、内置角色指令、custom tool 循环、同角色 Session 对话隔离及每个 Session dispose;直接新增并验证走完整六 Session 和五个 Markdown 工件;场景 PR 路径只创建 Main Planning → Runner → 新 Main Planning 三个 Session,策略判断后立即 blocked,不创建候选验证 Runner/Reviewer/Main Finalization,special finalize 排除临时普通工件,最终只持久化 `scenario-changes.patch`、Harness 生成的 `report.md`,并被 `isSpecialScenarioReviewRun()` 识别;最终汇总修订未发布 patch 但未重跑时仍 blocked;FixtureSessionFactory 不能作为本 AC 证据; 12. **AC-CLOSURE-ACCEPT-01**:local、live、release 三种验收状态和命令分离;live blocked 时 release 非零,README 不再称其为全量完成; 13. **AC-CLOSURE-ACCEPT-02**:每个受影响 AC 有独立、可追溯证据,不能依靠一个粗粒度 proof 批量标记通过; 14. **AC-CLOSURE-LIVE-01**:真实 GitHub + Provider + Pi + Playwright MCP + 私有 OSS + 非生产应用完成至少一个含 UI 截图和数据创建/清理的 passed Run;