2155f65c76
- 驱动/技能执行/: 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)
11 KiB
11 KiB
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.py,0 退出 = 全过(自测内核.py 打印 通过 58 / 失败 0)。
3. 门 1:类型检查(微软 pyright 为准)
- 项目根必须有
pyrightconfig.json(typeCheckingMode: 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,拿它交差被老板抓过。 - 两个已知告警怎么收干净:
field(default_factory=list)→ 写全类型参数:list[dict[str, Any]]/dict[str, str]/list[tuple[str, str]], 否则 pyright 拿工厂返回类型当字段类型,判list[Unknown]。import psycopg2→reportMissingModuleSource(编译轮子只有.so):.venv装types-psycopg2(已记进环境.efi.json的packages,required: 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 pyright→ 0 errors / 0 warnings / 0 informations- 五份自测全 0 退出(
自测内核.py要失败 0) python3 试跑引导器.py→PASS 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_think 与 chat_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 load 报 SIGABRT(引擎起来就死,不是 OOM 提示) |
--gpu 0.95 部分 offload + 用 -c 收住上下文;加载前先 nvidia-smi 看余量 |
| 30 | 模型输出常带 ```json 围栏或前后废话 |
剥 JSON 是驱动的活(示例驱动 剥JSON():先剥围栏,再退到第一个 { 到最后一个 }) |
新踩到的坑:先修代码,再补进这张表(以及技能里的坑表)—— 坑表是这套底座最贵的资产之一。