调试模式
仅当用户显式调用 debug-mode、$debug-mode、debug mode 或 instrumented debugging 后使用此技能。
如果用户未明确选择加入,则正常调试。仅在临时运行时插桩能实质性帮助时提及此技能。
核心循环
运行假设驱动的调试循环:
- 阅读相关代码、复现细节和现有日志。
- 列出 2-5 个排序的假设,使用例如
H1、H2、H3的 ID。 每个假设必须预测运行时探针将显示的内容。 - 启动或复用回环收集器(收集器约定)。
- 添加 3-8 个有针对性的探针以区分假设。使用发送到
DEBUG_URL + "/log"的结构化事件,切勿使用 stdout/stderr。遵循下文的事件结构、区域标记和帮助器。 - 在手动检查点停止。发送检查点模板。在用户回复
A、B或C之前,不要分析、修复或移除探针。 - 收到
A后,检查打印的LOG_FILE,将每个假设分类为CONFIRMED(已确认)、REJECTED(已拒绝)或INCONCLUSIVE(尚无结论),并且仅当日志能解释根本原因时进行最小的修复。遵循下文的证据摘要。 - 在一次带有
runId: "post-fix"标签的修复后运行中保持探针活跃。 - 用户对修复后检查点回复
B后,移除所有插桩并运行相关检查。遵循下文的清理清单。
硬性规则
- 绝不在添加探针后跳过手动复现检查点。
- 在此技能激活时,绝不要靠猜测进行修复。
- 在用户确认修复后检查之前,绝不要移除探针。
- 绝不要提交调试日志或临时插桩代码。
- 绝不要记录秘密、令牌、cookies、授权头、API 密钥、原始请求体、可能包含私有数据的原始响应,或非必要的个人数据。
收集器约定
打包的收集器特意保持小巧:
GET /health检查现有收集器是否可复用。POST /log接受一个 JSON 对象并异步追加一行 NDJSON。 它在验证后返回200;该行在后台写入。- 不同的会话写入独立的文件并拥有独立的队列,因此写入可以跨会话并行进行。
- 日志默认保存在操作系统临时目录下,位于工作区之外。
--ensure打印DEBUG_URL、SESSION_ID、LOG_DIR、LOG_FILE和HEALTH_URL。- 收集器在第一个事件时创建
LOG_FILE。不要在复现后执行touch、预创建、截断或清除它。 - 收集器仅限回环。不要将其绑定到
0.0.0.0或任何公共接口。
使用以下命令启动或复用:
node <skill-dir>/scripts/log-server.mjs --ensure --session <session_id> --host 127.0.0.1 --port 0
在阻止本地端口监听器的托管沙箱中,在首次尝试时请求代理的正常批准。将原因限定为启动或复用这个仅限回环的调试收集器。
检查点模板
添加探针后,停止并发送此形状,填充真实的会话详情:
我已添加调试模式探针,收集器正在写入:
- 会话:<session_id>
- 日志文件:<LOG_FILE>
- 调试端点:<DEBUG_URL>/log
请手动复现该 bug,然后回复:
A - 已复现
B - 已修复
C - 其他;描述发生的情况
对于修复后验证,仅更改开场句:
我已保持调试模式探针活跃以进行修复后验证,收集器正在写入:
- 会话:<session_id>
- 日志文件:<LOG_FILE>
- 调试端点:<DEBUG_URL>/log
请手动验证原始 bug,然后回复:
A - 已复现
B - 已修复
C - 其他;描述发生的情况
将检查点回复解释为一个小的状态机:
- 修复前的
A:读取 NDJSON 日志,分类假设证据,然后仅修复已确认的原因或添加更窄的探针。 - 修复后的
A:bug 仍然复现。读取修复后日志,继续使用更窄的假设或探针。 - 修复前的
B:不是终止状态。将其视为 bug 在插桩条件下未复现的证据,并请求澄清或更窄的复现步骤。 - 修复后的
B:移除探针并运行最终检查。 - 任何时间的
C:将用户的文本视为证据。调整复现步骤、假设或探针。
事件结构
使用结构化的、低容量的事件。一个典型的事件如下所示:
{
"session": "<session_id>",
"runId": "pre-fix",
"probe": "settings.beforePersist",
"hypothesis": "H1",
"file": "src/settings/save.ts",
"fn": "saveSettings",
"vars": {
"enabled": true,
"userId": "redacted"
}
}
修复前使用 runId: "pre-fix",修复后验证使用 runId: "post-fix"。对于高频路径,仅记录状态变化或积极采样。
区域标记
包裹所有临时插桩代码,以便清理可以是机械性的:
// #region DEBUG_MODE_PROBE <session_id> settings-before-persist
debugModeLog({
probe: "settings.beforePersist",
hypothesis: "H1",
file: "src/settings/save.ts",
fn: "saveSettings",
vars: { enabled, userId: "redacted" },
});
// #endregion DEBUG_MODE_PROBE <session_id>
常见的注释形式:
// #region DEBUG_MODE_PROBE <session_id> ... JavaScript, TypeScript, Java, C#, Go, Rust, C, C++
# #region DEBUG_MODE_PROBE <session_id> ... Python, Ruby, Shell, YAML
<!-- #region DEBUG_MODE_PROBE <session_id> --> HTML, Vue, Svelte
/* #region DEBUG_MODE_PROBE <session_id> */ CSS 和 C 风格的块上下文
-- #region DEBUG_MODE_PROBE <session_id> ... SQL, Lua
帮助器
对于浏览器或前端 JavaScript,使用 assets/browser-log-helper.js 作为规范的帮助器模板。将其复制到被插桩的模块或脚本中,替换 <session_id> 和 <DEBUG_URL>,并保持函数名 debugModeLog。
对于 Node.js 或服务器端 JavaScript,使用 assets/node-log-helper.js 作为规范的帮助器模板。将其复制到被插桩的模块或脚本中,替换 <session_id> 和 <DEBUG_URL>,并保持函数名 debugModeLog。
对于不依赖第三方库的 Python:
# #region DEBUG_MODE_PROBE <session_id> debug-log-helper
import json
import urllib.request
DEBUG_MODE_URL = "<DEBUG_URL>/log"
def debug_mode_log(event):
try:
payload = {"session": "<session_id>", **event}
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(
DEBUG_MODE_URL,
data=data,
headers={"content-type": "application/json"},
method="POST",
)
urllib.request.urlopen(req, timeout=0.5).close()
except Exception:
pass
# #endregion DEBUG_MODE_PROBE <session_id>
证据摘要
在收到 A 回复后,在编辑代码之前总结证据:
H1 设置状态在 API 调用前丢失
状态:已确认
证据:settings.beforePersist 记录了 enabled=false,而 UI 事件记录了 enabled=true。
H2 API 拒绝该值
状态:已拒绝
证据:本次复现中没有发生 API 调用。
下一步:修复 onToggle 和 saveSettings 之间的本地状态交接。
如果每个假设都是 REJECTED(已拒绝)或 INCONCLUSIVE(尚无结论),则从不同的子系统生成新假设并添加更窄的探针。不要凭感觉打补丁。
故障排除
- 日志为空:确认应用执行了插桩路径,会话 ID 匹配,并且端点包含
/log。 - 浏览器请求被阻止:检查混合内容、CSP 的
connect-src、扩展隔离或 content-script 上下文。 - CORS/预检问题:收集器处理
OPTIONS;如果仍然失败,尝试navigator.sendBeacon、同源开发服务器代理或服务器端插桩。 - 主机被拒绝:使用
127.0.0.1、localhost或::1;切勿绑定到局域网或公共接口。 - 沙箱阻止监听器:使用所需的批准重试一次此回环收集器。如果批准被拒绝,说明本地收集被阻止,并且仅当存在安全的基于文件的探针路径时才回退。
- 日志过多:用更窄的状态变化探针替换嘈杂的探针。
- 无法复现:询问确切的步骤、环境、输入数据或屏幕录制;不要凭空编造修复。
清理清单
在声明任务完成之前:
- 重新运行原始复现步骤,或最接近的可用自动化检查。
- 移除每对标记为
DEBUG_MODE_PROBE <session_id>的区域。 - 搜索会话 ID、
DEBUG_MODE_PROBE、#region DEBUG_MODE_PROBE和#endregion DEBUG_MODE_PROBE。 - 移除打印的
LOG_FILE处的会话 NDJSON 日志,或确认应将其保留为本地证据。 - 仅保留产品修复和任何有用的回归测试。