fix(backend): create_commit 直接引用经典空树 SHA(W1-C2 #165,ADR-0054) - #2
Conversation
…b 一律 422(e2e .github#206 实测,conductor run 32493680834)(1/2)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughChangesGitHub 空提交创建
Suggested labels: Merge Risk: ⚪ Minimal · up to This change uses the GitHub-compatible classic empty-tree SHA when creating commits and adds regression coverage for the request shape; no actionable merge-blocking risk remains beyond normal checks and review. 🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (1 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
PR Summary by QodoFix GitHubRefBackend create_commit to use canonical empty tree SHA
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1. Parent 分支未锁请求形状
|
There was a problem hiding this comment.
Pull request overview
该 PR 修复 GitHubRefBackend.create_commit 在真实 GitHub Git Data API 上无法创建“空树”的问题:不再调用 POST /git/trees 试图创建空树,而是直接使用 Git 的经典空树 SHA 作为 commit 的 tree,从而让租约/台账的 commit 能在真实 API 上成功落地(元数据仍仅存于 commit message)。
Changes:
GitHubRefBackend.create_commit移除/git/trees调用,改为使用常量EMPTY_TREE_SHA直接创建 commit。- 新增 wire-level 回归测试,锁定
create_commit的 HTTP 请求形状(确保不再回归到/git/trees)。
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
arbiter/backend.py |
为 GitHub 后端引入经典空树 SHA 常量,并让 create_commit 直接引用该 tree 创建 commit。 |
tests/test_github_backend_wire.py |
新增对 GitHubRefBackend.create_commit 的请求形状回归测试(mock _request)。 |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| import unittest | ||
| from unittest.mock import patch | ||
|
|
||
| from arbiter.backend import GitHubRefBackend |
| def fake_request(method, path, body=None): | ||
| calls.append((method, path, body)) | ||
| return 201, {"sha": "beef"} | ||
|
|
There was a problem hiding this comment.
1. Parent 分支未锁请求形状 🐞 Bug ⚙ Maintainability
tests/test_github_backend_wire.py 的 parent 用例未断言只发生一次请求、且请求路径必须是 /git/commits,因此未来若仅在 parent 分支回归引入额外调用(例如再调用 /git/trees)可能不会被该用例稳定捕获。该测试文件的意图是“HTTP 请求形状回归锁定”,建议对 parent 场景同样加上请求次数与路径断言。
Agent Prompt
## Issue description
`test_create_commit_with_parent` 目前只断言了 `parents` 透传,但没有锁定:
- 仅一次 HTTP 调用
- 调用路径必须是 `.../git/commits`
- 不允许任何额外调用(例如回归引入 `/git/trees`)
这与该文件的“请求形状回归测试”目标不完全一致。
## Issue Context
`create_commit` 存在 `if parent:` 分支(parent 场景与非 parent 场景可能在未来被人改出差异),因此需要在 parent 用例里也做同等强度的 wire-level 断言。
## Fix Focus Areas
- tests/test_github_backend_wire.py[43-55]
- arbiter/backend.py[126-129]
## Suggested change
在 `test_create_commit_with_parent` 中:
1) 让 `fake_request` 对非 `/git/commits` 的调用直接 `AssertionError`(与第一个用例一致)。
2) 在调用后断言 `len(calls) == 1`。
3) 断言 `method == "POST"` 且 `path.endswith("/git/commits")`。
4) 同时断言 `body["tree"] == GitHubRefBackend.EMPTY_TREE_SHA`,确保 parent 场景也使用空树常量。
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
清偿项(全部行为保持,裁决语义/退出码/错误通道零变化): - kernel.adjudicate:删除防重放段无操作的 try/except InfraError: raise 纯透传 包装(异常本就由函数级 infra 通道统一上报);防重放语义(seen ref + 台账) 与 CasConflict→noop/replay-detected 路径逐字节不变 - kernel.EXIT_CODE:改由 EXIT_ALLOW/EXIT_DENY/EXIT_INFRA 常量组装, 消除字面量双写(原三常量从未被引用,属死代码) - backend.LocalGitBackend:4 处重复的 subprocess.run(git -C …) 样板收敛为 _exec_git 单一入口;各调用方的异常包装与报错文案逐字保留 ("git 子进程失败"/"git rev-parse 失败"两通道不合并) - 魔法常量具名化:timeout=30×4 → GIT_TIMEOUT_SECONDS;重试 3 次/0.15s → LOCK_RETRY_MAX_ATTEMPTS / LOCK_RETRY_SLEEP_SECONDS - 函数内 import(time / urllib.request|error|parse)上提至模块顶部 (backend.py 是静态扫描白名单中的唯一网络模块,tests/test_no_llm.py 不受限) 不动项:#2 空树 SHA 链路与 _quote_ref_path refs/ 剥离逻辑零触碰; capabilities.yaml / AGENTS.md / ci.yml / README / tests 断言数量不减。 验证:python -m py_compile arbiter/*.py ✓; python -m unittest discover -s tests → 73 tests OK ×2 连跑; python -m arbiter.policy capabilities.yaml → POLICY-OK default-deny=verified。 Co-authored-by: randypanding <randypanding@users.noreply.github.com>
动机
W1-C3 AC-1 e2e 演习(陌生 agent,卡 .github#206)抓出:
GitHubRefBackend.create_commit先POST /git/trees空 body 建空树,GitHub 对空树创建一律 422 Invalid tree info({}/tree:[]/base_tree 姿势全拒)——租约创建在真实 API 上从未成功过。单测全走 LocalGitBackend 故未暴露(conductor run 32493680834 实证,fail-closed ABORT 语义正确工作:拒绝+不绕过)。变更
create_commit删除 /git/trees 调用,直接以经典空树 SHA4b825dc…为 tree 调POST /git/commits(租约元数据全在 commit message,无需树内容)tests/test_github_backend_wire.py(3 例,HTTP 请求形状层回归锁定:trees 零调用、tree=常量、parent 透传、常量值本体断言)验证
unittest:72 tests OK(69+3)AC 映射(#165 AC-2/AC-5 补强)
真实 GitHub 后端的 CAS 链路至此才有实证;fail-closed 行为已被 e2e 负向验证(infra=ABORT 非绕过)。
回滚:revert 本 PR(内核其余路径零改动)。
Summary by CodeRabbit