Files
efi-kernel/文档/10-验收与质量门.md
lou 2155f65c76 加"技能执行"示例驱动: 把 skill 真跑一遍 (选模型 / 拼 prompt / 校验输出 / 重试)
- 驱动/技能执行/: oneshot + system 解释器. 读自带 技能/*.json -> 按 tier 选模型 ->
  拼 prompt -> 调 OpenAI 兼容端点 -> 剥 JSON -> 逐条按档校验 -> 落盘 + 写 events
  main 档只锁外层 (plan 是数组 + 每步有 want); small 档锁死 (单值 want + 必须在契约
  清单里 + args 键白名单 + confidence 只许 0/0.5/1)
- 契约清单只读 PG 的 drivers 表拿 (不 import 别的驱动、不翻别人的文件夹);
  也支持 EFI_SKILL_CONTRACTS 显式给一份 (手工跑 / PG 不在时)
- 思考型模型把 max_tokens 吃光时, 把预算翻倍重试一次; 本机端点强制不走代理
- 驱动/Json解码: 补 provides ["Json解码:解析"] -- skill 样例里一直在用这个契约名, 之前没人提供
- 文档同步: README / 文档 02 / 文档 06 / 文档 10 (坑 27~30) / 设计 01 / 设计 05 (补记执行侧)
- .gitignore: 盖住 驱动/*/输出/ (运行时产物不进 git)
2026-09-17 12:39:10 +08:00

11 KiB
Raw Permalink Blame History

10 · 验收与质量门

底座的可信度靠四道门:类型检查、五份真机自测、AST 等价(改注释时)、端到端 11 项。 任何一道不过就是没过 —— 老板的口径:"单元测试不算测试,要真实集成测试",所以自测都真起进程、真写库。 这份文档是改完代码后照着勾的清单,末尾是全部已知坑的总表。

1. 四道门(一条命令一跑)

cd ~/桌面/工作区/内核

uvx --from pyright pyright                       # 门 1: 微软 pyright 严格档 -> 0 errors 0 warnings
                                                 # (项目根 pyrightconfig.json: strict + extraPaths)
for t in 自测进程 自测内核 自测配置 自测db 自测日志; do
  ./.venv/bin/python 内核/$t.py || echo "❌ $t";  # 门 2: 五份真机自测
done
python3 内核/自测AST等价.py <改前备份> <现在的文件>   # 门 3: 只改注释/文档串时证明逻辑零动
python3 试跑引导器.py                             # 门 4: 端到端 11 项, PASS 11 / FAIL 0 / 残留无

