Prhub

#1890 Update the mechanical-refactor-verify skill to the latest sglang version

原始 PR 作者 fzyzcjy 合并时间 2026-08-26 07:21 文件变更 42 提交数 1 评论 1 代码增减 +8985 / -227

执行摘要

升级 refactor 验证技能,新增 proof 生成与链式验证工具链

该 PR 是 #1837(refactoring and enhancements 跟踪 issue)的一部分,目标是让机械重构可被机器验证。PR 标题明确说明要同步最新 sglang 版本的 skill,commit message 也注明是 copied skill files 并经过 pre-commit 适配。升级后,mechanical-refactor-verify skill 不再只是简单封装 git 命令,而是能从 commit diff 推断 reproduce recipe、生成独立证明脚本、并验证整条机械重构链,从而支撑 #1837 下系列 launch scripts 重构 PR 的自动化审核。

值得精读。核心看点是 mechanical_refactor_reproduction_utils.py 中 AST 定位 + 源码文本拼接的原子原语设计,以及 mechanical_refactor_proof_generator.py 中从 diff 反推 recipe 的启发式推断;这两者组合实现了「机器证明机械重构」的闭环。对计划做大规模代码移动或希望自动化重构 review 的团队有直接借鉴价值。建议重点关注 verify_mechanical_refactor 的 worktree 校验流程和 infer_recipe 对不支持场景(rename、语句级重排)的显式拒绝策略。

讨论亮点

PR 无实质性技术争论,review_comments 为 0。唯一一条审核评论来自 guapisolo 的 APPROVED:

treasure, better merge to main first as standalone PR

即认可该变更价值,并建议作为独立 PR 先合入 main,而不是积压在功能分支里。该建议已被合并者采纳。Issue 侧仅有一条 gemini-code-assist 的弃用声明,与本次变更无关。

实现拆解

整个升级分为四步:

  1. 重构复现工具层:新增 scripts/mechanical_refactor_reproduction_utils.py(约 1359 行),在旧 verify_mechanical_refactor 基础上提供 Repro 构建器,组合 move_symbolextract_to_new_moduleextract_functionlower_call_sitesrequalify_call_sitesadd_importremove_imported_name 等 AST 定位、源码文本拼接的原子原语;并改进 exec_command 失败路径为抛 RuntimeError 而非直接 sys.exit,便于上层捕获。

  2. 新增证明生成器:新增 scripts/mechanical_refactor_proof_generator.py(约 1401 行),通过 _per_file_diff 解析 commit 的逐文件增删行,用 _enclosing_function_enclosing_class_of_def 等辅助函数在 base 状态 AST 上推断移动、调用点降级、导入重定向,生成 repro_scripts/<sha>.py 独立脚本并执行,diff 为空才 PASS。

  3. 新增链式验证 CLI:新增 scripts/mechanical_refactor_reproduction_cli.py(约 484 行),提供 verify_chainCommitVerdictChainResult 等数据模型,按 mechanical_provable / non_mechanical_provable 关键字分类链上每个 commit,并行运行 proof 并用 --skip-passed 缓存结果,输出 chain_report.md,exit code 反映整链 verdict。

  4. 删除旧入口并补齐测试:删除旧的 mechanical_refactor_verify_utils.py(80 行),其能力由新 scripts 目录取代;同时新增 scripts/tests/ 下 31 个测试文件,覆盖 proof generator 的 recipe 推断、reproduction utils 的符号移动与导入原语、CLI 的链验证语义,测试通过 sys.path.insert 直接引用被测模块,未接入 CI 而由开发者手工运行。

文件 模块 状态 重要度
.claude/skills/mechanical-refactor-verify/scripts/mechanical_refactor_reproduction_utils.py 复现工具 added 8.98
.claude/skills/mechanical-refactor-verify/scripts/mechanical_refactor_proof_generator.py 证明生成 added 8.98
.claude/skills/mechanical-refactor-verify/scripts/mechanical_refactor_reproduction_cli.py 链式验证 added 8.78
.claude/skills/mechanical-refactor-verify/mechanical_refactor_verify_utils.py 旧版工具 removed 8.03
.claude/skills/mechanical-refactor-verify/scripts/tests/proof_generator/test_infer_moves.py 证明生成 added 7.49
.claude/skills/mechanical-refactor-verify/scripts/tests/reproduction_utils/test_move_symbol.py 符号移动 added 7.49

关键符号

infer_recipe recipe_to_script generate_range verify_mechanical_refactor verify_chain move_symbol extract_to_new_module extract_function lower_call_sites requalify_call_sites exec_command main

关键源码片段

.claude/skills/mechanical-refactor-verify/scripts/mechanical_refactor_reproduction_utils.py dependency-wiring

新增约 1359 行,是整个工具链的核心:提供 AST 定位的原子移动原语(move_symbol、extract_to_new_module、extract_function 等)和 verify_mechanical_refactor 的 worktree 逐字节校验流程。

def verify_mechanical_refactor(
    base_commit: str,
    target_commit: str,
    transform: "Callable[[Path], None]",
) -> None:
    """在一次性 worktree 中复现机械重构,并与目标 commit 做逐字节比对。    流程:基于 base_commit 创建临时 worktree -> 运行 transform 还原变更 ->
    对变更文件跑 pre-commit -> 与 target_commit 做字节级 diff,diff 为空才算 PASS。
    """
    repo_root = exec_command("git rev-parse --show-toplevel")
    worktree_dir = tempfile.mkdtemp(prefix="verify-mechanical-")
    branch_name = f"verify-mechanical-{base_commit[:8]}"
