# Bug诊断 ## 输入要求 1. **错误信息**(必填):错误日志、异常堆栈或报错截图 2. **相关代码**(必填):出错的代码片段 3. **运行环境**(可选):操作系统、语言版本、依赖版本 4. **复现步骤**(可选):如何触发这个错误 ### 输出示例 ```` ## Bug诊断报告 **错误类型**:运行时(白屏 500) **错误信息**:Uncaught TypeError: Cannot access offset of type bool **发生位置**:e/class/functions.php / GetFcache / 第 204 行 ## 根因分析 **问题描述**:反序列化缓存后未做类型校验,直接当下标访问。 **详细分析**:`unserialize` 失败返回 `false`(bool);旧缓存格式非数组时,直接 `$cache['key']` 在 PHP 8.1+ 触发 TypeError。 **相关代码**: ```php $cache = unserialize($str); return $cache['key']; // unserialize 失败返 false(bool) 时当下标访问报 TypeError ``` ## 修复方案 ```php $cache = unserialize($str); if (!is_array($cache)) return ''; return $cache['key'] ?? ''; ``` ## 验证方法 1. `php -l` 语法通过 2. 用旧格式缓存触发该路径,确认不再白屏 ## 预防措施 - 反序列化结果先做 is_array 校验再访问下标 ```` ## 执行流程 ### 第一步:Spec场景检查 诊断前先检查相关spec中的scenario: - **如有spec**:确认bug是否涉及spec中的scenario,检查scenario的Given/When/Then是否被正确实现 - **spec与实现不一致**:可能是spec理解偏差导致的bug - **无spec**:诊断后建议补充spec防止同类bug ``` ✓ Spec场景检查: - 相关Scenario: [scenario名称] - 预期行为: [spec定义] - 实际行为: [观察到的行为] - 偏差分析: [spec vs 实现] ``` ### 第二步:已知问题检查 检查项目记忆中的已知问题: - 搜索项目记忆中的类似bug记录 - 检查是否有已知的workaround - **发现新问题**:诊断完成后提示记录到项目记忆 ### 第三步:错误解析 - 识别错误类型(语法错误、运行时错误、逻辑错误、环境错误) - 提取关键信息(错误码、错误消息、发生位置) - 分析堆栈跟踪(调用链、最后执行位置) ### 第四步:根因分析 | 错误类型 | 常见根因 | 分析方法 | | -------------- | ------------------------------ | ---------------------- | | **语法错误** | 拼写错误、括号不匹配、缩进错误 | 定位到具体行号和字符 | | **运行时错误** | 空指针、数组越界、类型错误 | 检查变量状态和数据流 | | **逻辑错误** | 条件判断错误、算法缺陷 | 追踪执行路径和中间结果 | | **环境错误** | 依赖缺失、版本不兼容、配置错误 | 检查环境和依赖信息 | | **并发错误** | 竞态条件、死锁、资源竞争 | 分析线程/协程交互 | #### 推断交叉验证规则 根因分析中,AI 推断只能作为候选假设,不能直接作为结论交付。每个候选根因至少匹配一种验证证据: | 证据类型 | 适用场景 | 验证方式 | | ---------- | ------------------------- | ----------------------------------------------------- | | 日志/堆栈 | 报错、异常、线上问题 | 对齐错误时间、调用链、文件行号和错误码 | | 复现测试 | 稳定可触发的功能缺陷 | 构造最小输入,先复现失败,再验证修复后通过 | | 源码路径 | 逻辑错误、数据流异常 | 从入口追踪到出错分支,说明变量状态变化 | | 环境/版本 | 依赖、运行时、配置差异 | 对比语言版本、依赖版本、配置项和平台差异 | | 外部权威源 | 框架/API/数据库行为不确定 | 引用官方文档、发行说明或已验证的项目内规范 | | 运行证据 | 性能、并发、资源泄漏 | 使用 benchmark、profile、EXPLAIN、线程/堆/GC 日志验证 | 如果证据不足,必须输出"最可能原因"和"待验证动作",不得写成已确认根因。若多个候选根因都符合症状,按可能性排序并给出最小排除步骤。 ### 根因判定门禁(先判后修) 给出修复方案前,必须先回答:**这是根因(root cause)还是只打补丁(symptom patch)?** 禁止未区分就直接改码。 - **根因判定信号**:修复是否能消除所有同类触发路径?还是只在当前输入/当前位置挡住了症状? - **打补丁的识别**:若修改只针对"这个报错这次没出现"(如加一个 `if (x) return`),而未说明为什么会进入该状态,即为补丁,必须继续追问上游成因。 - **强制追问链**:每发现一个补丁式修复,必须写下"为何会进入该非法状态",直到追溯到真正成因或明确标注"上游根因待查"。 - **图/状态机类 Bug**:涉及图遍历、环检测、状态机、依赖解析的缺陷,先建立方向语义模型(边方向、遍历方向、状态迁移是否解耦)再判定根因,不得仅凭"跑通了"判定修复有效。 命中"只打补丁"时,在报告中单独标注「补丁风险」,并给出上游根因的最小排查动作。 ### 第五步:定位问题 - 指出具体的代码位置(文件、函数、行号) - 说明变量在错误时刻的状态 - 追踪数据流找到问题源头 ### 第六步:提供修复(Surgical Changes) - 给出修复后的代码 - 说明修复原理 - **Karpathy约束**:只修改修复Bug必需的代码,不改相邻代码、风格、注释 - 提供验证修复的方法 ### 第七步:定义成功标准(Goal-Driven Execution) 基于已确定的根因和修复方案,明确定义"修复成功"的标准: - **复现测试**:写一段能稳定触发Bug的测试/步骤 - **成功标准**:修复后应达到什么状态 - **验证方法**:如何确认修复有效 **示例**: ``` 成功标准:用户邮箱为空字符串时,validate_user() 抛出 ValueError 而非崩溃。 复现测试:调用 validate_user({'email': ''}) → 应抛出 ValueError。 验证方法:运行复现测试 → 通过。 ``` ### 第八步:记录到项目记忆 修复完成后,将关键决策和变更记录到项目记忆(参见 `project-memory-management.md`): - 记录 Bug 根因和修复方案(Decision Record 模式) - 记录新增的预防措施和编码规范(Convention Capture 模式) - 更新已知问题清单,防止同类 Bug 复发 ## 实战请求示例 ### 示例一:PHP/CMS 白屏或 500 ```text 帮我诊断这个 CMS 后台 500。 环境:EmpireCMS 7.5,PHP 8.2,MySQL 5.7。 现象:进入 /e/admin 后白屏,前台正常。 错误信息:贴出 php_errors.log 中最新 30 行。 最近变更:刚改过后台插件 action_xxx.php。 要求:先判断可能原因,不要直接改缓存文件;给出最小复现和修复验证命令。 ``` 优先加载:`bug-diagnosis.md`、`cms-development.md`、`code-review.md`。 ### 示例二:接口偶发超时 ```text 帮我定位订单列表接口偶发超时。 环境:Laravel 10,PHP 8.2,MySQL 8.0。 现象:keyword 为空时正常,带手机号搜索偶尔超过 5 秒。 已有证据:贴出慢查询 SQL、接口参数、表行数、EXPLAIN 结果。 要求:区分已确认根因和待验证假设;不要直接加索引,先说明索引影响和回滚方案。 ``` 优先加载:`bug-diagnosis.md`、`mysql-database.md`、`performance-benchmark.md`。 ## 输出格式 ```` ## Bug诊断报告 **错误类型**:[语法/运行时/逻辑/环境/并发] **错误信息**:[核心错误消息] **发生位置**:[文件/函数/行号] ## 根因分析 **问题描述**:[一句话说明] **详细分析**:[逐步推理过程] **相关代码**: ```[问题代码]``` ## 修复方案 ```[修复后的代码]``` **修复说明**:[为什么这样修复] ## 验证方法 1. [步骤1] 2. [步骤2] ## 预防措施 - [建议1] - [建议2] ```` ## 质量标准 - 根因分析必须基于代码和日志证据,不能猜测 - 修复代码必须可运行,且能解决原问题 - 必须提供验证方法,让用户确认修复有效 - 对于不确定的根因,标注"最可能的原因"并列出其他可能性 - 环境相关错误必须说明具体的环境要求或版本限制 - 不得建议用户"重启试试"或"重新安装"作为首要方案 - **Karpathy红线**:修复前必须先写复现测试,修复后验证测试通过 - **Karpathy红线**:只修改修复Bug必需的代码,不改相邻代码、风格、注释 - **证伪门禁**:每个结论交付前,先构造一个反例尝试推翻它;构造不出反例才允许交付。跑通 ≠ 正确。环检测三次没写对,根因不是没清单,而是每次写完都没人攻击它;本门禁把"跑通就交付"逼成"证伪后交付" ## CMS 常见 Bug 模式 当诊断对象为 PHP+MySQL CMS 时,优先排查以下模式: | Bug 类型 | 典型表现 | 常见根因 | 修复方向 | | ------------ | ------------------------------------------------- | --------------------------------------- | ---------------------------------------------------------- | | PHP 版本兼容 | `Fatal error: Uncaught TypeError` / `Deprecated:` | 低版本代码运行在高版本 PHP | 参见 `cms-development.md` PHP 8.x 兼容性检查表 | | CMS 缓存失效 | 修改代码后页面无变化 | CMS 模板/数据缓存未清理 | 清理 `runtime/` `e/tmp/` `data/dbcache/` 后重试 | | 模板引擎错误 | 标签不解析或输出原始标签 | 模板语法错误或引擎版本差异 | 检查模板标签闭合和 CMS 版本对应语法 | | 数据库表前缀 | `Table 'xxx_tablename' doesn't exist` | 表前缀配置与实际不一致 | 检查 CMS 配置文件中的表前缀设置 | | MySQL 慢查询 | 页面卡顿 / SQL 超时 / CPU 飙高 | 缺索引、全表扫描、排序临时表 | 采集 SQL、参数、表行数和 EXPLAIN,参考 `mysql-database.md` | | MySQL 死锁 | `Deadlock found when trying to get lock` | 事务顺序不一致或锁范围过大 | 缩短事务、统一更新顺序、检查索引命中 | | 序列化数据 | `unserialize(): Error at offset` | WordPress `wp_options` 等序列化数据损坏 | 用 `maybe_unserialize()` 或修复序列化字符串长度 | | 伪静态路由 | 404 或路由不生效 | `.htaccess` / Nginx rewrite 规则缺失 | 检查伪静态规则和 CMS 路由配置 | | 文件编码 | 中文乱码 / `headers already sent` | UTF-8 BOM / GBK 编码混用 | 统一 UTF-8 无 BOM,用二进制方式读写文件 | 详见 `cms-development.md`。 ## 关联 reference - **karpathy-coding-guidelines**(Karpathy编码规范)— 修复前可用 `karpathy-coding-guidelines` 确认修复策略符合精准修改原则 - **code-review**(代码审查)— 修复后可用 `code-review` 检查是否引入新问题 - **test-generation**(测试用例生成)— 修复后可用 `test-generation` 生成回归测试 - **code-generation**(代码生成)— 复杂修复可用 `code-generation` 生成替代实现 - **cms-development**(CMS二次开发)— PHP+MySQL CMS 场景参考 `cms-development.md` 的兼容性检查和常见 Bug 模式 - **mysql-database**(MySQL数据库)— 数据库报错、慢查询、死锁、表结构和索引问题参考 `mysql-database.md` - **project-memory-management**(项目记忆管理)— 记录 Bug 根因、修复方案和预防措施 ## 失败回退机制 | 步骤 | 失败条件 | 回退目标 | 最大重试 | 不可恢复时升级路径 | | --------------------------------------------- | --------------------------------------- | ---------------------------------------- | -------- | ------------------------------------------------- | | 第一步:Spec场景检查 | 无spec或spec与实现不一致 | 基于代码和错误信息诊断,标注"无spec对照" | 1 | 诊断后建议走 Spec驱动开发 补全spec防止同类bug | | 第二步:已知问题检查 | 项目记忆不可用或无相关记录 | 跳过已知问题检查,标注"记忆未加载" | 1 | 基于当前信息独立诊断,诊断完成后提示手动记录 | | 第三步:错误解析 | 错误信息不完整,无法分类 | 基于已有信息匹配最接近的错误分类 | 2 | 告知所需最小信息集(错误消息+触发操作),等待补充 | | 第四步:根因分析 | 多种可能根因均符合症状,无法唯一确定 | 列出候选根因,按可能性排序 | 2 | 输出诊断矩阵(候选根因×验证方法),由用户逐一排除 | | 第五步:定位问题 | 涉及第三方库/外部服务,代码不可审视 | 标注第三方边界,定位调用链最近的可控点 | 1 | 给出workaround方案,建议向第三方提issue | | 第六步:提供修复(Surgical Changes) | 修复方案需大规模重构(超出Bug修复范围) | 给出最小修复+重构建议供后续规划 | 2 | 拆分为Bug修复(立即)和架构优化(单独任务) | | 第七步:定义成功标准(Goal-Driven Execution) | 修复涉及多系统联调,单次验证不充分 | 定义分层验证标准(单元→集成→端到端) | 1 | 给出回归测试checklist,建议灰度发布验证 | | 第八步:记录到项目记忆 | 项目记忆系统不可用 | 输出Decision Record到本地文件 | 1 | 标注"记忆未沉淀",提示用户手动保存 |