2. 五份自测(真机、不 mock

自测 项数 覆盖什么 会不会碰生产
内核/自测进程.py 11 真起进程、独立进程组、/proc 判活、pid 复用不认领、SIGTERM 收子树、秒退只读本次日志 只写 内核/logs/自测进程/gitignore 里)
内核/自测内核.py 58 纯逻辑:脏配置 / 契约匹配 / 成环 / 状态机 / 拼命令 / 该拉起 不碰 PG、不写注册表
内核/自测配置.py ~10 环境.efi.json 解析、版本比较、包要求解析 只读
内核/自测db.py 182+ 真库真 SQL:8 张表 / 43 函数(11 组:建表 / 注册表 / 状态白名单 / 事件 / 扫描 / 命令 / 调用(含同锁回归)/ LISTEN-NOTIFY / 咨询锁 / 引导器台账 / 清场终检) _自测db_ 前缀 + 事务回滚 + 两道终检;跑完 8 张表逐表行数与开跑前一致
内核/自测日志.py 86 级别门槛 / 行解析 / 写 / 尾读过滤 / 真轮转 6MB 超限文件 / 真起子进程跟日志 / 选项解析(含报错分支)/ JSON Lines / 真起进程验分隔头 / 清场 全部在 tempfile.mkdtemp() 里;开头结尾拍生产 内核/logs/*.log 快照核对

跑法:./.venv/bin/python 内核/自测XXX.py0 退出 = 全过自测内核.py 打印 通过 58 / 失败 0)。

3. 门 1:类型检查(微软 pyright 为准)

  • 项目根必须有 pyrightconfig.jsontypeCheckingMode: strict + extraPaths: ["内核"])和 .vscode/settings.json python.analysis.extraPaths: ["内核"])。没这两个,中文模块名(import db/进程/日志)解析不了 → 先报 3 条"无法解析导入",再级联出几百条"类型未知"假警报。
  • 判据是微软 uvx pyright(与 Pylance 同引擎)。uvx --from basedpyright basedpyright 只当补充: 2026-09-16 实测它把同一份 扫描.py 的 6 errors + 2 warnings 报成 0/0,拿它交差被老板抓过。
  • 两个已知告警怎么收干净:
    1. field(default_factory=list) → 写全类型参数:list[dict[str, Any]] / dict[str, str] / list[tuple[str, str]], 否则 pyright 拿工厂返回类型当字段类型,判 list[Unknown]
    2. import psycopg2reportMissingModuleSource(编译轮子只有 .so):.venvtypes-psycopg2 (已记进 环境.efi.jsonpackagesrequired: false+ 那两行加 # pyright: ignore[reportMissingModuleSource]
  • 它是能抓真 bug 的:同一轮里靠它抓出 main() 漏传 配置 参数(裸跑直接 TypeError)。

4. 门 3:AST 等价(只改注释时用)

cp 内核/内核.py /tmp/基准.py          # 1 先备份
# ... 改注释 / 换标点 ...
python3 内核/自测AST等价.py /tmp/基准.py 内核/内核.py

判据:输出 [OK] AST 完全等价 就过;若打印 diff只剩"字符串常量里的标点差异"也算通过 (那是文案,不是逻辑)。人工重抄上千行抄错一行自己看不出来,这个工具 30 秒给结论。

5. 门 4:端到端 11 项(试跑引导器.py

老板亲自跑的验收:把 UEFI.boot.py 每条命令真跑一遍,每步打"命令原文 + 原样输出 + 判定",末尾汇总表。 覆盖:用法 / 体检 / 环境 --json / 包台账 / 环境状态快照 / 内核状态 / 透传列表 / 裸跑 / 内核 启动 --守护 / 内核 日志 / 内核 停止;收尾再扫一遍 /proc 确认零残留--假内核 会临时把内核入口换成只会心跳的假内核(演示"引导器管住一个常驻进程"),跑完按原样字节还原。

  合计: PASS 11 | 预期 0 | FAIL 0
  残留: 无
  结论: 全过

第 8 项"裸跑"判定是 -1 = PASS:裸跑 = 前台起常驻内核,会一直挂着(设计如此);脚本超时收掉前台壳, 真正的常驻内核留给第 11 项收。

6. 发布前 checklist(照着勾)

  • uvx --from pyright pyright0 errors / 0 warnings / 0 informations
  • 五份自测全 0 退出自测内核.py失败 0
  • python3 试跑引导器.pyPASS 11 | FAIL 0 | 残留: 无
  • ps -eo pid,cmd | grep -E "内核/内核.py|心跳.py|请求.py" | grep -v grep
  • PG 里没有自测残留:8 张表按 _自测db_ 前缀各查一次 = 0 行
  • calls 里没有卡住的 pending/waiting/running(除非真的正在跑)
  • git status 干净,且没有 logs/.venv/__pycache__/运行.efi.json 被加进来
  • 文档同步(09-扩展指南.md 末尾的同步清单逐项过一遍)
  • 设计/ 与代码一致(字段表 / 判定表 / DDL / CLI
  • 新坑写进技能 kernel-driver-framework 的坑表(否则下次自己再踩)

7. 已知坑总表(按"踩到的顺序",改代码前扫一眼)

# 防法
1 UPDATE ... ORDER BY 在 PG 里非法 排序 + 跳锁必须写子查询(WHERE id IN (SELECT … FOR UPDATE SKIP LOCKED)
2 调用成环不能拿"调用方自己"判(它就是链尾) 判据 = 要的契约匹配出的提供方已在链上
3 killpg 会把自己也收了(同一进程组) 组 == os.getpgrp() 时只 os.kill(pid)
4 oneshot 跑完就退被判成"崩了" 状态机按 mode 分支(复核拉起一个 两处)
5 前台起常驻内核会一直阻塞 脚本给超时;超时只杀直接子进程,孙进程(常驻内核)会活下来,调用方自己收
6 杀调度进程时 pgrep -f "内核/内核.py 调度" 匹配到自己 /proc/*/cmdline 拆 argv 精确比对;pkill 与启动分两条执行
7 模块级常量被同名函数遮蔽(内核日志 打印成 <function …> 路径常量统一叫 XX路径
8 RETURNING id 配默认游标返回 tuple → 行["id"] 报错 cursor_factory=RealDictCursor
9 僵尸 Z 杀不动 → 停止永远报"还有 N 个没收掉" 按"死透"判:组员跳 Z、_等死 把 Z 当已死;判活仍如实报 zombie
10 秒退时读整份日志 → 把上次的输出当本次死因 本次启动的字节偏移读(从位置读日志;分隔头写完后取偏移)
11 同锁两条请求互相排队、双双卡死2026-09-16 实测) 领调用waiting 一起领;同锁在跑 只认 running;排队也立 deadline
12 命令输出混进日志文件(引导器把内核 stdout 一起重定向) 三条道分家 + 守护模式 EFI_LOG_CONSOLE=0
13 日志轮转在运行中做 → 进程继续写老 inode(日志"丢了" 只在拉起进程之前轮转
14 -f 跟日志读到半行 → 乱码 按行缓冲(rpartition(b"\n")),半个留到下一轮;轮转/清空时位置归零
15 自测里 日志.跟 子进程传 str 而非 Path → 子进程秒退 一律传 Path(自测第 6 组抓到的)
16 无参数命令分发写成 if 命令 == "日志" and 参数: → 台账形态进不去 去掉 and 参数f"日志 {参数[0]}" 换成 ' '.join(参数)
17 自测残留检查用宽关键词("自测日志" in cmdline)把自己算进去 → 假残留 认子进程特征(如 "日志.跟(" + 临时目录)并跳过读不到的 /proc/<pid>
18 批量补空格用 \] 通配正则 → 一次改坏 430 处(-> list[str] : 只匹配来源字符 re.sub(r"】(?=\S)", "] ", s);改前整目录备份
19 basedpyright 漏报(0/0 而微软 pyright 报 6 errors 判据一律以 uvx pyright 为准
20 field(default_factory=list)list[Unknown] 工厂写全类型参数
21 extraPaths → 390 条"类型未知"假警报 项目根配 pyrightconfig.json + .vscode/settings.json
22 自测里 通知() 完立刻 poll() → 误报(NOTIFY 要等发方提交) 等通知(连接, 超时) 轮询(poll + sleep 0.05
23 自测按下标核对真值用了 db._查(私有) 用公开的 db.查(连接, sql, 参数)
24 "上游只是没启动"被算成下游"依赖失效" → 天天假警 只有上游 崩了/失败 才算(停止 不算)
25 自测想"行在就取某列"写成 行["x"] if 行 else None → 被判 reportOptionalSubscript 统一走 值(行, "列名") 助手
26 一组抛异常拖停整个自测 跑组(名称, 动作) 每组装 try/except + traceback,末了出汇总表
27 思考型模型(DeepSeek / Qwen3 系)把 max_tokens 全用在思考上 → content 回来是空串,看着像"模型没答"2026-09-17 实测:9B 思考 4000+ token 还没完,82s 空手而归) 驱动把预算翻倍重试一次(示例驱动已做);/no_thinkchat_template_kwargs: {enable_thinking:false} 只在认它的模型上有效,别指望
28 EFI_LLM_BASE 指本机(127.0.0.1)时,本机 Clash 的 http_proxy 会把请求也劫走 → 连不上模型 本机端点强制不走代理(build_opener(ProxyHandler({}))
29 8G 卡装 7.95GB 的 GLM → lms loadSIGABRT(引擎起来就死,不是 OOM 提示) --gpu 0.95 部分 offload + 用 -c 收住上下文;加载前先 nvidia-smi 看余量
30 模型输出常带 ```json 围栏或前后废话 剥 JSON 是驱动的活(示例驱动 剥JSON():先剥围栏,再退到第一个 { 到最后一个 }

新踩到的坑:先修代码,再补进这张表(以及技能里的坑表)—— 坑表是这套底座最贵的资产之一。