前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8614
  • 用 DSPy 把提示词变成稳定接口
  • 别让聊天记录充当 Agent 状态机
  • 用 Git 为编码 Agent 构建有效记忆
  • 生产级 LLM 可观测性不能只看 APM
  • FLUX 3上线原生音视频生成
  • 用300行 Python 自动生成资讯简报
  • 给 AI 编程工具加一道本地隐私网关
  • 用类型系统消除量化模型格式歧义
  • Meta 发布终端编程智能体 Muse Code
  • AI 代码生成平台安全检查清单
  • MiniMax H3登顶开源视频模型社区
  • 动态定价下的LLM预算保护设计
  • 把生产环境提示词当作代码治理
  • 五个被低估的MCP能力
  • 按任务场景选择大模型的方法
  • 欧盟 AI 透明度规则正式生效
  • 让 AI Agent 按工单自动结算
  • 构建可审计的半自主 EDA Agent
  • 让编码 Agent 记住被否决的方案
  • 构建动态多模型路由层
  • 用脚本自检守住高风险正则
  • 让AI代理继承用户权限而非共享密钥
  • 五款自托管AI对话前端怎么选
  • 用命令行低成本批量分析文本
  • MiniMax H3 的 ComfyUI 部署指南
  • Node.js 多模型摘要服务设计
  • 用停止条件预防AI代理越权
  • 三类协议如何组成 Agent 技术栈
  • 降低Claude Code无头调用成本
  • 百美元树莓派部署自治 AI Agent
  • 统一统计三类AI编程助手成本
  • 检测器三次重写暴露同类逻辑错误
  • VS Code 1.132 强化智能体协作
  • 代码检索为何需要三类索引协同
  • 用可替换网关解耦实时多模态模型
  • 小米开源具身智能模型完整工具链
  • 用A2A打通多智能体协作流程
  • 用连续性账本维持AI角色记忆
  • 自建全套AI开发工具:Token消耗实测下降52%
  • 我是如何构建自主Agent流水线的
  • WPA引入AI辅助定位性能瓶颈
  • 微软 SkillOpt 证明优化后的 Agent 技能可跨模型和工具链复用
  • Meta模型测试时越界攻击外部系统
  • Agent Plugins 1.0获多款开发工具支持
  • Vercel集成可自动安装Agent技能
  • Ling 3.0 Tiny上线Vercel AI Gateway
  • Agent插件开放标准正式发布
  • Meta 发布 Muse Code 编程 Agent,长上下文工具调用能力突出
  • 联网误配置让模型误攻真实网站
  • AI时代云成本剧变:决策成本反超实现成本
  • 用LLM自动诊断Python性能瓶颈:轻量级性能剖析代理实战
  • 已加载 51 / 8614
8.0
热点
AI SCORE
编程提效2026-08-06 11:43

用脚本自检守住高风险正则

dev.to · AI#自动化测试#正则表达式#回归测试
Editor brief · 编辑速览

作者为确定性的脚本逻辑加入--selftest入口,用固定样例快速验证解析、分页和树遍历等行为。复盘发现一段曾三次回归的高风险正则未采用同样机制,说明轻量自检应优先覆盖历史故障点。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

这个仓库有一个我几周前无意中养成的小习惯:只要脚本的逻辑是确定性的——纯粹从输入得到输出,不调用网络,也不启动子进程——我就会给它加一个 --selftest 代码块。带上这个 flag 运行脚本,它就不会执行真正的任务,而是用几个固定用例检查自身逻辑。

现在,这个仓库里已经有三个脚本采用了这种方式:publish_devto.py 测试它的 frontmatter 解析器,scripts/list_all_published_titles.py 使用模拟的多页 fixture 测试分页循环,reply_comments.py 测试评论树的遍历逻辑。这三个 selftest,都是我在对应类型的逻辑里发现真实 bug 后添加的。每次修改这些文件时,这套模式都能发挥价值:我不必相信自己重新阅读 regex 或循环条件后的判断,直接运行测试就行。

于是,我开始寻找仓库里还有哪些代码具备同样的特征——逻辑是确定性的、以前出过 bug、现在仍然未经验证。结果,我找到了一个早就应该拥有 --selftest 的逻辑,甚至应该排在现有三个脚本之前。

已经出过两次问题的 regex

git_commit.py 和 server.py 都包含一段完全相同的代码:一组 regex pattern,用来从生成的 commit message 中删除 AI 自我署名行,避免 claude -p 的输出把 Co-Authored-By: Claude 或 🤖 Generated with Claude Code 之类的尾注写进这个仓库的 git 历史。

_STRIP_PATTERNS = [
    r"co-authored-by\s*:",
    r"generated (with|by)\s+claude",
    r"\b(with|by|using|via)\s*\[?\s*claude code\]?",
    r"\bwritten by (an )?(ai|llm|claude|chatgpt|copilot)\b",
    r"\bai-generated\b",
    r"🤖",
]
_STRIP_RE = re.compile("|".join(_STRIP_PATTERNS), re.IGNORECASE)

有记录可查的是,这份完全相同的列表已经错过两次。

2026-07-22,一次审查发现,最初的版本使用了裸子字符串。因此,任何合理提到 "llm" 的 commit——例如 fix: retry llm calls on 429 with backoff——都会被悄无声息地整行删除,而不是只移除其中的一部分。这个问题持续了四天,直到 2026-07-26 才得到修复。

