Skip to content

Latest commit

 

History

History
617 lines (420 loc) · 37.4 KB

plan-20260909.md

File metadata and controls

617 lines (420 loc) · 37.4 KB

Storage-only LFS(push_auth=none / token)计划(2026-09-09)

路径说明(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;依据 plan-template.md,核对日期 2026-09-09。

文档职责

本文解决「trunk / storage-only 形态下 Git LFS 不可用」的缺口:今天 LFS 批/锁只认 UserStorage mono access token,且 push_policy=trunk 硬关闭路由,导致无用户系统的 storage-only 部署无法完成含 LFS 指针的推送与拉取。目标是交付:LFS 写授权与 Git receive-pack 共用 git.push_auth(none 匿名可写、token 用 [[git.push_tokens]] + 组件边界 paths),review 形态保持现有 UserStorage 逻辑不变,并在 trunk HTTP 表面重新挂载 /info/lfs 与 /api/v1/lfs,附带进程级往返测试与部署文档反向声明。

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

适用范围

  • LFS HTTP 批/锁鉴权闸门(objects/batch、locks;不含改写 object 能力 URL 模型)。
  • Trunk / storage-only HTTP 路由挂载与 OpenAPI 表面(/info/lfs、/api/v1/lfs)。
  • 与 push_auth=none / push_auth=token 对齐的策略矩阵与单测。
  • storage-only 下 LFS push → fetch → git lfs pull 进程级集成测试。
  • 部署与产品文档:docs/deploy-trunk.md、docs/monorepo.md、docs/refactoring/protocol.md、docs/refactoring/trunk-push.md(LFS 不可用声明 supersede)、docs/refactoring/integration.md、本目录 README.md。

非目标

  • 不引入 Cedar / 用户系统 / OAuth 到 storage-only LFS。
  • 不改变 review 形态的 UserStorage LFS 鉴权。
  • 不实现 SSH git-lfs-transfer;storage-only 下 SSH receive-pack 仍关闭;LFS 走 HTTP(含既有 hybrid git-lfs-authenticate 若 SSH 仍监听 upload-pack——本计划不扩展 SSH 凭据体系)。
  • 不重开 DEFER-TP-05(多 token 运维强化:轮换、审计、限流)。
  • 不改 LFS 对象存储后端、内容定址校验、或 capability URL「batch 注册后 PUT/GET 不逐请求鉴权」模型。
  • 不把 plan-20260905 的 TP-18「关闭 LFS」历史验收改写为失败;本计划 supersede 该产品决策。

成功定义

  • push_policy=trunk + push_auth=none:匿名客户端可完成 LFS upload batch / lock 写与后续 pointer 推送所需的对象上传(与匿名 receive-pack 同一网络前提)。
  • push_policy=trunk + push_auth=token:出示有效 [[git.push_tokens]] 密文可写;无 token 或 paths 不覆盖 LfsRepoContext 路径则写失败(401/403);读仍可遵循 git.anonymous_access。
  • push_policy=review(省略 push_auth):LFS 行为与今日一致(写需 mono access token)。
  • Trunk HTTP 挂载 /info/lfs 与 /api/v1/lfs;OpenAPI 如实列出;不再返回 push_policy=trunk: LFS is review-only 404。
  • 部署文档删除「LFS 仅 review」;monorepo.md §8 表 trunk 列改为「可用(push_auth)」。
  • 全部非延后任务卡 Lifecycle=done 且 Acceptance=complete;计划级 Codex/Claude 双评审对本计划文档 PASS;实现阶段另走每卡 ER-05。

事实基线

所有行号和源码锚点必须在开工当天刷新(GC-01)。下列锚点核对日为 2026-09-09。

类别 当前事实 证据
工作树 VCS 本 checkout 使用 Libra(.libra);任务卡发布按 AGENTS.md / .cursor/rules/task-card-release.mdc 走 libra add / libra commit / libra push origin main(模板 GC-12/ER-07 的 git * 文案对本 checkout 不适用,以 AGENTS 为准) test -d .libra;libra status --short --branch
mega2 tip 51d750dcbc6a2198e38d326ce008ed13ad0cf95f libra log -1
包版本 0.8.2 Cargo.toml:3
LFS 闸门 enforce_lfs_access 在 PushPolicy::Trunk 直接 404;写路径只经 lfs_authenticated_user → UserStorage src/api/router/lfs_router.rs:206-258
LFS 策略纯函数 lfs_access_allowed(Read/Write, anonymous_access, authenticated);Write 恒需 authenticated lfs_router.rs:169-182 与单测 :598-607
Trunk HTTP 表面 protocol_surface 臂不 merge LFS、不 nest /info/lfs;review 臂才挂载 src/server/http_server.rs:658-780
OpenAPI trunk_openapi_doc / storage_only_openapi_doc 无 LFS merge;装配测试断言 trunk 不得注册 /lfs http_server.rs:785-798;src/api/router/mod.rs:85-105
URI rewrite rewrite_lfs_request_uri 仍装在 HTTP middleware;捕获 LfsRepoContext http_server.rs:802-835
Push 认证 lookup_push_token + token_covers_repo / token_path_authorizes;push_auth=none 旁路 src/contract/git_protocol/mod.rs:79-156;src/config/model.rs:1072-1143
配置样例 push_auth / [[git.push_tokens]] 注释 config/config.toml:360-371;docs/deploy-trunk.md:9-76
产品声明 trunk LFS 不可用;GAP-13 / TP-18 关闭 docs/deploy-trunk.md:74-76;docs/monorepo.md:237-240;docs/plan/plan-20260905.md GAP-13 / TP-18
协议事实源 LFS 认证段落仍只描述 UserStorage 写闸门 docs/refactoring/protocol.md:807
既有 IT integration_git_lfs = review + mono access token + CL ref(GM-05) tests/integration_git_lfs.rs;docs/refactoring/integration.md:46
工作区前置 .env.test 存在;测试栈约定 Postgres 15432 / Redis 16379 .env.test / docker-compose.test.yml
外部参照 N/A(不依赖 Mega pin;Git LFS 协议以 git-lfs 上游文档为线索) N/A

当前缺口

ID 缺口 影响 证据 计划动作
GAP-LF-01 Trunk 硬关闭 LFS(404 + 不挂载) storage-only 无法传大文件指针 lfs_router.rs:241-245;http_server.rs:773-779 LF-01、LF-02
GAP-LF-02 LFS 写只认 UserStorage,不认 push_tokens / none 与 receive-pack 认证模型分叉;无用户系统时 LFS 写无授权路径 lfs_router.rs:206-214 LF-01
GAP-LF-03 无 trunk/push_auth 下的 LFS 进程级往返 回归只能靠 review IT,漏掉 storage-only tests/integration_git_lfs.rs 仅 CL/token LF-03
GAP-LF-04 部署/产品文档声明 LFS review-only 运维与实现目标矛盾;本计划交付前须 supersede deploy-trunk.md:74-76;monorepo.md:240 LF-04

与其它计划的关系

计划/文档 关系 本计划处理
plan-20260905.md(TP-18 / GAP-13) 前置:trunk 形态与 push_auth 已交付;当时关闭 LFS 不重做 TP-18;本计划 supersede「LFS 不可用」产品决策
docs/refactoring/trunk-push.md 设计事实源曾写「LFS 写路由关闭;token-aware LFS 另立议题」 LF-04 将 LFS 段改为「已由 plan-20260909 交付」
docs/deploy-trunk.md / docs/monorepo.md 运维/产品反向声明 LF-04 同步
docs/refactoring/protocol.md LFS HTTP 认证契约 LF-01 同步 trunk 臂
plan-long.md 无直接 PT 编号强制关联 索引登记本计划;不改 PT 状态除非索引要求
AGENTS.md / 任务卡发布规则 Libra 发布工作流 遵守;本计划文档卡 Version increment=N/A

评审结论与修订记录

计划成稿前自审:

维度 结论 修订动作
合理性 storage-only 无 LFS 则大文件工作流不可用;与 push_auth 对齐是明确独立议题 本计划承接
可行性 闸门/挂载/IT/文档可拆为 4 张 S–M 卡;无 schema 见实施顺序
任务卡粒度 鉴权轴 / 挂载轴 / IT 轴 / 文档收口轴分离;无 L/XL 见粒度审计表
依赖与顺序 LF-01→LF-02→LF-03;LF-04 依赖 LF-02(行为面已定)并可与 LF-03 串行于其后 DAG 无环
完整性 测/文档/回滚/安全边界齐全 见各卡
安全性 none 匿名 LFS 写 = 匿名 receive-pack 同级;token paths 必须用 LfsRepoContext ADR-LF-01/02;部署警告保留
功能正确性 review 回归;capability URL 模型不变 ADR-LF-03
接口兼容 无新配置键;仅行为扩展 trunk 兼容
数据流 无新 DB schema N/A
性能 闸门多一次常量时间 token 扫描(与 receive-pack 同阶) 继承 GC-10
可靠性 无新分布式状态 N/A
可维护性 复用 lookup_push_token / token_path_authorizes,禁止复制前缀规则 ADR-LF-01

修订历史

日期 触发 变更内容 原卡 → 新卡 受影响的引用
2026-09-09 成稿 首版:LF-01..LF-04;ADR-LF-01..03;GAP-LF-01..04;supersede plan-20260905 LFS 关闭决策 N/A 全文
2026-09-09 Claude R1 FAIL ①LF-01 AC 按 G-03 拆分;②Verification 改为 trunk 臂不触 UserStorage 的正向单测;③四卡登记 D 组 N/A;④LF-02 装配测试改名;⑤测试矩阵去掉不存在的 workflow LF-01..LF-04 字段修订 粒度审计表、测试矩阵、Review log
2026-09-09 Claude+Codex R2 FAIL LF-01 AC 诚实计数仍为 10(401∧WWW-Authenticate;helper 可见性∧禁止复制)。改为恰好 8 条独立谓词:去掉 header/复制算法出 AC(改由既有 challenge 单测 + GC-LF-02 / 写集约束);helper 导出写入 Description/写集 LF-01 粒度审计表、Review log

已决议设计决策

ADR-LF-01: LFS 写授权对齐 git.push_auth

  • Status: Accepted
  • Context: Trunk 无 UserStorage;receive-pack 已有 token/none;LFS 写仍走用户 token 导致 GAP-LF-02。
  • Decision: 当 push_policy=trunk(storage-only 启动强制显式 push_auth)时:push_auth=none → Read/Write 均放行;push_auth=token → 用与 Git HTTP 相同的 Bearer/Basic 密文解析,经 lookup_push_token 认证;Write 另要求 token_covers_repo(或等价公开 helper)覆盖 LfsRepoContext 路径(空前缀视为 /,仅全库 token)。Read 在 token 形态下仍允许 anonymous_access || authenticated。省略 push_auth 的 review 形态保持 UserStorage 现状。
  • Alternatives considered: (1) 仅 none 开 LFS——拒绝,因生产 storage-only 常用 token;(2) 为 LFS 另造配置键——拒绝,违反 GC-02 / 与 push 分叉。
  • Consequences: 必须把 token_covers_repo 提成 pub(crate)(或迁到 config 旁单一事实源)供 lfs_router 使用,禁止复制组件边界算法。
  • Revisit when: DEFER-TP-05 多 token 运维规范落地,或需 per-OID ACL。

ADR-LF-02: push_auth=none 下匿名 LFS 写合法

  • Status: Accepted
  • Context: 用户目标含「不使用任何权限即可 LFS 提交」;与 push_auth=none 匿名 receive-pack 一致。
  • Decision: trunk + none 时 LFS Write 不要求凭据;安全边界完全依赖部署网络(受控内网/回环/Unix socket),部署文档必须保留与 receive-pack 同级警告。
  • Alternatives considered: none 下仍强制 token——拒绝,违背 storage-only 匿名形态。
  • Consequences: 公网暴露 none = 匿名 LFS 上传 + 匿名 push;启动既有警告覆盖。
  • Revisit when: 需要在 none 上叠加边缘代理鉴权时。

ADR-LF-03: Object 能力 URL 与 review 回归不变

  • Status: Accepted
  • Context: PUT/GET /objects/{oid} 故意不逐请求鉴权;改之会弄断 git-lfs 客户端。
  • Decision: 本计划不改 handler 层内容定址 / batch 元数据前置;闸门仍在 batch 与 locks。review 形态单测与 integration_git_lfs(CL)不得被本计划破坏。
  • Alternatives considered: 给 PUT 加 token——拒绝(已知 broken pipe 风险,见 protocol.md)。
  • Consequences: 匿名直连 PUT 仍只能写入已 batch 注册且哈希匹配的字节。
  • Revisit when: git-lfs 客户端稳定附带 transfer 凭据。

全局工程约束

以下约束对本文所有任务生效(并遵守模板 GC-01..GC-12;本 checkout 发布命令以 AGENTS.md 的 Libra 为准):

  • GC-LF-01: Trunk LFS 鉴权不得查询 UserStorage;不得引入 Cedar。
  • GC-LF-02: 路径前缀授权必须复用 token_path_authorizes / token_covers_repo,禁止第二套算法。
  • GC-LF-03: Review 形态(省略 push_auth)行为比特级兼容今日(写需 mono access token;读跟 anonymous_access)。
  • GC-LF-04: 不新增配置键;不新增 crate 级 #[allow(...)];生产路径不新增裸 unwrap/expect。
  • GC-LF-05: 文档 supersede 必须显式指向本计划 ID,避免与 plan-20260905 历史验收叙述冲突时被读成回归。

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

全文遵守 plan-template.md 的 ER-01..ER-12。对本计划的特化:

  • VCS: 本 checkout 用 libra status / libra add <paths> / libra commit -m / libra push origin main;提交后以 Libra 等价方式确认 tip 前进;禁止 --force。模板正文中的 git * 在本仓执行时替换为上述 Libra 命令。
  • ER-04 A 组(LFS/Git 协议表面): 命中 lfs_router / http_server / ceres/lfs 的卡必须跑模板「Git 协议 / LFS」行的 focused 门骨架,本地等价以 scripts/git_protocol_smoke.sh + 模板骨架为准;storage-only IT 卡须在 Verification 写清 push_policy=trunk fixture,不得把 review 的 integration_git_lfs 绿当成 trunk 证据。
  • ER-04 D 组(本 checkout): .github/workflows/ 与 .github/workflow/ 均无 workflow 文件(2026-09-09 核对)。所有卡的 D 组一律写 N/A(本 checkout 无 CI workflow 文件,无 paths 过滤器可命中);Acceptance 在取得 C 覆盖后可直接到 complete,不经 remote-pending。
  • ER-08: 实现卡默认 Version increment=patch;本计划文档成稿提交(非任务卡实现)不 bump。

实施顺序

  • LF-01 -> LF-02
  • LF-02 -> LF-03
  • LF-02 -> LF-04
  • LF-03 -> LF-04(文档收口在 IT 着陆后,避免文档宣称未测行为;LF-04 写集与 LF-03 文档文件若相交则串行)

依赖登记表

ID direction 类型 对象 Owner 产物与可用性判据 证据 超时与失败策略
DEP-LF-01 incoming 跨计划 plan-20260905 TP-15/18/19/20(trunk + push_auth 已交付) 本计划 判据 = tip 含 push_auth 校验与 storage-only HTTP plan-20260905.md Review log R21/R24/R25/R27 PASS 缺失则本计划不得开工
DEP-LF-02 outgoing 跨计划文档 plan-20260905 GAP-13 / TP-18「LFS 不可用」叙述 plan-20260905 维护者(只读历史) 本计划 LF-04 在 trunk-push / deploy 文中写 supersede;不回改 TP-18 AC 勾选历史 本计划 ADR-LF-01;LF-04 AC 接收方无需动作;冲突时以本计划 + 部署文档为准

发布分组与并发窗口

ID 成员 唯一发布点 窗口规则 失败回滚顺序 理由
N/A — — 默认每卡独立发布(G-07) — 四卡写集可顺序独立切片

并发声明: 实现阶段全串行(LF-01→LF-02→LF-03→LF-04);写集本可 LF-01∥审计,但挂载前必须先有闸门,故不并发。

发布者: 执行本计划的单一 Agent(ER-12)。

发布窗口顺序: LF-01 → LF-02 → LF-03 → LF-04。

Phase 0: 基线冻结

目标: 确认 tip 仍关闭 LFS;push_auth API 可复用;无并行改动 lfs_router/http_server LFS 臂。

进入条件: DEP-LF-01 满足;工作区目标文件无未确认脏改动(ER-01)。

退出条件: 事实基线表行号已在开工日刷新;可进入 Phase 1。

Phase 1: 鉴权与挂载

目标: LF-01 + LF-02 使 trunk 上 LFS 可达且授权正确。

进入条件: Phase 0 退出。

退出条件: trunk+none / trunk+token / review 三臂单测绿;OpenAPI 含 LFS;手工或库测证明不再 404 LFS is review-only。

Phase 2: IT 与文档收口

目标: LF-03 进程往返 + LF-04 文档 supersede。

进入条件: Phase 1 两卡均 Acceptance=complete(或至少 locally-accepted 且 ER-05 PASS 后进入发布)。

退出条件: storage-only LFS IT 绿;deploy/monorepo/protocol/trunk-push/integration/plan README 一致;计划完成门可走。

任务卡

字段全局默认与例外

  • Release boundary 默认: independent
  • Task type 默认: implementation
  • Rollback mode 默认: revert
  • Migration and rollback 默认: N/A(无 schema)
  • Security and privacy 默认: 继承 GC-07、GC-LF-01..02;none 警告见 ADR-LF-02
  • Performance budget 默认: 继承 GC-10(token 扫描与 receive-pack 同阶)
  • Docs and compatibility impact 默认: 按 GC-05 同步相关 docs 与 config/config.toml 注释(若触及)

默认覆盖:

任务 偏离的字段 取值与理由
LF-04 Task type / Release boundary / Version increment / C/D coverage from docs / no-release / N/A / 继承 LF-03:纯文档收口

规则 waiver: 无(无 EX-*)。

任务卡粒度审计表

任务 type axis recovery complete self-contained AC VER landing / prod-files scope deps writeset release split-from exception
LF-01 implementation trunk LFS 鉴权对齐 push_auth revert 后回 UserStorage-only+trunk404 yes yes 8/8 4/8 2/2 M DEP-LF-01 no-overlap independent N/A N/A
LF-02 implementation trunk HTTP 挂载 LFS 路由+OpenAPI revert 卸载路由 yes yes 7/8 3/8 2/2 M LF-01 no-overlap independent N/A N/A
LF-03 implementation storage-only LFS 进程往返 IT revert 删/改测试 yes yes 4/8 3/8 1/1 M LF-02 no-overlap independent N/A N/A
LF-04 docs 部署/产品文档 supersede LFS 可用 revert 文档 yes yes 6/20 3/20 0/0(docs) M LF-02,LF-03 no-overlap no-release N/A N/A

Task LF-01: Trunk LFS 鉴权对齐 push_auth

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 重写 enforce_lfs_access:去掉 trunk 硬 404;按 ADR-LF-01/02 分流 none/token/review;将 token_covers_repo 提为 pub(crate)(或迁入 config)供本卡复用(GC-LF-02,禁止在 lfs_router 复制算法);扩展策略单测。

Out of scope:

  • 路由挂载与 OpenAPI(由 LF-02 承接)
  • 进程级 IT(由 LF-03 承接)
  • 部署文档 supersede(由 LF-04 承接)
  • Object PUT/GET 鉴权模型变更(永久非目标,ADR-LF-03)
  • WWW-Authenticate 头格式变更(沿用既有 lfs_auth_challenge;由既有/扩展单测覆盖,不单列 AC)

Current evidence:

事实 证据
Trunk 404 lfs_router.rs:241-245
UserStorage 认证 lfs_router.rs:206-214
Push token 查找 git_protocol/mod.rs:143-156
路径前缀 config/model.rs:1143;token_covers_repo 现为私有 mod.rs:130

Acceptance criteria:

  • PushPolicy::Trunk + push_auth=none:无凭证 Write 允许
  • PushPolicy::Trunk + push_auth=none:无凭证 Read 允许
  • PushPolicy::Trunk + push_auth=token:无凭证 Write 返回 401
  • PushPolicy::Trunk + push_auth=token:有效 token 且 paths 覆盖 LfsRepoContext 时 Write 允许
  • PushPolicy::Trunk + push_auth=token:有效 token 但 paths 不覆盖时 Write 返回 403
  • PushPolicy::Trunk + push_auth=token 且 anonymous_access=true:无凭证 Read 允许
  • PushPolicy::Review(省略 push_auth):Write 仍需有效 UserStorage mono access token
  • src/ 内不再存在 LFS is review-only 拒绝路径(trunk 硬 404 已移除)

Verification:

  • source .env.test && cargo test -p mega2 --lib 'api::router::lfs_router::tests' -- --nocapture
  • source .env.test && cargo test -p mega2 --lib 'contract::git_protocol::tests' -- --nocapture(若导出 helper 触及)
  • (new) 单测:trunk + push_auth=token 的 Write 成功与失败路径均不调用 user_storage() / login_user_from_mono_access_token;无凭证 Write 仍走既有 lfs_auth_challenge(含 WWW-Authenticate)
  • 零命中守卫(模板退出码模板):rg -n 'LFS is review-only' src/ → 退出码 1

Dependencies: DEP-LF-01

Deliverables: N/A

Implementation write set: src/api/router/lfs_router.rs;src/contract/git_protocol/mod.rs(pub(crate) token_covers_repo 或迁至 src/config/model.rs);docs/refactoring/protocol.md(随附:增补 trunk/push_auth 臂)

Release write set: Inherited

Files likely touched: 同上

Docs and compatibility impact: docs/refactoring/protocol.md(随附同步集)

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: ADR-LF-01/02;GC-LF-02;fail-closed 当 trunk 却缺 push_auth

Performance budget: Inherited

Estimated scope: M(landing=2;prod-files=2)

Version increment: patch

Release boundary: independent

C/D coverage from: self

D-group (ER-04): N/A(本 checkout 无 CI workflow 文件,无 paths 过滤器可命中)

Granularity: type=implementation; axis=trunk LFS 鉴权对齐 push_auth; recovery=revert 恢复 UserStorage+trunk404; complete=yes; self-contained=yes; AC=8/8; VER=4/8; landing=2; prod-files=2; scope=M; deps=DEP-LF-01; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task LF-02: Trunk / storage-only 挂载 LFS 路由与 OpenAPI

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 在 protocol_surface 臂 merge lfs_router::routers() 并 nest /info/lfs;更新 trunk_openapi_doc / storage_only_openapi_doc 与装配测试,使 OpenAPI 反映 LFS 可用。

Out of scope:

  • 鉴权策略(LF-01)
  • 进程 IT(LF-03)
  • deploy/monorepo 长文 supersede(LF-04;本卡仅保证机器表面正确)

Current evidence:

事实 证据
protocol_surface 不挂 LFS http_server.rs:735-780
测试禁止 trunk LFS api/router/mod.rs:85-105

Acceptance criteria:

  • push_policy=trunk(及 storage-only)下 /info/lfs 由 LFS router 处理(不再落入 git smart-protocol catch-all)
  • 同上形态下 /api/v1/lfs 由 LFS router 处理
  • trunk_openapi_doc() / 等价装配 paths 含 lfs
  • 装配测试重命名为 trunk_http_assembly_merges_lfs_as_does_review(或等价名)
  • 该装配测试断言 trunk 注册 LFS
  • review 臂挂载与 cedar_guard 行为不变
  • rewrite_lfs_request_uri 继续向 handler 注入 LfsRepoContext

Verification:

  • source .env.test && cargo test -p mega2 --lib 'api::router::' -- --nocapture
  • source .env.test && cargo test -p mega2 --lib 'server::http_server::' -- --nocapture
  • OpenAPI 单测或装配断言:trunk 文档 paths 含 lfs(sanitized)

Dependencies: LF-01

Deliverables: N/A

Implementation write set: src/server/http_server.rs;src/api/router/mod.rs(测试);必要时 src/api/api_router.rs 注释

Release write set: Inherited

Files likely touched: 同上

Docs and compatibility impact: 运行时 OpenAPI;详细运维文案交 LF-04

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 依赖 LF-01 闸门;禁止在无 LF-01 时单独发布本卡

Performance budget: Inherited

Estimated scope: M(landing=2;prod-files=2)

Version increment: patch

Release boundary: independent

C/D coverage from: self

D-group (ER-04): N/A(本 checkout 无 CI workflow 文件,无 paths 过滤器可命中)

Granularity: type=implementation; axis=trunk HTTP 挂载 LFS+OpenAPI; recovery=revert 卸载; complete=yes; self-contained=yes; AC=7/8; VER=3/8; landing=2; prod-files=2; scope=M; deps=LF-01; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task LF-03: storage-only LFS 进程级往返

Task type: implementation

Lifecycle / Acceptance: done / complete

Description: 扩展或新增集成测试:在 push_policy=trunk 下分别覆盖 push_auth=none 与 push_auth=token 的 LFS push → fetch → git lfs pull(子路径 monorepo,对齐 trunk 直推 main,非 CL ref)。

Out of scope:

  • SSH LFS(永久非目标于本计划)
  • 多 token 轮换运维(DEFER-TP-05)
  • 部署长文(LF-04)

Current evidence:

事实 证据
仅 review/CL LFS IT tests/integration_git_lfs.rs
Trunk git CLI IT 模式 tests/integration_git_cli.rs trunk 用例(锚点开工刷新)

Acceptance criteria:

  • push_auth=none + trunk:匿名(或无 UserStorage)完成 LFS 对象上传并 push 含 pointer 的提交到可拉取的 main(或子路径约定)
  • push_auth=token + trunk:带静态 token 往返成功;缺 token 的 LFS 写或 push 失败可观测
  • 既有 integration_git_lfs_http_round_trip(review/CL)仍通过
  • docs/refactoring/integration.md 登记新 target/用例名

Verification:

  • source .env.test && cargo test -p mega2 --test integration_git_lfs -- --test-threads=1(含新用例;需 git-lfs;按 AGENTS/IT 前置)
  • 若拆新 target:cargo test -p mega2 --test <new> -- --test-threads=1
  • 同步检查 docs/refactoring/integration.md 表格行存在

Dependencies: LF-02

Deliverables: N/A

Implementation write set: tests/integration_git_lfs.rs(或 tests/integration_git_lfs_trunk.rs);docs/refactoring/integration.md;必要时测试 helper

Release write set: Inherited

Files likely touched: 同上

Docs and compatibility impact: docs/refactoring/integration.md

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 测试 token 按 ER-11 脱敏,不得进验收证据明文

Performance budget: N/A(IT 墙钟不设预算)

Estimated scope: M

Version increment: patch

Release boundary: independent

C/D coverage from: self

D-group (ER-04): N/A(本 checkout 无 CI workflow 文件,无 paths 过滤器可命中)

Granularity: type=implementation; axis=storage-only LFS 进程往返 IT; recovery=revert 测试; complete=yes; self-contained=yes; AC=4/8; VER=3/8; landing=1; prod-files=1; scope=M; deps=LF-02; writeset=no-overlap; release=independent; split-from=N/A; exception=N/A

Task LF-04: 部署与产品文档 supersede

Task type: docs

Lifecycle / Acceptance: done / complete

Description: 删除「trunk LFS 不可用 / 仅 review」运维与产品声明,改为与 push_auth 对齐的 LFS 边界;在 trunk-push.md 与 plan-20260905 交叉处写明由本计划 supersede;更新 docs/plan/README.md 索引。

Out of scope:

  • 任何 src/ / Cargo.toml 改动(发现需要则 ER-03 重分类)
  • 实现行为变更(由 LF-01..03 承接)

Current evidence:

事实 证据
deploy LFS §6 review-only docs/deploy-trunk.md:74-76
monorepo §8 表 docs/monorepo.md:237-240
trunk-push 关闭清单 docs/refactoring/trunk-push.md 阶段 4.3 关闭表

Acceptance criteria:

  • docs/deploy-trunk.md:§2/§6 改为 LFS 随 push_auth;none 匿名 LFS 写警告与 receive-pack 同级;删除「另立 token-aware 议题」作为未决项的表述
  • docs/monorepo.md §8:trunk LFS 列为「可用(push_auth)」
  • docs/refactoring/trunk-push.md:LFS 关闭决策改为「已由 plan-20260909 开启」并指向 ADR-LF-01
  • docs/plan/README.md 登记本计划
  • 本卡文件内新增 docs/*.md 链接全部存在
  • docs/errors.md:N/A 说明(无新 MegaError 变体)或短节登记

Verification:

  • 结构与链接门:上述文件存在且章节完整
  • libra status --short --branch 无 src/ / Cargo.toml 越界(本卡提交)
  • 零悬空:对本卡新增链接跑存在性检查

Dependencies: LF-02,LF-03

Deliverables: docs/deploy-trunk.md;docs/monorepo.md;docs/refactoring/trunk-push.md(相关段);docs/plan/README.md;docs/errors.md(短节或 N/A);本文件 Review log 更新(若收口)

Implementation write set: 上列 docs 路径

Release write set: N/A

Files likely touched: 同上

Docs and compatibility impact: 本卡即文档

Rollback mode: revert

Migration and rollback: N/A

Security and privacy: 必须保留 push_auth=none 网络边界警告(ADR-LF-02)

Performance budget: N/A

Estimated scope: M(产物文件 ≤15)

Version increment: N/A(随 LF-03 或独立 docs 提交进入仓库;不 bump crate)

Release boundary: no-release

C/D coverage from: LF-03

D-group (ER-04): N/A(本 checkout 无 CI workflow 文件;继承 LF-03 同为 N/A)

Granularity: type=docs; axis=文档 supersede LFS 可用; recovery=revert 文档; complete=yes; self-contained=yes; AC=6/20; VER=3/20; landing=0; prod-files=0; scope=M; deps=LF-02,LF-03; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A

测试矩阵

类别 必须覆盖 Target / command
单元 push_auth×LfsAccess 矩阵;review 回归;paths 拒绝 cargo test -p mega2 --lib 'api::router::lfs_router::tests'
HTTP / OpenAPI trunk 装配含 LFS cargo test -p mega2 --lib 'api::router::' / server::http_server::
集成(进程) trunk none/token LFS 往返;review CL LFS 回归 cargo test -p mega2 --test integration_git_lfs -- --test-threads=1
Git 协议 / smoke 本地等价 scripts/git_protocol_smoke.sh(模板 LFS 骨架);D 组 N/A——本 checkout 无 .github/workflows/*.yml 脚本 + IT;勿引用不存在的 workflow 文件
安全 none 匿名写;token 路径边界;trunk 臂无 UserStorage 单测 + IT
配置 无新键;既有 validate 仍绿 cargo run -p mega2 -- --config config/config.toml config validate(按改动)
性能 N/A N/A
live/gated git-lfs 二进制 IT 前置

追溯表

任务 来源/证据 mega2 落点 文档/兼容动作 指定测试
LF-01 GAP-LF-01/02;ADR-LF-01/02 lfs_router.rs;git_protocol/mod.rs protocol.md --lib 'api::router::lfs_router::tests'
LF-02 GAP-LF-01 http_server.rs;api/router/mod.rs 运行时 OpenAPI --lib 'server::http_server::' / api::router::
LF-03 GAP-LF-03 tests/integration_git_lfs*.rs integration.md --test integration_git_lfs
LF-04 GAP-LF-04;DEP-LF-02 docs only deploy/monorepo/trunk-push/plan README/errors 链接门

里程碑验收与回滚

里程碑 完成条件 发布/证据 回滚或前滚
M0 计划双评审 PASS;Phase 0 基线冻结 本文件 Review log;libra tip 含本计划 revert 计划文档提交
M1 LF-01+LF-02 发布 两枚 patch 版本;单测/OpenAPI revert 各卡提交
M2 LF-03+LF-04 发布/收口 IT 绿;文档 supersede revert;docs 随 LF-03 tip

故障恢复矩阵

故障点 可接受残留 恢复动作 禁止结果
LF-02 已推但 LF-01 回滚 路由开着但鉴权错误 禁止此序;发布顺序强制 LF-01→LF-02;若发生则前滚恢复闸门 匿名或 UserStorage 误用导致越权写
IT 环境缺 git-lfs 无 安装钉扎版本或按 IT 文档失败,不标完成 把 SKIP 当 PASS
push_auth=none 误暴露公网 运行中服务 运维关端口/改 token;文档警告 静默当作安全默认

风险登记

风险 影响 缓解 任务
挂载早于鉴权发布 高:错误授权模型曝光 依赖边 LF-01→LF-02;发布者串行 LF-01/02
LfsRepoContext 空前缀误授权 中:全库写入 空前缀当 /;全库-only;单测 LF-01
review IT 被 trunk fixture 污染 中 隔离配置;回归跑旧用例 LF-03
文档与 plan-20260905 历史冲突 低 GC-LF-05 supersede 措辞 LF-04

性能与容量摘要

操作 单次成本 累积成本 预算/上限 验证
LFS batch 鉴权 token 扫描 O(n tokens) 常量时间摘要比较 每请求一次 与 receive-pack 同阶;n 保持运维小集 无新 bench;代码审查
LFS 对象 PUT 既有 sha256 流式校验 按对象大小 不本计划扩张 既有 handler

兼容与文档收口

  • docs/errors.md 已同步或 N/A(LF-04)
  • docs/refactoring/protocol.md / trunk-push.md / integration.md 已同步(LF-01/03/04)
  • config/config.toml 注释若需提及 LFS+push_auth 则同步,否则 N/A
  • 运行时 OpenAPI 证据(LF-02)
  • README.md / AGENTS.md:若根 README 提及 LFS review-only 则同步,否则 N/A
  • callisto/storage/migration:N/A
  • 新 docs/*.md 引用真实存在(LF-04)
  • docs/plan/README.md + plan-long.md 索引:成稿已登记(R3 核对)

Review log

Round Scope Result P0/P1 P2 处置 Evidence
R1 本计划成稿(Claude) FAIL P1:LF-01 AC 计数超限;VER 零命中不可满足;缺 D 组登记 + 矩阵指向不存在 workflow 已于同日修订关闭 target/tmp/plan-20260909-claude-r1.txt
R1 本计划成稿(Codex) 未跑通(Not inside a trusted directory) — R2 以 --skip-git-repo-check 重跑 target/tmp/plan-20260909-codex-r1.txt
R2 修订后双评(Claude + Codex) FAIL P1:LF-01 AC 诚实计数仍 10 已于 R3 前改为 8 条独立谓词 target/tmp/plan-20260909-claude-r2.txt;target/tmp/plan-20260909-codex-r2.txt
R3 AC 计数收口后双评(Claude + Codex) PASS 无 P2:LF-01 VER 严格计数可能 5;LF-02 AC#6「与」严格可读作 8/8;LF-03 AC 拆分后约 6/8——不阻塞 target/tmp/plan-20260909-claude-r3.txt;target/tmp/plan-20260909-codex-r3.txt
R4 LF-01 实现(Claude) FAIL P1:新测例 field_reassign_with_default 破 clippy 门 改为 struct literal + ..Default target/tmp/lf01-claude-r1.txt
R4 LF-01 实现(Codex) PASS 无 沙箱未跑 cargo target/tmp/lf01-codex-r1.txt
R5 LF-01 clippy 修复后(Claude + Codex) PASS 无 计划卡勾选为本发布收口 target/tmp/lf01-claude-r2.txt;target/tmp/lf01-codex-r2.txt
R6 LF-02 实现(Claude + Codex) PASS 无 P2:装配测手拼 vs trunk_openapi_doc 漂移风险;/info/lfs 在 layer 栈外(与 review 对称) target/tmp/lf02-claude-r1.txt;target/tmp/lf02-codex-r1.txt
R7 LF-03 实现(Claude) FAIL P1:trunk 用例强制 host git 但未钉扎 PUBLIC_BASE_URL,compose runner 下 LFS href 指向 host.docker.internal 改为 boot_service_http_trunk 强制 127.0.0.1 target/tmp/lf03-claude-r1.txt
R7 LF-03 实现(Codex) PASS 无 — target/tmp/lf03-codex-r1.txt
R8 LF-03 修复后(Claude + Codex) PASS 无 计划卡勾选为本发布收口 target/tmp/lf03-claude-r2.txt;target/tmp/lf03-codex-r2.txt
R9 LF-04 文档(Claude) PASS 无 P2:收口勾选随本发布 target/tmp/lf04-claude-r1.txt
R9 LF-04 文档(Codex) FAIL P1:卡仍 pending 而索引已写完成 勾选 LF-04 + 完成判据后重评 target/tmp/lf04-codex-r1.txt
R10 LF-04 收口后(Claude + Codex) PASS 无 计划卡勾选为本发布收口 target/tmp/lf04-claude-r2.txt;target/tmp/lf04-codex-r2.txt

非目标与延后项

ID 延后内容 原因 重启条件 承接位置
DEFER-LF-01 SSH pure git-lfs-transfer / storage-only SSH 推送凭据 storage-only 关闭 SSH receive-pack;HTTP hybrid 足够 产品要求 SSH LFS 推送 未来日期计划
DEFER-LF-02 LFS 对象 PUT 逐请求鉴权 客户端不稳附凭据(ADR-LF-03) git-lfs 行为变更 ADR-LF-03 revisit
DEFER-LF-03 多 token 轮换/审计/限流 与 DEFER-TP-05 同范围 trunk-push 阶段 5 规范 plan-20260905 DEFER-TP-05

完成判据

  • 全部任务满足 G-*;粒度审计表已填
  • LF-01..LF-04 均 Lifecycle=done 且 Acceptance=complete(LF-04 继承 LF-03 的 C/D)
  • 各卡 Verification 已记录
  • 计划完成门:cargo +nightly fmt --all --check、cargo clippy --all-targets --all-features -- -D warnings、source .env.test && cargo test --all 全绿;cargo build / cargo build --tests 0 警告 0 错误
  • 文档/OpenAPI/测试矩阵已收口
  • 无迁移;各卡 Rollback mode 已验证(revert)
  • 本计划文档双评审最终 PASS(R3 Claude + Codex);实现卡各自 ER-05 已执行(LF-01 R5、LF-02 R6、LF-03 R8、LF-04 R10)
  • 实现卡版本 bump + libra push 证据齐全;LF-04 N/A bump
  • 修订历史完整(含 R1/R2 FAIL 与 R3 收口)
  • docs/plan/README.md / plan-long.md 索引已同步