​
    try:
        print(f"[1/4] Creating worktree at {base_commit[:8]}...")
        # 从 base_commit 拉出独立 worktree,避免污染当前开发环境
        exec_command(
            f"git worktree add -b {branch_name} {worktree_dir} {base_commit}",
            cwd=repo_root,
        )
​
        print("[2/4] Running transformation...")
        # transform 由调用方提供,内部组合各个原子移动原语
        transform(Path(worktree_dir))
​
        print("[3/4] Running pre-commit...")
        # 只对变更文件跑 pre-commit,避免全仓格式化引入无关噪音
        exec_command("git add -A", cwd=worktree_dir)
        changed = exec_command(
            f"git diff --cached --name-only --diff-filter=ACMR {base_commit}",
            cwd=worktree_dir,
        ).split()
        if changed:
            files = " ".join(shlex.quote(path) for path in changed)
            exec_command(f"pre-commit run --files {files}", cwd=worktree_dir, check=False)
        if exec_command("git status --porcelain", cwd=worktree_dir):
            git_add_and_commit("pre-commit fixes", cwd=worktree_dir)
​
        print(f"[4/4] Diffing against {target_commit[:8]}...")
        # 字节级 diff:任何差异都说明 transform 没有忠实复现原 commit
        diff = exec_command(
            f"git diff {target_commit} -- .",
            cwd=worktree_dir,
            check=False,
        )
​
        if diff:
            print(f"\nFAIL: diff is non-empty:\n{diff}")
            sys.exit(1)
        print("\nPASS: transform reproduces the commit exactly.")
​
    finally:
        # 故意保留 worktree 供人工复核,并打印清理命令
        print(f"\nWorktree left at: {worktree_dir}")
        print(f"Branch: {branch_name}")
        print("To clean up manually:")
        print(f"  git worktree remove {worktree_dir} && git branch -D {branch_name}")
.claude/skills/mechanical-refactor-verify/scripts/mechanical_refactor_proof_generator.py dependency-wiring

新增约 1401 行,负责从 commit diff 与 base 状态 AST 推断 reproduce recipe,并生成独立可运行的证明脚本,是 skill 从「手动写 transform」到「自动生成证明」的关键升级。

def _per_file_diff(commit: str, root: str) -> dict[str, dict]:
    """逐文件解析 commit 的删除/新增内容行(保留空白),并标记是否新文件。    返回结构供后续 AST 推断使用:removed 与 added 都按行保留原样,
    这样 ast 的行号能和文件真实行号对齐,保证定位准确。
    """
    out = _git_output(["show", commit, "--format=", "--no-color", "--no-ext-diff"], root)
    files: dict[str, dict] = {}
    path: str | None = None
    in_hunk = False
    for line in out.splitlines():
        header = re.match(r"diff --git a/(.*) b/(.+)$", line)
        if header:
            # 每个文件的 diff 起始行,初始化独立的增删缓冲区
            path = header.group(2)
            files[path] = {"removed": [], "added": [], "new": False, "deleted": False}
            in_hunk = False
        elif line.startswith("new file"):
            files[path]["new"] = True
        elif line.startswith("deleted file"):
            files[path]["deleted"] = True
        elif line.startswith("@@"):
            # 进入 hunk 后才开始收集 + / - 行,diff 头部的元信息不参与
            in_hunk = True
        elif in_hunk and line.startswith("+"):
            files[path]["added"].append(line[1:])
        elif in_hunk and line.startswith("-"):
            files[path]["removed"].append(line[1:])
    return files

评论区精华

独立 PR 合并建议 other

guapisolo 在审批时评价:treasure, better merge to main first as standalone PR。

结论:合并者采纳建议,将该 skill 升级作为独立 PR 合入 main。 · 已解决

风险与影响

  1. 大体积外部导入:约 9000 行新增且来源为 sglang 仓库,虽然 commit message 提到已跑 pre-commit 自动修复,但跨仓库复制的代码可能与本仓库 AST 版本、pre-commit hook 集合存在隐性差异,需关注后续运行反馈。
  2. 删除旧模块的兼容性风险:mechanical_refactor_verify_utils.py 被整体删除,旧 skill 使用者或外部脚本若仍 import 该模块会直接失败,需确认仓库内无残留引用。
  3. shell 执行面:exec_command 使用 shell=True 拼接命令字符串,参数来自 skill 内部受控代码,但若未来允许用户传入任意 commit/分支名,存在注入面,建议保持参数白名单。
  4. 测试运行方式不明确:31 个测试文件挂在 .claude/skills 下,未在现有 CI 工作流中发现对应接入点,存在测试被遗漏执行的风险。

影响集中在开发工具链而非运行时产品:skill 升级后,Claude Code 等 AI 助手在仓库内执行机械重构时,可获得 recipe 推断、逐字节复现和整链验证能力,显著降低 #1837 系列重构 PR 的审核负担。对团队而言,这是一套可复用的「重构可证明」方法论沉淀;对用户和系统无运行时影响。由于是独立 skill 目录,风险隔离良好,但后续所有机械重构 PR 都可能依赖该工具链的可靠性。

大体积外部导入代码 旧模块删除兼容性 shell 命令拼接执行 测试接入 CI 待确认

关联 Issue

#1837 Tracking issue for refactoring and enhancements

完整报告

参与讨论