路径说明(2026-09-20): 本文成稿时
docker-compose-storage-only.yml/docker-compose-storage-only.auth-none.yml/docker-compose.test.yml位于仓库根;2026-09-20 起三者迁入docker/目录(commit1854cae)。文中根目录原路径为历史记录,不再逐一回改;实际使用时请替换为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 形态的
UserStorageLFS 鉴权。 - 不实现 SSH
git-lfs-transfer;storage-only 下 SSH receive-pack 仍关闭;LFS 走 HTTP(含既有 hybridgit-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-only404。 - 部署文档删除「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 |
- 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。
- 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 上叠加边缘代理鉴权时。
- 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=trunkfixture,不得把 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-02LF-02 -> LF-03LF-02 -> LF-04LF-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。
目标: 确认 tip 仍关闭 LFS;push_auth API 可复用;无并行改动 lfs_router/http_server LFS 臂。
进入条件: DEP-LF-01 满足;工作区目标文件无未确认脏改动(ER-01)。
退出条件: 事实基线表行号已在开工日刷新;可进入 Phase 1。
目标: LF-01 + LF-02 使 trunk 上 LFS 可达且授权正确。
进入条件: Phase 0 退出。
退出条件: trunk+none / trunk+token / review 三臂单测绿;OpenAPI 含 LFS;手工或库测证明不再 404 LFS is review-only。
目标: 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 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 仍需有效UserStoragemono 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 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 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 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 核对)
| 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 --tests0 警告 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索引已同步