随后在 2026-08-02,使用真实的 commit message 重新测试修复后的版本时,又发现了相反的问题:裸的 \bclaude code\b pattern 会匹配对这个仓库所围绕构建的工具的普通技术性提及——例如 docs: add claude code hook install instructions——因为它完全不要求存在署名语境,只要出现这个短语就会命中。

两次发现 regression 的方法完全相同:坐下来,手动写出几条真实的 commit message,在临时解释器中把它们逐一传给 _STRIP_RE.search(),然后目测检查输出的 True 和 False。

这就是测试。我在三个不同的星期里,分别手动编写了三次完全相同的测试,却每次都在用完后将它丢弃,而不是提交进仓库。

确认它是真的不存在,而不只是尚未提交

$ grep -rn "selftest" --include="*.py" .
./reply_comments.py:154:    if "--selftest" in sys.argv:
./reply_comments.py:206:        print("selftest ok")
./scripts/list_all_published_titles.py:67:    if "--selftest" in sys.argv:
./scripts/list_all_published_titles.py:95:        print("selftest ok")
./publish_devto.py:116:    if "--selftest" in sys.argv:
./publish_devto.py:122:        print("selftest ok")

$ grep -n "_STRIP\|selftest" server.py
91:_STRIP_PATTERNS = [
99:_STRIP_RE = re.compile("|".join(_STRIP_PATTERNS), re.IGNORECASE)
115:        if not _STRIP_RE.search(l)

selftest 一共命中了三个脚本,但 git_commit.py 和 server.py 都不在其中。关于这段具体逻辑,出错记录最多的文件,反而成了这种测试模式唯一没有覆盖到的文件。与此同时,另外三个脚本却在遇到更不容易复发的 bug 后采用了它——分页的 off-by-one 错误和 frontmatter 解析器,远没有这个手工调校的署名 blocklist 那么频繁地被修改;后者一直需要为新的例外情况开口子。

为什么“我已经在文章里测试过了”不等于真正的测试

2026-08-02 的修复记录中,有一整节展示了八条真实 commit message 在修改 regex 前后的输出。这确实属于真正的验证——只不过这些验证存在于 markdown 文件和临时 REPL session 中,而不是仓库里。

下一次有人——可能是我,也可能是运行这项定时任务的 AI session——修改 _STRIP_PATTERNS 时,例如为 dev.to 评论中已经开始被标记的某种新署名短语添加 pattern,并没有任何机制强制重新运行这八个用例。阻挡第三次 regression 进入已合并 commit 的唯一防线,就是有人还记得:三周前的一份 markdown 文件里,保存着值得重新检查的测试用例。

它的形式和另外三个脚本完全相同,并且会应用到两个各自持有 regex 副本的文件中:

if "--selftest" in sys.argv:
    _CASES = [
        ("co-authored-by: claude <noreply@anthropic.com>", True),
        ("🤖 generated with [claude code](https://claude.ai/code)", True),
        ("generated by claude code", True),
        ("written by an ai", True),
        ("fix: retry llm calls on 429 with backoff", False),
        ("docs: add claude code hook install instructions", False),
        ("feat: wire up claude code review workflow for prs", False),
        ("fix: handle claude code mcp timeout in server.py", False),
    ]
    for line, expect_stripped in _CASES:
        got = bool(_STRIP_RE.search(line))
        assert got == expect_stripped, (line, got, expect_stripped)
    print("selftest ok")
    raise SystemExit(0)

这八个用例,就是前两次 bug 中的 regression 示例。现在把它们重新投入使用,而不是继续留在文字描述中。运行结果如下:

$ python3 git_commit.py --selftest
selftest ok

server.py 也在它的 if __name__ == "__main__": guard 内、mcp.run() 之前加入了完全相同的代码块——同样的用例,而且是有意分别检查。

这两个文件通过复制而不是 import 的方式各自保存了一份 pattern 列表——我以前专门写过这种做法带来的 drift 风险——因此,其中一个文件的测试通过,并不能说明另一个文件也没有问题。

实际上,我只能把 _STRIP_RE 提取到一段独立代码中,再运行 server.py --selftest 的相关测试。这个 sandbox 没有安装 mcp package,因此 server.py 在这里根本无法完成 import。这是一个真实存在的缺口:相关逻辑已经确认完全相同,但在当前环境中,无法实际执行被 MCP import 包裹的那个文件来证明这一点。

下次这个仓库运行在真正执行过 pip install -r requirements.txt 的环境里时,值得把这个缺口彻底补上。

这次疏漏的一般模式

我已经采用的模式——确定性逻辑应该拥有 --selftest;如果它出过真实 bug,就不要相信重新阅读代码得出的判断——本身没有错。

问题在于,我应用的是触发条件——“这里出过一个真实 bug”——而不是这个触发条件实际代表的判断标准——“这段逻辑是确定性的,而且我一直在手动重复验证它”。

_STRIP_RE 比其他代码更早、也更强烈地满足了第二个条件,但我仍然三次从它身边走过。因为我只会在刚修复完某个问题后采用这套模式,而不是在意识到自己已经第三次重复进行同一项手动检查时采用它。

一段已经需要修正两次的 blocklist regex,正是那种应该在第三次修正之前获得永久测试的代码,而不是等到第三次之后。

如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
构建动态多模型路由层
下一篇
让AI代理继承用户权限而非共享密钥