Files
WQ_GUI/.qwen/skills/code_replacement_state_audit/SKILL.md

6.3 KiB
Raw Blame History

name, description, source, extracted_at
name description source extracted_at
代码替换请求的现状审计 处理用户"代码替换/新增"指令时,先审计磁盘真实状态再用 ask_user_question 确认——避免覆盖已落盘的高版本代码 auto-skill 2026-06-03T05:36:58.746Z

代码替换请求的现状审计

适用场景

用户给出"代码替换"或"按某版本代码新增"指令,但没有提供与磁盘当前状态对比信息时。典型触发:

  • 用户贴了一段代码说"请帮我写/替换这个"
  • 用户引用某个文档/旧版本/旧 chat 说"按这个来"
  • 之前的 state_snapshot / memory / git log 描述可能与磁盘现状不一致

核心原则

永远不要盲信"用户给的代码是最新版本"——磁盘上的代码可能已经是更完善的版本(用户或其他 agent 已迭代过)。覆盖 = 丢功能。

直接覆盖的代价不一定是显式 bug也可能是"丢失用户已批准的设计决策"(如 duck-type 探测 / ctx 抽象 / 信号协议 / 二次确认窗 / 错误定位)。

5 步标准操作

1. 确认文件存在

globlist_directory 看目标文件是否已存在:

  • 不存在 → 新建
  • 存在 → 进入第 2 步审计

2. grep 关键符号 + 读关键段

  • 找"用户贴的代码"里的 3-5 个关键符号(函数名 / 类名 / 关键常量 / import
  • 在磁盘文件里 grep 同样的符号
  • read_file 关键段(行号从 grep 结果直接拿)

3. 构造差异对照表

列出:

| 目标文件 | 用户贴的版本 | 磁盘现有版本 | 直接覆盖会丢失 |

关键列"直接覆盖会丢失什么"——让用户判断成本。具体粒度到"功能模块 / 设计决策 / 防御层 / 入口协议",不要写"代码差异"这种空话。

4. ask_user_question 让用户拍板

3 个标准选项(措辞可调,但必须给出现状 + 三选一

  • A. 保留现状(推荐,磁盘已是更新版)—— 直接进 Smoke Test
  • B. 强制覆盖到旧版 —— 写明丢什么 + 备份建议git stash / 复制到 _old.py
  • C. 混合:只取某段增量 —— 见第 5 步

不要在第 1 次 ask 时就列具体的"哪段增量"——先让用户在 A/B/C 之间选。如果选 C再做第 5 步。

5. 若用户选 C识别"真正增量"

对比 1.0 vs 2.0,识别 1.0 真正独有的部分2.0 没有的):

  • 排除 1.0 比 2.0 简单的2.0 是超集 / 工厂分层 / 多了 CLI
  • 排除 1.0 整体被 2.0 工厂分层超越的_make_objective vs _build_model + _get_search_space
  • 关注 1.0 独有的功能层(即使 2.0 不"明显"需要)

对每个候选增量,再问一次"采纳哪段"让用户具体选multiSelect=false一次只选 1 段最稳)。

落地原则

执行"采纳 1.0 某段增量到 2.0"时:

  • 最小化外科手术式编辑:只动需要动的文件,只改需要改的段
  • 保留 2.0 的设计决策duck-type 探测 / ctx 抽象 / 信号协议 / 二次确认窗 / 错误定位)
  • 顶部 import 增量用 replace_all=False 单点插入,避免破坏其他 import 顺序
  • 同名变量全链路替换(如 self.configclean_config)要贯穿 ctx 构造 / v2 调用 / v1 fallback避免双源差异
  • 单步模式不一定要清洗(不走 panel 完整 config与清洗器无关
  • 清洗器这种"防患于未然"的代码要给日志self.log_message.emit(f"[清洗器] 已删除 N 个未知 key"))让运行时可见

验证三件套

落地后必跑:

  1. AST 语法检查ast.parse(open(p, encoding='utf-8-sig').read()) 对 5 个核心文件
    • 必加 utf-8-sigWQ_GUI 的 water_quality_gui.py line 1 是 BOMplain utf-8 必挂
  2. 关键符号 grep确认新代码的关键符号import / 关键函数调用都命中hit 数符合预期
  3. 顶层导入测试:用 mock PyQt5 + sys.path.insert(0, 'src/gui/core'),验证模块整体可加载
    • PyQt5 mock 模板见下方"参考代码"
    • Windows 环境调 Python用 conda env 的 python.exe 全路径,不要靠 PATH

反例(不要做)

  • "按用户贴的代码原封不动写入"——1.0 简化版的覆盖陷阱
  • "保留 state_snapshot 描述"——state snapshot 可能不准确(写的是意图,磁盘才是事实)
  • "用 git log 反推当前状态"——git log 不能反映工作区未提交改动
  • "靠 memory 推断当前状态"——memory 可能是 22 天前的(已确认过期)
  • "磁盘和用户给的代码看起来一样就不审计"——一行之差可能就是"防弹层"丢失

参考代码

PyQt5 mock 模板worker_thread.py 顶层导入测试)

import os, sys
os.environ['GDAL_FILENAME_IS_UTF8'] = 'YES'
os.environ['SHAPE_ENCODING'] = 'UTF-8'
sys.path.insert(0, 'src/gui/core')

import types
pyqt5 = types.ModuleType("PyQt5")
qtc = types.ModuleType("PyQt5.QtCore")
class _QThread:
    def __init__(self, *a, **kw): pass
class _Signal:
    def __init__(self, *a, **kw): pass
qtc.QThread = _QThread
qtc.pyqtSignal = _Signal
qtc.Qt = type("Qt", (), {"QueuedConnection": 1, "UserRole": 0})()
sys.modules["PyQt5"] = pyqt5
sys.modules["PyQt5.QtCore"] = qtc

import worker_thread
# 副作用: check_pipeline_dependencies() 会打印依赖检查日志(可忽略)

Windows 上跑 conda env python

cmd /c "D:\xxx\anconda\envs\XXX\python.exe D:\path\to\script.py"

PowerShell 单行 python -c "..." 在中文路径 / 双引号 / 单引号嵌套时易翻车,写临时 .py 文件再用 cmd /c最稳。

案例来源2026-06-03 WQ_GUI 路线 B MVP

  • 用户贴 1.0 简化版300 行 automl_trainer / 简化 worker_thread.run() / 简化 on_run_all_clicked
  • 磁盘上 2.0 落盘版545 行 automl_trainer_build_model + _get_search_space 工厂 / argparse CLI/ duck-type 探测 v2 + PipelineContext 抽象 / 完整二次确认窗 / 失败步骤 _focus_step 定位 / [DEPRECATED] stop 保留
  • 1.0 唯一真增量 = "防弹级参数清洗器"method_map 14 项 + inspect.signature 过滤未知 key + has_kwargs 豁免 + 未知 key 数量日志)
  • 落地worker_thread.py:run() 内 set_callback 之后插入 53 行清洗器self.config 6 处替换为 clean_config
  • 验证5 文件 AST 全通过 + 关键符号 7 项命中 + PyQt5 mock 下 import 成功
  • 净增行数407 → 457+50 行)