关于 safe-change
safe-change 是一项用于修改被多个调用方使用的函数、类或模块的编码技能。它先梳理依赖并记录现有行为,再指导最小化修改、兼容性检查及运行已有测试。
主要功能
- 01用 impact-check 梳理调用方与依赖
- 02记录修改前的可观察行为
- 03只进行任务要求的代码修改
- 04逐一检查调用方兼容性
- 05有现成测试时运行测试
适用场景
- 01安全修改共享函数的签名
- 02更新被多个调用方使用的模块
- 03更改返回类型前评估兼容性
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ rheinmir/ setup --skill safe-change安装后在 Claude Code 中输入/safe-change确认已加载。
详细介绍
技能:safe-change
内容
目的和背景
- 目的: 修改被多个调用方共用的代码(函数/类/模块),且不破坏现有调用方。
- 触发条件(何时使用): 修改任何被多个位置调用的函数、类或模块。
- 非目标: 不顺手重构相邻代码,不编写超出任务范围的测试,不手动查找调用方来替代
impact-check。
心智模型
共用符号 → impact-check(调用方 + 依赖项) → 当前可观察行为 → 最小改动 → 逐个调用方:保持向后兼容或明确更新 → 测试(如有) → “已更改 X。已验证 Y” → verify-before-commit。
输入和输出约定
| 字段 | 必需? | 含义 | |
|---|---|---|---|
| 输入 | 需要修改的符号/模块 + 变更要求 | 是 | 被多个调用方使用的对象 |
| 输入 | 模块的测试 | 否 | 有则运行;没有则在提交信息中明确说明 |
| 输出 | 最小改动 + 已验证/更新的调用方 | 是 | 已检查步骤 1 中的所有调用方 |
| 输出 | 确认语句“已更改 X。已验证 Y 仍然有效。” | 是 | 然后调用 verify-before-commit |
| 输出 | wiki/sources/draft/DDMMYY-<ten>.md | 是(除非没有产物) | 输出报告 |
规则和能力
- RULE-01(必须):无法保持向后兼容 → 继续之前先告知用户。
- RULE-02(必须):只处理任务要求的内容,不顺手重构。
- RULE-03(必须):没有测试时,可以注明这一点;不要编写超出任务范围的测试。
- 能力:查询调用方/依赖项关系图;读取和修改任务范围内的代码;运行本地测试;撰写 wiki 草稿。
失败边界
- 无法保持向后兼容 → 澄清:停止,并在继续之前告知用户(RULE-01)。
- 修改后测试失败 → 受阻,不要进入
verify-before-commit。 - 没有测试 → 合法的部分完成:在提交信息中明确说明,不要自行编写测试。
操作方式
主要工作流
| 步骤 | 类型 | 输入 | 操作 | 输出/退出条件 | 失败/后续 |
|---|---|---|---|---|---|
| W01 | 确定性 | 符号 | 运行技能 impact-check | 调用方 + 依赖项列表 | — |
| W02 | 判断 | 当前代码 | 记录可观察行为(返回值、副作用) | 行为基线 | — |
| W03 | 执行 | 要求 | 进行最小改动,不触碰相邻代码 | diff | 无法保持兼容 → B01 |
| W04 | 判断 | W01 中的调用方 | 逐个调用方验证向后兼容,或明确更新调用方 | 所有调用方均已检查 | — |
| W05 | 确定性 | 测试目录 | 查找测试;如有则运行 | 返回码为 0,或记录“无测试” | 测试失败 → 受阻;无测试 → B02 |
| W06 | 执行 | 结果 | 确认 + 调用 verify-before-commit + 输出报告 | 确认语句 + 草稿 | — |
各步骤的详细说明(W01–W06 的权威来源):
- 运行
impact-check技能,获取所有调用方和依赖项的列表。 - 记录当前可观察行为(返回值、副作用)。
- 进行最小改动。不要触碰相邻代码。
- 对步骤 1 中的每个调用方:验证向后兼容,或明确更新调用方。
CHECK: ls <test-dir>/*<module>* 2>/dev/null | head -3— 如果存在测试,RUN: <test-cmd>。如果没有,则在提交信息中明确说明。- 确认:“已更改 X。已验证 Y 仍然有效。”然后调用
verify-before-commit。
分支
| ID | 类型 | 条件 | 行为 | 跳过/失败 | 汇合点 |
|---|---|---|---|---|---|
| B01 | 恢复 | 无法保持向后兼容 | 停止,并在继续之前告知用户 | 用户未批准 → 已取消 | 用户批准后进入 W04 |
| B02 | 条件必需 | 模块没有测试 | 在提交信息中明确写明“无测试”,不编写新测试 | — | W06 |
验证和停止
继续条件:impact-check 列表中的所有调用方都已检查,且测试(如有)的返回码为 0。在确认语句 + verify-before-commit 处停止;不要自行继续重构。
示例
- 正向: 在
fetch_page()中添加可选参数timeout=30,有 4 个调用方 → 影响检查列出 4 个调用方,且这 4 个调用方都未传递该参数,因此兼容 → 模块测试通过 → “已更改 fetch_page 签名。已验证 4 个调用方仍可正常工作。” → 提交前验证。 - 边界情况/失败: 将
get_user()的返回类型从 dict 改为 object,2 个调用方使用user["id"]→ 无法保持兼容 → 停止并告知用户(B01),未经批准不得修改调用方。
交付 — 输出报告
所有主要技能任务完成后,向 wiki 写入一份提案草稿。
步骤
1. 构建文件名:
- 格式:
DDMMYY-<ten>.md DDMMYY= 今天的日期(例如,2026 年 6 月 2 日为020626)<ten>= 2–4 个 kebab-case 单词,用于概括所完成的工作(例如,landing-page-coteccons、brand-kit-fintech、ingest-auth-spec)
2. 写入 llmwiki/wiki/sources/draft/DDMMYY-<ten>.md:
---
type: draft
title: "DDMMYY-<ten>"
status: proposed
tags: [<skill-name>, output-report]
timestamp: YYYY-MM-DD
---
# DDMMYY-<ten>
**Type:** draft
**Status:** proposed
**Tags:** <skill-name>, output-report
**Proposed:** YYYY-MM-DD
## What
<One sentence — what this skill invocation produced or decided>
## Output
<Key artefacts, files created/modified, or decisions made>
## Files
| File | Action |
|------|--------|
| `path/to/file` | created / modified |
## Notes
- Invoked via: `/<skill-name>` skill
## Origin
- **Draft:** `wiki/sources/draft/DDMMYY-<ten>.md`
- **Commit:** _(filled by verify-before-commit)_
- **Date promoted:** _(filled by verify-before-commit)_
3. 更新 wiki 索引和日志:
llmwiki/wiki/index.md— 追加一行:| [DDMMYY-<ten>](sources/draft/DDMMYY-<ten>.md) | draft | YYYY-MM-DD |llmwiki/wiki/log.md— 追加:## YYYY-MM-DD — <skill-name> — <ten>
仅当该技能未产生任何产物且未作出任何决策时跳过(例如,纯显示模式
/caveman-stats)。
评论
支持 Markdown