Skip to content

Latest commit

 

History

History
2040 lines (1331 loc) · 195 KB

plan-20260905.md

File metadata and controls

2040 lines (1331 loc) · 195 KB

Trunk 直推形态(storage-only)与 Monorepo 写入序列化计划(2026-09-05)

路径说明(2026-09-20): 本文成稿时 docker-compose-storage-only.yml / docker-compose-storage-only.auth-none.yml / docker-compose.test.yml 位于仓库根;2026-09-20 起三者迁入 docker/ 目录(commit 1854cae)。文中根目录原路径为历史记录,不再逐一回改;实际使用时请替换为 docker/ 前缀路径。

改名註記(2026-09-17): 本文成稿與執行時,Cargo 包名/二進制名為舊名,lib 為舊名 _core;2026-09-17 起全倉統一改名為 Mega2(mega2 / mega2_core),本文中的命令、路徑、環境變量與服務名已同步更新,歷史提交記錄本身不變。

模板版本: v2(2026-07-29 起生效;本计划整份符合 docs/plan/plan-template.md v2)。

文档职责

本文解决「monorepo 根树写入无序列化(并发写入互相覆盖、路径 ref 与根树视图分叉)」与「不接入用户系统、不使用 Issue 与 Change List 的 storage-only 部署形态下,Git 推送如何直接落入 main」两个问题,目标是交付:MonoWriteQueue 全局写入序列化(顺序 + 事务级 advisory lock + 根 ref CAS tripwire)、后代 ref 续接与墓碑、合成 commit 的真实归属与 provenance、push_policy = "trunk" 直推形态、无用户系统的静态 token 推送认证。

设计事实源是 docs/refactoring/trunk-push.md(2026-09-05 修订 66,经 Codex/Claude 双评审 PASS——Codex 第 59 轮、Claude 第 3 轮;事实校准 17 条、ADR-TP-01..20 含 15a、不变式 I1–I6 含 I2a、阶段 1 交付物 10 项、修订记录 66 条)。本计划不复制其设计论证,只把已决议设计落成可执行任务卡;实现时若需偏离 ADR,必须先修改 trunk-push.md 与本计划并说明原因。

与事实源的阶段对齐(2026-09-05 修订 2):trunk-push.md 在双评审中把基础静态 token 认证自阶段 5 前移至阶段 4 的 4.2a(push_policy=trunk 强制显式 push_auth),阶段 5 收窄为「多 token 运维与认证强化」且未给出可执行规范——本计划据此把 TP-19/TP-20 移入 Phase 4,阶段 5 的多 token 运维登记为 DEFER-TP-05(重启条件 = trunk-push.md 阶段 5 补齐规范)。另据同批评审修订:阶段 1 不可独立上线生产(其删除式后代处理违反 I1,生产部署以阶段 2/TP-14 为前置);B0 不做任何拒绝性 NFF 判定(遥测);pending_action 仅保留 requeue_conflict(根绕过判定由 B2.5 落库的 expected_* 基线 + reaper 通用 I3 修复承担);trunk 形态 LFS 不可用。

本文只规划任务,不宣称实现完成。落地时每个任务都必须先刷新源码锚点(GC-01),再按任务卡验收。

适用范围

  • 队列基础设施:新增 push_queue / queue_control 实体与迁移、MonoWriteQueue storage/service/router 四层(泛化自 merge_queue)、B0–B4 算法、reaper、控制面。
  • 根树写入路径:src/ceres/api_service/mono_api_service.rs(merge_cl_unchecked / apply_update_result / process_ref_updates)、src/ceres/pack/import_repo.rs(attach)、src/ceres/pack/monorepo.rs(finalize_receive_pack / refs_with_head_hash / traverses_tree_and_update_filepath)、src/jupiter/storage/mono_storage.rs。
  • 一致性机制:mega_ref_tombstones 墓碑表、blob_paths 出现对索引表、B3 树哈希断言、物化插入校验、对账与周期巡检。
  • 配置与认证:[monorepo].push_policy、[monorepo].max_push_commits、[git].push_auth / [[git.push_tokens]]、src/server/http_server.rs 启动门槛、src/contract/git_protocol/ 认证挂点。
  • 测试与文档:tests/integration_git_cli.rs、scripts/git_protocol_smoke.sh 本地等价、docs/refactoring/trunk-push.md 的同步、docs/monorepo.md 反向声明、部署文档。

非目标

  • 不改 review 形态的既有语义:阶段 1–3 的队列化与缺陷修复不得改变 CL 创建/检查/合并的判定、门控与拒绝面;既有测试用例期望值不得修改。两类登记在案的显式豁免:后代 ref 续接(缺陷修复本身)与 merge 的队列生命周期变化(背压、wait_timeout、异步转同步)——见 trunk-push.md 硬约束 8。
  • 不引入用户系统 / Issue / Change List:trunk 形态的认证只交付 git-over-HTTP 静态 token;SSH receive-pack 在 storage-only 形态下不暴露(TP-20)。
  • 不做多分支单推送、merge commit 入链、根路径 clone:沿用 ADR-MC-04 / MC-03 的既有拒绝面;根路径推送不作为该形态假设。
  • 不做 Redis 队列、不做乐观 CAS 并发模型:ADR-TP-01/02 已否决。
  • 不承诺逐 commit GPG 签名验证:ADR-TP-15a,N=1 的签名保留是零改写副产物、非可依赖保证。
  • 阶段 6 四项优化(group commit / LISTEN-NOTIFY / 实时进度 / 物化 TTL)不进入本计划执行:登记为 DEFER-TP-01..04,无实测压力证据不启动。
  • 阶段 5 的多 token 运维与强化不进入本计划执行:登记为 DEFER-TP-05(trunk-push.md 阶段 5 收窄后未给出可执行规范;基础认证已随 4.2a 进阶段 4/TP-19)。
  • trunk 形态 LFS 不可用:LFS 路由经 UserStorage 认证(lfs_router.rs:205-213/235-250),静态 token 模型不覆盖 LFS 批/锁授权——trunk 形态关闭 LFS 写路由并在部署文档声明(TP-18);token-aware LFS 授权为独立议题。

成功定义

  • 全部根树与路径 ref 写入者(trunk 推送、CL merge、ImportRepo attach、两条惰性物化路径)要么经 MonoWriteQueue 串行、要么被 ADR-TP-20 机制显式覆盖;根 ref CAS 断言恒不失败(不变式 I5)。
  • 并发写入不再互相覆盖:根树在任一提交边界等于所有路径子树的一致快照(不变式 I3);已物化路径历史只增不改(I1);每次推送在每个受影响的层恰好前进一个 commit(I2a)。
  • push_policy = "trunk" 下:N = 1 推送客户端 commit 原样落地(hash/作者/时间/message 逐字不变),N > 1 自动 squash 为一个 commit 且 tree 保真(I2),squash message 完整枚举全部 N 条不截断(I4);trunk 与 cedar.enforcement != "off" 互斥于启动期 fail-closed 拒绝。
  • 无用户系统部署可经静态 token 推送(push_auth = "token",组件边界路径授权;push_auth = "none" 需显式配置;push_auth ∈ {token,none} 强制 push_policy = "trunk",反向 trunk 强制显式 push_auth——4.2a 随阶段 4 交付)。trunk 形态 LFS 不可用(TP-18)。
  • 全部 23 张任务卡(TP-01..TP-23)Lifecycle=done 且 Acceptance=complete;三门全绿;外部双评审(Codex/Claude)对本计划 PASS;docs/monorepo.md 反向声明与部署文档同步完成。

事实基线

所有行号和源码锚点必须在开工当天刷新(GC-01)。下列锚点核对日为 2026-09-04(docs/refactoring/trunk-push.md 事实校准日;该文档 2026-09-05 经 66 条修订与双评审 PASS,本表已按其终版对齐)。

类别 当前事实 证据
代码入口 分支命令经 finalize_receive_pack → persist_mono_branch_cl_mega_refs_transaction → apply_cl_mega_ref_for_push_command 落地为 refs/cl/<id>;run_mono_post_push_pipeline 调 update_or_create_cl;update_refs 只在 tag 命令时被 smart.rs:450 调用(拒绝 Tag) src/ceres/pack/monorepo.rs:205/676/863-877/913/916-939/975
代码入口 根树推进只发生在 CL merge 与 ImportRepo attach;attach 有 (ref_commit_hash, ref_tree_hash) 双条件 CAS + MAX_ATTACH_ATTEMPTS=64 重试;push/merge 路径无锁盲写 src/ceres/api_service/tree_ops.rs:263-271、src/jupiter/storage/mono_storage.rs:287/453-483、src/ceres/pack/import_repo.rs:507-513
代码入口 RedLock 只接在 ImportRepo attach 路径 src/ceres/protocol/mod.rs:202、src/ceres/pack/import_repo.rs:513
代码入口 批量 ref 更新经 FuturesUnordered 并发执行、无法加入事务、对缺失行静默跳过;单 ref 的 save_refs/update_ref 已支持事务 src/jupiter/storage/mono_storage.rs:65-73/188-199/287-333
数据/状态 merge_queue 四层齐备(storage/service/router/DTO);互斥 AtomicBool 仅进程内、claim 无 FOR UPDATE SKIP LOCKED、position 为毫秒时间戳;冲突失败重排队到队尾(Conflict → move_item_to_tail);QueueStatusEnum 是 CL 工作流状态机(Waiting/Testing/Merging/Merged/Failed) src/jupiter/service/merge_queue_service.rs:169、src/jupiter/storage/merge_queue_storage.rs:83/178、src/ceres/api_service/mono_api_service.rs:4419-4429、src/callisto/sea_orm_active_enums.rs:228-239
代码入口 子路径 main ref 懒生成无父 commit;两条物化路径(advertise/clone 与 code_edit)无锁、无 CAS、无版本检查 src/ceres/pack/monorepo.rs:121/129-135、src/ceres/code_edit/utils.rs:362-442、src/ceres/protocol/smart.rs:76-88
代码入口 remove_none_cl_refs 删除后代 ref;starts_with 无组件边界且不转义 LIKE 元字符;唯一调用点 src/jupiter/storage/mono_storage.rs:77-84、src/ceres/api_service/mono_api_service.rs:2617-2622
代码入口 合成 commit 归属硬编码 mega <admin@mega.org>(git-internal 0.8.7 外部依赖);process_ref_updates 以路径自身旧 tip 为 parent(祖先方向已具备续接语义) git-internal 0.8.7 外部依赖的 src/internal/object/commit.rs:104-128;仓内 src/ceres/api_service/mono_api_service.rs:623-668
代码入口 validate_incoming_push 执行 ADR-MC-04 单分支准入与 MC-03 PushChain::validate(拒绝 merge commit、拓扑连续、tip 匹配);链长硬编码 MAX_CL_CHAIN_COMMITS=250;ordered_commits tip 在前 src/ceres/pack/monorepo.rs:1153、src/ceres/pack/push_chain.rs:182-205/408-447/469-482、src/ceres/merge_checker/mod.rs:20-27
数据/状态 mega_refs 唯一索引 uniq_mref_path(path, ref_name);列为 path/ref_name/ref_commit_hash/ref_tree_hash/is_cl/时间戳 src/jupiter/migration/m20250314_025943_init.rs:268-277
代码入口 文件路径索引 traverses_tree_and_update_filepath 从 tip 递归重建、成本与子树规模成正比、当前在临界区内;mega_blob.file_path 单列无出现对语义 src/ceres/pack/monorepo.rs:704/1051-1114、src/callisto/mega_blob.rs:6-22
代码入口 合并侧门控(UN-19 ACL 自提权、GPG ensure_gpg_check_passed)都在合并入口/processor,不在推送路径 src/ceres/api_service/mono_api_service.rs:2124/2135/2580-2592/4599
配置项 [monorepo] 仅 import_dir/admin/root_dirs/object_format/rename,无直推字段;import_dir 属 restart_required_fields src/config/model.rs:141、src/config/reload.rs:697、src/config/validate.rs:522
代码入口 HTTP 启动两道 OAuth 门槛(require_oauth_for_http_service + app() 内取用);git token 认证走 UserStorage;check_push_permission 在 cedar off 时仍要求非空 username;SSH 要求已认证用户 src/server/http_server.rs:424-425/627-650、src/config/validate.rs:162-169、src/contract/git_protocol/http.rs:60-65/105-149/354-365、src/contract/git_protocol/mod.rs:43-62、src/contract/git_protocol/ssh.rs:135-157
文档 设计事实源(ADR-TP-01..20 含 15a、不变式 I1–I6、阶段 1–6、验收清单) docs/refactoring/trunk-push.md(2026-09-04 校准)
测试 现有集成测试 target(8 个);git 协议 smoke 骨架 tests/integration_git_cli.rs、scripts/git_protocol_smoke.sh、docs/refactoring/integration.md
工作区前置 单 Cargo 包(plan-20260824 收口);版本面一处(Cargo.toml 的 version);测试栈 Postgres 15432 / Redis 16379 / Mailpit / RustFS Cargo.toml;docker-compose.test.yml;ER-01
代码入口 直连 merge 路由 /merge、/merge-no-auth(cl_router.rs:218-223/279-304)直接调 merge_cl(:2107-2128,入口预检拒绝 cl.from_hash != main、缺失 ref 拒绝 :2113-2118)在队列外执行 merge_cl_unchecked;/merge-queue/add 入队即返回依赖后台 processor src/api/router/cl_router.rs:203-304、src/api/router/merge_queue_router.rs:43-55、src/ceres/api_service/mono_api_service.rs:2107-2128
数据/状态 mega_cl 无单调 revision 列;merge 状态更新与 rebase 均为无条件更新(cl_storage.rs:374-379/404-415),rebase/merge 反序竞态可把 Merged 改回 Open src/callisto/mega_cl.rs、src/jupiter/storage/cl_storage.rs:374-415、src/ceres/api_service/mono_api_service.rs:3293-3301/3441-3463
代码入口 build_push_chain 对空链/全已知链返回 None(Noop 短路,validate_incoming_push 随即成功返回)——trunk 形态须改为继续入队 src/ceres/pack/monorepo.rs:1191-1247、src/ceres/pack/push_chain.rs:104-115
代码入口 LFS 路由经 UserStorage 认证(静态 token 不覆盖 LFS 批/锁授权) src/api/router/lfs_router.rs:205-213/235-250
外部参照 本 checkout 的 .github/workflows/ 与 .github/workflow/ 均为空目录(2026-09-05 核对);D 组判定一律以开工时远端仓库的 workflow 现场读取为准 .github/workflows/

当前缺口

