📘 Khy-OS 文档站 🧭 新手先读:核心概念

🐞 错误自查手册 · 发给 AI,让它逐条对照

<!-- 受众: AI(直接投喂) | 用途: 排错/自查时发给 AI,让它逐条对照修 -->
<!-- 这些是发给 AI 读的内容。人类查错索引在 ../给人看/排错速查-给人.md 。 -->

🐞 错误自查手册 · 发给 AI,让它逐条对照#

本文件整篇都可直接发给 AI。发给它时说一句:「对照本手册逐条自审你刚才的改动,命中哪条就修哪条」
或出错时把最像的那条发给它。每条格式:症状 → 根因 → 定位 → 修复 → 预防。
分五类:P(AI流程) / W(小模型专属) / B(代码缺陷原型) / G(网关适配) / E(环境打包)。


§0 改代码前先过这张自查清单#

动手前逐条确认:
[ ] 我要加的东西,仓库里有没有现成实现?(先 grep,别造第二份真源)
[ ] 我的新逻辑是不是纯叶子?(零IO/确定性/绝不抛/可单测)
[ ] 有没有 KHY_XXX 门控、默认开、登记进 flagRegistry?
[ ] 门控关掉后,行为和改动前逐字节相同吗?异常 fail-soft 回退了吗?
[ ] 我的改动是不是严格超集?(只补漏/补错,没动既有正确输出)
[ ] 它真接到 executeTool/toolUseLoop/aiManagementServer 了吗?(不然不算在产)
[ ] 单文件会不会超 2500 行?
[ ] 我会不会声称"做完了"但其实没交付结论/没接线/没验证?

P 类 · AI 做事流程错误(你最容易犯)#

P1 · 声称"已落地"其实是死代码
症状:报告"已实现并接入",但线上行为没变。根因:只写了模块+隔离单测,无调用链到达它;隔离单测全绿≠在产。
定位:grep -rl "require(.*/<模块名>" services/backend/src --include=*.js | grep -vE "/<模块名>/|tests/"
修复:接到 executeTool/toolUseLoop/aiManagementServer 之一,接线处 try/catch fail-soft。预防:见 .ai/GUARDS-AI.md §0。

P2 · 为同一概念建第二份真源
症状:两套做同一件事的实现,日后改一处漏另一处。定位:.ai/GUARDS-AI.md §2 列了每个概念唯一权威实现。
修复:删新建那份,改 require 既有单一真源。预防:动手前 grep 概念关键词。

P3 · 忘加门控 / 门控默认关 / 没登记
症状:新行为硬上无法回退;或父门控关了子还在跑。定位:flagRegistry.js;守卫 check-flag-registry.js。
修复:加 KHY_XXX(default-on),登记 flagRegistry。预防:铁律 R3/R4。

P4 · 破坏了"关闭即逐字节回退"
症状:KHY_XXX=off 后行为和改动前不一致。根因:混进了顺手优化。
定位:置 KHY_XXX=off 跑同输入 diff 新旧输出。修复:新逻辑完全收进门控开分支。预防:每次改完做 gate-off 对比。

P5 · 跑了工具但没交付结论(静默截断)
症状:做了一堆 grep/read,最后只说"找到3处,逐个核对,先从第一处"就停了。根因:把进度旁白当交付。
定位:resultGuard.js(progress-only-after-tools)。修复:必须给出结论+具体改动/答案。预防:铁律 R9。

P6 · 用 --no-verify 跳守卫:撤销提交,先修红守卫再正常提交。禁止 --no-verify。

P7 · 猜规范号/撞号find docs -name '*DESIGN-ARCH*' | grep -oE 'DESIGN-ARCH-[0-9]+' | sort -u | tail -1 取最大值+1。

P8 · 幻觉引用不存在的文件/函数/flag:先 grep/find 确认目标真实存在再改;.ai/GUARDS-AI.md §3 列了已删孤儿模块。

P9 · 写成上帝组件:抽纯叶子,原文件同名别名 re-export;npm --prefix services/backend run arch:god


W 类 · 小模型/弱模型专属失败(完整设计见 docs/03_DESIGN_设计/[DESIGN-ARCH-013] 弱模型兼容.md)#

W1 · 工具结果过大撑爆上下文:小窗口(2K–8K)收大结果后截断/幻觉。定位 toolUseLoop.js _extractToolOutput()/_getActiveModelContextWindow()。现状已按窗口比例缩放(默认32768,硬截断15000),别破坏。

W2 · max_tokens 太低中途截断:已提高冷启动上限,别改回过低。

W3 · role:'tool' 被无原生函数调用模型拒收:已改写消息角色,加新适配别绕过这层。

W4 · JSON 工具调用被包在 markdown 代码块:解析器已容忍代码块内 JSON,别收窄。

W5 · 退化 no-op(echo/true/:/裸 cat):检测 isDegenerateNoOp(门控 KHY_DROP_DEGENERATE_ECHO),别破坏。

W6 · 工具名大小写变体绕过归一化:BASH/Bash/bash 都要覆盖(门控 KHY_PATCH_TOOLNAME_NORMALIZE)。

W7 · 空参数工具调用:已有空参补丁,补丁名集大小写不敏感覆盖(含 BASH/WebSearch)。

W8 · forward-promise 只承诺不交付:resultGuard.assessClosure(forward-promise)已检测追加收尾。见 P5。


B 类 · 真实代码缺陷原型(写新代码时对照做边界审查)#

