diff --git a/.dockerignore b/.dockerignore index 7e31159..4e1ba46 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,8 @@ .git -.github +.github/* +!.github/workflows +.github/workflows/* +!.github/workflows/quality.yml .cache .cynos .env diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 7a82b08..8923e9d 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -17,7 +17,7 @@ jobs: quality: name: quality runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 60 env: NODE_IMAGE: docker.m.daocloud.io/library/node:24.14.1-bookworm-slim@sha256:b506e7321f176aae77317f99d67a24b272c1f09f1d10f1761f2773447d8da26c NPM_REGISTRY: https://registry.npmmirror.com diff --git a/docs/changes/luowang-v07-production-closure/intent.md b/docs/changes/luowang-v07-production-closure/intent.md index bff34ff..92cd87f 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.3 +- 状态:Approved v0.4 - 关联规格:[spec.md](./spec.md) - 实现计划:[plan.md](./plan.md) - 上游基线:[罗网 Harness MVP](../luowang-harness-mvp/intent.md) @@ -13,7 +13,7 @@ 但当前代码和发布说明把“本地 fixture 回归通过”表述成了“34 个 AC 全量验收完成”,而真实外部 smoke 仍为 blocked;同时,生产路径存在几项会阻止 v0.7 闭环成立的缺口: 1. 角色方法全部硬编码在 Orchestrator 长提示词中,同一内容还同时作为 system prompt 和用户消息发送;Pi Skills 已被安全禁用,但罗网也没有版本化、按角色隔离的内置角色指令资源; -2. 用户指定 branch/tag/SHA 时,merge 和测试是两个独立动作,普通 Run API 还允许直接传任意 target,可能绕开固定 `scenario-testing` 分支; +2. 用户指定 branch/tag/SHA 时,merge 和测试是两个独立动作,普通 Run API 还允许直接传任意 target,可能绕开固定 `scenario-testing` 分支;首次创建该分支的同步接口也与初始化 Run 分离,没有进入 prepared/resolved、唯一 Run 和重启恢复闭环; 3. 生产默认测试数据管理器只能登记数据,没有“Runner 已通过 UI/API 删除并确认”的路径;只要登记数据且没有注入测试适配器,Run 就会被强制 blocked; 4. 当前场景和执行进度只在 Run 创建时初始化为 `null`、`0/0`,真实 Runner 不会上报变化; 5. Main · 规划只得到 Git 正式报告摘要和 GitHub Issues,无法查询 SQLite 中特殊 blocked、interrupted、场景 PR 和归档失败等详细历史 Run; @@ -28,7 +28,7 @@ 1. Main · 规划、Runner、Reviewer、Main · 最终汇总和初始化方法成为罗网自身版本化的 Built-in Role Instructions(内置角色指令),由应用按 Session 确定性加载并完整注入;它们是发布物中的固定 Markdown 资源,不是 Pi Skills;目标仓库、宿主机和用户目录中的 Skills 仍不会被发现或执行; 2. 固定方法、安全边界、动态 Run 上下文和本次请求分层传递,不再重复注入同一长提示词;不同角色只看到自己需要的动态事实; -3. 人工 merge 请求进入现有 SQLite FIFO,在轮到它时生成可跨重启恢复的 prepared merge,完成 `non-force push → 固定 resolved target → Run`;prepared commit 在本地持久 Git 仓库中保持可达,普通人工测试不能直接绕开场景测试分支; +3. 人工 merge 请求进入现有 SQLite FIFO,在轮到它时生成可跨重启恢复的 prepared commit,完成 `non-force push → 固定 resolved target → Run`;远端场景测试分支不存在时,同一 `manual-merge-source + initialization=true` 请求从用户指定 commit 安全创建分支并且只创建一个初始化 Run;prepared commit 在本地持久 Git 仓库中保持可达,普通人工测试和首次建分支都不能绕开队列; 4. Runner 可以登记测试数据并通过 UI/API 删除,但 Runner 的清理声明或自填文本不能直接变成完成事实;只有受控 adapter 独立核验,或 Reviewer 读取由 Harness 直接捕获的工具/adapter 输出或 Playwright 截图后确认,数据才视为已清理,任何未确认残留仍可靠地使结果 blocked; 5. 网站在真实执行中显示总场景数、已完成数、当前场景和脱敏活动,而不是只依赖 UI fixture; 6. Main · 规划可以按需查询有限、只读、相关的历史 Run 摘要;Main · 最终汇总先从本次 `draft-report.md` 和 `review.md` 形成 Bug 候选,再通过受限只读工具查询可能相同的历史 Issue/Run 并决定 create/link;Runner 和 Reviewer 均不获得历史查询工具; @@ -58,7 +58,7 @@ - v0.7 PDF 是本变更的产品与架构权威;本变更只细化其生产闭环,不增加相反设计; - 保留单实例、单租户、单目标仓库、单场景测试分支、单测试环境、单 active Run 和 FIFO; -- 不引入多阶段 checkpoint、通用工作流引擎、发布 gate、多 worker、复杂 worktree 或新的长期状态文件; +- 不引入多阶段 checkpoint、通用工作流引擎、发布 gate、多 worker、复杂 worktree 或新的长期状态文件;首次建场景分支复用 `manual-merge-source` 和既有 `initialization` 字段,不增加第四种请求; - 继续使用 `passed | failed | blocked`,不照搬其他项目的五状态、三轴结论或复杂聚合模型; - 罗网始终只有 `agents.main`、`agents.runner`、`agents.reviewer` 三组 Agent 配置;正常 Run 创建 Main · 规划、Runner、Reviewer、Main · 最终汇总四个互相隔离的 Session,不增加 Planner/Finalizer 配置; - 内置角色指令只规定工作方法,不提供权限;所有读取、写入、Secret 和副作用权限继续由代码中的 custom tools、Secret Store、adapter、writer、路径 allowlist 和 patch 校验强制执行; @@ -88,7 +88,7 @@ 除最后的真实联合验收外,其余实现阶段不得因缺少外部 Secret 而停工。进入真实验收前,项目负责人必须提供或确认: -1. **测试项目**:默认继续使用 `https://github.com/cynos-ai/cynos-website`;确认它是可信、允许写入测试资产和创建测试 PR/Issue 的独立目标,而不是罗网仓库;如需更换,必须在验收开始前明确新 URL; +1. **测试项目**:默认继续使用 `https://github.com/cynos-ai/cynos-website`;确认它是可信、允许写入测试资产和创建测试 PR/Issue 的独立目标,而不是罗网仓库;live 首次建分支验收开始时,该目标的已配置 `scenario-testing` 必须不存在且可由指定初始 commit 创建,若默认项目不能安全提供该前置条件则必须换用新的独立测试仓库; 2. **GitHub 权限**:仅授予该测试仓库的临时或专用 Token,允许 Metadata 读取、Contents 读写、Pull Requests 读写和 Issues 读写;不授予组织管理、Actions 管理或其他仓库权限; 3. **非生产应用**:可访问的测试/预发布 Base URL、环境说明、允许验证的 API/UI 流程、可控的 passed/failed/blocked 条件,以及确认不会触碰生产数据; 4. **测试账号和清理能力**:专用账号及角色、测试数据命名约束、通过 UI/API 删除本次数据的方式,以及可独立证明数据已不存在的脱敏查询/截图/API 证据;如果环境不能删除或不能验证临时数据已清理,则不能完成 live 验收; @@ -105,7 +105,7 @@ 本变更成功不以“新增了多少文件或测试”为标准,而以以下事实同时成立为准: - 已知生产路径缺口均有用户可观察的修复和自动回归; -- 实际 Pi SDK Session 而非 FixtureSessionFactory 分别证明正常四 Session Run、初始化直接新增场景的六 Session 流程,以及需要场景 PR 时立即结束的三 Session 特殊 blocked 流程,覆盖模型消息、受控工具循环、Session 隔离与 dispose; +- 本地与 live 均从目标仓库尚无 `scenario-testing` 开始,证明 `manual-merge-source + initialization=true` 经 internal ref、prepared/resolved 和唯一 Run 创建分支并进入陌生项目初始化;实际 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 40b1c73..28c569e 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.3 +- 状态:Implementation Plan v0.4 - 关联 Intent:[intent.md](./intent.md) - 关联 Spec:[spec.md](./spec.md) - 上游计划:[罗网 Harness MVP Plan](../luowang-harness-mvp/plan.md) @@ -13,7 +13,7 @@ 完成后必须同时证明: 1. 角色方法被确定性、按角色、安全地加载; -2. 所有正式 target 都来自固定场景测试分支; +2. 所有正式 target 都来自固定场景测试分支;该分支首次创建也经过 FIFO、prepared/resolved 和唯一初始化 Run; 3. 测试数据、当前进度和历史 Run 在生产路径中真实可用; 4. 本地验收真实经过 Pi SDK Session,而不是只调用 FixtureSessionFactory; 5. 真实 GitHub、Provider、Pi、MCP、OSS 和非生产应用联合验收通过; @@ -70,7 +70,7 @@ Closure Phase 0–6 不需要真实 GitHub Token、Provider Key、测试账号 | 类别 | 人类提供/确认 | 最小权限或要求 | 缺失结果 | |---|---|---|---| -| 测试仓库 | 默认 `https://github.com/cynos-ai/cynos-website`,或明确替换 URL | 可信、不是罗网仓库、允许 `scenario-testing` 测试写入 | Phase 7 blocked | +| 测试仓库 | 默认 `https://github.com/cynos-ai/cynos-website`,或明确替换 URL;用户确认的初始 branch/tag/SHA | 可信、不是罗网仓库、允许测试写入;live 开始时 `scenario-testing` 不存在且可从初始 commit 创建 | Phase 7 blocked | | GitHub Token | `LUOWANG_LIVE_GITHUB_TOKEN` | 仅该仓库 Metadata read、Contents read/write、PR read/write、Issues read/write | Phase 7 blocked | | 非生产应用 | `LUOWANG_LIVE_BASE_URL`、环境说明 | 非生产、合成数据、一个 passed 流程、两个独立可逆 failed 条件、一个 blocked 条件、可删除并独立核验测试数据 | Phase 7 blocked | | 测试账号 | username/password 及角色 | 专用、非个人/生产账号,只给 Runner | Phase 7 blocked | @@ -90,6 +90,8 @@ Closure Phase 0–6 不需要真实 GitHub Token、Provider Key、测试账号 # 非 Secret:需要明确回复 TEST_REPOSITORY_URL=https://github.com/cynos-ai/cynos-website SCENARIO_BRANCH=scenario-testing +SCENARIO_BRANCH_ABSENT_AT_START=yes|no +INITIAL_SOURCE_REF= REPOSITORY_IS_TRUSTED=yes|no TEST_BASE_URL= ENVIRONMENT_DESCRIPTION= @@ -221,24 +223,24 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET `AC-CLOSURE-INSTR-01`、`AC-CLOSURE-INSTR-02`、`AC-CLOSURE-INSTR-03` 通过;三组配置、四类 Session 和角色行为测试保持,未扩大任一角色权限。 -## 8. Closure Phase 2:人工 merge 与测试进入同一 FIFO +## 8. Closure Phase 2:首次建分支、人工 merge 与测试进入同一 FIFO ### 目标 -任何 branch/tag/SHA 只有先进入 `scenario-testing` 才能成为正式 target;人工 merge 不再是队列外副作用。 +任何 branch/tag/SHA 只有先进入 `scenario-testing` 才能成为正式 target;人工 merge 和首次创建场景分支都不再是队列外副作用。目标仓库尚无场景分支时,同一个 `manual-merge-source + initialization=true` 请求完成首次创建并且只创建一个陌生项目初始化 Run。 ### 修改范围 -1. 通过新 migration 为现有测试请求队列增加 `request_kind`、`source_ref`、`prepared_merge_commit`、`resolved_target_commit`;后两个字段是请求幂等事实,不建立通用 checkpoint。严格实现 Spec §4.4 的旧行规则: +1. 通过新 migration 为现有测试请求队列增加 `request_kind`、`source_ref`、`prepared_merge_commit`、`resolved_target_commit`;后两个字段是请求幂等事实,不建立通用 checkpoint。复用并持久化队列已有 `initialization`,不增加第四种请求。严格实现 Spec §4.4 的旧行规则: - terminal 行只读保留,不重新执行;有关联 Run 时从 Run Store 回填 resolved; - 有 `run_id` 的 running/waiting_archive 只恢复既有 Run/归档;`waiting_archive` 缺少 `run_id` 时统一 failed,不重新排队; - queued/running-without-run automatic 行迁为 `automatic-head`,调度时取新 HEAD; - queued/running-without-run manual/api 且旧 target 为空时迁为 `manual-current-head`; - queued/running-without-run manual/api 且旧 target 非空时明确 failed,不把旧 target 猜成 sourceRef 或 merge 授权; - 旧 `target_ref` 只作历史兼容读取,新调度不使用; -2. 在 Queue/Automation owner 中实现 Spec §4 三类请求;自动请求仍只合并 queued automatic,人工请求永不合并; +2. 在 Queue/Automation owner 中实现 Spec §4 三类请求;自动请求仍只合并 queued automatic,人工请求永不合并。场景分支不存在时 automatic 不产生批次,已排队 automatic/current-head 和未标记 initialization 的 merge-source 均明确失败且无 Run; 3. 在 Repository/Queue owner 中以持久目标仓库 object store 管理确定性本地 ref `refs/luowang/merge-requests/`;该 ref 不进入 push refspec、不推送到目标仓库,也不作为业务分支展示; -4. 调度 `manual-merge-source` 时严格执行: +4. 远端场景分支已存在时,调度 `manual-merge-source` 严格执行普通路径: - fetch 并解析 source ref; - 基于当时远端 `scenario-testing` HEAD 生成本地 `merge --no-ff` commit; - 先创建 internal ref 指向该 commit,确保 object 可达; @@ -246,43 +248,54 @@ LUOWANG_LIVE_OSS_ACCESS_KEY_SECRET - non-force push 同一 prepared commit; - push 成功后持久化同值的 `resolved_target_commit`; - 只使用 `resolved_target_commit` 创建或关联唯一 Run; -5. 恢复逻辑按 Git ref 和 SQLite 事实共同判断: - - 只有 prepared:internal ref 必须指向同一 SHA;远端已包含则补写 resolved,否则只 push 该 ref 的 commit;ref 缺失/不匹配且远端未包含时失败,不重做 merge; +5. 远端场景分支在调度 fetch 后不存在且请求为 `manual-merge-source + initialization=true` 时,严格执行首次创建特例: + - 解析一次 `sourceRef` 并固定 source commit; + - 创建 internal ref 指向 source commit; + - 持久化 `prepared_merge_commit = source commit`; + - 以 expected-absent/compare-and-create 条件 non-force 创建远端 `scenario-testing`,不能覆盖或推进竞争创建的 ref; + - 持久化 `resolved_target_commit = prepared_merge_commit`; + - 只使用该 resolved 创建或关联一个 `initialization=true` Run,不另行触发初始化; +6. 恢复逻辑按 Git ref 和 SQLite 事实共同判断: + - 只有 prepared:internal ref 必须指向同一 SHA;push 成功、拒绝、连接中断或进程退出均先 fetch,远端已包含 prepared 就补写同值 resolved;普通路径否则只 push 同一 commit,首次路径在远端仍不存在时只重试 compare-and-create 同一 commit;ref 缺失/不匹配且远端未包含时失败,不重做 merge/建分支; + - 首次路径遇到已存在且不包含 prepared 的远端分支时才按竞争失败;若已包含 prepared,则只把 prepared 认定为已发布,不改用较新 HEAD;两种情况都不转普通 merge、不重建 commit; - 已有 resolved:校验它位于远端场景分支历史,忽略后来新增 HEAD,创建或关联唯一 Run; - internal ref 已有但 prepared 为空:视为 ref/DB 间崩溃,明确失败并清理,不猜测 prepared; - 已有关联 Run:不再创建第二个; -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 文案,明确“已排队”而不是“已经合并”。 +7. 已有分支路径中来源已是祖先时不生成 merge commit;internal ref 指向当时远端 HEAD,再持久化 prepared/resolved 后创建 Run; +8. 请求在 queued/running/waiting_archive 期间保留 internal ref,不受普通 workspace cleanup、fetch/prune 或 Git GC 影响;completed/failed/interrupted 后幂等清理,启动时清理无队列行的孤儿 ref; +9. 改造 `/api/repository/merge` 和网站入口为异步入队,支持 `initialization=true` 并返回 queue/request ID;首次建分支 UI 复用该入口; +10. 删除 `/api/repository/scenario-branch` 的同步 Git 写入;兼容期若保留端点,只返回迁移错误并指向 merge-source initialization 入口; +11. 普通 `/api/runs` 和网站 Run 表单移除任意 target 输入;非空旧字段明确 `400`;重测入口复用原请求说明但在调度时读取当前场景测试分支 HEAD; +12. Orchestrator 只接收调度层持久化且已证明发布到场景测试分支的 `resolved_target_commit` 和原请求 `initialization`;保留 checkout 后 SHA 一致性检查; +13. 更新 API/UI 文案,明确“已排队”而不是“已经合并/已经创建”。 ### 专项验证 -使用临时 bare remote 和真实 Queue/Repository/Recovery 生产代码: +使用从未创建 `scenario-testing` 的临时 bare remote 和真实 Queue/Repository/Recovery 生产代码: -- 空库和 `v0.1.0` schema 都能迁移四个字段;migration 重复启动不重复改写; +- 空库和 `v0.1.0` schema 都能迁移四个字段;已有 `initialization` 不丢失,migration 重复启动不重复改写; - 分别构造 automatic/manual/api × queued/running-without-run/running-with-run/waiting_archive-with-run/waiting_archive-without-run/completed/failed/interrupted 旧行:断言 request kind、requeue/recovery/fail/只读行为与 Spec §4.4 表完全一致;`waiting_archive` 缺少 Run ID 必须 failed; - 旧 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,先创建 `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;请求 terminal 后 internal ref 被幂等清理,重复清理安全;无队列行的孤儿 ref 在启动对账后删除; -- 来源已是祖先时不重复 merge,internal ref/ prepared/resolved 指向当时 HEAD 并创建新的人工 Run; +- 分支不存在时 automatic 不产生批次,queued automatic/current-head 和 `initialization=false` 的 merge-source 均不创建分支或 Run;旧 `/api/repository/scenario-branch` 不再产生同步 Git 副作用; +- 排队 `manual-merge-source + initialization=true`,按用户指定 branch/tag/SHA 解析一次 source commit;internal ref、`prepared_merge_commit` 和 source commit 三者相等,internal ref 先于 prepared 创建; +- 首次 compare-and-create 成功后,远端 HEAD、prepared、resolved 和唯一 initialization Run target 全部相等;队列只关联一个 Run,Run 保留 `initialization=true`; +- 首次路径在 prepared 后、push 前退出:删除临时工作树/clone、重启并执行 `git gc`;远端仍无分支时只从 internal ref 发布同一 SHA;远端已包含 prepared 时只补写 resolved; +- 首次路径在 push 后、resolved 前退出:恢复同一 resolved,不重复建分支;resolved 后、Run 创建前让远端分支前进,恢复仍只创建一个以旧 resolved 为 target 的 initialization Run; +- 在首次 compare-and-create 前由竞争者创建不包含 prepared 的同名分支:请求 failed,不推进竞争 HEAD、不转普通 merge、不重建 prepared、不创建 Run;竞争者创建的分支若已包含 prepared,则按幂等发布成功补写 `resolved=prepared`,Run 仍只测试 prepared 而非竞争 HEAD; +- 场景分支建立后再排队普通 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`,恢复只 push 同一 SHA,不重新生成 merge; +- 两条路径在 internal ref 创建后、prepared 写入前退出:请求明确 failed、ref 被清理且不创建 Run;prepared 存在但 ref 缺失/不匹配且远端不含该 commit 时同样 failed; +- 普通路径在 push 后、resolved 前退出可从远端包含关系补写同一 resolved,不重复 merge;resolved 后、Run 前场景分支再前进仍使用旧 resolved; +- 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 计算不回归。 ### 退出条件 -`AC-CLOSURE-MERGE-01`、`AC-CLOSURE-TARGET-01`、`AC-CLOSURE-MERGE-02` 通过;没有队列外人工 merge 写入路径。 +`AC-CLOSURE-MERGE-01`、`AC-CLOSURE-TARGET-01`、`AC-CLOSURE-MERGE-02` 和上游 `AC-GIT-01` 通过;没有队列外人工 merge/首次建分支写入路径,push outcome 后崩溃不需要新增 checkpoint 即可确定恢复。 ## 9. Closure Phase 3:真实测试数据清理确认 @@ -404,7 +417,7 @@ Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总 1. 建立本地可控模型协议服务或等价 adapter,使测试不调用公网但真实经过生产 `createPiAgentSessionFactory` 和 `createAgentSession()`; 2. 为普通 Run 建立真实生产路径验收:Main Planning Session → Runner Session → Reviewer Session → Main Finalization Session;四个 Session 各自新建和 dispose,两个 Main Session 共用 `agents.main` 配置但不共享对话,通过五个 Markdown 工件交接; -3. 为陌生项目初始化建立完整真实 Pi 路径: +3. 为陌生项目初始化建立完整真实 Pi 路径:从尚无 `scenario-testing` 的临时 bare remote 提交 `manual-merge-source + initialization=true`,先真实经过 internal ref → prepared → 首次 non-force 创建 → resolved → 唯一 initialization Run,再进入: - Main Planning Session:静态勘察; - Runner Session:运行时侦察; - **新的** Main Planning Session:候选综合; @@ -416,7 +429,7 @@ Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总 - 需要场景 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 暂时不可用、进程重启、队列恢复,以及 internal ref + 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; @@ -429,20 +442,21 @@ Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总 - 普通 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; +- 初始化用例开始时远端没有 `scenario-testing`;断言 `manual-merge-source + initialization=true` 只发布 internal ref 固定的 prepared source commit、写入同值 resolved 并创建一个 initialization Run;不调用队列外首次建分支端点; - 初始化直接新增场景用例真实经过六个新 Session;两个 Main Planning Session 互不共享对话,两个 Runner Session 互不共享对话,每次只获得本阶段内置角色指令和工具; - 初始化场景 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、internal-ref/prepared/push/resolved 各退出点、临时工作区删除与 Git GC、terminal ref 清理、归档失败重试、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,扫描阴性。 ### 退出条件 -`AC-CLOSURE-PI-01`、`AC-CLOSURE-ACCEPT-01`、`AC-CLOSURE-ACCEPT-02` 通过;merge、归档、Indexer、重启和队列恢复的确定性故障证据已在 local 完成,Phase 7 只关注真实外部联合证明。 +`AC-CLOSURE-PI-01`、`AC-CLOSURE-ACCEPT-01`、`AC-CLOSURE-ACCEPT-02` 和上游 `AC-GIT-01` 通过;首次建分支、merge、归档、Indexer、重启和队列恢复的确定性故障证据已在 local 完成,Phase 7 只关注真实外部联合证明。 ## 13. Closure Phase 7:真实联合验收和发布 @@ -455,9 +469,9 @@ Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总 实现 Agent 在任何副作用前输出一份不含值的检查表: ```text -[ ] 测试仓库 URL 已确认 +[ ] 测试仓库 URL 和初始 source ref 已确认 [ ] GitHub Token 四项最小权限检查通过 -[ ] scenario-testing 可 non-force 写入/PR +[ ] scenario-testing 在验收开始时不存在,可首次创建并在之后 non-force 写入/PR [ ] 非生产 Base URL 已确认 [ ] passed 流程、两个独立 failed 条件及一个 blocked 条件已确认且可复位 [ ] 专用测试账号已配置 @@ -475,32 +489,33 @@ Main · 规划能查询 SQLite/Recovery 中相关历史;Main · 最终汇总 ### 实施与验收范围 1. 构建候选 `quality` 和 `runtime` 镜像,从独立持久卷启动一个非 root 罗网实例; -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 直接捕获的受控查询输出/Playwright 截图并确认;写五个工件、Git 正式报告,完成 Indexer 回读和实时 0/N→N/N; -6. 使用人类预先给出的两个独立、可逆失败条件完成一个真实 failed Run,确认至少两个不同 Bugs,幂等创建/关联多个 Issues,报告及 Issues 完成后才推进; -7. 完成一个真实 blocked Run:保留已确认 Bug(如有)但不推进;阻塞来源使用可控非生产依赖,不破坏环境; -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、重启或队列故障; -12. 发现生产问题时停止发布,在独立 `fix/*` 修复、合入 develop、重建候选并重跑受影响 AC 和完整 release acceptance; -13. 全部通过后由项目负责人选择 `v0.1.1` 或 `v0.2.0`,更新版本/README/变更说明; -14. 发起 `develop → main` PR,合并后创建指向发布 commit 的新 tag;核对 `v0.1.0` 指向未变化; -15. 轮换/撤销临时 GitHub Token、Provider Key、OSS Key 和测试账号,或记录它们作为专用长期凭据继续保留的人工决定。 +2. 通过网站/API 配置真实测试仓库、用户确认的初始 source ref、环境、Provider、Main/Runner/Reviewer 三个模型、Playwright MCP、私有 OSS 和账号;不得出现 Planner/Finalizer 独立配置或第四个模型检查; +3. 在任何 Git 写入前证明远端 `scenario-testing` 不存在,再运行其余 connectivity checks 并保存脱敏结果;若分支已存在则本次 live blocked,不能删除含人类资产的分支来继续; +4. 提交 `manual-merge-source + initialization=true`,从指定 source commit 首次创建 `scenario-testing`;验证 FIFO、internal ref 先于 prepared、`prepared == source commit`、expected-absent non-force 创建、`resolved == prepared`,并创建且只创建一个固定该 target 的陌生项目 initialization Run;不能调用队列外首次建分支接口; +5. 场景分支建立后,再使用普通 merge-source 请求把可控产品/需求变化纳入 `scenario-testing`,验证已有分支的 `merge --no-ff`、prepared/resolved 和固定 target; +6. 完成一个真实 passed UI Run:真实 Pi 创建 Main · 规划、Runner、Reviewer、Main · 最终汇总四个隔离 Session,执行 Playwright MCP 操作、截图、OSS 上传和 Reviewer 看图;创建并删除测试数据,提交清理 claim 后由 adapter 独立核验,或由 Reviewer 实际读取 Harness 直接捕获的受控查询输出/Playwright 截图并确认;写五个工件、Git 正式报告,完成 Indexer 回读和实时 0/N→N/N; +7. 使用人类预先给出的两个独立、可逆失败条件完成一个真实 failed Run,确认至少两个不同 Bugs,幂等创建/关联多个 Issues,报告及 Issues 完成后才推进; +8. 完成一个真实 blocked Run:保留已确认 Bug(如有)但不推进;阻塞来源使用可控非生产依赖,不破坏环境; +9. 验证陌生项目 initialization 的真实场景 PR 特殊路径只创建三个 Agent Session 并仅持久化 patch + Harness report;PR 合并后旧 Run 不变,当前 HEAD 人工重测创建新 Run;若首次建分支 Run 采用直接新增路径,则另行提交一个已有分支的 initialization Run 覆盖该特殊路径; +10. 验证场景/报告 allowlist、历史报告 blob SHA 不变、罗网仓库无测试资产; +11. 验证所有测试数据和 OSS 临时探测对象按策略清理;被正式 Git 报告引用的证据对象保留到项目负责人明确执行后续保留/删除决定,不得在验收收尾时误删; +12. 运行 `npm run test:acceptance:release`;它必须复用 Phase 6 的 local 确定性故障证据并执行本 Phase live 联合证明,保存分层 JSON/Markdown 结果;不在真实 GitHub/官网环境重复制造首次建分支竞争、merge 冲突、归档、Indexer、重启或队列故障; +13. 发现生产问题时停止发布,在独立 `fix/*` 修复、合入 develop、重建候选并重跑受影响 AC 和完整 release acceptance; +14. 全部通过后由项目负责人选择 `v0.1.1` 或 `v0.2.0`,更新版本/README/变更说明; +15. 发起 `develop → main` PR,合并后创建指向发布 commit 的新 tag;核对 `v0.1.0` 指向未变化; +16. 轮换/撤销临时 GitHub Token、Provider Key、OSS Key 和测试账号,或记录它们作为专用长期凭据继续保留的人工决定。 ### 必须保存的非 Secret 证据 - 候选镜像 digest、发布 commit; -- 测试仓库 URL、场景分支、source/merge/target commits; +- 测试仓库 URL、首次写入前场景分支不存在的证明、初始 source、prepared/resolved、后续 merge/target commits; - passed/failed/blocked Run IDs; - 内置角色指令 IDs/hash、Main/Runner/Reviewer 三个模型 ID; - 场景进度 API/页面截图; - OSS object keys/稳定受保护 URL 和 Reviewer 读取事实; - 报告 commit、场景 PR、多个 Issue URLs; - 清理前后脱敏数据 ID/查询结果; -- Phase 6 local 的重启/归档重试/队列恢复证据引用,以及本次 live Indexer 回读结果; +- Phase 6 local 的首次建分支/merge 重启恢复、归档重试、队列恢复证据引用,以及本次 live Indexer 回读结果; - local/live/release AC 矩阵和命令退出码; - `v0.1.0` 与新 tag 指向。 diff --git a/docs/changes/luowang-v07-production-closure/spec.md b/docs/changes/luowang-v07-production-closure/spec.md index ce75d3f..b1f76d3 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.3 +- 状态:Implementation Baseline v0.4 - 关联 Intent:[intent.md](./intent.md) - 实现计划:[plan.md](./plan.md) - 上游规格:[罗网 Harness MVP Spec](../luowang-harness-mvp/spec.md) @@ -8,7 +8,7 @@ ## 1. 规格范围与优先级 -本 Spec 只覆盖以下增量:角色工作方法装载、人工 merge 与固定 target、测试数据清理确认、实时场景进度、Main Planning 历史 Run、验收分层、外部资源交付和后续发布。 +本 Spec 只覆盖以下增量:角色工作方法装载、首次创建/人工 merge 与固定 target、测试数据清理确认、实时场景进度、Main Planning 历史 Run、验收分层、外部资源交付和后续发布。 发生冲突时: @@ -24,7 +24,7 @@ - `agents.main`、`agents.runner`、`agents.reviewer` 三组 Agent 配置已存在;正常 Run 创建 Main · 规划、Runner、Reviewer、Main · 最终汇总四个独立 Session,生产 Session 使用 Pi SDK; - ambient extensions、Skills、Prompt Templates、Themes 和 Context Files 已关闭; - 当前角色方法硬编码在 Orchestrator,完整提示词同时进入 system prompt 和首条用户消息; -- `/api/repository/merge` 直接执行 merge,`/api/runs` 接受任意 `targetCommit`; +- `/api/repository/scenario-branch` 在队列外同步创建首次场景分支,`/api/repository/merge` 直接执行 merge,`/api/runs` 接受任意 `targetCommit`; - 默认 TestDataManager 没有清理实现,登记数据后无法确认已清理; - `currentScenario` 和 `scenarioProgress` 只初始化、不随真实 Runner 更新; - Run Store 已保存详细 Run,但 Main · 规划上下文只包含正式报告摘要和 GitHub Issues; @@ -171,20 +171,24 @@ User Message | 请求 | 输入 | 调度时行为 | |---|---|---| | `automatic-head` | Git/Cron 请求文本 | 使用调度时已计算的场景测试分支最新可测试 HEAD;仍允许自动请求合批 | -| `manual-current-head` | 人工/API 请求文本、可选 initialization | fetch 后固定当前远端场景测试分支 HEAD;人工请求不合并、不丢失 | -| `manual-merge-source` | 人工请求文本、`sourceRef`、明确确认 | 轮到时 fetch,`merge --no-ff` 到场景测试分支,non-force push,固定发布后的新 HEAD,再创建 Run | +| `manual-current-head` | 人工/API 请求文本、可选 `initialization` | fetch 后固定当前远端场景测试分支 HEAD;人工请求不合并、不丢失 | +| `manual-merge-source` | 人工请求文本、`sourceRef`、明确确认、可选 `initialization` | 分支存在时执行 `merge --no-ff`;分支不存在且 `initialization=true` 时从解析后的 source commit 首次创建;两种路径都先固定 prepared/resolved,再创建 Run | -队列 migration 必须增加并持久化 `request_kind`、`source_ref`、`prepared_merge_commit`、`resolved_target_commit`;字段使用数据库命名,API 可继续使用对应 camelCase。`prepared_merge_commit` 和 `resolved_target_commit` 是请求幂等事实,不是通用 checkpoint 或工作流状态。不得把 branch/tag/任意 SHA 继续伪装成可直接 checkout 的 `targetCommit`。 +首次创建不是第四种请求,继续复用队列已有的 `initialization` 事实。队列 migration 必须增加并持久化 `request_kind`、`source_ref`、`prepared_merge_commit`、`resolved_target_commit`;字段使用数据库命名,API 可继续使用对应 camelCase。`prepared_merge_commit` 和 `resolved_target_commit` 是请求幂等事实,不是通用 checkpoint 或工作流状态。不得把 branch/tag/任意 SHA 继续伪装成可直接 checkout 的 `targetCommit`。 + +远端场景测试分支不存在时,`automatic-head` 不产生可测试批次;已排队的 `automatic-head` 或 `manual-current-head` 必须明确失败且不创建 Agent Run。`manual-merge-source` 只有携带 `initialization=true` 才能进入首次创建特例;否则明确失败并提示以初始化请求重提。 ### 4.2 API 和网站行为 -- 网站“合并 branch/tag/SHA”提交 `manual-merge-source`,返回 queue ID,不再同步返回已经完成的 merge; +- 网站“合并 branch/tag/SHA”提交 `manual-merge-source`,返回 queue ID,不再同步返回已经完成的 merge;请求可以明确携带 `initialization=true`; +- 首次创建场景分支使用同一 merge-source 入口,提交用户确认的 `sourceRef`、`confirmed=true`、`initialization=true`,不能先创建分支再另行触发初始化 Run; +- `POST /api/repository/scenario-branch` 不再允许在队列外同步调用 `ensureScenarioBranch()` 产生 Git 副作用;兼容期若保留该端点,只返回明确的迁移错误并指向 merge-source initialization 入口,不能自行创建分支或 Run; - 普通 `POST /api/runs` 只提交 `manual-current-head`,不接受调用者指定 target commit;旧字段若保留兼容期,任何非空值必须被拒绝并提示改用 merge-source 或 Run 重测入口,不能静默绕过; - 已有 Run 的“重测”复用原请求说明/场景意图,但在真正调度时固定**当前**场景测试分支 HEAD;本变更不提供分支已经前进后任意回放历史 SHA 的通用入口; -- 初始化请求同样只能针对当前场景测试分支 HEAD,或先通过 merge-source/首次建分支把来源纳入固定分支; +- 场景分支已存在时,初始化请求可以使用 `manual-current-head + initialization=true`,或使用 `manual-merge-source + initialization=true` 先纳入 source 再直接创建一个初始化 Run; - API 响应和网站显示 queued、merge/running、waiting archive、completed/failed/interrupted 等现有事实,不增加跨 Run checkpoint。 -### 4.3 固定 merge 结果、Git 可达性与恢复幂等 +### 4.3 固定 merge/首次创建结果、Git 可达性与恢复幂等 `manual-merge-source` 在罗网的**本地持久 Git 仓库**中为每个队列请求使用确定性 internal ref: @@ -194,7 +198,7 @@ refs/luowang/merge-requests/ 该 ref 不是业务分支,只用于让 prepared commit object 在进程重启、临时工作区清理和本地 Git GC 后仍可达;它不得被 push 到目标仓库,也不得加入任何默认 push refspec。 -执行顺序固定为: +远端 `scenario-testing` 已存在时,执行顺序固定为: ```text 解析 source ref @@ -207,15 +211,32 @@ refs/luowang/merge-requests/ → 请求 completed 或明确 failed/interrupted 后清理 internal ref ``` -具体规则: +远端 `scenario-testing` 在该请求被调度并 fetch 后仍不存在,且请求携带 `initialization=true` 时,首次创建特例固定为: + +```text +解析 sourceRef 并固定 source commit +→ 创建本地 internal ref 指向 source commit +→ 持久化 prepared_merge_commit = source commit +→ 以“远端 ref 必须仍不存在”为前置条件创建 scenario-testing +→ 持久化 resolved_target_commit = 已发布的同一 source commit +→ 使用 resolved_target_commit 创建且只创建一个 initialization Run +→ 请求 completed 或明确 failed/interrupted 后清理 internal ref +``` + +首次创建没有已有 HEAD,因此不生成伪造的 merge commit;字段名仍为 `prepared_merge_commit`,但在该特例中它表示已准备发布且由 internal ref 保持可达的 source commit。远端创建必须是 compare-and-create/expected-absent 的 non-force 写入:只能从不存在创建,不能覆盖或推进刚被其他操作者创建的同名 ref。 + +两条路径共同遵守: +- `sourceRef` 只在首次准备时解析一次;internal ref 创建后不再重新解析可能移动的 branch/tag,也不根据后续 HEAD 重建 commit; - `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 工作树或进程内对象都不能成为唯一来源; +- 已有分支路径中,来源已经是场景测试分支祖先时不创建重复 merge commit;internal ref 指向当时远端 HEAD,再把该 SHA 持久化为 prepared/resolved,仍可创建本次人工 Run; +- 首次创建路径中,prepared 后无论 push 返回成功、拒绝、连接中断还是进程退出,都使用同一可恢复判定:先校验 internal ref 并 fetch;远端 ref 仍不存在则只重试 compare-and-create 同一 prepared SHA;远端历史已包含 prepared 则说明该不可变 target 已发布,补写 `resolved_target_commit = prepared_merge_commit`,但绝不采用较新的远端 HEAD;远端 ref 已存在且历史不包含 prepared 才是竞争失败,不转成普通 merge、不重建 commit,也不创建 Run; +- 首次创建的 expected-absent 条件绝不允许本请求推进或覆盖已存在的 ref;“远端已包含 prepared”是幂等发布成功,不是改用竞争 HEAD。协议不持久化或依赖进程内 push outcome,避免在收到结果后、写 terminal/resolved 前再次崩溃产生不可恢复歧义; +- 进程在 prepared 后、push 前退出时,恢复逻辑必须从 internal ref 读取并校验同一 object;临时 clone、merge 工作树或进程内对象都不能成为唯一来源; - prepared 存在但 internal ref 缺失/指向其他 SHA,且远端也不包含 prepared commit 时,请求明确失败,不重新生成 merge;如果远端已包含 prepared,则按已成功 push 恢复并持久化同一 resolved; -- 进程在 push 后、写入 resolved 前退出时,恢复逻辑 fetch 远端并检查是否已包含 `prepared_merge_commit`;已包含则持久化同一 `resolved_target_commit`,不得重复 merge 或改用更新后的 HEAD; -- `resolved_target_commit` 已存在时,恢复逻辑只校验该 commit 已发布在远端场景测试分支历史中,然后创建或关联唯一 Run;即使场景分支后来又有新 commit,本请求 target 也不改变; -- internal ref 已创建但 SQLite 尚无 prepared(进程恰在两步之间退出)时,不猜测或重做 merge:当前请求明确失败并清理该 ref;没有对应队列行的孤儿 ref 也在启动对账后清理; +- 进程在 push 后、写入 resolved 前退出时,恢复逻辑 fetch 远端并检查是否已包含 `prepared_merge_commit`;已包含则持久化同一 `resolved_target_commit`,不得重复 merge、重复建分支或改用更新后的 HEAD; +- `resolved_target_commit` 已存在时,恢复逻辑只校验该 commit 已发布在远端场景测试分支历史中,然后创建或关联唯一 Run;首次创建请求的 Run 必须保留 `initialization=true`;即使场景分支后来又有新 commit,本请求 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。 @@ -432,7 +453,7 @@ commands[] https://github.com/cynos-ai/cynos-website ``` -项目负责人在 live 前确认或明确替换。目标必须可信、非罗网仓库、允许测试写入并有可清理的 `scenario-testing`。Token 使用 fine-grained repository access,仅限该仓库: +项目负责人在 live 前确认或明确替换。目标必须可信、非罗网仓库并允许测试写入;live 的首次建分支用例开始时,已配置的 `scenario-testing` 必须不存在,且操作者确认可从指定初始 commit 创建。不能安全提供“分支不存在”前置条件时必须换用新的独立测试仓库,不能删除含有人类资产的既有分支来凑验收。Token 使用 fine-grained repository access,仅限该仓库: | 权限 | 最小值 | 用途 | |---|---|---| @@ -441,7 +462,7 @@ https://github.com/cynos-ai/cynos-website | Pull requests | Read and write | 场景审核 PR | | Issues | Read and write | 创建/关联 confirmed bugs | -不要求 Administration、Actions、Packages、Deployments 或组织级权限。人类还需确认场景测试分支保护允许该测试身份 non-force push 或创建 PR,并允许验收结束后关闭明显测试 PR/Issue;长期验收证据是否保留由项目负责人决定。 +不要求 Administration、Actions、Packages、Deployments 或组织级权限。人类还需确认该测试身份可以在 ref 不存在时创建场景测试分支、之后执行 non-force push 或创建 PR,并允许验收结束后关闭明显测试 PR/Issue;长期验收证据是否保留由项目负责人决定。 ### 9.2 非生产应用 @@ -491,6 +512,7 @@ https://github.com/cynos-ai/cynos-website ```text LUOWANG_LIVE_REPOSITORY +LUOWANG_LIVE_INITIAL_REF LUOWANG_LIVE_GITHUB_TOKEN LUOWANG_LIVE_BASE_URL LUOWANG_LIVE_TEST_USERNAME @@ -516,8 +538,10 @@ thinking level、环境说明、额外账号和外部 allowlist 可以使用非 |---|---| | 内置角色指令缺失/错误 | Session 不启动,Run 明确失败或 blocked;不退回 Pi Skills 或 ambient 资源 | | 普通 Run 指定任意 target | `400` 拒绝并提示固定分支入口 | -| merge conflict/远端竞争 | 队列请求失败,不创建 Run、不推进、不自动改代码,清理本地 internal ref | -| prepared 未发布且 internal ref 缺失/不匹配 | 请求失败,不重做 merge、不改变 target;若远端已包含 prepared 则按成功 push 恢复 | +| 场景分支不存在但请求不是 `manual-merge-source + initialization=true` | 不创建分支和 Agent Run;automatic 不产生批次,current-head/非初始化 merge-source 明确失败 | +| 直接调用旧 `POST /api/repository/scenario-branch` | 不产生 Git 副作用,明确提示改用排队的 merge-source initialization 入口 | +| merge conflict/首次创建时远端历史不含 prepared/其他远端竞争 | 队列请求失败,不创建 Run、不推进、不自动改代码、不改用其他 HEAD,清理本地 internal ref | +| prepared 未发布且 internal ref 缺失/不匹配 | 请求失败,不重做 merge/建分支、不改变 target;若远端已包含 prepared 则按成功 push 恢复 | | 数据只有 Runner 清理声明、Agent 自填文本、证据未受控/未读取、Reviewer 拒绝或 adapter 未确认 | Run blocked,列脱敏残留和核验状态 | | Runner 没有场景 | 显示 `0/0`;是否 passed 仍执行既有零场景审核规则 | | Run 历史或 Issue 候选查询失败 | 标记 unavailable,不伪装空历史/空候选 | @@ -528,7 +552,7 @@ thinking level、环境说明、额外账号和外部 allowlist 可以使用非 ## 11. 兼容与迁移 - SQLite schema 变更使用版本化、可重复执行 migration;现有队列、Run 和归档数据必须前向升级; -- API 删除或拒绝 `targetCommit` 时更新网站和测试;如保留过渡字段,只能明确报错,不能继续执行旧的不安全语义; +- API 删除或拒绝 `targetCommit` 时更新网站和测试;如保留过渡字段,只能明确报错,不能继续执行旧的不安全语义;旧 `/api/repository/scenario-branch` 同样不得保留同步写分支语义; - 已有 completed/、报告、Issues、场景 PR、last completed target 和 `v0.1.0` tag 不修改;特殊场景审核 Run 继续只以 patch + report 识别; - `refs/luowang/merge-requests/*` 只存在于罗网本地持久 Git 仓库,不迁移为目标仓库分支、不写入远端;升级启动时只对账和清理没有对应请求的孤儿 ref; - 内置角色指令资源属于罗网发布物,不是 Pi Skills,不写目标仓库; @@ -549,18 +573,18 @@ 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、创建本地 `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**:internal ref 保证 prepared object 经重启、临时工作区清理和 Git GC 后仍可达;结合 `prepared_merge_commit`、`resolved_target_commit` 和唯一 Run 关联,使 merge 冲突、远端竞争、push 前后重启恢复不重复 merge、不改变本次 target、不创建错误 Run;请求 terminal 后幂等清理 internal ref; +4. **AC-CLOSURE-MERGE-01**:人工 branch/tag/SHA 请求进入 FIFO;远端场景分支已存在时按顺序生成 `merge --no-ff` commit,尚不存在且 `initialization=true` 时把解析后的 source commit 作为 prepared;两者都先创建本地 `refs/luowang/merge-requests/`、持久化 `prepared_merge_commit`、non-force 发布、持久化同值 `resolved_target_commit`,并且只创建一个以该不可变 commit 为 target 的 Run;首次路径的 Run 保留 initialization,internal ref 从不推送; +5. **AC-CLOSURE-TARGET-01**:普通人工/API Run 不能直接指定任意 target;自动、人工和初始化 Run 的 target 都是远端场景测试分支历史上的不可变 commit;场景分支不存在时 automatic/current-head 不创建 Run,首次建分支不能在队列外发生; +6. **AC-CLOSURE-MERGE-02**:internal ref 保证普通 merge 和首次建分支的 prepared object 经重启、临时工作区清理和 Git GC 后仍可达;结合 `prepared_merge_commit`、`resolved_target_commit` 和唯一 Run 关联,使 merge 冲突、首次创建时远端不含 prepared 的竞争、push 前后重启恢复不重复 merge/建分支、不改用其他 HEAD、不改变本次 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 可通过 `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 证据; +11. **AC-CLOSURE-PI-01**:本地生产路径集成从远端尚无 `scenario-testing` 开始,经 `manual-merge-source + initialization=true` 首次创建并只创建一个陌生项目初始化 Run;该 Run 用真实 `createAgentSession()` 覆盖 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;普通四 Session Run 另行通过;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; -15. **AC-CLOSURE-LIVE-02**:live 另外验证含两个 confirmed Bugs/Issues 的 failed Run、blocked 不推进、merge-source、场景 PR、当前 HEAD 人工重测、正式报告、Indexer 回读和实时进度; +15. **AC-CLOSURE-LIVE-02**:live 从真实目标仓库尚无 `scenario-testing` 开始,以 `manual-merge-source + initialization=true` 完成首次 non-force 创建、prepared/resolved 恢复事实和唯一初始化 Run;另外验证含两个 confirmed Bugs/Issues 的 failed Run、blocked 不推进、已有分支 merge-source、场景 PR、当前 HEAD 人工重测、正式报告、Indexer 回读和实时进度; 16. **AC-CLOSURE-SECRET-01**:所有 live Secret 只从受控输入进入候选实例/Secret Store,不出现在命令输出、环境回显、API 响应、日志、工件、Git、PR/Issue 或验收报告; 17. **AC-CLOSURE-DOC-01**:README 准确说明 Docker 优先、本地原生编译依赖、local/live 验收边界和实际发布状态; 18. **AC-CLOSURE-RELEASE-01**:全部验收通过后发布新的 SemVer,tag 与 main 发布 commit 一致,`v0.1.0` 保持原指向。