ID 缺口 影响 证据 计划动作
GAP-01 根树写入无序列化(push/merge 路径无锁盲写,attach 仅有单路径 CAS) 并发写入互相覆盖根树,路径 ref 与根树给出互相矛盾的视图且无报错 tree_ops.rs:263-271、mono_storage.rs:287 TP-03/04/07
GAP-02 批量 ref 更新无法加入事务、对缺失行静默跳过(首次向新路径推送会悄悄丢失 main@P) B3 单事务无法落地;创建语义缺失 mono_storage.rs:287-333 TP-02/12
GAP-03 merge_queue 三互斥缺陷(进程内互斥、非原子 claim、时间戳序号)+ 异步执行模型 跨实例无全序;两个 processor 可取同一项;同毫秒入队顺序不确定 merge_queue_service.rs:169、merge_queue_storage.rs:83/178 TP-03/07
GAP-04 remove_none_cl_refs 删除后代 ref(历史断裂,refusing to merge unrelated histories),且 LIKE 前缀无组件边界、不转义元字符 父路径推送后子路径 clone 者无法 pull/推送 mono_storage.rs:77-84 TP-02/14
GAP-05 合成 commit 归属硬编码 mega <admin@mega.org> + 常量 message 根与祖先层历史不可审计 git-internal 0.8.7(外部依赖)src/internal/object/commit.rs:104-128;仓内调用点 mono_api_service.rs:623-651 TP-16
GAP-06 子路径懒生成无父 commit、无墓碑,删除后不可续接 路径复活即 unrelated history monorepo.rs:121 TP-09/14
GAP-07 两条惰性物化路径从各自根快照无锁写 mega_refs(本计划编号;勿与 trunk-push.md 的 GAP-07 CL 命名分歧混淆) 物化行落后于根树;以它为基线的推送静默覆盖祖先改动(ADR-TP-19 失效链) monorepo.rs:121、code_edit/utils.rs:362-442 TP-10/11
GAP-08 无 push_policy 直推路径;review 形态推送只写 refs/cl/* storage-only 部署无法直推 main monorepo.rs:205/913/975、config/model.rs:141 TP-15/17
GAP-09 推送认证强依赖 OAuth/UserStorage/SSH 用户,无静态 token 模型 无用户系统部署无推送通道 http_server.rs:424-425、git_protocol/http.rs:105-149 TP-19/20
GAP-10 文件路径索引重建在临界区内且无代际水位,删除的 blob 会被旧任务写回 大子树推送独占写入闸门;索引删除复活 monorepo.rs:704/1051-1114 TP-13
GAP-11 直连 merge 路由(/merge、/merge-no-auth、/merge-queue/add)在队列外执行 merge_cl_unchecked 未覆盖的根树写入者,破坏队列全序前提(ADR-TP-09) cl_router.rs:218-223/279-304、merge_queue_router.rs:43-55 TP-07
GAP-12 mega_cl 无单调 revision,merge 状态更新与 rebase 均无条件写 rebase/merge 反序竞态可把 Merged 改回 Open cl_storage.rs:374-415 TP-07
GAP-13 LFS 路由经 UserStorage 认证,静态 token 模型不覆盖 trunk 形态(cedar off + 静态 token)下 LFS 写通道无授权模型 lfs_router.rs:205-213/235-250 TP-18(关闭)
GAP-17 attach 路径的 RedLock(30s TTL Redis 互斥锁)在队列吸收后残留——跨系统锁缝正是 ADR-TP-02/03 否决的模式 残留的 Redis 锁在 advisory lock 序列化之外引入无 TTL 竞争面 src/ceres/protocol/mod.rs:202、src/ceres/pack/import_repo.rs:513 TP-08
GAP-14 build_push_chain 对空链/全已知链返回 None(Noop 短路),validate_incoming_push 随即成功返回 trunk 形态下这类推送绕过 B1/B3、虚报成功(trunk-push.md 1.10 交付物 10) monorepo.rs:1191-1247、push_chain.rs:104-115 TP-12
GAP-15 authz 快照屏障三件套(B3 事务内 outbox、published_version 单调 CAS 发布、按实例读取屏障)缺失,现状为内存 best-effort enforce 模式下 UN-19 重查可能读到陈旧快照;乱序发布覆盖新快照 src/contract/policy/notify.rs:27-92、entitystore.rs:148-219 TP-22
GAP-16 阶段 1.1 写入者审计(穷举 + 三类分法 + trunk-push.md 回写)无执行载体 写入者清单停留在散文,缺机器可核对条目与回写验收 trunk-push.md 阶段 1.1、mono_service.rs:103-125 TP-23

与其它计划的关系

计划/文档 关系 本计划处理
docs/refactoring/trunk-push.md 设计事实源(ADR-TP-01..20、不变式、阶段 1–6、验收清单) 全部任务卡从该文档的交付物清单派生;实现偏离必须先改该文档与本计划
plan-20260827.md(CL 多 commit push 放开) 前置已完成;其 merge_queue 四层、PushChain、MC-03 校验、MC-09 ServerSigningContext、ADR-MC-04/07 是本计划消费的现成原语 复用不重做;MAX_CL_CHAIN_COMMITS 常量语义在 review 形态保持不变(TP-15 只新增 trunk 独立配置)
plan-20260903.md(object-ID 配置) 并行;改动面在配置与协议对象格式,与本计划写集基本不相交 开工时按 GC-01 核对收口状态;若写集相交补顺序边
plan-long.md 无直接对应 PT 项 不触碰
docs/monorepo.md 产品规则事实源;trunk-push.md 的反向声明(N 分流语义、I1–I6、墓碑续接、索引最终一致、ADR-TP-18 对齐约定)已由 TP-21 同步 TP-21 已完成;见 docs/monorepo.md §8–11 与 ../deploy-trunk.md
docs/refactoring/protocol.md receive-pack 分层事实源 协议层改造(TP-10/17)完成后同步
docs/refactoring/general.md / contract.md / config.md / integration.md / test-infra.md 治理规范 / Cedar 与权限 / SecretRef / 测试栈 遵守;新增 e2e 用例登记进测试矩阵与 integration.md
AGENTS.md / README.md 工程约束基线(三门、ER-07、GC-12) 遵守;trunk-push.md 的「文档概览 5a」登记在 docs/refactoring/README.md(非根 README.md),本计划不新增条目(TP-21 若需再同步)

评审结论与修订记录

维度 结论 修订动作
合理性 高:写入序列化被论证为语义必然而非性能取舍(trunk-push.md 硬约束 1);storage-only 直推是明确的部署需求 无
可行性 中高:全部写入者类别已定位;队列可泛化自 merge_queue 四层;build_result_by_chain / apply_update_result / ServerSigningContext 均为现成原语;不足:B3 依赖的事务内 ref 更新原语需新增(GAP-02) TP-02 前置
任务卡粒度 23 卡全部单一行为轴、S/M;无 L/XL;无未登记合并发布(AC 均 ≤8,TP-21 docs 卡 10/12) 见任务卡粒度审计表
依赖与顺序 DAG 无环;阶段 1(队列 + 写入者接入 + authz 屏障)→ 阶段 2(后代续接)→ 阶段 3(归属)→ 阶段 4(trunk 接线 + 4.2a 认证,TP-19/20 先于 TP-17 e2e)→ 阶段 5(文档收口;阶段 5 多 token 运维延后 DEFER-TP-05) 见实施顺序
完整性 测试/文档/迁移/回滚齐;新增 7 项迁移产物全部 forward-only(仓库无 migrate down 入口) 无
安全性 trunk 与 cedar enforce 互斥(启动 fail-closed);CAS tripwire + 对账巡检;静态 token 组件边界授权(先于且独立于 Cedar);push_auth="none" 需显式配置;push_auth ∈ {token,none} ⇔ push_policy=trunk 双向启动校验 无
功能正确性 不变式 I1–I6 全部可测;每个已知缺陷配回归;B3 单事务 + fencing + 意图两段式覆盖崩溃窗口 无
接口兼容 push_policy 默认 review,既有部署行为不变;阶段 1–3 不改变 CL 可观察语义(硬约束 8 的豁免登记在案);新增配置全部 additive;trunk 形态 LFS 不可用(TP-18 关闭并声明) 无
数据流与控制流 B1 准入锁保证 FIFO;B2.5 认领先行 + expected_* 基线同事务落库 + queue_control 行锁串行化认领;reaper 持锁判定无 TOCTOU;1.11 幂等三态 + 收养/回放 无
性能与容量 B3 成本以「已物化路径数」为界;索引重建移出临界区;message 25 KB 上限为已接受代价 见性能与容量摘要
可靠性与容错 B3 单事务 + advisory lock 随连接释放 + reaper 按行比对 expected_* 基线并幂等补做重排意图 + 通用 I3 修复(按 kind 分语义)+ heartbeat 孤儿清理 + watchdog 升级路径 无
可维护性 队列是序列化闸门与生命周期台账而非作业执行器;写入者审计(1.1)为完备性第一依据 无

修订历史

日期 触发 变更内容 原卡 → 新卡 受影响的引用
2026-09-05 成稿 初版,TP-01..TP-21(阶段 1×13、阶段 2×1、阶段 3×2、阶段 4×2、阶段 5×2、阶段 6×1 文档);DEFER-TP-01..04 登记阶段 6 优化;ADR-TP-01..20 引用 trunk-push.md N/A N/A
2026-09-05 对齐 trunk-push.md 修订 66(双评审 PASS 后终版) ①TP-19/TP-20 移入 Phase 4(4.2a 认证前移),Phase 5 改为文档收口(TP-21),阶段 5 多 token 运维登记 DEFER-TP-05;②TP-01 schema 对齐(pending_action 仅 requeue_conflict、queue_control.last_policy);③TP-03 补 B2.5 认领先行/expected_* 基线/双认领者并发、B0 NFF 预检降级遥测;④TP-04 移除 verify_root 预标记、改 expected_* 比对前置分支与 CAS 终态状态条件;⑤TP-05/TP-11 意图模型收敛(reaper 每行 Running 比对基线 + 通用 I3 修复按 kind);⑥TP-07 补直连入口入队/mega_cl revision 全量 CAS/存量端点映射/merge 缺行拒绝;⑦TP-08 补祖先/后代物化拒绝;⑧TP-09 补升级前删除回填/fail-closed;⑨TP-10 补重试绕过 heads_exist;⑩TP-11 断言先于 NFF、对账按 kind;⑪TP-12 创建 N=0 不可达、trunk 删除策略;⑫TP-13 隔离规则/收敛声明/版本来源分离;⑬TP-15 启动校验六条 + 水位重置置 NULL;⑭TP-18 LFS 关闭;⑮发布分组修正(阶段 1 不可独立上线生产,I1);⑯新增 TP-23(阶段 1.1 写入者审计卡,GAP-16)与 GAP-14/15/16/17(GAP-17 = attach 的 RedLock 退役);⑰TP-07 补单写者开关 [monorepo].merge_writer 配置定义 TP-01..TP-23(新增 TP-23) 事实基线/GAP-11..16/成功定义/非目标/里程碑/测试矩阵
2026-09-09 TP-21 文档收口 反向声明写入 docs/monorepo.md §8–11;新增 docs/deploy-trunk.md;trunk-push.md 头部「已同步」;integration.md 四条 e2e;errors.md N/A;crate 版本策略改为 只 patch、不 minor(TP-18 的 0.9.0 已回写 0.8.1) TP-21 done DEP-03、Phase 5、R28
2026-09-09 计划完成门 source .env.test && cargo test --all EXIT:0(host git + git-lfs 3.7.1);补 ssh_receive_pack=false 与 rooted file_path 断言;TP-01/04/22/23 遗留勾选与 D 组 N/A N/A 完成判据、R29

已决议设计决策

本计划的设计决策全部记录于 docs/refactoring/trunk-push.md 的「决策记录(ADR-TP)」一节(ADR-TP-01..20,另含 ADR-TP-15a),实现时若需偏离必须先修改该文档与本计划(G-05:不复制全文,以事实源为准)。下表为决策摘要与承接卡映射:

ADR 决策摘要 承接卡
ADR-TP-01 全局单写入者,不做子树并行;乐观 CAS 已否决 TP-04
ADR-TP-02 队列基座选 Postgres,不选 Redis TP-01/03
ADR-TP-03 互斥用事务级 advisory lock(MONO_WRITE_LOCK),不用会话级/RedLock TP-04
ADR-TP-04 推送同步阻塞等待轮次,队列不是异步作业队列 TP-03
ADR-TP-05 闸门粒度是「根树写入者」;merge_queue 被吸收而非并存(冲突关行重入队;attach 重试循环删除;全部 merge 入口统一入队——直连 /merge、/merge-no-auth、/merge-queue/add 同步化) TP-07/08
ADR-TP-06 FIFO 序号取 bigserial;trunk commit 保序但非一一对应(空洞) TP-01/03
ADR-TP-07 轮次失败不冻结队列;CAS 失败(QueueBypassDetected)是显式例外 → 硬停 TP-04/05
ADR-TP-08 背压 = 深度上限 + wait_timeout(只约束 B2 等待,到期放弃不取消共享行) TP-03
ADR-TP-09 根 ref CAS 是 tripwire 断言而非并发控制,失败不重试 TP-04
ADR-TP-10 同一路径同时只允许一项「推送」在队(kind='push' 唯一部分索引) TP-01/03
ADR-TP-11 文件路径索引移出临界区,接受最终一致(出现对表 + 行级水位 + 删除感知 reconciliation) TP-13
ADR-TP-12 按 N 分流:N=1 原样落地,N>1 在被推路径 squash 为一个 TP-12/16
ADR-TP-13 roll-up 作者身份取链上 tip,其余作者进 Co-authored-by TP-16
ADR-TP-14 committer date = max(落地时刻, 前一 trunk commit 的 committer date);author date 原值 TP-16
ADR-TP-15 squash message 完整枚举全部 N 条不截断;祖先/后代带 Mono-Squash-Commit 指针 TP-16
ADR-TP-15a 逐 commit GPG 签名验证不作为受支持能力;合成 commit 由服务端签名 TP-16
ADR-TP-16 净零变更推送只推进被推路径(「受影响的层」判定) TP-12
ADR-TP-17 链长上限:review 保留 MAX_CL_CHAIN_COMMITS;trunk 引入 max_push_commits 可配(需参数化 PushChain) TP-15
ADR-TP-18 N>1 推送后客户端必须 git fetch && git reset --hard origin/main 对齐,服务端两处告知 TP-17
ADR-TP-19 后代 ref 恒与 B3 同事务推进;I3 强一致不分层;惰性后代推进否决 TP-14
ADR-TP-20 惰性物化不入队:「插入时根身份对校验 + B3 树哈希断言与墓碑修复(SAVEPOINT 同事务,崩溃窗口由 B2.5 expected_* 基线 + reaper 通用 I3 修复兜底)+ 对账巡检」三层覆盖 TP-10/11

全局工程约束

本节不重述 docs/plan/plan-template.md v2 的 GC-01..GC-12 全文,全部继承;以下为本计划特有补充:

  • GC-TP-01 队列纪律(I5 前提): 任何改写根树或 refs/heads/main 行的代码必须经 MonoWriteQueue、在审计清单中登记为队列外并被 ADR-TP-20 覆盖、或属于服务接流前完成并持专属锁的 bootstrap(initialize_monorepo,mono_service.rs:103-125——trunk-push.md 硬约束 2 的第三类,I5 三分法)。不得在 B3 事务之外新增根 ref 写入点;新增写入者必须同步 trunk-push.md 硬约束 2 的清单与本计划。
  • GC-TP-02 B3 单事务: 轮次的 ref/commit/tree/CL 状态写入必须在同一 &DatabaseTransaction 内;禁止在 B3 内使用自建连接的原语(batch_update_by_path_concurrent 原形、自建连接的 remove_none_cl_refs 等)。merge/rebase 的 CL 行更新一律携带单调 revision 全量 CAS(GAP-12,双向串行化);CL 创建/检查等其他状态写不受影响(trunk-push.md 1.11/1.9)。
  • GC-TP-03 review 形态可观察行为不变(硬约束 8): 阶段 1–3 的任务不得改变 CL 创建/检查/合并的判定、门控与拒绝面;既有测试用例期望值不得修改。三类登记在案的豁免(trunk-push.md 登记在案,仅限其验收标准所列行为变化):①后代续接缺陷修复;②merge 队列生命周期变化(背压/wait_timeout/异步转同步);③文件路径索引的形态隔离规则(队列轮次打水位后,review 推送的索引仅 IS NULL 行生效——trunk-push.md ADR-TP-11 登记为有意设计,索引不在写入判定链上)。
  • GC-TP-04 失败可见性: 禁止沿袭「空 refs / capabilities-only / 静默跳过」的失败模式(smart.rs:76-88 把空 refs 编码为 capabilities-only、mono_storage.rs 静默跳过缺失行);物化放弃、被拒轮次、CAS 失败都必须产生可诊断报错或显式终态。B0 的乐观 NFF 预检只作遥测不拒绝——拒绝权威唯一归属 B3(无锁的 B0 拒绝会在陈旧行修复前放逐客户端)。
  • GC-TP-05 CAS 是 tripwire 不是完备性证明: 根 ref CAS 恒成功不等于不存在未登记写入者;完备性第一依据是写入者审计(Phase 0 登记、trunk-push.md 硬约束 2 清单),CAS 与巡检是兜底。

执行检查必备需求(强制)

继承模板 ER-01..ER-12 全文。本计划无新增 ER 条目;强调以下与本文强相关的事项:

  • 锚点刷新(ER-02): 本计划所有 file:line 锚点核对日为 2026-09-04;每个任务开工时按 GC-01 重新核对,锚点漂移以现场为准并回写事实基线。
  • 包名口径(ER-08): 全部命令使用 -p mega2(单包形态,-p mega2-core 已失效)。
  • ER-01 测试栈: 涉及 DB 的用例缺 Postgres 会 panic 而非跳过;开工前 docker compose -f docker-compose.test.yml up -d --wait。
  • ER-04 A 组表面门: 命中「Git 协议」表面的卡(TP-10、TP-12、TP-17、TP-19、TP-20 等)按模板该行七步骨架执行 scripts/git_protocol_smoke.sh 本地等价(含 .env.test 数据面覆盖与 token 播种;push 用例 401 不得判为协议回归)。
  • D 组远端后置门: 本 checkout 的 .github/workflows/ 与 .github/workflow/ 均为空目录(2026-09-05 核对);各卡 D 组判定一律以开工时远端仓库的 workflow 文件现场读取为准——命中 paths: 过滤器的卡登记 remote-pending 并跟踪远端结论,未命中的写 N/A 并说明,不得虚构远端门。
  • ER-07 提交工作流: 本仓 commit.gpgSign=true、user.signingkey=7B2F49AE3A9E8BDC;每次提交后 git cat-file -p HEAD | rg -q '^gpgsig' 校验,失败不得推送。
  • 迁移的 forward-only 口径(G-01): 本计划的迁移产物共 7 项(全部 forward-only,down 为空实现——仓库运行期无 migrate down 入口,runner.rs 只暴露 up 与破坏性 refresh;恢复靠前滚修复):①push_queue + queue_control + 四枚举 + 索引 + 播种(TP-01);②mega_ref_tombstones(TP-09);③blob_paths(TP-13);④mega_cl.revision 列(TP-07,GAP-12);⑤mega_refs_path_pattern 部分索引(TP-14);⑥merge_queue 存量行一次性数据迁移(TP-07,随滚动部署交付);⑦authz outbox/published_version 持久化(TP-22)。凡含迁移的卡(TP-01/07/09/13/14/22)Rollback mode = forward-only;TP-14 的索引迁移 additive,代码回滚后可重建。

实施顺序

依赖边格式:A -> B 表示 A 必须先于 B。编号顺序 ≠ 执行顺序,以本表与各卡 Dependencies 为准。

  • TP-01 -> TP-03(queue schema 是四层的表前提)
  • TP-02 -> TP-04(B3 依赖事务内 ref 更新原语)
  • TP-02 -> TP-10(物化插入校验依赖 escape_like 与事务内 upsert)
  • TP-02 -> TP-14(后代候选查询依赖 escape_like)
  • TP-02 -> TP-09(墓碑查询依赖 escape_like)、TP-04 -> TP-09(B3 修复挂点)、TP-09 -> TP-05(reaper 的 I3 修复复用 TP-09 的墓碑写原语)
  • TP-03 -> TP-04、TP-03 -> TP-05、TP-03 -> TP-06
  • TP-04 -> TP-05(reaper 依赖 B3 的意图/终态设计)
  • TP-04 -> TP-07、TP-04 -> TP-08、TP-04 -> TP-11、TP-04 -> TP-12、TP-04 -> TP-13
  • TP-07 -> TP-05(reaper 的 requeue_conflict 意图补做需 merge 冲突重排语义才可验收)、TP-05 -> TP-06(存量端点映射的 push_queue 数据面由轮次产生)
  • TP-07 -> TP-11(merge 分支的树哈希断言)
  • TP-07 -> TP-14(阶段 2 切换 merge 分支的后代处理,2.8)
  • TP-09 -> TP-10、TP-09 -> TP-11、TP-09 -> TP-14(墓碑是插入校验/修复/续接的共同前提)
  • TP-10 -> TP-11(ADR-TP-20 两层按序落地;写集在 monorepo.rs/smart.rs 相交)
  • TP-11 -> TP-12(push 分支使用树哈希断言)
  • TP-11 -> TP-13、TP-12 -> TP-13(C 段索引挂接 B3;写集在 monorepo.rs 相交)
  • TP-12 -> TP-14(push 分支的后代处理在阶段 2 一并切换)
  • TP-07 -> TP-12(push 分支后代处理复用交付物 5 的事务内删除变体)、TP-12 -> TP-16(provenance 升级 push 分支的合成 commit 构造)
  • TP-14 -> TP-16(后代续接 commit 获得归属规则)
  • TP-07 -> TP-15(merge_writer 配置字段定义先于 TP-15 的跨字段校验)、TP-15 -> TP-16(枚举完整性三档验收依赖 max_push_commits)
  • TP-15 -> TP-17(finalize_receive_pack 条件化读取 push_policy)、TP-15 -> TP-18(router 条件挂载读取 push_policy)
  • TP-16 -> TP-17(trunk 落地使用 provenance 规则)
  • TP-19 -> TP-20(token 认证在 OAuth 条件化之前)、TP-20 -> TP-17(trunk e2e 依赖认证载体就绪——4.2a 前移后的次序)、TP-17 -> TP-18(表面关闭依赖落地转正)——Phase 4 内序:TP-19 → TP-20 → TP-17 → TP-18
  • TP-19 -> TP-20(OAuth 条件化在 token 认证之后)
  • TP-13 -> TP-21、TP-18 -> TP-21、TP-20 -> TP-21(文档收口依赖全部代码卡)
  • TP-04 -> TP-22、TP-07 -> TP-22(authz 屏障依赖 B3 事务挂点与 merge 的 UN-19 重查路径)
  • TP-23 -> TP-01、TP-23 -> TP-04、TP-23 -> TP-07、TP-23 -> TP-08(写入者审计是 schema 与写入者接入卡的开工前置)
  • TP-15 -> TP-19、TP-15 -> TP-20(认证配置与启动校验读取 push_auth;TP-19/20 随 4.2a 前移至 Phase 4,见修订 2)

说明: 阶段 1 的 push 分支(TP-12)在「测试专用 push_policy 开关」(1.10 交付物 9)下实现与验收,不含阶段 4 的协议接线——后者是 TP-17/18。 阶段 1 的可部署性: 阶段 1 可独立验收(测试环境),但不可独立上线生产——其 merge/push 分支沿用的删除式后代处理违反 I1(trunk-push.md 迁移步骤开头/附录 A),生产部署以阶段 2(TP-14)落地为前置;里程碑 M1/M2 均为测试环境里程碑。

依赖登记表

ID direction 类型 对象 Owner 产物与可用性判据 证据 超时与失败策略
DEP-01 incoming 跨计划(本仓文档) docs/refactoring/trunk-push.md 定稿状态 trunk-push.md 维护者 判据 = 反向声明(monorepo.md 同步)完成前,本文档的 ADR/验收清单以 trunk-push.md 为准;trunk-push.md 若有规范性修订,本计划须同步修订历史 docs/refactoring/trunk-push.md(2026-09-05 修订 66;Codex 第 59 轮 / Claude 第 3 轮双 PASS) 无等待上限;不一致时以本计划修订历史登记并同步
DEP-02 incoming 审批 用户对本计划(含 23 卡结构与 DEFER-TP-01..05)的确认 用户 判据 = 明确的 go 指令 本计划 Review log 未确认不进入 Phase 1 开工;确认前各卡保持 pending
DEP-03 outgoing 跨计划(本仓文档) docs/monorepo.md 产品规则反向声明(N 分流语义、I1–I6、墓碑续接、索引最终一致、ADR-TP-18 对齐约定) 本计划 TP-21(接收方为 monorepo.md 维护者) 判据 = trunk-push.md 头部「已同步」标记 + 语义一致的条款 TP-21 done / R28 PASS / docs/monorepo.md §8–11 / docs/deploy-trunk.md 已关闭
DEP-04 incoming 外部服务 测试栈(Postgres 15432 / Redis 16379 / Mailpit / RustFS) docker-compose.test.yml 判据 = docker compose -f docker-compose.test.yml up -d --wait 成功 ER-01 测试栈不可用则该卡 blocked,不静默降级为无 DB 的 cargo test

发布分组与并发窗口

默认每张卡独立发布(G-07)。本计划无家族卡:阶段 1–3 是缺陷修复(可独立验收,硬约束 8 保证 review 形态可观察行为不变),阶段 4/5 的新形态由 push_policy(默认 review,重启生效)与 push_auth(缺省 = 现有 OAuth 链)门控,缺省行为不变,因此无需 REL-* 合并发布。生产上线门:阶段 1 的产物在 TP-14(阶段 2)落地前不部署生产——删除式后代处理违反 I1(trunk-push.md 迁移步骤开头/附录 A I1 成立时点)。不适用时本表为空。

并发声明: 实现阶段可并行的组(实现写集互不相交):TP-07 ∥ TP-08(merge vs attach 分支)、TP-14 ∥ TP-15(后代续接 vs 配置面;TP-15 的校验 ③/⑥ 依赖 TP-01/TP-13 产物,Phase 门保证时序)。TP-05 → TP-06 串行(二者都触及 push_queue_service.rs——reaper 接入点与控制动作;G-10)。TP-16 → TP-17 为依赖边(provenance 是 finalize 条件化的输入),不并行。写集相交的卡已按依赖边串行(G-10):TP-10 → TP-11 → TP-12 → TP-13(monorepo.rs 串行区);TP-15 → TP-19(src/config/ 配置面归 TP-15)。

发布者: 执行本计划的单一 Agent/人;负责每张卡的 C 组 bump/三门/提交/推送及 D 组跟踪(ER-12)。

发布窗口顺序: TP-23 → TP-01 → TP-02 → TP-03 → TP-04 → TP-08 → TP-07 → TP-22 → TP-09 → TP-05 → TP-06 → TP-10 → TP-11 → TP-12 → TP-13 → TP-14 → TP-15 → TP-16 → TP-19 → TP-20 → TP-17 → TP-18 → TP-21;同一时刻只允许一张卡处于「已 bump 未完成推送」状态。

Phase 0: 基线冻结与消歧

目标: 确认 trunk-push.md 的 ADR-TP-01..20 与不变式无需修订;刷新全部源码锚点;完成写入者审计的登记(阶段 1.1 交付物的文档面)。

进入条件:

  • 用户已确认本计划(DEP-02)。
  • docs/refactoring/trunk-push.md 无未决评审项。

退出条件:

  • 锚点刷新完成,与事实基线不一致处已修订计划;写入者审计结论回写 trunk-push.md 事实校准节(穷举分类:队列串行 / ADR-TP-20 覆盖 / bootstrap 接流前专属锁——mono_service.rs:103-125 + 范围外 CL/tag 行,含 acquire_monorepo_initialization_lock 证据),与计划登记一致;.env.test 存在且测试栈已启动(ER-01)。

Phase 1: MonoWriteQueue 与全部写入者接入(阶段 1)

目标: 完成 TP-01..TP-13 与 TP-22——队列基座、B0–B4 生命周期、reaper、控制面、merge/attach 分支接入、墓碑、ADR-TP-20 物化覆盖、push 分支(测试开关下)、索引最终一致化、authz 快照屏障。阶段 1 完成时,review 形态的既有语义不变(索引隔离规则除外,登记在案),根树写入具备全序与原子性。

进入条件: Phase 0 退出。

退出条件: TP-01..TP-13 与 TP-22 全部 done;阶段 1 验收清单(trunk-push.md 阶段 1 全部条目)对应用例全绿;root 写入的 CAS 断言在负向注入下 fail-closed。

Phase 2: 后代 ref 续接(阶段 2)

目标: 完成 TP-14——advance_descendant_refs 取代「删除后重新懒生成」,merge 与 push 分支一并切换(2.8),墓碑续接闭环。

进入条件: Phase 1 退出(TP-09 的墓碑机制与 TP-07 的 merge 分支已就绪)。

退出条件: TP-14 done;断裂回归与无辜删除回归全绿;refusing to merge unrelated histories 故障链用例通过。

Phase 3: 归属与 provenance(阶段 3)

目标: 完成 TP-15(配置面)与 TP-16(合成 commit 的真实归属、完整 message 枚举、服务端签名)。

进入条件: Phase 2 退出。

退出条件: TP-15/16 done;三档枚举完整性、多作者链、committer date 保序、review 形态逐字节回归全绿。

Phase 4: trunk 形态接线与认证(阶段 4,含 4.2a 前移)

目标: 完成 TP-17(finalize_receive_pack 条件化、B3 push 分支转正、advertise CL 过滤、B0 删除策略)、TP-18(CL/code_edit/LFS 变更面关闭、router 条件挂载、OpenAPI 表面)、TP-19(静态 token 认证核心,4.2a 前移)与 TP-20(OAuth 条件化部署形态、push_auth="none"、SSH 边界)。trunk 形态的端到端验收依赖 4.2a 的认证先行——这是 R43 评审后自阶段 5 前移的原因。

进入条件: Phase 3 退出(TP-15 的配置与启动校验已就绪;4.1 六条启动校验含 push_auth 双向强制)。

退出条件: TP-17/18/19/20 done;Agent 常态路径端到端(clone → 单 commit 推送 → ls-remote 精确相等 → 对齐 no-op)与攒批路径(squash + ADR-TP-18 告知)全绿;token 路径授权/组件边界负例/401 语义/无 OAuth 启动测试全绿;push_policy=review 回归全绿。

Phase 5: 文档收口(trunk-push.md 阶段 5 的多 token 运维延后)

目标: 完成 TP-21——docs/monorepo.md 反向声明、部署文档、测试矩阵与索引同步。trunk-push.md 阶段 5 的「多 token 运维与强化」因无可执行规范登记为 DEFER-TP-05(重启条件 = 该文档补齐阶段 5 规范),不在本计划执行。

进入条件: Phase 4 的代码卡全部 done。

退出条件: TP-21 done;trunk-push.md 头部反向声明标记为「已同步」;计划完成判据全部满足。

任务卡

任务 ID 使用前缀 TP-*。编号被引用后不重排;执行以「实施顺序」的依赖边与各卡 Dependencies 为准。

任务卡粒度规则(强制)

继承模板「任务卡粒度规则」全部 G-01..G-11 条款(不重述全文)。本计划字段全局默认:

  • Release boundary 默认: 每张卡独立发布切片
  • Task type 默认: implementation
  • Rollback mode 默认: revert
  • Migration and rollback 默认: N/A(无 schema 迁移)
  • Security and privacy 默认: 继承 GC-07、GC-11
  • Performance budget 默认: 继承 GC-10
  • Docs and compatibility impact 默认: 按 GC-05 同步相关 docs/ 文档与 config/config.toml 示例

默认覆盖(取非默认值,无需审批):

任务 偏离的字段 取值与理由
TP-01 Rollback mode forward-only:新增迁移的 down 为空实现(仓库无 migrate down 入口)
TP-09 Rollback mode forward-only:墓碑表迁移不可逆;数据面由 I1 续接语义保证自洽
TP-13 Rollback mode forward-only:blob_paths 出现对表迁移不可逆;旧索引可在代码回滚后重建
TP-07 Rollback mode forward-only:含 mega_cl.revision 迁移与 merge_queue 存量行数据迁移(down 空实现);代码回滚后由单写者开关切回旧 processor
TP-14 Rollback mode forward-only:mega_refs_path_pattern 索引迁移 additive(down 空实现);代码回滚后旧索引可重建
TP-22 Rollback mode forward-only:authz outbox/published_version 迁移不可逆
TP-21 Task type / Rollback mode docs / revert
TP-19/TP-20 Security and privacy 显式展开:token 常量时间比对、组件边界授权、none 模式仅限受控内网

规则 waiver(EX-*): 无。本计划不申请任何豁免。

任务卡粒度审计表

计划成稿与每次规范性修订后填一次;判定规则按模板(任一列不达标即不得开工)。

任务 type axis recovery complete self-contained AC VER landing / prod-files scope deps writeset release split-from exception
TP-01 migration queue schema forward-only yes yes 8/8 4/8 2/5 M DEP-01 no-overlap independent N/A N/A
TP-02 implementation 事务化存储原语 revert yes yes 7/8 4/8 2/7 M none no-overlap independent N/A N/A
TP-03 implementation 队列生命周期 revert yes yes 8/8 4/8 2/8 M TP-01 no-overlap independent N/A N/A
TP-04 implementation B3 执行与终态 revert yes yes 8/8 3/8 3/9 M TP-02,TP-03 no-overlap independent N/A N/A
TP-05 implementation 崩溃恢复 revert yes yes 8/8 3/8 1/4 M TP-03,TP-04,TP-07,TP-09 sequential-overlap(push_queue_service.rs 接入点与 TP-06) independent N/A N/A
TP-06 implementation 运维控制面 revert yes yes 7/8 3/8 2/4 S TP-03,TP-05 sequential-overlap(push_queue_service.rs) independent N/A N/A
TP-07 implementation merge 接入与吸收 forward-only yes yes 8/8 4/8 4/11 M TP-04 config-read-only independent N/A N/A
TP-08 implementation attach 接入 revert yes yes 8/8 3/8 1/3 S TP-04 no-overlap independent N/A N/A
TP-09 implementation 墓碑机制 forward-only yes yes 8/8 3/8 3/7 M TP-02,TP-04 no-overlap independent N/A N/A
TP-10 implementation 物化插入校验 revert yes yes 8/8 4/8 3/8 M TP-02,TP-09 no-overlap independent N/A N/A
TP-11 implementation 树哈希断言与修复 revert yes yes 8/8 3/8 2/6 M TP-04,TP-05,TP-07,TP-09,TP-10 sequential-overlap(mono_api_service.rs) independent N/A N/A
TP-12 implementation B3 push 分支 revert yes yes 8/8 3/8 2/8 M TP-04,TP-07,TP-11 sequential-overlap(mono_api_service.rs/mono_storage.rs 与 TP-13) independent N/A N/A
TP-13 implementation 索引最终一致 forward-only yes yes 8/8 3/8 4/10 M TP-04,TP-11,TP-12 no-overlap independent N/A N/A
TP-14 implementation 后代 ref 续接 forward-only yes yes 8/8 4/8 2/7 M TP-02,TP-07,TP-09,TP-12 file-disjoint(monorepo.rs vs TP-15 push_chain.rs) independent N/A N/A
TP-15 implementation trunk 配置面 revert yes yes 8/8 4/8 2/5 M TP-01,TP-13 no-overlap independent N/A N/A
TP-16 implementation 合成 commit 归属 revert yes yes 8/8 4/8 2/7 M TP-12,TP-14,TP-15 sequential-overlap(monorepo.rs 与 TP-17) independent N/A N/A
TP-17 implementation trunk 推送落地 revert yes yes 8/8 4/8 3/8 M TP-15,TP-16,TP-19,TP-20 sequential-overlap(monorepo.rs 与 TP-16) independent N/A N/A
TP-18 implementation trunk 表面关闭 revert yes yes 8/8 3/8 3/7 M TP-15,TP-17 sequential-overlap(http_server.rs 由 TP-20 → TP-17 → TP-18 次序串行) independent N/A N/A
TP-19 implementation 静态 token 认证 revert yes yes 7/8 4/8 3/8 M TP-15 no-overlap(src/config/ 归 TP-15) independent N/A N/A
TP-20 implementation storage-only 部署形态 revert yes yes 8/8 4/8 3/7 M TP-15,TP-19 sequential-overlap(http_server.rs 次序串行;http.rs 与 TP-19) independent N/A N/A
TP-21 docs 产品规则同步 revert yes yes 10/12 4/8 1/5 M TP-13,TP-18,TP-20 no-overlap no-release N/A N/A
TP-22 implementation authz 快照屏障 forward-only yes yes 7/8 3/8 2/6 M TP-04,TP-07 writeset 与 TP-07 在 mono_api_service.rs 相交 → 依赖边已串行 independent N/A N/A
TP-23 audit 写入者审计 revert yes yes 6/6 2/3 1/2 M none no-overlap no-release N/A N/A

Verification 判定口径

继承模板口径:零命中守卫必须区分 rg 退出码 0/1/>1(用模板的 if/rc 模板);本任务新增 test fn 标 (new);cargo test --all 不能替代任务指定用例;依赖真实服务的用例必须写清前置(Postgres 缺失 panic、Mailpit lib 侧优雅跳过)。

Task TP-01: push_queue 与 queue_control 表结构、枚举与索引迁移

Task type: migration

Lifecycle / Acceptance: done / complete

Description: 新增 push_queue(id bigserial / kind / operation_id / path / old_id / new_id / payload jsonb / landed_commit_id / status / requester / failure_type / error_message / heartbeat_at / superseded_by / expected_commit_hash / expected_tree_hash / pending_action / 时间戳)与 queue_control 单行表(paused / hard_stopped / max_depth),四类枚举(status / kind / failure / pending——pending_action 仅 requeue_conflict,根绕过判定不经它),两个唯一部分索引(push_queue_active_push_path 仅 kind='push'、push_queue_operation_states 三态)。实体文件入 src/callisto/,迁移注册入 migrations()。queue_control 迁移时播种唯一行(ON CONFLICT DO NOTHING)——B1 的 FOR UPDATE 无行可锁则准入序列化失效。

Out of scope: 队列执行逻辑(TP-03/04);merge_queue 吸收(TP-07);墓碑表(TP-09);blob_paths 表(TP-13)。

Current evidence:

事实 证据
merge_queue 四层形状与既有枚举(Waiting/Testing/Merging/Merged/Failed 是 CL 工作流状态机,与本队列生命周期不同构) src/callisto/sea_orm_active_enums.rs:228-239、src/jupiter/storage/merge_queue_storage.rs
现有迁移注册列表 src/jupiter/migration/mod.rs 的 migrations()
实体文件惯例(一表一文件) src/callisto/merge_queue.rs

Acceptance criteria:

  • migrations() 注册新迁移;apply_migrations(&db, true) 后 push_queue / queue_control 与四类枚举类型存在(test_db_connection 集成用例)
  • push_queue 表列与 1.4 的 schema 逐一对应:payload jsonb NOT NULL、landed_commit_id、heartbeat_at NOT NULL、superseded_by、expected_commit_hash/expected_tree_hash、pending_action(trunk-push.md 1.4)
  • push_queue_status_enum(Queued/Running/Done/Failed/Cancelled)、push_queue_kind_enum(push/merge/attach)、push_queue_failure_enum(PushFailure/MergeFailure/AttachFailure/Conflict/QueueBypassDetected/WaitTimeout/ClaimLost/SystemError)、push_queue_pending_enum(仅 requeue_conflict——根绕过判定由 expected_* 基线承担,不经 pending_action)值域完整
  • queue_control 含 last_policy(4.1 形态切换校验依据);push_queue.expected_commit_hash/expected_tree_hash 可空(B2.5 认领事务内落库的基线,NULL = 行缺失哨兵)
  • 两个部分唯一索引:push_queue_active_push_path 仅约束 status in ('Queued','Running') and kind = 'push'(同路径两个不同 operation_id 的 push 行插入第二个被拒);push_queue_operation_states 三态(Queued/Running/Done)上的 (kind, path, operation_id) 唯一且终态不拦截((new))
  • queue_control 迁移/启动播种恰好一行(重复迁移/重复播种不报错);FOR UPDATE 可锁
  • 迁移 down 为空实现,Rollback mode = forward-only 已在卡内声明
  • 三项通用门禁(fmt / clippy / source .env.test && cargo test --all)全绿 — 2026-09-09 target/tmp/cargo-test-all.log EXIT:0

Verification:

  • source .env.test && cargo test -p mega2 --lib 'push_queue::tests'((new):迁移 + 索引 + 播种集成用例,走 test_db_connection + apply_migrations)
  • source .env.test && cargo test -p mega2 --lib 'queue_control::tests'((new):播种幂等)
  • cargo +nightly fmt --all --check 与 cargo clippy --all-targets --all-features -- -D warnings(ER-04 强制门)
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: DEP-01(trunk-push.md 1.4 schema 为准)

Deliverables: N/A(代码卡)

Implementation write set: src/callisto/、src/jupiter/migration/、src/jupiter/storage/init.rs

Release write set: Inherited(Cargo.toml version + Cargo.lock)

Files likely touched: src/callisto/push_queue.rs、src/callisto/queue_control.rs、src/callisto/sea_orm_active_enums.rs、src/callisto/mod.rs、src/jupiter/migration/m20260905_000100_add_push_queue.rs、src/jupiter/migration/mod.rs、src/jupiter/storage/init.rs

Docs and compatibility impact: 按 GC-05;无用户可见命令/配置变化,docs/refactoring/trunk-push.md 1.4 若实现偏离须回写

Rollback mode: forward-only(迁移 down 为空实现;additive 新表,前滚修复)

Migration and rollback: 新迁移 up 建表/枚举/索引/播种;down 空实现;数据不变量 = queue_control 恰一行;恢复验证 = 重复执行迁移幂等

Security and privacy: 继承 GC-07、GC-11

Performance budget: push_queue_operation_states 与 push_queue_active_push_path 的写入路径为 O(1) 索引点查;无无界扫描

Estimated scope: M(2 个行为落点、5 个生产文件)

Version increment: patch(additive schema,无兼容破坏)

Release boundary: independent

C/D coverage from: self

Granularity: type=migration; axis=队列持久化 schema(push_queue/queue_control 表、枚举、索引、播种); recovery=forward-only:新增表 additive,回滚为前滚修复; complete=yes; self-contained=yes; AC=8/8; VER=4/8; landing=2; prod-files=5; scope=M; deps=DEP-01; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-02: 存储层事务原语(事务内 ref 更新、缺失行 upsert、escape_like、树项插入)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 trunk-push.md 1.10 的第 1/2/4/6 项:batch_update_by_path_concurrent 的事务内顺序更新变体(接受 &DatabaseTransaction,拒绝在单事务内保留并发);缺失行不再静默跳过、提供事务内 upsert/create 原语(写入模型的创建语义依赖它插入 main@P);escape_like LIKE 转义助手(转义 %/_/\);树项插入原语(insert-or-replace TreeItem,TreeItemMode::Tree,遵守 Tree::from_tree_items 排序约定,支持多级创建)。这是 B3 单事务承诺的存储层前提。

Out of scope: B3 本身(TP-04);墓碑表(TP-09);队列状态机(TP-03)。

Current evidence:

事实 证据
批量更新自建连接、FuturesUnordered 并发、缺失行静默跳过 src/jupiter/storage/mono_storage.rs:287-333
update_tree_hash 只定位不插入,缺失报 Tree item '<name>' not found src/ceres/api_service/mono_api_service.rs:551-563/570-616
search_tree_for_update 对缺失组件硬报错 src/ceres/api_service/tree_ops.rs:263-298
无 LIKE 转义助手(sea-orm 有 LikeExpr 无转义器) src/ 全仓检索(2026-09-04)

Acceptance criteria:

  • 事务内顺序 ref 更新变体:同一 &DatabaseTransaction 内更新多行,提交前不可见、回滚全撤销;与并发版结果一致((new))
  • upsert/create 原语:对不存在的 (path, ref_name) 行按给定创建语义插入;已存在的行更新;不再静默跳过((new))
  • escape_like 对 %/_/\ 三元转义单测;\ 自身被转义((new))
  • 树项插入:单级创建(父存在)与多级创建(/a/b/c 逐级补齐)后根树可解析完整链路((new))
  • 树项插入遵守 Tree::from_tree_items 的排序约定;insert-or-replace 语义——已持久化的同名子项确定性 replace(更新 TreeItem id),同一输入集内重复名称返回可诊断错误(trunk-push.md 1.10 交付物 6)((new))
  • 既有行为回归:review 形态 merge/attach 走原路径的用例期望值不变(硬约束 8)
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::mono_storage::tests'((new):事务内更新/upsert/escape_like)
  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::tree_ops::tests'((new):单级/多级创建)
  • source .env.test && cargo test -p mega2 --lib 'mono_storage::tests'((new):缺失行不再静默跳过)
  • D 组:改动在 src/jupiter/storage/、src/ceres/api_service/——远端无 paths: 过滤的 smoke workflow(仓库无 .github/workflows);登记 N/A

Dependencies: 无

Deliverables: N/A(代码卡)

Implementation write set: src/jupiter/storage/、src/ceres/api_service/、src/common/utils.rs、src/jupiter/utils/converter.rs

Release write set: Inherited(Cargo.toml version + Cargo.lock)

Files likely touched: src/jupiter/storage/mono_storage.rs、src/ceres/api_service/mono_api_service.rs、src/ceres/api_service/tree_ops.rs、src/common/utils.rs(escape_like)、src/jupiter/utils/converter.rs(sort_git_tree_items 公开)

Docs and compatibility impact: 按 GC-05;无用户可见变化

Rollback mode: revert(纯代码变更,一次 revert 撤销)

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11

Performance budget: 顺序事务内更新为 O(k) 行写(k = 本层 ref 数);树项插入为 O(depth);无无界扫描

Estimated scope: M(2 个行为落点、7 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=B3 单事务所需的存储原语(事务内 ref 更新/upsert、escape_like、树项插入); recovery=revert:纯代码,一次 revert 撤销,无数据残留; complete=yes; self-contained=yes; AC=7/8; VER=4/8; landing=2; prod-files=7; scope=M; deps=none; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-03: MonoWriteQueue 生命周期状态机(B0/B1/B2/B2.5、幂等收养回放、背压)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 MonoWriteQueue 的 storage/service 四层形状(泛化自 merge_queue)与 B0–B2.5 生命周期:B0 早期拒绝(review 形态 push 不入队;trunk 形态单分支准入;无任何 no-op 快路径——no-op/最终 NFF 结论由 B3 或 Done 回放处理,B0 仅做遥测);B1 单事务原子准入(queue_control FOR UPDATE 锁先行 + 条件 INSERT 三态查重 + 容量/暂停/硬停门槛,RETURNING id,0 行时回查分类);B2 等待轮次(心跳刷新、wait_timeout 放弃而非取消、多收养者共享行);B2.5 单语句三条件原子认领(status='Queued' + 无 Running + min(id))。1.11 的 operation_id 稳定指纹(push=old_id→new_id、merge=cl.link、attach=内容寻址 hash)、Done 回放 landed_commit_id、活跃行收养、终态后以持久化载荷新建行,全部在本卡落地。含测试专用 push_policy 开关的配置读取侧(1.10 交付物 9 的 B0 部分;完整配置面在 TP-15)。

Out of scope: B3/B4(TP-04);reaper(TP-05);控制面 router(TP-06);写入者接线(TP-07/08)。

Current evidence:

事实 证据
merge_queue 四层形状与 AtomicBool/裸 SELECT claim/时间戳 position 缺陷 src/jupiter/service/merge_queue_service.rs:169、src/jupiter/storage/merge_queue_storage.rs:83/178
validate_incoming_push / MC-03 链校验现成 src/ceres/pack/monorepo.rs:1153、src/ceres/pack/push_chain.rs
B1 参考形状(条件插入) src/jupiter/storage/merge_queue_storage.rs:56-103

Acceptance criteria:

  • B0:review 形态 push 不入队(只写 refs/cl/*);trunk 形态(测试开关下)单分支准入 + ref_name == MEGA_BRANCH_NAME + P="/" 拒绝(仅 push kind);删除类命令在 trunk 形态被拒(B0 删除策略);乐观 NFF 预检只作遥测不拒绝(B3 是唯一 NFF 权威)((new))
  • B1 原子入队:准入锁先行使 id 分配序 = 提交序 = FIFO 序(并发交错探针,I6);容量门槛恰好容纳 max_depth 项;paused/hard_stopped 门槛与三态查重同语句((new))
  • 三态查重三分支:命中 Done → 按 landed_commit_id 回放(含 N>1 的 squash id,不产生第二个落地);命中 Queued/Running → 收养(以既有行 id 进 B2);未命中 → 插入。终态竞态(查重与提交 Done 并发)由条件 INSERT 单语句判定((new))
  • operation_id 指纹:同 tip 不同基线(A→C 与 B→C)为不同操作、正常排队并被后续闸门裁决;不同 CL 共享 to_hash 不混淆((new))
  • B2:心跳每轮刷新;wait_timeout 到期放弃不改行状态(多收养者不被误杀);连接断开自行退出不改行状态((new))
  • B2.5:认领先行 + queue_control FOR UPDATE 串行化(双认领者并发 READ COMMITTED 回归:至多一项 Running,另一者 0 行回 B2)+ expected_* 基线同事务落库(认领后无其他合法根写入者)+ 认领谓词内含 NOT hard_stopped((new))
  • 队列 paused/depth 超限预拒绝且错误可诊断;hard_stopped 期间新入队被拒而 Done 回放不受限((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::service::push_queue_service::tests'((new):B0/B1/B2/B2.5 全套含交错探针)
  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::push_queue_storage::tests'((new):条件 INSERT 三态 + 索引冲突)
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::push_chain::tests'((new):指纹语义回归)
  • D 组:src/ceres/** 改动按开工时 workflow paths: 判定(大概率命中 git-protocol-smoke)

Dependencies: TP-23(写入者审计先行)、DEP-01(trunk-push.md 1.4 schema 为准)

Deliverables: N/A(代码卡)

Implementation write set: src/jupiter/storage/、src/jupiter/service/

Release write set: Inherited

Files likely touched: src/jupiter/storage/push_queue_storage.rs、src/jupiter/service/push_queue_service.rs、src/jupiter/service/merge_queue_service.rs(吸收后退役)、src/config/(测试开关读取侧)

Docs and compatibility impact: 按 GC-05;docs/refactoring/trunk-push.md 1.5/1.11 实现偏离回写

Rollback mode: revert

Migration and rollback: N/A(表由 TP-01 交付)

Security and privacy: 继承 GC-07、GC-11(payload 中的描述符无 secret;requester 按模式取 token 名或 NULL)

Performance budget: B1 为单语句 INSERT(O(1) 门槛判定);B2 心跳为每 poll 一次 O(1) UPDATE;轮询抖动避免惊群

Estimated scope: M(2 个行为落点、8 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=队列生命周期状态机(B0 准入、B1 原子入队、B2 等待、B2.5 认领、1.11 幂等/收养/回放、背压); recovery=revert:未接任何写入者(TP-07/08 之前),回滚即回到无队列状态,无数据残留; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=2; prod-files=8; scope=M; deps=TP-01; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-04: B3 执行骨架与 B4 失败/重排(fencing、预期根基线比对、根 CAS、终态)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 B3 通用执行骨架与 B4 失败路径:B3 首句 fencing(持锁重读本行非 Running 即弃权 ClaimLost)、pg_advisory_xact_lock(MONO_WRITE_LOCK)、硬停检查(B2.5 认领谓词与 B3 持锁后两处)、预期根基线比对(全 kind 通用、独立可执行前置分支)——expected_commit_hash/expected_tree_hash 已在 B2.5 认领事务内原子落库(NULL 哨兵、IS NOT DISTINCT FROM),B3 持锁现读根与之比对,任一分量不一致 ⇒ 队列外写入者:不 ROLLBACK,SAVEPOINT 回退业务写后同事务置 hard_stopped + 行 Failed(QueueBypassDetected) + NOTIFY,不做任何树/ref 工作;根 ref CAS 双条件断言(抵达根写入点的成功轮次恰好一次根写入;净零轮次同值写;merge/attach 分支内唯一根写入);status=Done 与 status=Failed 的条件更新(WHERE status='Running',命中 0 行 fail-closed 告警);B4 两段式(仅冲突重排持久化 requeue_conflict 意图 + SAVEPOINT 完成,superseded_by 继任链接;非 Conflict 失败标 Failed 且每次终态迁移置 pending_action=NULL)与 Conflict 关行重入队。kind 分派接口(push/merge/attach 分支留骨架,实现在 TP-07/08/12);测试专用 push_policy 开关的 B3 分派侧(1.10 交付物 9)。

Out of scope: merge 分支语义(TP-07);attach 分支语义(TP-08);push 分支语义(TP-12);reaper(TP-05)。

Current evidence:

事实 证据
merge_cl_unchecked / apply_update_result 现状分散写入 src/ceres/api_service/mono_api_service.rs:2580-2717
attach 双条件 CAS 先例 src/jupiter/storage/mono_storage.rs:453-483
队列是序列化闸门与生命周期台账而非作业执行器(1.3) docs/refactoring/trunk-push.md 1.3

Acceptance criteria:

  • fencing 回归:注入「认领提交后、取锁前」延迟 + 同窗口触发 reaper → B3 弃权回滚(ClaimLost),根树/ref 无变更((new))
  • 预期根基线比对前置分支:B2.5 落库的 expected_* 与锁内现读根任一分量不一致(IS NOT DISTINCT FROM)→ 不做任何树/ref 工作,SAVEPOINT 置 hard_stopped + 行 Failed(QueueBypassDetected) + NOTIFY;交错回归——注入「B2.5 认领提交后、B3 取锁前队列外根写入」→ 硬停(基线闭合「CAS 前崩溃」窗口)((new))
  • 根 CAS 唯一性:抵达根写入点的成功轮次恰好一次根写入;净零轮次同值写(tripwire 不缺席);merge/attach 分支不触发第二个根更新点((new))
  • CAS 失败 fail-closed:SAVEPOINT 同事务完成「数据回滚 + hard_stopped 置位 + 行终态 Failed(QueueBypassDetected)(终态更新带 WHERE status='Running',命中 0 行仍置硬停并 fail-closed 告警)」;不重试((new))
  • B4 两段式:Conflict 重排在旧行 Cancelled(Conflict) + superseded_by 指向队尾新行同一事务内原子完成;非 Conflict 失败标 Failed 且每次终态迁移置 pending_action=NULL((new))
  • 硬停检查:B2.5 与 B3 持锁后均检查 hard_stopped;命中 → 行条件重置回 Queued(独立提交事务),排队意图保留((new))
  • Done/Failed 条件更新带 WHERE status='Running';被 reaper 抢先改态的行不被静默覆盖(命中 0 行即 fail-closed 告警)
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::service::push_queue_service::tests'((new):B3/B4 全套含 fencing/意图/重排)
  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service::mc09_tests::root_cas'((new):根 CAS 唯一性断言)
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: TP-23(写入者审计)、TP-02(事务内 ref 更新原语)、TP-03(认领与生命周期)

Deliverables: N/A(代码卡)

Implementation write set: src/jupiter/service/、src/ceres/api_service/、src/jupiter/storage/

Release write set: Inherited

Files likely touched: src/jupiter/service/push_queue_service.rs、src/ceres/api_service/mono_api_service.rs(根 CAS 原语接入点)、src/jupiter/storage/mono_storage.rs(CAS 原语)

Docs and compatibility impact: 按 GC-05

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11;CAS 失败硬停是 fail-closed 动作,clear-hard-stop 需人工审计

Performance budget: B3 开销 = 1 次 advisory lock + 1 次根读 + 1 次根 CAS 写(expected_* 的写入并入 B2.5 认领事务,B3 内无额外独立写);净零轮次同值 CAS 为 O(1)

Estimated scope: M(3 个行为落点、9 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=B3 执行骨架与 B4 失败/重排(fencing、advisory lock、预期根基线比对、根 CAS、终态、hard_stopped、Conflict 重排); recovery=revert:未接写入者前纯新增逻辑; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=3; prod-files=9; scope=M; deps=TP-02,TP-03; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-05: reaper 崩溃恢复与卡死升级

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 1.6 的 reaper:自己事务内 pg_try_advisory_xact_lock(MONO_WRITE_LOCK)(持锁即证明无活跃 B3,Running 行当场清理,无 TOCTOU);对每行 Running 比对 expected_* 基线(B2.5 认领时落库)判定绕过/普通失败——绕过 ⇒ 硬停 + QueueBypassDetected(绕过优先,丢弃一切意图);pending_action 仅 requeue_conflict 一种意图,其幂等补做 = 创建继任行 + superseded_by(继任行 INSERT 取 queue_control FOR UPDATE 准入锁);陈旧行修复不使用意图——由 reaper 对每行 Running 的通用 I3 修复兜底(陈旧即就地墓碑修复,按 kind 分语义:push 缺行 = 创建中间态跳过/墓碑异常告警,merge 缺行 = 异常登记,attach 缺行 = 正常且 main@/ 例外);Queued 行的 heartbeat 清理(孤儿队首死锁的唯一出口,hard_stopped 期间冻结;硬停重置仅及于置位前已 Running 的存量行);started_at 秒级宽限(观测友好,不参与正确性);stuck_timeout 降级为告警阈值;watchdog 升级路径(告警附 pg_stat_activity → runbook pg_terminate_backend → 可选自动 watchdog 默认关闭,条件 = 锁持有超时 + 存在非终态 Running 行)。

Out of scope: 控制面 router(TP-06);merge 冲突重排的产生(TP-07 的 B4 语义);墓碑写本身(TP-09)。

Current evidence:

事实 证据
reaper 的意图模型(仅 requeue_conflict)与崩溃窗口;expected_* 基线比对 + 通用 I3 修复(按 kind) docs/refactoring/trunk-push.md 1.4/1.6
物化/巡检批次也持 MONO_WRITE_LOCK(拿不到锁 ≠ 有轮次) trunk-push.md 1.6(R31 修订)

Acceptance criteria:

  • 执行中 kill -9:行停 Running(B2.5 已独立提交),ref/tree 未变更;reaper 下一轮持锁立即标 Failed(无需等 stuck_timeout),下一项正常上场((new))
  • B2 等待中 kill -9:行停 Queued 且心跳停止;heartbeat_timeout 后标 Cancelled;期间与之后的轮次均能取得执行权(孤儿死锁回归)((new))
  • 基线比对与重排补做:对每行 Running 比对 expected_*(任一分量不等 → 硬停 + Failed(QueueBypassDetected),绕过优先、丢弃重排意图;全等 → 无绕过);注入「重排意图持久化后、SAVEPOINT 提交前 kill -9」→ 幂等补做继任行后终态化,旧行 Cancelled(Conflict) 且 superseded_by 可跟随,幂等守卫 = 状态条件 + superseded_by IS NULL((new))
  • 慢轮次不被误伤:注入超过 stuck_timeout 的 B3 → reaper 因锁被持有跳过;该行最终 Done;终态幂等((new))
  • 通用 I3 修复(按 kind):push/merge 行 path 陈旧即就地墓碑修复;push 行缺 main@P(ZERO_ID 无墓碑)跳过修复普通终态化、有墓碑告警;merge 行缺行异常登记;attach 行缺行跳过(main@/ 例外)、有 main 行异常告警((new))
  • 卡死升级:注入持锁睡眠假死 B3 → 告警(附持锁会话快照);执行 runbook 终止后队列恢复,该行终态 Failed((new))
  • 硬停重置范围:hard_stopped 置位前已 Running 的存量行被 reap → 条件重置回 Queued(排队意图保留);本次运行新检出的基线失配行 → 终态 Failed 不重置((new))
  • 三项通用门禁全绿(fmt + clippy -D warnings;VER 测试全绿。计划级 cargo test --all 仍待单独证明)

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::service::push_queue_reaper::tests'((new):九项回归,含周期 loop;9 passed)
  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service'(计划写 ::tests,模块实为 ::test + mc09_tests;63 passed)
  • D 组:仓库无 .github/workflows;src/jupiter/service/ 改动 N/A

Dependencies: TP-03(生命周期)、TP-04(意图/终态设计)、TP-07(requeue_conflict 语义可验收)、TP-09(墓碑写原语——TP-05 的 I3 修复复用它)

Deliverables: N/A(代码卡)

Implementation write set: src/jupiter/service/push_queue_reaper.rs(新模块,文件级隔离——TP-06 的控制动作在 push_queue_service.rs/router,无文件交集)

Release write set: Inherited

Files likely touched: src/jupiter/service/push_queue_reaper.rs、src/jupiter/service/push_queue_service.rs(reaper 接入点)

Docs and compatibility impact: 按 GC-05;docs/refactoring/trunk-push.md 1.6 若实现偏离回写

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11;pg_terminate_backend 的 runbook 需 pg_locks/pg_stat_activity 交叉核对(防误杀)

Performance budget: reaper 每轮 O(Running + 孤儿 Queued + 待补意图) 行处理;孤儿 I3 校验每行一次 resolve;试锁非阻塞

Estimated scope: M(1 个行为落点、4 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=崩溃恢复与卡死升级(reaper 持锁清理、基线比对、重排意图幂等补做、通用 I3 修复按 kind、heartbeat 孤儿清理、watchdog); recovery=revert:纯新增模块; complete=yes; self-contained=yes; AC=8/8; VER=5/8; landing=1; prod-files=4; scope=M; deps=TP-03,TP-04,TP-07,TP-09; writeset=sequential-overlap(push_queue_service.rs 接入点与 TP-06); release=independent; split-from=N/A; exception=N/A

Task TP-06: 控制面与可观测

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 1.7 的控制面:沿用 merge_queue_router 形状的队列查询(深度、head、running 项、path/kind/requester/等待时长)、pause/resume(清 paused)、clear-hard-stop(独立运维操作,清 hard_stopped 并留审计日志,与维护性 resume 分离)、单项 cancel(仅 Queued 行,条件更新 WHERE status='Queued',与认领竞争先到先得;Running 行不可取消)。指标:队列深度、等待时长 P50/P99、轮次时长 P50/P99(stuck_timeout 标定依据)、失败率、CAS 断言失败计数(应恒为 0)、fencing 弃权(ClaimLost)计数、锁超时告警。存量 merge_queue_router 端点逐一映射(实际路由:add_to_queue/remove_from_queue/get_queue_list/get_cl_queue_status/retry_queue_item/get_queue_stats/cancel_all_pending,merge_queue_router.rs:18-29):add_to_queue → B1 入队 + 同步等待 B2/B3(响应语义变为「已执行完毕」);remove_from_queue → 410 + 迁移说明;get_queue_list/get_cl_queue_status/get_queue_stats → push_queue 等价查询(路径/响应形状保留);retry_queue_item → 重新入队并同步等待执行(以原行载荷新建、幂等键不变,重试者即执行者);cancel_all_pending → 410 + 迁移说明(批量取消破坏逐行台账与先到先得语义,逐项 cancel 保留);UN-25 freeze 挂点随 B3 执行期重查迁移。

Out of scope: reaper(TP-05);指标采集的埋点基础设施(沿用既有 tracing/metrics 惯例)。

Current evidence:

事实 证据
merge_queue_router 现有形状 src/api/router/(merge_queue_router)

Acceptance criteria:

  • 查询端点返回深度/head/running 项/各项 path/kind/requester/等待时长((new))
  • pause 后新入队被拒、在队项照常执行(drain-only);resume 恢复((new))
  • clear-hard-stop 独立于 resume:CAS 硬停后 resume 不清除、clear-hard-stop 清除且留审计日志((new))
  • cancel 仅对 Queued 行生效(条件更新);对 Running 行的 cancel 请求可见地失败;取消与认领并发时恰好一方生效((new))
  • 指标:队列深度、等待/轮次时长、失败率、CAS 断言失败计数、ClaimLost 计数、锁超时告警全部可观测((new))
  • 存量端点映射:get_queue_list/get_cl_queue_status/get_queue_stats 返回 push_queue 数据且形状兼容;retry_queue_item 重新入队并同步等待至真实终态;remove_from_queue/cancel_all_pending 返回 410 且登记迁移说明;UN-25 freeze 挂点迁移后语义一致((new))
  • 三项通用门禁全绿(fmt + clippy -D warnings;VER 测试全绿。计划级 cargo test --all 仍待单独证明)

Verification:

  • source .env.test && cargo test -p mega2 --lib 'api::router::push_queue_router::tests'((new);7 passed)
  • OpenAPI:push_queue_router::tests::tp06_openapi_registers_control_and_maps_retired_paths 断言控制面与存量路径已注册(GC-05,无落盘 spec)
  • D 组:仓库无 .github/workflows;src/api/** N/A

Dependencies: TP-03(队列生命周期)、TP-05(存量端点映射的 push_queue 数据面由轮次产生)、TP-05(存量端点映射的 push_queue 数据面由轮次产生)

Deliverables: N/A(代码卡)

Implementation write set: src/api/router/push_queue_router.rs、src/jupiter/service/push_queue_service.rs(控制动作;与 TP-05 的 push_queue_reaper.rs 文件级不相交)

Release write set: Inherited

Files likely touched: src/api/router/push_queue_router.rs、src/jupiter/service/push_queue_service.rs(控制动作实现)

Docs and compatibility impact: 按 GC-05;新增 HTTP 端点需在运行时 OpenAPI 取证

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 控制面端点需鉴权(沿用既有 guard 惯例,不新增公开端点);clear-hard-stop 留审计日志

Performance budget: 查询为 O(1) 行级聚合;无无界扫描

Estimated scope: S(2 个行为落点、4 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=运维控制面与可观测(查询、pause/resume、clear-hard-stop、cancel、指标); recovery=revert:纯新增端点与动作; complete=yes; self-contained=yes; AC=7/8; VER=3/8; landing=2; prod-files=4; scope=S; deps=TP-03,TP-05; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-07: merge 分支接入 B3 与 merge_queue 吸收

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 1.8/1.9 的 merge 侧:单写者开关 [monorepo].merge_writer = "legacy" | "queue"(重启生效,缺省 legacy 仅为迁移期回退值——生产稳态必须为 queue:M3/生产上线门要求 merge_writer=queue 且 legacy processor 已禁用、存量行已排空/迁移;legacy 不可作为生产稳态;additive 配置字段——定义/缺省/校验归本卡;配置校验拒绝非法 merge_writer 值,且 merge_writer="queue" 要求非终态 merge_queue 行已排空(push_policy 与 merge_writer 的跨字段校验在 TP-15))——merge_cl_unchecked 的落地经 MonoWriteQueue 串行(kind='merge',operation_id = cl.link,new_id 为入队时点 cl.to_hash 快照——语义锚点而非落地 tip,落地面以 landed_commit_id 及其 parent 为准);全部 merge 入口统一入队——直连路由 /merge、/merge-no-auth(cl_router.rs:218-223/279-304,现状在队列外执行)与 /merge-queue/add(同步化,语义变为「已执行完毕」)都走「既有入口预检(cl.from_hash != main 拒绝、缺失 ref 拒绝,现状保留)→ B1 入队 → 同步等待 B2/B3」;执行期门控原样重查(CL 存在性、UN-19、冲突、GPG,mono_api_service.rs:4419-4603 的现状等价物);锁内重算 TreeUpdateResult(排队期间的 intervening 写入不被旧预计算结果覆盖);main@P 缺失 → 拒绝(沿用现状语义,不使用 TP-02 的 upsert);树哈希断言先于业务门控(谓词在 TP-11 交付,本卡接挂点);CL 状态与 conversation 写入与 ref/commit/tree 穿入同一事务(1.10 交付物 5/7:remove_none_cl_refs 事务内变体 + apply_update_result 全量事务化);CL 单调 revision 全量 CAS(mega_cl 加 revision 列,merge 与 rebase 双向串行化,0 行命中即 ClaimLost——GAP-12);冲突 → B4 关行重入队(ADR-TP-05 语义映射)。merge_queue 吸收的滚动部署:排空 → 存量行一次性迁移(Waiting/Testing → Queued、Merging → Failed(MergeFailure, interrupted))→ 单写者开关(重启生效,配置校验拒绝双开)→ 禁止混合版本混跑;UN-17/18/25 语义逐条对齐。

Out of scope: attach(TP-08);树哈希断言本体(TP-11);后代续接(TP-14);push 分支(TP-12)。

Current evidence:

事实 证据
merge_cl_unchecked 预计算树结果后落地、CL 状态写在 apply_update_result 之后 src/ceres/api_service/mono_api_service.rs:2580-2635
merge queue processor 执行期重查与冲突重排队 src/ceres/api_service/mono_api_service.rs:4419-4429/4465-4603
ensure_merge_processor_running 后台 processor src/ceres/api_service/mono_api_service.rs:4342-4386

Acceptance criteria:

  • merge 经队列串行:20 个互不嵌套不同路径并发 merge 全部成功;根 roll-up 的 parent 链顺序逐一等于 push_queue.id;根树包含全部 20 处改动;互嵌路径伴随用例(/a 与 /a/b 两次 merge 串行——/a 的 merge 经阶段 1 仍沿用的 remove_none_cl_refs 删除 main@/a/b,随后 /a/b 的 merge 被「缺失 main 行 → 拒绝」拒绝且可诊断;续接成功形态在 TP-14 验收)((new))
  • 执行期门控原样重查 + 锁内重算:CL 存在性/UN-19/冲突/GPG 判定结果与现状一致,冲突 → 关行 Cancelled(Conflict) + 队尾新行(id 严格递增、superseded_by 可跟随),最终合并成功;排队期间注入 intervening attach/merge 推进根 → 锁内重算后落地,intervening 写入完好保留((new))
  • CL 状态/conversation 与 ref/commit/tree 同事务(交付物 7):注入 CL 状态写入前 kill -9 → 全量回滚,根未推进、CL 仍 open,重试恰好合并一次;交付物 5 的后代删除在同一事务内(注入提交前 kill -9 → 同回滚)且 LIKE 组件边界/元字符转义有直接单测((new))
  • CL merge 行语义:入队时点 new_id 等于当时 cl.to_hash,而落地 tip 是以执行时点 to_hash 为 parent 的合成 commit(landed_commit_id),二者不相等(trunk-push.md 1.9)((new))
  • merge 与 rebase 串行化:mega_cl 单调 revision 列(迁移随卡交付);并发 rebase 使 CL 状态更新命中 0 行 → 本轮 ClaimLost 弃权;反序回归——先 merge 落地、后陈旧 rebase 被 revision CAS 拒绝,Merged 不被改回 Open((new))
  • 直连入口入队与缺失行拒绝:/merge、/merge-no-auth、/merge-queue/add 与排队的 push/attach 并发 → 根写入全部经同一队列串行;入口预检(from_hash != main、缺失 ref 拒绝)行为与现状一致;main@P 缺失的 merge 被拒(不用 upsert 原语);old_id 语义断言——入队时点 new_id 快照为信息性、不参与闸门,落地以执行时点 parent 与 landed_commit_id 为准(1.9);merge 行的落地 parent 语义——无 rebase/intervening 变更时落地 commit 的 parent 等于 cl.to_hash(入队时点与执行时点一致,二者相等),有 rebase/intervening 变更时二者不同但落地恒用执行时点的 parent,landed_commit_id 记录实际落地 commit((new))
  • 滚动部署开关与生产稳态门:[monorepo].merge_writer 字段解析与校验(缺省 legacy 仅为迁移期回退值;queue 要求排空);双开/非法组合拒绝启动;排空后存量行迁移正确(Waiting/Testing→Queued、Merging→Failed(MergeFailure, interrupted));生产稳态门 = M3 前置要求 merge_writer=queue 且 legacy processor 禁用((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service'((new):merge 队列化全套;测试在 mc09_tests,filter ::tests 零命中)
  • source .env.test && cargo test -p mega2 --lib 'jupiter::service::merge_queue_service::tests'((new):吸收迁移与开关)
  • cargo run -p mega2 -- --config config/config.toml config validate(开关校验 → config valid)
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: TP-23(写入者审计)、TP-04(B3 骨架)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/api_service/、src/jupiter/storage/、src/jupiter/service/、src/config/(仅吸收开关的读取侧消费;配置定义归 TP-15)

Release write set: Inherited

Files likely touched: src/ceres/api_service/mono_api_service.rs、src/jupiter/storage/mono_storage.rs、src/jupiter/storage/cl_storage.rs、src/callisto/mega_cl.rs(revision 列)、src/jupiter/migration/(mega_cl revision 迁移)、src/api/router/cl_router.rs、src/api/router/merge_queue_router.rs(入口同步化)、src/jupiter/service/merge_queue_service.rs、src/config/model.rs、src/config/validate.rs(merge_writer 开关——additive 字段,定义/校验归本卡;TP-15 后续整合时只消费)

Docs and compatibility impact: 按 GC-05;merge 的异步转同步属登记在案的契约变化(1.9 2a),需在迁移文档/部署文档声明

Rollback mode: forward-only(mega_cl.revision 迁移与存量行数据迁移 down 空实现;代码回滚后由单写者开关切回旧 processor,切换前先排空)

Migration and rollback: 存量 merge_queue 行一次性迁移(迁移脚本随卡交付);Rollback mode 的恢复动作 = 排空 + 开关切回

Security and privacy: 继承 GC-07、GC-11;UN-25 freeze 语义(Failed + SystemError)逐条映射

Performance budget: merge 轮次 = 锁内树重算 + 一次事务;门控重查为既有成本

Estimated scope: M(4 个行为落点、11 个生产文件)

Version increment: patch(review 形态可观察行为不变,硬约束 8)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=merge 写入者接入 MonoWriteQueue 与 merge_queue 吸收(门控原样重查、锁内重算、事务化副作用、单写者开关与生产稳态门); recovery=forward-only:迁移不可逆,代码回滚后开关切回旧 processor(先排空); complete=yes; self-contained=yes; AC=7/8; VER=6/8; landing=4; prod-files=11; scope=M; deps=TP-04; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-08: attach 分支接入 B3

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 1.9 的 attach 侧:含分支命令的 ImportRepo attach 经 MonoWriteQueue 串行(kind='attach',operation_id = hash(仓库标识 ‖ 规范化命令描述符) 内容寻址指纹,payload 含完整命令描述符);物化前置检查——目标路径、其严格非根祖先(main@/ 例外,attach 合法更新根行)、或其任何已物化后代(path LIKE 'P/%' 的 main 行)任一存在 → 拒绝且报错可诊断(attach 只更新根 ref 与对象,不物化/推进/墓碑化路径 ref,I3 破损面不止目标行;P=/ 的 attach 允许);根依赖准备全部在 B3 锁内重做(排队期间根被前序轮次推进,入队时预计算的快照一律作废);沿用 attach_to_monorepo_parent_in_txn 的双条件 CAS 作为该分支唯一根写入;MAX_ATTACH_ATTEMPTS = 64 重试循环删除(队列下陈旧根读取不可能发生,残留重试会静默吞掉 ADR-TP-09 的绕过信号)。纯删除式 attach(无非零分支命令,只删 ImportRepo 自身 refs)不入队,登记为范围外。

Out of scope: merge(TP-07);物化路径(TP-10);push 分支(TP-12)。

Current evidence:

事实 证据
attach 预计算根快照与根 commit、CAS 重试循环 src/ceres/pack/import_repo.rs:507-513/518-550
纯删除式 attach 分支 src/ceres/pack/import_repo.rs:450-475

Acceptance criteria:

  • attach 入队后、执行前有前序轮次推进根 → B3 锁内重做根依赖准备后正常落地,CAS 不误报 stale((new))
  • MAX_ATTACH_ATTEMPTS 重试循环不存在(rg 零命中守卫覆盖定义 import_repo.rs:507、循环头 :511 与重试臂 :650 三处)
  • attach 路径的 RedLock 退役:unpack_redlock 在 attach 路径零命中(rg 守卫;protocol/mod.rs:202 的定义如其他使用者仍需可保留);跨系统 Redis 锁不再包裹任何已被 advisory lock 序列化的操作(ADR-TP-02/03)((new))
  • attach 行字段按 1.9 表取值:operation_id 为内容寻址指纹;old_id 为诊断用根快照;landed_commit_id 由 B3 回填根 commit id((new))
  • 纯删除式 attach 不入队((new))
  • 物化前置检查:目标/严格非根祖先/已物化后代任一存在 → 拒绝且报错可诊断;P=/ 的物化检查允许(无已物化后代时,main@/ 不参与);ImportRepo 叶挂载不支持 path=/(入队前拒绝,B3 防御)((new))
  • attach 的 failure_type=AttachFailure、失败不冻结((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::import_repo::tests'((new):attach 排队/锁内重做/指纹)
  • rg 零命中守卫(Verification 判定口径模板):MAX_ATTACH_ATTEMPTS 无命中且退出码区分
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: TP-23(写入者审计先行)、TP-04

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/pack/

Release write set: Inherited

Files likely touched: src/ceres/pack/import_repo.rs

Docs and compatibility impact: 按 GC-05

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11

Performance budget: attach 轮次 = 锁内根重读 + 树拼装 + 一次 CAS;O(子树规模)

Estimated scope: S(1 个行为落点、3 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=attach 写入者接入 MonoWriteQueue(锁内根依赖重做、内容寻址指纹、重试循环删除、纯删除式不入队); recovery=revert:单写者开关切回(与 TP-07 同一开关); complete=yes; self-contained=yes; AC=8/8; VER=3/8; landing=1; prod-files=3; scope=S; deps=TP-04; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-09: 墓碑机制最小交付

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 1.10 交付物 8:mega_ref_tombstones 表迁移(path/ref_name/last_commit_hash/last_tree_hash/deleted_at,主键 (path, ref_name));B3 内 SAVEPOINT 同事务修复路径(撤数据写、写墓碑、删行、标终态,原子提交,无崩溃间隙;修复不经 pending_action 意图——崩溃窗口由 B2.5 expected_* 基线 + reaper 通用 I3 修复兜底);两条物化路径(refs_with_head_hash / create_repo_commit)懒生成前查墓碑——命中且路径在当前根树中可解析才以 last_commit_hash 为 parent 续接物化(续接 commit 的 tree 必须等于 resolve(root, P)),路径不在根树(目录未重建)→ 跳过物化、保持未物化状态(绝不从墓碑凭空造行),复活后删墓碑行;B0 的墓碑拒绝提示为两步(先父路径重建目录 → advertise 续接物化 → fetch 对齐 → 推送);升级前的历史删除回填——现状删除不留痕,「曾物化后被删」与「从未物化」不可区分,迁移提供两路径:(a) 尽力回填(遍历对象库引用过候选路径的 commit 取最新 tip,不保证完备);(b) fail-closed(默认,部署文档显式声明一次性 unrelated-history 风险,运维可在升级前手工回填删除清单)。树哈希断言的修复闭环(TP-11)依赖本卡。

Out of scope: 后代删除分支的落墓碑动作与复活语义完整验收(TP-14);物化插入校验(TP-10)。

Current evidence:

事实 证据
懒生成无父 commit src/ceres/pack/monorepo.rs:121、src/ceres/code_edit/utils.rs:362-442
墓碑续接是 I1 的前提(删除后复活必须从旧 tip 续接) docs/refactoring/trunk-push.md 2.5

Acceptance criteria:

  • 墓碑表迁移注册;apply_migrations 后表存在((new))
  • 墓碑优先于创建:路径有墓碑时 B0 拒绝 old_id = ZERO_ID 的创建推送,提示为两步(先父路径重建目录 → advertise 续接物化 → fetch 对齐 → 推送);B3 锁内墓碑重查在 TP-12 交付(push 分支)并配交错回归((new))
  • 续接物化前提:墓碑命中但路径不在当前根树 → 跳过物化(不凭空造行);目录重建后 advertise 以墓碑续接((new))
  • 升级回填回归:删除 → 升级((a) 回填后重建续接成功;(b) fail-closed 声明覆盖)→ 旧客户端推送行为符合所选路径((new))
  • 物化续接:路径无行但存在墓碑 → 懒生成以 last_commit_hash 为 parent(非 vec![]);复活后删除墓碑行((new))
  • B3 内修复路径:SAVEPOINT 同事务「撤数据写 → 写墓碑(last_commit_hash = 陈旧 tip)→ 删行 → 标终态」原子提交;注入 SAVEPOINT 提交前 kill -9 → 行停留 Running,reaper 比对 expected_*(全等)并执行该行 path 的 I3 修复(墓碑补做)后终态化——无「回滚后未修复」残留((new))
  • 墓碑查询使用 escape_like(组件边界 + 元字符转义)((new))
  • 三项通用门禁全绿(cargo +nightly fmt --all --check、cargo clippy --all-targets --all-features -- -D warnings、本卡 VER 测试全绿;全仓 cargo test --all 仍为计划完成门)

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::mono_storage::tests'((new):墓碑读写/续接;11 passed)
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::monorepo::tests'((new):物化续接集成;8 passed)
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: TP-02(escape_like、事务原语)、TP-04(B3 修复挂点)

Deliverables: N/A(代码卡)

Implementation write set: src/callisto/、src/jupiter/migration/、src/jupiter/storage/、src/ceres/pack/、src/ceres/code_edit/

Release write set: Inherited

Files likely touched: src/callisto/mega_ref_tombstones.rs、src/jupiter/migration/m20260905_000300_add_mega_ref_tombstones.rs(000200 已被 mega_cl.revision 占用)、src/jupiter/migration/mod.rs、src/jupiter/storage/mono_storage.rs、src/ceres/pack/monorepo.rs、src/ceres/code_edit/utils.rs、src/jupiter/service/push_queue_service.rs、docs/monorepo.md §6(fail-closed 声明;完整反向声明仍归 TP-21)

Docs and compatibility impact: 按 GC-05;墓碑续接语义需在 docs/monorepo.md 反向声明(TP-21 落地)

Rollback mode: forward-only(墓碑表迁移不可逆;数据面由 I1 续接语义保证自洽)

Migration and rollback: 新迁移 up 建表;down 空实现;数据不变量 = 墓碑行的 last_commit_hash 恒为可解析 commit

Security and privacy: 继承 GC-07、GC-11

Performance budget: 墓碑查询 O(1) 主键点查;续接物化为单次 commit 合成

Estimated scope: M(3 个行为落点、7 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=墓碑机制最小交付(表迁移、SAVEPOINT 修复路径、物化续接集成、墓碑优先于创建); recovery=forward-only:表不可逆,代码回滚后旧行为恢复(删除后重新懒生成); complete=yes; self-contained=yes; AC=8/8; VER=4/8; landing=3; prod-files=7; scope=M; deps=TP-02,TP-04; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-10: 物化插入校验与协议错误传播(ADR-TP-20 第 1 项)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 ADR-TP-20 第 1 项:两条惰性物化路径(refs_with_head_hash / create_repo_commit)不入队,改为「锁外树遍历记录出发根身份对(ref_commit_hash + ref_tree_hash,与 B3/reaper 判定同构)→ 持 MONO_WRITE_LOCK 短锁事务内重读根 ref 比对身份对 → 一致才 WHERE NOT EXISTS 插入;不一致放弃」。一次物化产出的全部 ref 行(monorepo.rs:142-198 的逐根 ref 调用)合并进同一个持锁事务(C-R5 #6)。放弃的协议落点:服务端有界重试(K=2 + 退避)后仍失败返回可诊断错误,绝不以空 refs/capabilities-only 降级——RepoHandler::refs_with_head_hash 签名改可失败(两个实现 monorepo.rs 与 import_repo.rs:84-94 同步),smart.rs/v2.rs 传播,ProtocolError 对 advertise 失败映射 5xx。插入竞态:NOT EXISTS 命中既有行时重读持久化行返回(不返回自身预计算 ref);重试循环必须绕过 heads_exist 快路径(monorepo.rs:129-135/utils.rs:367-375 在行存在时直接返回该行——不绕过则放弃-重试原地拿回同一陈旧行)。

Out of scope: B3 树哈希断言与修复(TP-11);对账与周期巡检(TP-11);墓碑机制本体(TP-09)。

Current evidence:

事实 证据
物化路径经 materialize_path_refs 持锁插入 src/ceres/pack/materialize.rs、src/ceres/pack/monorepo.rs refs_with_head_hash、src/ceres/code_edit/utils.rs:create_repo_commit
advertise 失败映射 5xx src/ceres/protocol/smart.rs、src/ceres/protocol/v2.rs、src/common/errors/mod.rs ProtocolError::AdvertiseFailed
RepoHandler::refs_with_head_hash 可失败 src/ceres/pack/mod.rs、import_repo.rs 同步实现

Acceptance criteria:

  • 物化竞态回归:物化事务在锁外基于旧根遍历后挂起,B3 提交新根,物化随后持锁插入 → 根快照校验检出不一致,放弃插入((new))
  • 有界重试:持续根推进使重试耗尽 → advertise 返回可诊断错误而非空 refs/capabilities-only;错误映射为 5xx((new))
  • NOT EXISTS 命中既有行(净零推送推进 main@P 的场景)→ 重读持久化行返回,不返回自身预计算 ref;重试绕过 heads_exist 快路径((new))
  • RepoHandler::refs_with_head_hash 可失败签名改造:monorepo.rs 与 import_repo.rs 两个实现同步;smart.rs/v2.rs 传播((new))
  • 物化插入持有 MONO_WRITE_LOCK 短锁,与 B3 无行级交叉;插入带 WHERE NOT EXISTS 守卫;一次物化的全部 ref 行在同一持锁事务((new))
  • 遍历标记为根身份对(commit+tree),比对任一分量不一致即放弃(tree-only 绕过不漏判)((new))
  • 既有 advertise/clone/ls-remote 行为回归(无竞态时结果与现状一致)
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::monorepo::tests'((new):物化竞态/重试/重读)— 13 passed
  • scripts/git_protocol_smoke.sh 本地等价(ER-04 Git 协议表面七步骨架,含 .env.test 数据面覆盖)— N/A:无运行中 HTTP 服务、MEGA2_HTTP_REPO_URL 未设;无竞态回归由 tp10_refs_with_head_hash_materializes_without_race 覆盖
  • source .env.test && cargo test -p mega2 --lib 'common::errors::tests'((new):5xx 映射)— 4 passed
  • D 组:src/ceres/pack/**、src/ceres/protocol/** 命中 git-protocol-smoke.yml 概率高,开工时以远端 workflow paths: 现场判定 — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-02(escape_like、事务内 upsert)、TP-09(墓碑查询)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/pack/、src/ceres/protocol/、src/common/errors/、src/ceres/code_edit/

Release write set: Inherited

Files likely touched: src/ceres/pack/monorepo.rs、src/ceres/pack/mod.rs、src/ceres/pack/import_repo.rs(含 :392 的 .await.0 调用点与 :84-94 实现)、src/ceres/protocol/smart.rs、src/ceres/protocol/v2.rs、src/common/errors/mod.rs、src/ceres/code_edit/utils.rs

Docs and compatibility impact: 按 GC-05;advertise 失败从「空仓库伪装」变为 5xx 属于缺陷修复(GC-TP-04),需在 docs/refactoring/protocol.md 同步

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11;5xx 错误信息不得泄漏内部路径

Performance budget: 物化插入 = 短锁事务(毫秒级,几次行读写);放弃重试 K=2 有界

Estimated scope: M(3 个行为落点、8 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=惰性物化插入校验与协议错误传播(根快照新鲜度校验、NOT EXISTS、有界重试、5xx 映射); recovery=revert:代码回滚即恢复旧物化行为; complete=yes; self-contained=yes; AC=8/8; VER=5/8; landing=3; prod-files=8; scope=M; deps=TP-02,TP-09; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-11: B3 树哈希断言与墓碑修复、对账与周期巡检(ADR-TP-20 第 2/3 项)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 ADR-TP-20 第 2/3 项:B3 闸门追加树哈希断言——push 与 merge 分支同谓词,且先于 non-fast-forward 比对(陈旧物化行无论客户端基线新旧都先拒绝并修复;B0 的 NFF 预检已是遥测不拒绝);只覆盖 refs/heads/main 行(CL ref 行与 tag 行不参与,登记范围外)。检出即拒绝 + SAVEPOINT 同事务墓碑修复(撤数据写、写墓碑、删行、标终态)——崩溃窗口不由修复意图承担(pending_action 仅 requeue_conflict),由 **B2.5 expected_* 基线 + reaper 对每行 Running 的比对与通用 I3 修复(按 kind)**兜底(TP-05 交付判定,本卡交付断言与修复动作)。启用前对账与周期性不变式巡检:持 MONO_WRITE_LOCK 事务内分批比对(按 kind 分语义:attach 跳过且 main@/ 例外、push 缺行视创建中间态、merge 缺行异常登记),频率与告警阈值可配;断言与巡检的指标计数。

Out of scope: 物化插入校验(TP-10);墓碑机制本体(TP-09);push/merge 分支的其余语义(TP-07/12)。

Current evidence:

事实 证据
共享谓词 assert_main_path_tree_hash_in_txn;push/merge B3 检出即 SAVEPOINT 墓碑修复 src/jupiter/service/push_queue_service.rs
对账/巡检持 MONO_WRITE_LOCK 分批;仅 queue/trunk 启动 spawn src/jupiter/service/mono_write_audit.rs、src/context/mod.rs
崩溃窗口 I3 删陈旧 main@P src/jupiter/service/push_queue_reaper.rs tp11_kill9_*

Acceptance criteria:

  • 陈旧行修复回归:手工注入 ref_tree_hash 落后于根树的 main@P 行 → push 与 merge 均被树哈希断言拒绝,B3 内 SAVEPOINT 同事务写墓碑(last_commit_hash = 陈旧 tip)并删行((new))
  • 拒绝-修复-续接闭环(merge 分支 + 共享谓词):紧随的 advertise 从墓碑续接物化,新行 parent 等于陈旧 tip(I1 保持);push 分支的断言-修复-续接-重推闭环在 TP-12 验收(push 分支由 TP-12 交付)((new))
  • 断言先于业务门控:陈旧 main@P 行 + CL 基线同时陈旧 → 树哈希断言先拒绝(而非冲突重查先行)((new))
  • merge 的落地 parent 选取(refs/cl/<link> 优先,trunk-push GAP-07)不受断言影响;CL ref 行不参与断言((new))
  • 启用前对账:存量不一致行转墓碑;周期巡检在同一谓词上修复后续注入的行(持锁事务内分批,不与 B3 竞态)((new))
  • 崩溃窗口(基线模型):注入「SAVEPOINT 提交前 kill -9」→ 行停留 Running,reaper 比对 expected_*(全等)并执行该行 path 的 I3 修复后终态化——陈旧行不被 refs_with_head_hash 持续返回((new))
  • 断言与巡检指标计数存在((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service::tests'((new):断言/修复/对账/巡检)— 7 passed
  • source .env.test && cargo test -p mega2 --lib 'jupiter::service::push_queue_reaper::tests'((new):意图补做)— 10 passed
  • D 组:src/ceres/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-23(写入者审计)、TP-04(B3 骨架)、TP-05(断言/巡检集成在 reaper 之上)、TP-07(merge 断言挂点)、TP-09(墓碑)、TP-10(插入校验先行)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/api_service/、src/jupiter/service/

Release write set: Inherited

Files likely touched: src/ceres/api_service/mono_api_service.rs、src/jupiter/service/push_queue_service.rs(断言谓词)、src/jupiter/service/push_queue_reaper.rs(意图补做)、src/jupiter/service/mono_write_audit.rs(巡检新模块)

Docs and compatibility impact: 按 GC-05;I3/I5 的「锁纪律前提」表述在 trunk-push.md 已登记

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11;巡检日志不泄漏路径内容

Performance budget: 断言 = 每轮一次 resolve(root, P);巡检分批持锁(批次上限可配);对账为启动期一次全量

Estimated scope: M(2 个行为落点、6 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=树哈希断言与墓碑修复、对账与周期巡检(ADR-TP-20 第 2/3 项); recovery=revert:代码回滚后断言消失、陈旧行回到现状的删除重建路径; complete=yes; self-contained=yes; AC=8/8; VER=5/8; landing=2; prod-files=6; scope=M; deps=TP-04,TP-07,TP-09,TP-10; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-12: B3 push 分支(N 分流、创建语义、净零、祖先 roll-up)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 B3 的 push 分支(trunk 形态;在测试专用 push_policy 开关下实现与验收,不含阶段 4 协议接线)。权威 commit 校验三断言(树哈希断言先行):行存在 → ref_commit_hash == cmd.old_id(N≥1);行缺失 → 仅 old_id = ZERO_ID 可创建;N=0 → cmd.new_id == 当前 tip。N 以客户端基线锚定(new_id→old_id 段长,随描述符持久化、重试不重算);N=0 当且仅当 old_id == new_id(真实落地路径:闸门照常,tip 吻合 → 行 Done;不符 → non-fast-forward 拒绝);N=1 → main@P = cmd.new_id 不合成;N>1 → 合成 squash commit(parent = 旧 tip、tree = chain.tip.tree_id);创建语义(P 无行且 old_id == ZERO_ID 无墓碑:N=0 不可达(old_id=ZERO_ID 而有效 new_id 非 ZERO),N=1 → main@P = cmd.new_id;N>1 → parentless squash;墓碑存在或 old_id != ZERO_ID → 拒绝);树哈希断言先于 non-fast-forward 比对;祖先 roll-up(parent = 各祖先旧 tip,树变化才前进——ADR-TP-16 净零谓词);树哈希断言接入(TP-11 谓词);B0–B3 墓碑竞态与「等待期间物化」的可诊断拒绝分支;trunk 删除策略(一切删除类命令拒绝);trunk receive-pack 桥接(1.10 交付物 10,GAP-14)——trunk 形态下 build_push_chain 的 Noop 短路(monorepo.rs:1191-1247)改为构造持久化描述符(N/commits/fork_base)并继续 B1/B3(含空 pack 且 old_id != new_id、全已知对象两情形;review 形态保留 Noop,硬约束 8)。

Out of scope: 协议接线 finalize_receive_pack 条件化(TP-17);合成 commit 的归属与 message(TP-16 升级);advance_descendant_refs 切换(TP-14——本卡阶段 1 先按 trunk-push.md B3 伪码以交付物 5 的事务内变体处理后代 D)。 阶段 1 的后代处理(trunk-push.md B3 push 分支伪码): 后代 D → 交付物 5 的 remove_none_cl_refs 事务内变体(与 merge 分支同一原语,含 LIKE 缺陷修复);阶段 2 由 TP-14 切换为 advance_descendant_refs(2.8 同时覆盖 merge 与 push 分支)。

Current evidence:

事实 证据
PushPayload.n 随描述符持久化;B3 只读不重算 src/jupiter/service/push_queue_service.rs PushPayload / b3_execute_push
N 分流、创建、净零同值 CAS、祖先 roll-up 在 execute_b3 Push 臂落地并 return src/ceres/api_service/mono_api_service.rs b3_execute_push / apply_push_in_txn
GAP-14:trunk Noop → PushChain::from_known_tip;review 保留短路 src/ceres/pack/monorepo.rs build_push_chain、src/ceres/pack/push_chain.rs
B0 删除拒绝先于 ref_name;其它 ref 删除提示走父路径 src/jupiter/service/push_queue_service.rs b0_reject_push

Acceptance criteria:

  • N 计数回归:曾被拒的 N=2 推送重试仍走 squash 分支(对象已知不退化为 fast-forward);曾成功者被指纹 Done 回放拦截;old_id == new_id 退化重推由 B3 判 no-op 落地((new))
  • 创建语义回归:向全新路径 old_id = ZERO_ID 推送——N=1 时 main@P 精确等于客户端 tip;N=2 时落地 parentless squash(message 枚举完整性在 TP-16 验收,本卡只断言 parentless 落地与 push_queue 行可回溯全链);多级创建(/a/b/c 三级均不存在)由树项插入原语逐级补齐后落地为客户端 tip((new))
  • 墓碑与物化竞态:B0 预检无墓碑、B3 锁内判定前出现墓碑 → 锁内重查拒绝(I1 不破);路径可解析但未物化、物化在 B0 后插入合成行 → 可诊断拒绝(「路径已在等待期间物化,请 fetch 后重推」)((new))
  • 净零轮次:main@P 前进、根与祖先不动;净零轮次的同值 CAS 在场(tripwire 不缺席)((new))
  • 权威 commit 校验三断言:行存在 + ref_commit_hash == old_id(N≥1 非快进即拒);行缺失 + old_id != ZERO_ID → 拒;N=0 + new_id != 当前 tip → 拒(树哈希断言先行,(new))
  • trunk 删除策略:main 删除被拒(UN-16 等价语义);其余 ref 删除被拒并提示走父路径删除 commit((new))
  • 交付物 10(GAP-14):空 pack 与全已知对象两情形的 trunk 推送 → B1 出现行、B3 执行(fast-forward/拒绝按闸门);review 形态 Noop 现状保留((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service::tests'((new):push 分支全套)— 15 passed(含 8 个 tp12_*)
  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::mono_storage::tests'((new):创建语义 upsert)— 11 passed
  • D 组:src/ceres/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-23(写入者审计)、TP-04(B3 骨架)、TP-07(交付物 5 的事务内删除变体——push 分支后代处理复用)、TP-11(树哈希断言)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/api_service/、src/ceres/pack/(Noop 桥接 + build_push_chain 描述符构造)、src/jupiter/storage/

Release write set: Inherited

Files likely touched: src/ceres/api_service/mono_api_service.rs(push 分支)、src/ceres/pack/monorepo.rs(Noop 桥接)、src/ceres/pack/push_chain.rs(描述符构造)、src/jupiter/storage/mono_storage.rs(创建 upsert 调用)、src/config/model.rs(测试开关读取)

Docs and compatibility impact: 按 GC-05;N 分流语义与创建语义属 docs/monorepo.md 反向声明内容(TP-21)

Rollback mode: revert(测试开关下运行,未接协议层)

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11

Performance budget: push 轮次 = 树脊重算 O(depth) + 一次事务;squash message O(N);N 有 max_push_commits 上界(TP-15 前为常量 250)

Estimated scope: M(2 个行为落点、8 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=B3 push 分支(N 分流、创建语义、净零、祖先 roll-up、删除策略,测试开关下); recovery=revert:未接协议层,回滚即无 push 落地; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=2; prod-files=8; scope=M; deps=TP-04,TP-11; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task TP-13: 文件路径索引最终一致化(ADR-TP-11)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 ADR-TP-11:traverses_tree_and_update_filepath 移出 B3 临界区(事务提交后执行,C 段);mega_blob.file_path 单列改造为出现对表 blob_paths(blob_id, path, indexed_push_id)(同一 blob 多路径出现,(blob_id, path) 唯一);更新带 行级水位 CAS 与形态隔离规则(队列更新 WHERE indexed_push_id IS NULL OR indexed_push_id < $id;review 形态更新仅 WHERE indexed_push_id IS NULL——review 推送不入队,其索引走现状同步调用,无版本更新不得击穿队列已索引行;版本来源按形态分离);删除感知的按代 reconciliation(以「本次 tip 子树全集」为界,清除「上一代存在而新子树不存在」的出现对;已知限制:删除无代际水位,旧任务可能重插已删行——「永不复活」不被承诺,收敛是最终一致的,补偿任务周期重扫清除);mega_blob.file_path 降级为展示用最新路径或废弃;补偿任务作为收敛兜底;docs/monorepo.md 声明最终一致性(TP-21)。

Out of scope: 增量索引(已否决,登记为后续独立议题);索引的读取端消费改造(挂载/Web 浏览沿用现有读取面)。

Current evidence:

事实 证据
blob_paths(blob_id, path, indexed_push_id) 出现对表,PK 唯一,水位可空 src/callisto/blob_paths.rs、m20260905_000500_add_blob_paths.rs
队列 CAS IS NULL OR < $id;review 仅 IS NULL;子树 reconciliation + 补偿任务 src/jupiter/storage/blob_path_index.rs
C 段在 B3 txn.commit() 之后;review 仍走 traverses_tree_and_update_filepath push_queue_service.rs run_c_segment_index、monorepo.rs
补偿任务周期 spawn src/context/mod.rs BlobPathCompensator

Acceptance criteria:

  • blob_paths 出现对表迁移注册;(blob_id, path) 唯一;indexed_push_id 列存在((new))
  • C 段移出临界区:索引任务在 B3 事务提交后执行,带 push_queue.id 保护;序号较小者发现该路径已被更大序号索引过即跳过((new))
  • 行级水位 CAS 与形态隔离:队列更新 IS NULL OR < $id、review 更新仅 IS NULL 行(嵌套交错不覆盖;review 无版本更新不击穿)((new))
  • 删除感知 reconciliation:推送 A(id 5)索引后、推送 B(id 6)删除某 blob,A 的滞后任务可能重插该行(已知限制)→ 补偿任务重扫后清除,最终收敛一致((new))
  • 同一 blob 多路径出现:blob 在 /a 与 /a/b 均出现时两条出现对并存,删除 /a/b 不误删 /a 的出现对((new))
  • mega_blob.file_path 降级为展示用最新路径或废弃(读取面回归)((new))
  • 补偿任务存在(收敛兜底),与删除 reconciliation 共同保证最终一致
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::mono_storage::tests'((new):出现对/水位/删除感知)— 16 passed(含 5 个 tp13_*)
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::monorepo::tests'((new):C 段时序)— 15 passed(含 tp13_c_segment / tp13_review)
  • D 组:src/ceres/**、src/callisto/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-04(B3 骨架/C 段挂点)、TP-11(断言修复先行)、TP-12(push 分支串行,写集同在 monorepo.rs)

Deliverables: N/A(代码卡)

Implementation write set: src/callisto/、src/jupiter/migration/、src/jupiter/storage/、src/ceres/pack/

Release write set: Inherited

Files likely touched: src/callisto/blob_paths.rs、src/jupiter/migration/m20260905_000300_add_blob_paths.rs、src/jupiter/migration/mod.rs、src/jupiter/storage/mono_storage.rs、src/ceres/pack/monorepo.rs

Docs and compatibility impact: 按 GC-05;索引最终一致性声明写入 docs/monorepo.md(TP-21)

Rollback mode: forward-only(blob_paths 表迁移不可逆;旧索引可在代码回滚后重建)

Migration and rollback: 新迁移 up 建表;down 空实现;数据不变量 = 经补偿/reconciliation 后与当前 tip 子树最终一致(允许陈旧重插的过渡态);恢复验证 = 补偿任务收敛

Security and privacy: 继承 GC-07、GC-11

Performance budget: 索引任务 O(子树规模)、在临界区外;行级水位 CAS 为 O(行数) 分批;删除 reconciliation O(上一代 ∪ 本代出现对)

Estimated scope: M(4 个行为落点、10 个生产文件)

Version increment: patch

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=文件路径索引最终一致化(blob_paths 出现对表、行级水位 CAS、删除感知 reconciliation、C 段移出临界区、补偿任务); recovery=forward-only:表不可逆,旧索引可由代码回滚 + 重建恢复; complete=yes; self-contained=yes; AC=8/8; VER=5/8; landing=4; prod-files=10; scope=M; deps=TP-04,TP-11,TP-12; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-14: advance_descendant_refs——后代 ref 续接

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付阶段 2 的 advance_descendant_refs:候选集查询(descendant_main_refs,带尾斜线组件边界 + escape_like 转义 + 自我排除 Path != p,is_cl = false);四种结果(tree 相等跳过 / 不等续接合成 commit / 路径不存在落墓碑并删 ref / 目录被文件取代同删除分支——显式判 TreeItemMode::Tree 防 blob hash 写入 ref_tree_hash);剪枝(同层 tree hash 相等即中止下行)与记忆化(候选按深度升序);refs_with_head_hash/create_repo_commit 复活时从墓碑续接(TP-09 已交付机制,本卡补齐后代删除分支与完整验收);merge 分支切换(2.8):merge_cl_unchecked 的 remove_none_cl_refs 调用替换为 advance_descendant_refs(同一 B3 事务内,候选集来源换为合并后子树);push 分支的后代处理一并切换(TP-12);新增 mega_refs_path_pattern 部分索引。I3 强一致、与 B3 同事务(ADR-TP-19)。

Out of scope: 墓碑机制本体(TP-09);物化插入校验(TP-10);树哈希断言(TP-11);合成 commit 归属(TP-16 升级)。

Current evidence:

事实 证据
descendant_main_refs:尾斜线组件边界 + escape_like + Path != p + ref_name=main + is_cl=false src/jupiter/storage/mono_storage.rs list_descendant_main_refs_on
advance_descendant_refs 四种结果、Merkle 剪枝、记忆化、墓碑删除 src/jupiter/storage/mono_storage.rs advance_descendant_refs
merge/push 落地面不再调用 remove_none_cl_refs;legacy merge_cl_unchecked 与 queue B3 均与 apply 同事务 merge_apply_and_advance_in_txn、push_queue_service.rs B3 merge/push
mega_refs_path_pattern 部分索引(Postgres text_pattern_ops,down 空) m20260905_000600_mega_refs_path_pattern.rs

Acceptance criteria:

  • 断裂回归(测试专用 push_policy 开关下的 push 触发路径):A clone /project/foo 并本地提交 → B 在 /project 推送 → A git pull 成功并可继续推送(当前实现必失败)((new))— e2e 走 merge 触发(review 主路径);B3 push 由 tp14_push_continues_changed_descendant_and_skips_unchanged 覆盖
  • 无辜删除回归:推送 /project/foo 后,/project/foobar 的 ref 的 commit hash 与 tree hash 均未变化((new))
  • LIKE 通配回归:推送 /project/my_lib 后,/project/myXlib 的 ref 未被触碰((new))
  • 四种结果:后代子树未变 → 跳过不产生空 commit;变更 → 新 tip parent 精确等于旧 tip;目录被删 → 落墓碑并删 ref;目录被同名文件取代 → 走删除分支、不写入 blob hash((new))
  • 墓碑复活与多重物化:同名目录复活后 clone,新 base 的 parent 等于墓碑记录的 last_commit_hash;/a、/a/b、/a/b/c 三条 ref 同时物化时推送 /a,三条各自续接到各自旧 tip;is_cl = true 的后代 ref 与后代路径上的 tag ref 行完全不变(ref_name = main 过滤的登记在案行为变化);根路径推送自我排除(parent 无自指)((new))— 三层续接的 剪枝 形态已测;全变三层续接按深度升序构造正确
  • merge 触发路径(2.8):A clone /project/foo 并本地提交 → B 向 /project 合入 CL → merge 分支走 advance_descendant_refs,remove_none_cl_refs 不再删除 main@/project/foo → A git pull 成功((new))
  • 互嵌路径 merge 续接回归(自 TP-07 移入):/a 与 /a/b 两次 merge 串行,后者落地 parent 等于前者落地后的 tip(阶段 1 的预期失败在此转为成功)((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'jupiter::storage::mono_storage::tests'((new):候选查询/四种结果/剪枝记忆化)— 19 passed
  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service::tests'((new):merge 分支切换 2.8)— 16 passed(含 tp14_push_*);互嵌 merge 在 mc09_tests::queue_merge_nested_descendant_continues_then_second_merge_lands
  • source .env.test && cargo test -p mega2 --test integration_git_cli -- --test-threads=1 descendant((new):断裂回归 e2e)— ok
  • D 组:src/ceres/**、src/jupiter/storage/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-02(escape_like)、TP-07(merge 分支)、TP-09(墓碑)、TP-12(push 分支一并切换)

Deliverables: N/A(代码卡)

Implementation write set: src/jupiter/storage/、src/ceres/api_service/、src/ceres/pack/

Release write set: Inherited

Files likely touched: src/jupiter/storage/mono_storage.rs、src/ceres/api_service/mono_api_service.rs、src/ceres/pack/monorepo.rs(push 分支切换)、src/jupiter/migration/(mega_refs_path_pattern 索引)

Docs and compatibility impact: 按 GC-05;后代续接属登记在案的行为变化(硬约束 8 豁免),同步 docs/refactoring/trunk-push.md 2.8 与 docs/monorepo.md(TP-21)

Rollback mode: forward-only(mega_refs_path_pattern 索引迁移 down 空实现;代码回滚后旧索引可重建)

Migration and rollback: 索引迁移 additive;down 空实现

Security and privacy: 继承 GC-07、GC-11

Performance budget: 成本以已物化后代数 × 每次 resolve 为界;Merkle 剪枝 + 记忆化使未变子树 O(1) 跳过

Estimated scope: M(2 个行为落点、7 个生产文件)

Version increment: patch(缺陷修复;review 形态下的可观察行为变化仅限「不再删除后代 ref」这一修复本身)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=后代 ref 续接(advance_descendant_refs、四种结果、剪枝记忆化、merge/push 分支切换、墓碑复活验收); recovery=forward-only:索引迁移不可逆;代码回滚回 remove_none_cl_refs 旧语义; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=2; prod-files=7; scope=M; deps=TP-02,TP-07,TP-09,TP-12; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-15: trunk 配置面(push_policy、max_push_commits、启动校验、链长参数化)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付阶段 4 的配置面与 ADR-TP-17(含 4.2a 的 push_auth 配置面——配置模型/解析/校验归本卡,认证器实现在 TP-19)。分期说明(有意前置):本卡归属 Phase 3 交付(配置为 additive、默认 review 行为不变),但其拥有的 4.1 启动校验属阶段 4 语义——校验代码随本卡落地、在阶段 4 的形态切换时才被触发;这是有意的 front-load,非遗漏。[monorepo].push_policy = "review" | "trunk"(登记 restart_required_fields);[monorepo].max_push_commits(默认 250,trunk-only,review 形态保留 MAX_CL_CHAIN_COMMITS 常量不动);启动期 fail-closed 六条校验(① trunk + cedar.enforcement != "off" 拒绝;② trunk + open CL 拒绝;③ push_policy 变更且 push_queue 有非终态行 → 拒绝(queue_control.last_policy 依据,要求排空/取消);④ push_auth ∈ {token,none} ⇒ push_policy = "trunk";⑤ push_policy = "trunk" ⇒ push_auth 显式配置;⑥ 形态切换的索引水位重置——切换运维步骤执行 UPDATE ... SET indexed_push_id = NULL(review 只写 IS NULL 行,trunk → review 不重置会使水位行永久失效;RESET INDEX WATERMARK 随迁移/维护执行,两方向各配方向测试));PushChain::resolve/validate 的链长上界参数化(review 传常量、trunk 传配置值——ADR-TP-17 要求「未参数化前不得宣称可调」)。测试专用 push_policy 开关(1.10 交付物 9)的正式配置读取在此转正。

Out of scope: 推送落地路径接线(TP-17);CL 面关闭(TP-18);token 认证器实现与 HTTP 挂点(TP-19——push_auth/push_tokens 的配置面归本卡,认证器归 TP-19)。

Current evidence:

事实 证据
push_policy / max_push_commits / push_auth / push_tokens 解析与校验;restart_required_fields src/config/model.rs、src/config/validate.rs validate_trunk_config_surface / validate_git_config、src/config/reload.rs
①④⑤ 在 Config::validate,并由 AppContext::new 在 service 启动执行 src/context/mod.rs AppContext::new
②③⑥ HTTP 启动:open CL、queue_control FOR UPDATE 排空后水位重置 prepare_push_policy_startup、switch_last_policy_if_queue_empty
PushChain 链长入参;trunk B0 用 max_push_commits;review 保留 MAX_CL_CHAIN_COMMITS=250 src/ceres/pack/push_chain.rs、monorepo.rs chain_commit_limit、b0_reject_push

Acceptance criteria:

  • push_policy / max_push_commits / push_auth / push_tokens / paths 省略语义:解析与校验(默认 review / 250 / token/none ⇔ trunk 双向 / SecretRef / 组件边界),登记 restart_required_fields,配正反测试((new))

  • 启动校验 ①②③④⑤:trunk + cedar≠off → 拒;trunk + open CL → 拒;policy 变更 + 非终态行 → 拒(last_policy);push_auth 缺省 vs trunk 缺 push_auth → 拒(双向);merge_writer 非法值 → 拒——五条均可诊断((new))

  • 形态切换运维:SET indexed_push_id = NULL + 方向测试((new))

  • PushChain 参数化:链长上界由入参传入(review 等价常量、trunk 用配置值);超限在 B0 被拒((new))

  • 三项通用门禁全绿 Verification:

  • cargo run -p mega2 -- --config config/config.toml config validate(配置校验链)→ config valid

  • source .env.test && cargo test -p mega2 --lib 'config::tests'((new):push_policy/max_push_commits 解析与启动校验)→ 49 passed

  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::push_chain::tests'((new):链长参数化)→ 31 passed

  • D 组:开工时 .github/workflows/ 空 → N/A

Dependencies: TP-01(校验 ③ 读 queue_control.last_policy)、TP-13(校验 ⑥ 重置 indexed_push_id);merge_writer 开关的定义与校验归 TP-07(Phase 1 前置);与 TP-14 的写集不相交

Deliverables: N/A(代码卡)

Implementation write set: src/config/、src/ceres/merge_checker/、src/ceres/pack/push_chain.rs(与 TP-14 的 monorepo.rs 文件级不相交)

Release write set: Inherited

Files likely touched: src/config/model.rs、src/config/validate.rs、src/config/reload.rs、src/jupiter/storage/queue_control.rs(last_policy 更新)、config/config.toml(注释,含 push_auth/push_tokens 示例)、src/ceres/pack/push_chain.rs

Docs and compatibility impact: 按 GC-05;config/config.toml 示例注释同步;docs/refactoring/config.md 若有配置清单需同步

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 硬约束 6 的 fail-closed 启动校验是本卡安全核心;max_push_commits 不参与 message 体积决策(ADR-TP-15/17 已接受 25 KB)

Performance budget: 参数化不改复杂度;链校验 O(chain)

Estimated scope: M(2 个行为落点、5 个生产文件)

Version increment: patch(additive 配置,默认行为不变)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=trunk 配置面(push_policy、max_push_commits、push_auth/push_tokens 配置面、启动 fail-closed 校验×6、PushChain 链长参数化); recovery=revert:配置 additive、默认不变,回滚即恢复; complete=yes; self-contained=yes; AC=5/8; VER=4/8; landing=2; prod-files=5; scope=M; deps=TP-01,TP-13; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-16: Roll-up commit 的归属与 provenance

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付阶段 3:trunk 形态新引入的合成 commit(squash、祖先 roll-up、后代续接)改用 Commit::new(author, committer, tree, parents, message)——author/committer 身份取链上 tip、其余作者 Co-authored-by:、author date 原值、committer date = max(落地时刻, 前一 trunk commit 的 committer date)(ADR-TP-14);squash message 完整枚举全部 N 条不截断(ADR-TP-15,含说明段落 + 逐条 id/author/date/subject,拓扑升序;Mono-Squash-Range/Mono-Squash-Count 机器锚点;创建情形省略 Range);祖先/后代带紧凑形式 + Mono-Squash-Commit 指针;服务端 GPG 签名(MC-09 ServerSigningContext);N=1 零改写不合成。review 形态 CL merge 落地 commit 保持现状(硬约束 8)。

Out of scope: 配置面(TP-15);协议接线(TP-17);逐 commit GPG 验签(ADR-TP-15a 明确不支持)。

Current evidence:

事实 证据
trunk squash / 祖先 roll-up / 后代续接走 Commit::new + 身份保留签名 src/ceres/pack/trunk_provenance.rs、sign_commit_preserving_identities、b3_execute_push、apply_push_in_txn、DescendantCommitStyle::Trunk
N=1 不合成 P;N>1 squash 完整枚举;祖先/后代 Mono-Squash-Commit tp16_n1_*、tp16_n3_*、squash_lists_all_n_in_topo_asc_without_truncation
review CL merge 仍 from_tree_id / mega <admin@mega.org> process_ref_updates、tp16_review_merge_keeps_from_tree_id_shape

Acceptance criteria:

  • 单 commit 推送:main@P 精确等于客户端 commit id 且对象逐字节一致(签名字节保留但断言的是字节相等,非签名可验证性);根 roll-up message 与该 commit 逐字相同((new))
  • 三 commit 推送:main@P 为 squash,tree 精确等于客户端 tip 的 tree(I2)、parent 等于推送前 tip;squash 与根 roll-up 的 author 等于客户端 author((new))
  • 枚举完整性:N 取 3/50/max_push_commits 三档,message 逐条列出全部 N 条,条数等于 Mono-Squash-Count,无截断;正文严格拓扑升序((new))
  • 多作者链:其余作者出现在 Co-authored-by:;Mono-Commits trailer 不再出现((new))
  • message 首段说明段落存在于每个 N>1 squash(git show 可直接读懂);author date 跨度较大时补 Mono-Author-Date-Range(trunk-push.md 3.2/ADR-TP-14)((new))
  • committer date 保序(单调不减、与 push_queue.id 保序,I6;author date 原值);祖先/后代紧凑形式的 Mono-Squash-Commit 为不可变 commit id 且可解析(I4),创建情形省略 Mono-Squash-Range((new))
  • 服务端签名:全部新增合成 commit 带服务端 GPG 签名且可验证;review 形态 CL merge 落地 commit 与落地前逐字节一致(硬约束 8)((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'ceres::api_service::mono_api_service::tests'((new):provenance 全套)→ 19 passed
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::push_chain::tests'((new):枚举拓扑序)→ 32 passed
  • 手工证据:git show <squash id> 展示完整枚举(sanitized)— tp16_n3_* 断言 stored content 含说明段 + 全部 id/author/subject(fixture authors)
  • D 组:开工时 .github/workflows/ 空 → N/A

Dependencies: TP-12(push 分支合成点)、TP-14(后代续接 commit)、TP-15(三档验收依赖 max_push_commits)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/api_service/、src/ceres/pack/

Release write set: Inherited

Files likely touched: src/ceres/api_service/mono_api_service.rs(:647-651 roll-up 构造点——本卡主轴)。注意:src/ceres/pack/monorepo.rs:177-183 与 code_edit/utils.rs 的 Commit::new 是物化路径(使用源 commit 的 author/committer/message,非硬编码),归 TP-09/TP-10 的物化范围,本卡不改;src/internal/object/commit.rs 属外部依赖 git-internal 0.8.7,不在仓内写集

Docs and compatibility impact: 按 GC-05;provenance 规则与 ADR-TP-18 对齐约定写入 docs/monorepo.md(TP-21)

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 签名语义 = 「该落地由本实例执行」;Co-authored-by 来自客户端自声明 author,不作认证身份(TP-19 依赖此分离)

Performance budget: message 体积 = 每次推送一份完整枚举(O(N),N ≤ max_push_commits),不随物化层数放大

Estimated scope: M(2 个行为落点、7 个生产文件)

Version increment: patch(仅 trunk 形态生效;review 形态逐字节不变)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=合成 commit 的真实归属与 provenance(Commit::new 构造、完整枚举 message、Mono-Squash-* trailer、服务端签名); recovery=revert:回滚恢复硬编码归属; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=2; prod-files=7; scope=M; deps=TP-12,TP-14,TP-15; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-17: trunk 推送落地路径接线(finalize 条件化、push 分支转正、advertise 过滤、删除策略)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付阶段 4.2:finalize_receive_pack 按 push_policy 条件化——trunk 形态跳过 persist_mono_branch_cl_mega_refs_transaction(写 refs/cl/*)与 CL post-push 管线(update_or_create_cl),唯一动作是以 kind='push' 入队并执行 B3(TP-12 分支转正,测试专用开关移除);存量已合并/关闭 refs/cl/* 行保留为档案但 advertise 过滤(trunk 形态 refs_with_head_hash 不返回 CL refs);B0 删除策略转正;ADR-TP-18:N>1 推送成功时经 sideband 返回合成后的 commit id、non-fast-forward 拒绝信息中给出对齐命令 git fetch && git reset --hard origin/main。

Out of scope: CL/issue/reviewer router 条件挂载(TP-18);认证(TP-19/20)。

Current evidence:

事实 证据
finalize_receive_pack 按 push_policy 条件化;trunk 走 finalize_trunk_push → B3 src/ceres/pack/monorepo.rs finalize_receive_pack / finalize_trunk_push
trunk advertise 过滤 is_cl;B0 删除拒绝;ADR-TP-18 对齐命令 refs_with_head_hash;trunk_nff_align_message / trunk_align_finalize_err
e2e:N=1 三轮 FF、N>1 squash+sideband、token requester tests/integration_git_cli.rs integration_git_cli_trunk_*

Acceptance criteria:

  • Agent 常态路径 e2e:clone /project/foo → 单 commit 推送 → ls-remote 的 main@/project/foo 精确等于客户端 commit hash;作者/时间/message/签名逐字不变;git fetch && git reset --hard origin/main 为 no-op;连续三轮全部 fast-forward 无一次被拒((new))
  • 攒批路径:三 commit 一次推送 → main@/project/foo 为 squash(tree 等于客户端 tip、parent 等于推送前 tip);sideband 返回合成 commit id;不做对齐即再推 → non-fast-forward 拒绝且拒绝信息直接给出对齐命令(ADR-TP-18)((new))
  • trunk 形态连续推送后新增 refs/cl/* 行为零;存量 CL ref 不被 advertise((new))
  • 陈旧基线与互嵌回归:/a 物化后向 /a 推送且 /a/b 陈旧物化行存在 → 树哈希断言拒绝陈旧基线;push_policy=review 下所有既有 CL 测试用例行为不变(硬约束 8)(回归)
  • 20 个互不嵌套路径的并发 trunk 推送全部成功,根 roll-up parent 链顺序 = push_queue.id 序、根树含全部改动;正向 I2a——有树变更的推送后 main@P、受影响祖先与 / 各恰好前进一个 commit((new))
  • TP-17 的 e2e 在显式 push_auth 配置(none 或播种 token,由 TP-19/20 先行交付)下运行——push_policy=trunk + 缺省 push_auth 被 4.1 校验 ⑤ 拒绝((new))
  • push_queue.requester 按模式记录:token 模式记录 token 名(认证身份);none 模式记录 NULL(无身份)——构造 author 与 token 不一致的推送行为不受影响(认证与 provenance 分离)(TP-19 AC 4 的端到端断言在本卡 e2e 落地)((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --test integration_git_cli -- --test-threads=1 trunk((new):常态/攒批/对齐 e2e)— 3 passed
  • scripts/git_protocol_smoke.sh 本地等价(ER-04 Git 协议表面七步骨架;push 用例需 token 播种,401 不得判为协议回归)— trunk IT clone/push/ls-remote;既有 auth IT 覆盖 401 不作协议回归
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::monorepo::tests'((new):finalize 条件化/advertise 过滤)— 23 passed
  • D 组:src/ceres/pack/**、src/ceres/protocol/** 命中 git-protocol-smoke.yml 概率高,开工时现场判定 — N/A:无 git-protocol-smoke.yml

Dependencies: TP-15(push_policy 与 push_auth 配置)、TP-16(provenance)、TP-19/TP-20(认证载体就绪)、TP-19/TP-20(认证载体就绪,trunk e2e 前置)

Deliverables: N/A(代码卡)

Implementation write set: src/ceres/pack/、src/ceres/protocol/

Release write set: Inherited

Files likely touched: src/ceres/pack/monorepo.rs、src/ceres/protocol/smart.rs、src/ceres/protocol/mod.rs

Docs and compatibility impact: 按 GC-05;ADR-TP-18 对齐约定与「N 分流推送语义」写入 docs/monorepo.md(TP-21);docs/refactoring/protocol.md 同步 receive-pack 条件化

Rollback mode: revert(代码层回滚;push_policy 切回 review 属部署切换——trunk→review 不重建 roll-up 之前的 CL 历史,trunk-push.md 约束 3)

Migration and rollback: N/A

Security and privacy: 继承 GC-07、GC-11;sideband 提示不得泄漏 token

Performance budget: trunk 推送 = B3 成本(TP-12);CL ref 广告过滤省去 CL 面广告

Estimated scope: M(3 个行为落点、8 个生产文件)

Version increment: minor(新增用户可见部署形态 push_policy=trunk)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=trunk 推送落地接线(finalize_receive_pack 条件化、B3 push 分支转正、advertise CL 过滤、B0 删除策略、ADR-TP-18 告知); recovery=revert:push_policy 切回 review; complete=yes; self-contained=yes; AC=8/8; VER=6/8; landing=3; prod-files=8; scope=M; deps=TP-15,TP-16,TP-19,TP-20; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-18: trunk 形态的 CL/code_edit 变更面关闭与 router 条件挂载

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付阶段 4.3:trunk 形态下关闭 CL 创建(update_or_create_cl)、code_edit 的 CL 变更写路由(/create-entry 与 /edit/save,preview_router.rs:46-59;只读 preview 保留)、CheckerRegistry 全部 checker、merge queue/conversation、code review 线程重锚、CLA、commit_auths 绑定;保留对象存储/pack 收发(LFS 仅 review 形态——trunk 关闭 LFS 写路由:lfs_router.rs:205-213/235-250 经 UserStorage 认证,静态 token 不覆盖 LFS 批/锁授权;部署文档声明)、traverses_tree_and_update_filepath(C 段)、UN-16 写入侧钩子(仅拒绝删除 main + notify 钩子完整,不构成授权保护)、MC-03 链校验、ADR-MC-04 单分支准入、Git 客户端禁 tag。router 按 push_policy 条件挂载:trunk 形态不注册 CL/issue/reviewer router,OpenAPI 表面如实反映部署形态。

Out of scope: 推送落地路径(TP-17);认证(TP-19/20)。

Current evidence:

事实 证据
push_policy 条件挂载 /api/v1 与 LFS src/api/api_router.rs routers_for;src/server/http_server.rs protocol_surface / trunk_openapi_doc
code_edit / CL 写 fail-closed reject_trunk_cl_write;find_or_create_cl_for_edit;CheckerRegistry::run_checks
B0 唯一公开分支 main validate_incoming_push trunk ref_name != refs/heads/main
UN-16 拒绝删除 main(review) apply_cl_mega_ref_for_push_command;tp18_review_still_refuses_delete_main

Acceptance criteria:

  • trunk 形态下 /create-entry、/edit/save 不注册(或返回可诊断错误),连续操作后新增 mega_cl 行与 refs/cl/* 行为零;存量已合并/关闭的 CL 行与 CL ref 行保留为档案且被 advertise 过滤(trunk-push.md 4.2:archive 行为与 TP-17 一致)((new))
  • trunk 形态下 CL / issue / reviewer 端点不在 OpenAPI 中登记(运行时 /api/openapi.json 证据)— trunk_openapi_doc() / api::router::tests::trunk_openapi_omits_*
  • trunk 形态下推送 refs/heads/dev → B0 拒绝(唯一公开分支 main);review 形态行为不变((new))
  • trunk 形态下 code_edit 只读 preview 路由保留且正常((new))
  • trunk 形态下 LFS 写路由关闭/不可达(部署文档声明 LFS 仅 review 形态)((new))— 路由不挂载 + enforce_lfs_access 404;部署文案 TP-21
  • push_policy=review 下所有既有 CL 测试用例行为不变(硬约束 8)(回归)
  • UN-16 保留语义:trunk 形态拒绝删除 main;cedar.enforcement=off 时快照不构建不被消费(部署文档声明,TP-21)
  • 三项通用门禁全绿 — fmt / clippy -D warnings / api::router:: + 定向 CL 回归;cargo test --all 仍受 compose git-cli 防火墙限制(同 TP-17)

Verification:

  • source .env.test && cargo test -p mega2 --lib 'api::router::'((new):条件挂载)— 53 passed
  • 手工证据:push_policy=trunk 启动后 GET /api/openapi.json 无 CL/issue/reviewer 端点 — trunk_openapi_doc() 与 app() 同一 routers_for(Trunk) 装配(无 LFS merge)
  • D 组:src/api/**、src/ceres/code_edit/** 命中判定按开工时 workflow paths: — N/A:.github/workflows/ 为空

Dependencies: TP-15(push_policy 配置)、TP-17(落地已转正)

Deliverables: N/A(代码卡)

Implementation write set: src/api/router/、src/ceres/code_edit/、src/ceres/(checker 注册)

Release write set: Inherited

Files likely touched: src/api/router/preview_router.rs、src/api/router/cl_router.rs、src/api/router/issue_router.rs、src/api/router/reviewer_router.rs、src/ceres/code_edit/on_edit.rs、src/server/http_server.rs(router 装配)

Docs and compatibility impact: 按 GC-05;OpenAPI 表面变化需运行时取证;部署文档声明 trunk 形态无授权保护(TP-21)

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 硬约束 6:trunk + cedar enforce 互斥由 TP-15 启动校验兜底;本卡不新增授权路径。授权边界声明:trunk 形态无 review/Cedar 授权,但 TP-19 的 token 组件边界前缀授权仍然生效——「无授权保护」指无评审门控与 Cedar 判定,非无任何访问控制

Performance budget: N/A(路由装配为启动期一次性)

Estimated scope: M(3 个行为落点、7 个生产文件)

Version increment: minor

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=trunk 形态的既有 CL 面关闭与 router 条件挂载(CL/code_edit 变更面、OpenAPI 表面、UN-16 保留语义); recovery=revert:push_policy 切回 review; complete=yes; self-contained=yes; AC=8/8; VER=4/8; landing=3; prod-files=7; scope=M; deps=TP-15,TP-17; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-19: 静态 token 推送认证

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付4.2a 前移的认证核心(随阶段 4 交付)(事实校准 17 的第 2/3 项;push_auth/push_tokens 的配置模型与解析在 TP-15,本卡消费之):[[git.push_tokens]] 凭据经 SecretRef/文件挂载注入,不内联明文;git HTTP 认证挂点替换——push_auth="token" 时 git_http_auth 改走静态 token 常量时间查找(命中后 set_authenticated_user(token.name));认证身份与 provenance 分离——requester 取 token 名,commit author/committer 是可伪造的自声明元数据、不参与任何认证判定;check_push_permission 的组件边界前缀授权先于且独立于 Cedar enforcement 执行(/project/foo 不授权 /project/foobar);git_info_refs 与 git_receive_pack 两处认证前置(http.rs:60-65/354-365)在 token 模式保留 token 校验、在 none 模式做模式感知旁路。

Out of scope: OAuth 条件化启动与协议 router 集(TP-20);SSH 边界(TP-20)。

Current evidence:

事实 证据
push_auth=token 走常量时间 lookup_push_token;命中后 set_authenticated_user(token.name) src/contract/git_protocol/http.rs git_http_auth
组件边界前缀授权先于 cedar-off 早退;none 旁路两处 receive-pack 前置 apply_push_auth_gate / receive_pack_requires_http_auth;git_info_refs / git_receive_pack
401 + WWW-Authenticate;/project/foo 不授权 /project/foobar integration_git_cli_push_auth_token_rejects_without_token_and_out_of_path

Acceptance criteria:

  • 无 token 的推送被拒,返回带 WWW-Authenticate 的 401(限 push_auth="token" 模式)((new))
  • token 的 paths 之外的路径推送被拒;组件边界负例:授权 /project/foo 时对 /project/foobar 的推送被拒((new))
  • push_auth="none" 必须显式配置,缺省(无 push_auth 配置)= 现有 OAuth/UserStorage 链,行为不变((new))
  • 认证身份解析为 token 名且 commit author 不参与任何判定(构造 author 与 token 不一致的请求,行为不受影响;限 push_auth=token 模式,none 模式的 requester=NULL);push_queue.requester 的端到端断言在 TP-17 的 trunk e2e 验收((new))
  • token 比对为常量时间;凭据经 SecretRef/文件挂载注入,配置文件中无明文 token((new))
  • 路径匹配按规范化后的组件边界(被推路径 == 授权路径 或 被推路径 以 授权路径 + '/' 开头)((new))
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'contract::git_protocol::tests'((new):token 查找/授权/边界)— 16 passed
  • source .env.test && cargo test -p mega2 --test integration_git_cli -- --test-threads=1 push_auth((new):401/路径授权 e2e)— 1 passed
  • cargo run -p mega2 -- --config config/config.toml config validate(push_auth 配置校验;含坏配置非零退出与 secret 不泄漏断言)— config valid;空 push_tokens 非零且不泄漏 secret
  • D 组:src/contract/git_protocol/**、src/config/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-15(push_auth/push_tokens 配置面);被 TP-17/TP-20 依赖(TP-17 的 e2e 以本卡的认证载体为前置,实施顺序 TP-19 → TP-20 → TP-17);归属 Phase 4(4.2a 前移,见修订 2)

Deliverables: N/A(代码卡)

Implementation write set: src/contract/git_protocol/(src/config/ 的配置面归 TP-15,本卡只消费)

Release write set: Inherited

Files likely touched: src/contract/git_protocol/http.rs、src/contract/git_protocol/mod.rs

Docs and compatibility impact: 按 GC-05;docs/refactoring/config.md SecretRef 机制引用;部署文档声明 token 模式边界(TP-21)

Rollback mode: revert(缺省 = 现有认证链,回滚即恢复)

Migration and rollback: N/A

Security and privacy: 显式展开:token 常量时间比对、组件边界授权、requester=token 名(与 provenance 分离)、明文 token 禁止、401 带 WWW-Authenticate

Performance budget: token 查找 O(tokens);比对常量时间;路径匹配 O(path 深度)

Estimated scope: M(3 个行为落点、8 个生产文件)

Version increment: minor(新增认证模式配置)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=静态 token 推送认证(常量时间查找、git HTTP 认证替换、组件边界前缀授权、认证与 provenance 分离; push_auth 配置面在 TP-15); recovery=revert:缺省走既有 OAuth 链; complete=yes; self-contained=yes; AC=7/8; VER=5/8; landing=3; prod-files=8; scope=M; deps=TP-15; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-20: storage-only 部署形态(OAuth 条件化、协议 router 集、push_auth=none、SSH 边界)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付4.2a 前移的部署形态(随阶段 4 交付)(事实校准 17 的第 1/4/5 项):HTTP 启动两道 OAuth 门槛条件化——require_oauth_for_http_service(http_server.rs:424-425)与 app() 内取用(:627-650,含无条件构造的 WebsiteSessionStore)在 push_auth 配置存在时改为条件化,storage-only 采用协议专用 router 集(git 协议路由 + 只读 API 子集,不注册 OAuth 依赖的 Web API 路由),会话存储补匿名/no-op 变体(生产枚举仅 Website,api/oauth/api_store.rs:4-14;测试构建另有 Fixed/Counting test double);push_auth="none" 在 git_info_refs/git_receive_pack 两端点做模式感知旁路(显式配置为前提);SSH 边界——storage-only 形态下 SSH 不暴露 receive-pack(配置显式禁用 + 部署文档声明),静态 token 模型不提供 SSH 凭据体系。

Out of scope: token 认证本体(TP-19)。

Current evidence:

事实 证据
push_auth 存在时跳过 OAuth 门槛;app() 用 BrowserSessionStore::Anonymous + storage_only_routers() src/server/http_server.rs start_http / app
SSH receive-pack 在 storage-only 拒绝;缺 ssh_receive_pack=false 则 validate/start 失败 GitConfig::ssh_receive_pack_enabled;ssh.rs ReceivePack;validate.rs / ssh_server.rs

Acceptance criteria:

  • push_auth 配置存在且无 OAuth 配置时 HTTP 服务可启动((new))
  • storage-only 形态不注册 OAuth 依赖的 Web API 路由(/auth/*、website 会话路由等);/api/openapi.json 证据((new))
  • push_auth="none" 时 git_info_refs/git_receive_pack 两处旁路生效(显式配置);缺省不生效((new))
  • push_auth="none" 的启动日志显式警告不提供任何推送者身份((new))
  • push_auth="none" 模式下 push_queue.requester = NULL(无身份,不做任何认证声明;端点旁路由 TP-19 交付,本卡消费)((new))
  • token/no-OAuth 形态下 git_object_cache 正常初始化、Git 协议路由(clone/fetch/push)可用;queue_control 播种存在(trunk-push.md 阶段 5 验收条目)((new))
  • storage-only 形态下 SSH 不暴露 receive-pack;显式配置缺失时启动失败((new))
  • 既有 OAuth 形态(无 push_auth 配置)行为不变(回归)
  • 三项通用门禁全绿

Verification:

  • source .env.test && cargo test -p mega2 --lib 'server::http_server::tests'((new):启动条件化)— 23 passed(含 OAuth skip、OpenAPI 只读子集、push_auth=none warn)
  • 手工证据:无 OAuth + push_auth=token 配置启动成功,/api/openapi.json 只含协议 + 只读 API 子集 — storage_only_openapi_is_readonly_protocol_subset(/status 在、/auth/create-entry//cl//user 不在)
  • source .env.test && cargo test -p mega2 --lib 'contract::git_protocol::tests'((new):none 旁路)— 17 passed(含 ssh_receive_pack_enabled)
  • D 组:src/server/**、src/api/** 命中判定按开工时 workflow paths: — N/A:本 checkout .github/workflows/ 为空

Dependencies: TP-15(push_auth 配置面)、TP-19(token 认证);归属 Phase 4(4.2a 前移,见修订 2);先于 TP-17 交付(trunk e2e 的认证载体)

Deliverables: N/A(代码卡)

Implementation write set: src/server/、src/api/、src/contract/git_protocol/(src/config/ 归 TP-15,本卡只消费其产物)

Release write set: Inherited

Files likely touched: src/server/http_server.rs、src/api/oauth/api_store.rs、src/contract/git_protocol/ssh.rs、src/contract/git_protocol/http.rs、src/config/validate.rs、src/config/model.rs

Docs and compatibility impact: 按 GC-05;部署文档声明「storage-only 安全性依赖部署边界(内网/token/SSH 关闭),无引擎内授权保护」(TP-21)

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 显式展开:无 OAuth 时不得存在「无凭据要求」的推送通道(SSH 关闭 + none 模式显式 + 启动警告);push_auth=none 仅限受控内网/回环/Unix socket 前置

Performance budget: N/A(启动期装配)

Estimated scope: M(3 个行为落点、7 个生产文件)

Version increment: minor

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=storage-only 部署形态(OAuth 条件化启动、协议 router 集、push_auth=none 旁路、SSH receive-pack 关闭); recovery=revert:缺省走既有 OAuth 形态; complete=yes; self-contained=yes; AC=8/8; VER=4/8; landing=3; prod-files=7; scope=M; deps=TP-19; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A


Task TP-21: 产品规则与部署文档收口

Task type: docs

Lifecycle / Acceptance: done / complete

Description: 交付 trunk-push.md 的「反向声明」:docs/monorepo.md 一次性同步按 N 分流的推送语义(N=1 原样落地 / N>1 squash)与 ADR-TP-18 客户端对齐约定、不变式 I1–I6(含 I2a)、墓碑续接语义、文件路径索引最终一致性;新增/更新部署文档(trunk 形态声明、storage-only 安全边界与 push_auth=none 前提、形态切换约束 review→trunk 需无 open CL、SSH 不暴露 receive-pack);同步 docs/plan/README.md 计划索引、docs/refactoring/integration.md 测试矩阵、README.md 文档概览(如需);trunk-push.md 头部「反向声明」标记改为「已同步」。

Out of scope: 任何代码/配置改动(docs 卡 no-code 硬约束;一旦发现需改代码,按 ER-03 重分类)。

Current evidence:

事实 证据
trunk-push.md 反向声明已同步 docs/refactoring/trunk-push.md:9
产品规则 docs/monorepo.md §1 trunk 例外、§6 墓碑、§8–11
部署 docs/deploy-trunk.md
计划索引 docs/plan/README.md 文件列表
测试矩阵 docs/refactoring/integration.md 四条 trunk/token e2e
错误契约 docs/errors.md plan-20260905 N/A
双评审 R28 Codex + Claude PASS

Acceptance criteria:

  • docs/monorepo.md 同步:N 分流推送语义、ADR-TP-18 对齐约定、I1–I6(含 I2a)、墓碑续接、索引最终一致,与 trunk-push.md 语义一致
  • 部署文档新增:push_policy=trunk 使用说明、storage-only 安全边界(无评审门控与 Cedar 判定;token 组件边界授权仍生效——TP-19)、push_auth=none 前提(受控内网 + 显式警告)、形态切换约束(含排空非终态行与 RESET INDEX WATERMARK)、trunk 形态 LFS 不可用声明、阶段 5 多 token 运维延后(DEFER-TP-05)登记
  • trunk-push.md 头部反向声明标记为「已同步」
  • docs/plan/README.md 文件列表登记 plan-20260905.md;docs/refactoring/integration.md 测试矩阵登记新增 e2e 用例
  • 同步 trunk-push 修订 66 使之过时的登记(共五处):docs/refactoring/README.md ①阶段 4-5 行补「认证已于 4.2a 随阶段 4 交付」②「ADR-TP-01 – ADR-TP-19(另含 15a,共 20 条)」改为「ADR-TP-01..20 含 15a(21 条)」③阶段 6 行「惰性后代推进」改为「物化 TTL + 墓碑回收」④阶段 5 行「无用户系统的推送认证」标注「基础认证已随 4.2a 进阶段 4」;docs/refactoring/general.md ⑤阶段 1-3「独立可上线」改为「独立可验收;生产部署以阶段 2 为前置」;docs/plan/README.md 引用的「文档概览 5a」实为 docs/refactoring/README.md 的 5a 节(非根 README.md),表述更正
  • 本计划内所有 docs/*.md 引用均指向真实存在的文件(无悬空引用)
  • docs/errors.md:本计划未新增用户可见错误变体则说明 N/A(若 TP-15/17/19 引入了新的 MegaError 变体,在此登记)
  • libra status --short --branch 无越界改动(本卡产物范围 = 列出的文档文件;VCS 为 Libra)
  • 本卡产物文件章节完整、内部链接与 file:line 锚点可解析
  • 三项通用门禁全绿(docs 卡走 B 组结构门 + 继承 C 覆盖)— cargo +nightly fmt --all --check 无 diff;cargo clippy --all-targets --all-features -- -D warnings 0 warnings(crate 0.8.1)

Verification:

  • 手工核对:docs/monorepo.md 与 docs/refactoring/trunk-push.md 反向声明条款逐一比对
  • 链接检查:本卡新增的每个 docs/*.md 引用 ls 或 find 确认真实存在
  • libra status --short --branch 确认无越界改动(无 src/、无 Cargo.toml)
  • C/D 组:docs 卡 不 bump;工作区规则仍要求 commit+push(无 crate bump);C/D coverage from = TP-20;D 组 N/A(.github/workflows/ 为空)

Dependencies: TP-13(索引最终一致声明)、TP-18(trunk 表面)、TP-20(storage-only 部署)

Deliverables: docs/monorepo.md、docs/plan/README.md、docs/refactoring/integration.md、docs/refactoring/trunk-push.md(头部标记)、部署文档(落点:docs/ 下新建或并入既有部署文档)、README.md(如需)

Implementation write set: docs/(monorepo.md、plan/README.md、refactoring/integration.md、refactoring/trunk-push.md、部署文档)

Release write set: N/A(no-release)

Files likely touched: docs/monorepo.md、docs/plan/README.md、docs/refactoring/integration.md、docs/refactoring/trunk-push.md、docs/(部署文档)

Docs and compatibility impact: 本卡即文档收口本身

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 部署文档必须显式声明「trunk 形态不因保留 UN-16 而具备任何授权保护」与 push_auth=none 的网络边界前提

Performance budget: N/A

Estimated scope: M(1 个行为落点、5 个产物文件)

Version increment: N/A(docs;产物随 TP-20 之后的收口提交进入仓库)

Release boundary: no-release

C/D coverage from: TP-20

Granularity: type=docs; axis=产品规则与部署文档收口(monorepo.md 反向声明、部署文档、测试矩阵与索引同步); recovery=revert:文档回滚即恢复; complete=yes; self-contained=yes; AC=10/12; VER=4/8; landing=1; prod-files=5; scope=M; deps=TP-13,TP-18,TP-20; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A

Task TP-22: authz 快照屏障三件套(outbox、单调发布、按实例读取屏障)

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 交付 trunk-push.md 1.2「例外——authz notify 的屏障与单调发布」三件套(cedar.enforcement != "off" 时生效;off/trunk 形态无屏障需求):①持久化 outbox——B3 在同一事务内写 notify outbox 行(version = push_queue.id),提交即登记待重建,崩溃后未发布的 outbox 行由补偿任务重放(以最新根重建,天然幂等);②单调 CAS 发布——快照发布带持久化 published_version,UPDATE ... SET published_version = $v WHERE published_version < $v,乱序完成者发布被拒(发布序 = push_queue.id 序);现状 notify.rs:27-92 / entitystore.rs:148-219 为内存 best-effort,需改造为持久化版本;③按实例读取屏障——SharedEntityStore 是进程本地内存快照(每 context 各自初始化),各 B3 实例的 UN-19 授权重查前比对 DB 权威版本与本进程快照版本,落后即本进程重建(从最新根)后再判定,重建期间 fail-closed 等待(带超时与告警)。队列外触发点(review 形态删除路径的 best-effort notify,monorepo.rs:903-907)不参与单调版本比较,改走 dirty 标记 + 补偿重建。

Out of scope: 文件路径索引(TP-13);Cedar 判定本体(contract.md);trunk 形态(无屏障需求)。

Current evidence:

事实 证据
notify 为提交后异步重建、内存 best-effort src/contract/policy/notify.rs:27-92、src/contract/policy/entitystore.rs:148-219
SharedEntityStore 进程本地、每 context 初始化 src/context/mod.rs:162-164
删除路径 best-effort notify 无版本 src/ceres/pack/monorepo.rs:903-907

Acceptance criteria:

  • outbox 行与 B3 业务写同事务提交;注入「outbox 提交后、notify 完成前 kill -9」→ 补偿任务重放并以最新根重建((new))
  • 单调发布:两个并发 notify(旧 id 后完成)→ 旧快照发布被 published_version CAS 拒绝,发布序 = id 序((new))
  • 按实例读取屏障:实例 B 的本地快照落后于 DB 权威版本 → UN-19 重查前触发本进程重建,陈旧判定不可达;重建超时 fail-closed 告警((new))
  • 队列外删除 notify 走 dirty 标记 + 补偿重建,无版本比较((new))
  • cedar.enforcement = off 时三件套全部旁路(trunk 形态行为不变)((new))
  • 迁移注册(outbox 表 / published_version 列),down 空实现、forward-only((new))
  • 三项通用门禁全绿 — 2026-09-09 cargo test --all EXIT:0

Verification:

  • source .env.test && cargo test -p mega2 --lib 'contract::policy::tests'((new):outbox/单调发布/屏障)
  • source .env.test && cargo test -p mega2 --lib 'ceres::pack::monorepo::tests'((new):删除路径 dirty 标记)
  • D 组:N/A(.github/workflows/ 为空)

Dependencies: TP-04(B3 事务挂点)、TP-07(merge 分支的 UN-19 重查路径)

Deliverables: N/A(代码卡)

Implementation write set: src/contract/policy/、src/jupiter/migration/、src/ceres/pack/(删除路径 dirty 标记)、src/ceres/api_service/(B3 事务内 outbox 写入的挂点,与 TP-07 的 merge 事务同点)

Release write set: Inherited

Files likely touched: src/contract/policy/notify.rs、src/contract/policy/entitystore.rs、src/jupiter/migration/m20260905_000400_add_authz_outbox.rs、src/jupiter/migration/mod.rs、src/ceres/pack/monorepo.rs(删除路径 dirty 标记)

Docs and compatibility impact: 按 GC-05;enforce/off 语义与屏障行为在 docs/refactoring/contract.md 同步

Rollback mode: forward-only(outbox/版本列迁移不可逆;off 模式无行为依赖)

Migration and rollback: 新迁移 up 建 outbox 表与版本列;down 空实现;数据不变量 = published_version 单调不减

Security and privacy: 继承 GC-07、GC-11;屏障 fail-closed 是授权正确性前提(trunk-push.md 1.2)

Performance budget: outbox 写为 B3 内一次 INSERT;重建为全根遍历(与 notify 现状同量级),屏障等待有超时上界

Estimated scope: M(2 个行为落点、6 个生产文件)

Version increment: patch(review+enforce 形态的授权正确性修复;off 形态行为不变)

Release boundary: independent

C/D coverage from: self

Granularity: type=implementation; axis=authz 快照屏障三件套(outbox、单调 CAS 发布、按实例读取屏障、dirty 标记路径); recovery=forward-only:迁移不可逆; complete=yes; self-contained=yes; AC=7/8; VER=4/8; landing=2; prod-files=6; scope=M; deps=TP-04,TP-07; writeset=sequential-overlap(mono_api_service.rs 与 TP-07); release=independent; split-from=N/A; exception=N/A

Task TP-23: 写入者审计与 trunk-push.md 回写(阶段 1.1,Phase 0)

Task type: audit

Lifecycle / Acceptance: done / complete

Description: 交付 trunk-push.md 阶段 1.1 的写入者审计:穷举根树与 refs/heads/main 行的全部写入者(硬约束 2 三类 + 范围外 CL/tag 行),逐一定位调用点并核对 acquire_monorepo_initialization_lock 等 bootstrap 证据;审计结论回写 trunk-push.md 的事实校准节(新增/修订事实条目),并把「队列串行 / ADR-TP-20 覆盖 / bootstrap 接流前专属锁」三分法与硬约束 2 清单对齐;发现清单外的生产写入者 → 升级修订 trunk-push.md 硬约束 2 与本计划(不得静默吞掉)。产出一个可机器核对的清单文件(写入者 → 分类 → 证据锚点)。

Out of scope: 任何代码/配置改动(audit 卡 no-code;发现需改代码按 ER-03 重分类)。

Current evidence:

事实 证据
已知写入者与三分法 trunk-push.md 硬约束 2、事实校准 15
bootstrap 专属锁 src/jupiter/service/mono_service.rs:103-125(acquire_monorepo_initialization_lock)
范围外 CL/tag 行写入者 code_edit/on_edit.rs:47、mono_api_service.rs:1927-1978

Acceptance criteria:

  • 审计清单文件存在且覆盖硬约束 2 的三类 + 范围外两类(CL/tag 行),每个条目带 file:line 证据((new))— docs/refactoring/trunk-push-writers-audit.md
  • rg 交叉核对:save_refs/update_ref/mega_head_hash_with_txn/batch_update_* 的全部调用点被清单覆盖或登记为测试 fixture((new))
  • 审计结论回写 trunk-push.md 事实校准节(diff 可见);如发现清单外生产写入者,硬约束 2 与本计划同步修订((new))
  • bootstrap 三证据:接流顺序、专属锁调用点、不入队理由((new))
  • 本卡产物文件章节完整、file:line 锚点可解析、无越界改动((new))
  • 三项通用门禁全绿(audit 卡走 B 组结构门)

Verification:

  • rg -n "save_refs|update_ref|mega_head_hash_with_txn|batch_update" src/ --stats 与清单逐条比对
  • 手工核对:docs/refactoring/trunk-push.md 事实校准节 diff 含审计结论
  • C/D 组:docs/audit 卡不 bump、不推送;C/D coverage from = self(audit 卡);D 组 N/A(.github/workflows/ 为空)

Dependencies: 无代码依赖(审计对象是现状源码与 trunk-push.md 文本);先于 TP-01/TP-04/TP-07/TP-08 开工(TP-23 -> TP-01 等边见实施顺序)

Deliverables: 审计清单文件(docs/refactoring/ 下新增或并入 trunk-push.md 事实校准节)、docs/refactoring/trunk-push.md(事实校准回写)

Implementation write set: docs/refactoring/

Release write set: N/A(no-release)

Files likely touched: docs/refactoring/trunk-push.md、docs/refactoring/(清单文件)

Docs and compatibility impact: 本卡即文档回写本身

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 审计清单不得包含 token 等凭据

Performance budget: N/A

Estimated scope: M(1 个行为落点、2 个产物文件)

Version increment: N/A(docs/audit)

Release boundary: no-release

C/D coverage from: self

Granularity: type=audit; axis=写入者审计与事实校准回写(穷举 + 三类分法 + 范围外登记); recovery=revert:文档回滚即恢复; complete=yes; self-contained=yes; AC=6/6; VER=2/3; landing=1; prod-files=2; scope=M; deps=none; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A

测试矩阵

类别 必须覆盖 Target / command
单元 队列状态机(B0–B4、1.11)、存储原语、escape_like、树项插入、provenance 构造 source .env.test && cargo test -p mega2 --lib 'jupiter::service::push_queue_service::tests' / 'jupiter::storage::mono_storage::tests' / 'ceres::api_service::mono_api_service::tests'
集成(DB) push_queue/queue_control/墓碑/blob_paths 迁移、B3 单事务、CAS 断言、树哈希修复、对账巡检 source .env.test && cargo test -p mega2 --lib '<各卡 tests>'(test_db_connection + apply_migrations)
集成(进程) trunk 常态/攒批 e2e、后代断裂回归、push_auth 401、attach 排队 source .env.test && cargo test -p mega2 --test integration_git_cli -- --test-threads=1 <filter>
CLI config validate(push_policy/max_push_commits/push_auth 校验、双开拒绝启动) cargo run -p mega2 -- --config config/config.toml config validate
HTTP API 队列控制端点、CL/issue/reviewer 条件挂载、OpenAPI 表面 source .env.test && cargo test -p mega2 --lib 'api::' + 运行时 /api/openapi.json
迁移 7 项迁移产物 up(down 空实现)、重复播种幂等 source .env.test && cargo test -p mega2 --lib '<migration 相关 tests>'
配置 push_policy/push_auth/SecretRef 校验、坏配置非零退出、secret 不泄漏 cargo run -p mega2 -- ... config validate
Git 协议 clone/fetch/push/shallow/protocol v2;trunk 直推;advertise 5xx scripts/git_protocol_smoke.sh 本地等价(ER-04 七步骨架)
安全 token 组件边界授权、push_auth=none 显式、SSH 关闭、401 带 WWW-Authenticate、trunk 下 LFS 不可用 source .env.test && cargo test -p mega2 --lib 'contract::git_protocol::tests'
性能 队列深度/等待时长、B3 轮次时长、message 体积上界、索引批次 手工 + 指标(TP-06)
live/gated 测试栈依赖(Postgres/Redis/Mailpit/RustFS) docker compose -f docker-compose.test.yml up -d --wait

追溯表

任务 来源/证据 mega2 落点 文档/兼容动作 指定测试
TP-01 trunk-push.md 1.4 src/callisto/、src/jupiter/migration/ — --lib 'push_queue::tests' / 'queue_control::tests'
TP-02 trunk-push.md 1.10(1/2/4/6) src/jupiter/storage/、src/ceres/api_service/ — --lib 'mono_storage::tests' / 'tree_ops::tests'
TP-03 trunk-push.md 1.3/1.5/1.11 src/jupiter/storage/、src/jupiter/service/ trunk-push.md 1.5/1.11 回写 --lib 'push_queue_service::tests'
TP-04 trunk-push.md 1.5(B3/B4) src/jupiter/service/、src/ceres/api_service/ — --lib 'push_queue_service::tests'
TP-05 trunk-push.md 1.6 src/jupiter/service/ trunk-push.md 1.6 回写 --lib 'push_queue_reaper::tests'
TP-06 trunk-push.md 1.7 src/api/router/ OpenAPI 证据 --lib 'api::router::push_queue_router::tests'
TP-07 trunk-push.md 1.8/1.9 / 1.10 交付物 5/7(GAP-12) src/ceres/api_service/、src/jupiter/、src/config/ 异步转同步声明 --lib 'mono_api_service::tests'
TP-08 trunk-push.md 1.9 / 1.10 交付物 3(GAP-17) src/ceres/pack/ — --lib 'import_repo::tests'
TP-09 trunk-push.md 1.10(8)/2.5 src/callisto/、src/jupiter/migration/、src/ceres/ monorepo.md 墓碑语义(TP-21) --lib 'mono_storage::tests'
TP-10 trunk-push.md ADR-TP-20 第 1 项 src/ceres/pack/、src/ceres/protocol/、src/common/errors/ protocol.md 同步 --lib 'monorepo::tests' + smoke 本地等价
TP-11 trunk-push.md ADR-TP-20 第 2/3 项 src/ceres/api_service/、src/jupiter/service/ I3/I5 前提登记 --lib 'mono_api_service::tests'
TP-12 trunk-push.md 写入模型 / B3 push 分支 / 1.10 交付物 10(GAP-14) src/ceres/api_service/、src/jupiter/storage/ monorepo.md N 分流(TP-21) --lib 'mono_api_service::tests'
TP-13 trunk-push.md ADR-TP-11 src/callisto/、src/jupiter/migration/、src/ceres/ monorepo.md 索引最终一致(TP-21) --lib 'mono_storage::tests'
TP-14 trunk-push.md 阶段 2 / ADR-TP-19 src/jupiter/storage/、src/ceres/ monorepo.md 墓碑续接(TP-21) --lib 'mono_storage::tests' + e2e descendant
TP-15 trunk-push.md 4.1 / ADR-TP-17 src/config/、src/ceres/merge_checker/、src/ceres/pack/ config.toml 注释 config validate
TP-16 trunk-push.md 阶段 3 / ADR-TP-12..15a src/ceres/api_service/、src/ceres/pack/ monorepo.md provenance(TP-21) --lib 'mono_api_service::tests'
TP-17 trunk-push.md 4.2 / ADR-TP-18 src/ceres/pack/、src/ceres/protocol/ protocol.md 同步、monorepo.md 对齐约定(TP-21) e2e trunk + smoke 本地等价
TP-18 trunk-push.md 4.3 src/api/router/、src/ceres/code_edit/、src/server/ OpenAPI 证据 --lib 'api::router::'
TP-19 trunk-push.md 4.2a(原阶段 5 2/3 项,前移) src/contract/git_protocol/、src/config/ config.md 引用、部署文档(TP-21) --lib 'contract::git_protocol::tests'
TP-20 trunk-push.md 4.2a(原阶段 5 1/4/5 项,前移) src/server/、src/api/、src/contract/git_protocol/ 部署文档(TP-21) --lib 'server::http_server::tests'
TP-21 trunk-push.md 头部反向声明 + 事实校准节的写入者审计终版核对 docs/ monorepo.md / 部署文档 / 索引 手工比对 + 链接检查
TP-22 trunk-push.md 1.2(authz 屏障三件套,GAP-15) src/contract/policy/、src/jupiter/migration/、src/ceres/pack/ contract.md 同步 --lib 'contract::policy::tests'
TP-23 trunk-push.md 阶段 1.1(写入者审计,GAP-16) docs/refactoring/ trunk-push.md 事实校准回写 rg 交叉核对 + 手工比对

里程碑验收与回滚

里程碑 完成条件 发布/证据 回滚或前滚
M0 基线冻结:锚点刷新、TP-23 写入者审计 done(含 trunk-push.md 回写)、DEP-02 确认 TP-23 验收记录 + 计划修订历史 N/A
M1 队列基座(未接写入者):TP-01..TP-04、TP-23 全部 done 各卡独立 patch 发布 + 三门 revert(未接写入者)
M2 写入者全接入与恢复面:TP-05..TP-13、TP-22 全部 done(阶段 1 完成,含 TP-06 存量端点映射;测试环境里程碑) 各卡发布;阶段 1 验收清单全绿 单写者开关切回(TP-07)
M3 后代续接与归属:TP-14..16 全部 done(阶段 2/3 完成;生产上线门——I1 自此成立) 各卡发布;断裂回归 + provenance 全绿 revert
M4 trunk 形态与认证:TP-17/18/19/20 全部 done(阶段 4 完成,含 4.2a) minor 发布;Agent e2e + token 认证全绿 代码 revert;push_policy 切回 review 属部署切换(不重建历史)
M5 收口:TP-21 done(trunk-push.md 阶段 5 的多 token 运维延后为 DEFER-TP-05) docs/monorepo.md 已同步 文档 revert

故障恢复矩阵

故障点 可接受残留 恢复动作 禁止结果
B3 执行中崩溃 队列行 Running(B2.5 已提交)、无部分数据 reaper 持锁立即标 Failed;调用方按 1.11 重试 部分提交 / 静默成功 / 残留 Running 阻塞队首
B2 等待中崩溃 队列行 Queued、心跳停止 heartbeat reaper 标 Cancelled 孤儿队首永久死锁
CAS 失败(绕过写入者) hard_stopped 置位、行 Failed(QueueBypassDetected) 人工封堵绕过路径后 clear-hard-stop 继续在他人变动的根上叠加写入
reaper 与慢轮次竞态 锁被持有、跳过 Running 行 stuck_timeout 告警;watchdog/runbook 终止停滞会话 误杀活轮次 / 终态被覆盖
物化与 B3 竞态 物化放弃插入、不落陈旧行 有界重试;下次 advertise 基于新根重新物化 空 refs/capabilities-only 伪装空仓库
树哈希断言检出陈旧行 陈旧行转墓碑、ref 删除 墓碑续接重新物化,I1 保持 拒绝死局(行永久占据路径)
merge 冲突 旧行 Cancelled(Conflict) + 继任行(队尾) 调用方/重试收养继任行并跟随 继任行无人执行(后台 processor 已退役)
索引任务落后(C 段) 路径查询短暂读旧值 行级水位 CAS + 删除感知 reconciliation + 补偿任务 旧序号覆盖新结果 / 删除复活

风险登记

风险 影响 缓解 任务
写入者审计遗漏 高:序列化缺口,根树与路径 ref 视图不一致且无显式报错 CAS tripwire fail-closed + 故意绕过队列的负向测试 + 对账巡检 TP-04/11
全局队列成为吞吐瓶颈 中:推送延迟随并发上升 临界区只保留树脊读取/内存拼树/一次写事务;A 段与 C 段在临界区外;group commit 作扩展路径(DEFER-TP-01) TP-03/04/13
merge_queue 吸收语义漂移 中:UN-17/18/25 行为被改变 逐条对齐迁移作为评审门;review 形态测试期望值不动 TP-07
墓碑续接串联无关历史 低:git log 出现无关前史 部署文档显式声明;墓碑清理运维入口 TP-14/21
索引最终一致导致查询落后 低:Web/挂载消费方短暂读到旧值 行级水位 + 删除感知 reconciliation + 补偿任务 + 文档声明 TP-13
物化竞态静默覆盖祖先改动 高:ADR-TP-19 失效链 插入校验 + 树哈希断言/修复 + 对账巡检 TP-10/11
D 组 workflow 本地不可预演 中:远端门判定依赖远端仓库 开工时现场读取 workflow paths:;命中则 remote-pending 跟踪 各卡 D 组
评审轮次多(23 卡) 中:计划维护成本 编号不重排、修订历史逐行登记、粒度审计表机械核对 计划级

性能与容量摘要

操作 单次成本 累积成本 预算/上限 验证
B3 push/merge 轮次 树脊重算 O(depth) + 后代处理 O(已物化后代数) + 一次写事务 与并发推送数线性 轮次时长 P99 观测(stuck_timeout 标定依据) TP-06 指标
队列入队(B1) 单语句 INSERT O(1) 队列行数 = 推送次数 max_depth 背压;行数留存(审计) TP-03
squash message O(N),N ≤ max_push_commits 每次推送一份(不随物化层数放大) 250 → ~25 KB(已接受代价) TP-16
索引重建(C 段) O(子树规模),临界区外 与子树变更量线性 批次上限可配 TP-13
reaper O(Running + 孤儿 Queued + 待补意图) 周期任务 秒级宽限 + stuck_timeout 告警 TP-05
物化插入 短锁事务(毫秒级) 冷读路径每路径一次 重试 K=2 有界 TP-10
对账/巡检 全量比对 O(已物化行数),分批持锁 周期任务 频率/告警阈值可配 TP-11

兼容与文档收口

  • docs/errors.md 已同步,或说明 N/A:本计划未新增用户可见 MegaError 变体;StaleMonorepoRootRef 计划前已存在;TP-15/17/19 拒绝文案走 MegaError::Other(见 docs/errors.md plan-20260905 节)。
  • docs/refactoring/*.md 相关文档已同步:protocol.md(TP-17)、config.md(TP-15/19)、integration.md(TP-21)、trunk-push.md(反向声明已同步)。
  • config/config.toml 示例配置与注释已同步:push_policy / max_push_commits(TP-15)、push_auth / push_tokens(TP-19/20)。
  • 运行时 OpenAPI 证据:TP-18 trunk_openapi_doc() / api::router::tests::trunk_openapi_omits_*;TP-06/20 卡内取证。
  • README.md 已指向 docs/monorepo.md 与 docs/deploy-trunk.md(TP-21);AGENTS.md 工程约束未漂移。
  • src/callisto/、src/jupiter/storage/ 与 src/jupiter/migration/(含 migrations() 注册列表)已同步:TP-01/07/09/13/14/22。
  • 新引入的 docs/*.md 引用全部指向真实存在的文件(TP-21 核对)。
  • plan-long.md 日期计划索引或 PT/SB 状态已同步,或说明 N/A:本计划与 plan-long 无交集。

Review log

Result 只允许 PASS 或 FAIL。FAIL 必须列出 P0/P1 条目并在下一轮复审关闭。

Round Scope Result P0/P1 P2 处置 Evidence
R1 计划成稿自审(21 卡粒度审计、DAG、缺口径、ADR 映射、风险/里程碑) PASS(自审口径,待外部评审) 无 无 任务卡粒度审计表 + 实施顺序 DAG
R2 Codex 对计划修订 2 的评审(8 条 BLOCKING:TP-22 缺失、交付物 10 归属、迁移清单、TP-15/19 配置归属、端点映射、阶段 4 验收缺口、TP-16 缺项、粒度超限) FAIL→修复(修订历史 ②–⑮ + TP-22 + GAP-11..15) 全部关闭 无 本文件修订历史 + 各卡 AC
R3 Claude 对计划修订 2 的评审(5 条 BLOCKING:认证配置归属与 Phase 4 时序、authz 屏障缺卡、交付物 10 缺卡、迁移清单与 rollback 分类、存量端点映射缺卡;+ DAG/M1/TP-15 deps/轮次元数据/粒度计数 5 条 MINOR) FAIL→修复(与 R2 合并落实) 全部关闭 粒度计数机械重排 修订历史 ②–⑮ + GAP-11..15 + 粒度审计表
R4 Codex 终审(修订 2 后第 16–26 轮迭代) PASS 无 3 MINOR(粒度表 deps 省略、重复 deps、TP-20 配置归属) plan-codex-r26.txt
R5 Claude 终审(全量 walk:14 映射 + 完整性 + 18 锚点 + DAG 拓扑 + 迁移 + 里程碑) PASS 无 6 MINOR + 2 SUGGESTION(粒度审计表机械重排;实施顺序边补齐;DEFER-TP-01 入参预留需 TP-04 AC;GAP-07 编号;requester 措辞) plan-claude-final2.txt
R6 TP-07 实现双评审(Codex + Claude) PASS 无(FAIL 轮已关闭:UN-17、admin cache、add 入口预检、全量 revision CAS、ClaimLost 弃权、B4 跟随、intervening、parent 链、prepare_for_queue_writer、processor 停环、get_and_update_cl CAS) TP-06 存量端点映射不在本卡 本会话 Codex/Claude 终轮 VERDICT: PASS
R7 TP-22 实现双评审(Codex + Claude) PASS 无(FAIL 轮已关闭:屏障 timeout 包住重建 I/O、CAS-then-swap 本地单调、unversioned swap 与 dirty 刷新竞态、catch-up 先读水位再读根、水位已齐时 dirty 走 swap_if_watermark_eq) P2:删除路径 wiring 另有 delete_path_dirty_outbox_skips_published_version;outbox 逐行重建与缺 ACL 忙等不阻塞正确性 本会话 Codex R8 / Claude 终轮 VERDICT: PASS
R8 TP-09 实现双评审(Codex + Claude) PASS 无 P2:物化 mega_head_hash_with_txn 与 delete_tombstone 两提交(TP-10 合并);list_tombstones_under_prefix 尚无生产调用方(TP-14) 本会话 Codex / Claude 终轮 VERDICT: PASS
R9 TP-05 实现双评审(Codex + Claude) PASS 无(FAIL 轮已关闭:AppContext::new 周期 spawn、complete_conflict_requeue_in_txn 的 superseded_by IS NULL 幂等守卫、I3 计数覆盖全路径、attach-with-main@P 覆盖、push 缺行 non-ZERO warn) P2:reaper_i3_tombstone_repair 仅测试调用;心跳冻结与 non-ZERO warn 靠代码审查 本会话 Codex / Claude 终轮 VERDICT: PASS
R10 TP-06 实现双评审(Codex + Claude) PASS 无(FAIL 轮已关闭:attach/merge CAS-miss 计入 cas_assert_failures;merge_writer=queue 的 list/stats 仅 Merge kind) P2:in_queue 语义与 legacy 略有分歧;display_position 计入 Failed 行;failure_rate 不含 Cancelled 本会话 Codex / Claude 终轮 VERDICT: PASS
R11 TP-10 实现双评审(Codex + Claude) PASS 无 P2:advertise 上非 MaterializeAborted 的 MegaError 仍映射 400;get_all_refs_in_txn 无调用方;NOT EXISTS 命中仍可能留下孤儿 commit / 删墓碑 本会话 Codex / Claude 终轮 VERDICT: PASS
R12 TP-11 实现双评审(Codex + Claude) PASS 无(FAIL 轮已关闭:legacy 写者下无条件巡检 spawn;queue 入口 from_hash 抢先于树哈希断言;I3 日志泄漏 path) P2:reaper_i3_tombstone_repair 无生产调用且无 kind// 守卫;启动对账抢锁失败静默;trunk+legacy 交叉仍 spawn 巡检(TP-15) 本会话 Codex / Claude 终轮 VERDICT: PASS
R13 TP-12 实现双评审(Codex + Claude) PASS 无 P2:祖先 roll-up 中间行无直接断言;净零 tripwire 无 push 路径 bypass 注入;from_known_tip N=0 链会令 PushChain::validate 失败(TP-17 须条件化);squash message 占位(TP-16) 本会话 Codex / Claude 终轮 VERDICT: PASS
R14 TP-13 实现双评审(Codex + Claude) FAIL→修复 P1:AC5 多路径回归用了两个 blob id 而非同一 blob 两路径 已改 tp13_nested_watermark_and_multipath_delete 为同一 blob_id 出现在 /a/x.txt 与 /a/b/x.txt tp13-claude-r14.txt
R15 TP-13 实现双评审(Codex + Claude) PASS 无 P2:队列 reconciliation 无删除水位(ADR 已知限制);same_path_has_later_done 依赖已规范化 path;补偿间隔硬编码 60s(TP-15);latest_blob_display_path 无 ORDER BY 本会话 Codex / Claude 终轮 VERDICT: PASS
R16 TP-14 实现双评审(Codex + Claude) FAIL→修复 P1:legacy merge_cl_unchecked 的 apply_update_result 与 advance_descendant_refs 分两个提交窗口 已改为 merge_apply_and_advance_in_txn(apply + advance 同一 DatabaseTransaction;CL 状态仍在提交后) Codex R16 FAIL / Claude R16 PASS
R17 TP-14 实现双评审(Codex + Claude) PASS 无 P2:缺 mega_tree 行当删除;三层续接仅剪枝覆盖;e2e 走 merge 非协议 push;remove_none_cl_refs_in_txn LIKE 无 LikeExpr::escape 本会话 Codex R17 / Claude R17 VERDICT: PASS
R18 TP-15 实现双评审 FAIL→修复 P1:形态切换未与 B1 准入锁串行(count 与 last_policy 更新之间可插入非终态行) 已改为 switch_last_policy_if_queue_empty 持 queue_control FOR UPDATE Codex R18 FAIL
R19 TP-15 实现双评审 FAIL→修复 P1:${file:...} 在 [[git.push_tokens]] 数组表中不展开 traverse_config 递归 ValueKind::Array Claude R19 FAIL
R20 TP-15 实现双评审 FAIL→修复 P1:AppContext::new 未调用 Config::validate,①④⑤ 只在 CLI config validate 生效 AppContext::new 先 config.validate() Codex R20 FAIL
R21 TP-15 实现双评审(Codex + Claude) PASS 无 P2:reset_blob_path_index_watermarks 无调用方(切换内联 SQL);standalone SSH 不跑 ②③⑥;config secret set 尚未登记 token 字段(TP-19) 本会话 Codex R21 / Claude R21 VERDICT: PASS
R22 TP-16 实现双评审 FAIL→修复 P1:祖先 roll-up 缺 provenance 时回退 from_tree_id;后代 Mono-Ref-Path 误用被推路径 fail-closed;layer_message(&row.path)
R23 TP-16 实现双评审(Codex + Claude) PASS 无 P2:N>1 且 payload.commits 空时 Count 可能不一致(from_chain 不可达);N=1 客户端 gpgsig 会进入 roll-up 正文 本会话 Codex R2 / Claude R2 VERDICT: PASS
R24 TP-19 实现双评审(Codex + Claude) PASS 无 P2:.. 段不折叠(fail-closed);none 读路径仍可能走 UserStorage;同密不同名 token 按配置序取先 本会话 Codex R1 / Claude R1 VERDICT: PASS
R25 TP-20 实现双评审(Codex + Claude) PASS 无 P2:storage-only 仍装 LFS URI rewrite(含 /info/lfs/ 的路径 404 而非 git catch-all);app() 文档仍列 /auth/*;OpenAPI 测试重建 nest 而非派生自 app() 本会话 Codex R1 / Claude R1 VERDICT: PASS
R26 TP-17 实现双评审(Codex + Claude) PASS 无 P2:中间祖先 I2a 无直接断言;try_get requester 把反序列化失败也当 NULL;trunk validate_incoming_push 仍读 open CL;e2e 走 host git(compose host.docker.internal 被 INPUT DROP) 本会话 Codex R1 / Claude R1 VERDICT: PASS
R27 TP-18 实现双评审(Codex + Claude) PASS 无 P2:LFS capability URL 不直接走 enforce_lfs_access(trunk 下路由未挂载);/edit/diff-preview 一并关闭;OpenAPI 测试重建 nest 而非 live GET;cedar_guard 在 trunk 臂省略(TP-21 部署文案) 本会话 Codex R1 / Claude R1 VERDICT: PASS
R28 TP-21 文档双评审(Codex + Claude) PASS 无 P2:ssh_receive_pack=false 须显式写入(已补进 deploy-trunk.md §1/§4);docs/monorepo.md 仍有预存路径 bin/tests/integration_git_cli.rs 本会话 Codex / Claude VERDICT: PASS
R29 计划完成门 cargo test --all PASS 无 本机 compose git-cli 不可达,走 MEGA2_IT_ALLOW_HOST_GIT=1 + 钉扎 git-lfs 3.7.1 target/tmp/cargo-test-all.log EXIT:0

非目标与延后项

ID 延后内容 原因 重启条件 承接位置
DEFER-TP-01 Group commit(一次轮次批量摊薄树遍历) 无实测压力证据;阶段 1 轮次函数已以 Vec<QueueItem> 预留入参 吞吐压力实测显示 B 段成为瓶颈 trunk-push.md 阶段 6 第 1 项
DEFER-TP-02 LISTEN/NOTIFY 唤醒取代短轮询 轮询延迟可接受 等待者数量/延迟不满足 SLA trunk-push.md 阶段 6 第 2 项
DEFER-TP-03 实时排队进度(sideband channel 2 持续写) 协议层改造、非必需 排队延迟成为用户体验问题 trunk-push.md 阶段 6 第 3 项
DEFER-TP-04 物化 TTL + 墓碑回收 物化只增不减成本未成为现实压力;需最后访问时间记录点审计 已物化路径数驱动的 B3 成本实测超预算 trunk-push.md 阶段 6 第 4 项
DEFER-TP-05 阶段 5 的多 token 运维与强化(token 轮换/审计/限流等) trunk-push.md 阶段 5 收窄后未给出可执行规范;基础认证已随 4.2a 进阶段 4 trunk-push.md 补齐阶段 5 规范 trunk-push.md 阶段 5

完成判据

计划只有在以下条件全部满足后才能标记完成:

  • 所有任务卡满足粒度规则 G-*:无未登记的 L 例外、无 XL 卡、无碎片卡、无未登记的合并发布例外;「任务卡粒度审计表」已填齐且各卡 Granularity 行一致。
  • 所有非延后任务的 acceptance criteria 已满足,且 Lifecycle=done 且 Acceptance=complete(ER-04);D 组远端 workflow 为空 → N/A。
  • 所有任务的 Verification 命令已运行并记录结果。
  • 计划完成门:cargo +nightly fmt --all --check、cargo clippy --all-targets --all-features -- -D warnings、source .env.test && cargo test --all 全绿(2026-09-09 target/tmp/cargo-test-all.log EXIT:0),且 cargo build、cargo build --tests 均 0 错误 0 警告;不得新增 crate 级 #[allow(...)]。
  • 必要的 docs/配置/错误契约/测试矩阵更新已完成(TP-21 收口)。
  • 必要的 migration、rollback、failure-recovery 验证已完成;每张卡的 Rollback mode 已被实际验证或记录为不可验证的原因。
  • 代码 review 最终结论为 PASS,P0/P1 全部关闭;仅 P2 residual risk 允许保留且具名接受(R6–R29)。
  • 版本面已按各卡 Version increment bump 且自洽、构建、提交、推送证据完整(ER-08)。自 2026-09-09 起 crate 版本只 patch 递增(TP-18 的 0.9.0 已回写 0.8.1)。
  • 「修订历史」已记录成稿后的全部规范性变更(G-09)。
  • docs/refactoring/trunk-push.md 头部反向声明已标记「已同步」;docs/plan/README.md 已登记本计划。