B1 · 裸 startsWith 边界未锚定(目录逃逸):proj vs proj-secrets 被误判在界内。修:p===base || p.startsWith(base+sep)

B2 · 大小写未折叠(denylist 绕过).SSH/authorized_keys/.BASHRC 变体绕过。修:比较前 toLowerCase()。

B3 · 正则缺锚点/边界:glob **+/x^.*x$ 误放 backup_x;冒号 KV 未锚把 https: 当键。修:加 \b/$/分隔符边界,KV 要求键是合法裸标识符。

B4 · 越界码点崩溃(不可信输入)&#x110000;String.fromCodePoint(cp>0x10FFFF) 抛 RangeError 崩掉整次抓取。修:cp<=0x10FFFF 校验 + 整体 fail-soft。

B5 · 密钥脱敏漏现代 key(泄漏进用户文案):sk-proj-/sk-svcacct-/sk-admin- 不被脱敏。修:脱敏正则覆盖现代前缀与字符集;同缺陷可能多份内联拷贝都要修。

B6 · cron step=0 死循环(DoS)*/0for(i+=0) 死循环 100%CPU。修:step>0 校验。

B7 · slice(-0) 语义反转(静默 no-op):keepRecent:0 时 slice(-0)===slice(0),"全压缩"变"全保留"。修:n===0?[]:arr.slice(-n)

B8 · 闭包捕获过期 resolve / 监听器泄漏:setTimeout 捕获旧 resolve 致清理不跑;abort 监听器每次正常完成泄漏。修:正确作用域 resolve,正常完成也 removeListener。

B9 · 字符集解码乱码:GB2312/GBK 站恒 toString('utf-8') 乱码。修:按声明 charset 用 TextDecoder,异常回退 utf-8(门控 KHY_WEBFETCH_CHARSET,gbk 依赖 full-ICU)。

B10 · SSRF: IPv4-mapped IPv6 hex 形绕过::ffff:7f00:1(127.0.0.1)/::ffff:a9fe:a9fe(169.254.169.254云元数据)被判 public。修:hex 形归一到 IPv4 再判私网(门控 KHY_SSRF_IPV4_MAPPED_HEX)。

B11 · 破坏性命令 flag 顺序/大小写/拼写敏感rm -fr ~/-r -f/-rfv/-Rf 绕过 safe 判定。修:大小写不敏感+顺序无关 lookahead,覆盖长短形。

B12 · 数值/格式边界错档:999500 显示"1000k"应"1.0m"。修:先定档再取该档值,别跨档拼接。

B13 · 上下文告警阈值小窗口下溢为负threshold-20000 在 8k/16k 窗口变负,从 token 0 就报"100%"。修:阈值 clamp 非负/按比例算。

B 类通用预防:处理外部/不可信输入或安全判定时问自己——边界锚定了吗?大小写折叠了吗?越界/空/0/负会怎样?坏输入崩还是 fail-soft?等价表示形都覆盖了吗?


G 类 · AI 网关 / 模型适配错误#

G1 · 模型名泄漏给不认识它的通道→404冷却:auto 降级把 A 家模型带给直连 B 家的通道。定位 aiGateway.js normalizeModelForAdapter。修:每通道对非本家族模型做对称防护(非家族→null 用默认)。

G2 · 模型默认值散落硬编码:升世代改漏一处。定位守卫 check-model-hardcoding.js。修:收敛单一真源叶子,消费点门控读取。

G3 · 鉴权形态过时(JWT vs 原始 Bearer):新版单段 key 被旧 id.secret 拆分逻辑拒绝。修:按 key 形态选鉴权(含.→JWT,否则原始 Bearer)。

G4 · 请求侧新字段被丢弃:thinking/reasoning_effort 响应侧读了请求侧没透传。定位 _protocolPipeline._applyOpenAISamplingParams。修:请求侧透传。

G5 · 视觉模型误判纯文本→无谓退回OCR:llama-4/gpt-4.1/glm-4.6v/grok-4 名字不含旧片段被判 false。定位 visionCapability VISION_NAME_HINTS。修:补精确族名片段(别裸 4/gemma 免误伤)。


E 类 · 环境 / 打包 / 发布 / 守卫错误#

E1 · Node 版本过低:需 Node≥20;platform/khy_platform/cli.py 会检查。见 [OPS-MAN-028] 环境要求。

E2 · 改了仓库源码 pip 用户没变化:pip 包是打包时快照。修:按 [OPS-MAN-042] 发布手册重新打 wheel 升版发布。

E3 · 版本号多处不一致:升版时多处同步改,别只改一处。

E4 · gbk 解码依赖 full-ICU:确保 Node 带 full-ICU。见 B9。

E5 · 守卫红了不知为什么:看钩子输出指向哪个 scripts/check-*.js,对照 R7 守卫清单修。

E6 · node:test 传目录幽灵失败 / describe 未定义:node --test 传具体文件而非目录;jest 用例用 jest 跑、node:test 用例用 node:test 跑,别混。

E7 · 磁盘膨胀 / 运行时目录当源码找:.khy/cache/data/.tmp 是未纳入版本库的运行时产物,源码看 .ai/MAP.md;数据主权根是 ~/.khyos/。


你报错/卡住时先做这三件事(别乱改)#

1) 只读体检:node services/backend/bin/khy.js maintain freshness
2) 在本手册里找最像的一条,按"根因→修复"做。
3) 还不行就把完整报错、改了哪些文件、跑了什么命令原样告诉我,别臆测硬改。