mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 06:47:29 +00:00
chore(id10): 摘掉两份交给 CI 线的收尾补丁——内容基于 efe0cf1,已被 ID:13/ID:17 作废
ID10_CI_CLOSEOUT.md 与 id10_ci_closeout.patch 是给 CI 线(ci/boot-graph-tests) 合入用的交付物,不属于本修复分支的代码改动,故从仓库摘出、改走消息渠道交付。 为什么删而不是保留:补丁自称基准是 ci/boot-graph-tests@efe0cf1(实测对该提交 git apply --check EXIT=0),但对 CI 线当前 headcaf1b71三个 hunk 全部失败, 且是**事实变更**而非行号漂移: · 3864f36(ID:13)删死包 internal/kernelboot/modules,整机判据迁到 internal/kernelmod/all ⇒ 排除行的包名已变,补丁仍按旧包名匹配 · 6d04bd2(ID:17)撤了 webui 那条 test 级排除与证据步① ⇒ 补丁尾部要删的 「两个排除项对应的缺陷均仍在」一行在 CI 线上已不存在 · 文档里的复跑命令 ./internal/kernelboot/modules/ 在本分支上没有测试文件 (该 registry_test.go 来自 CI 线 ed8f28e),所述 25/25 证据无法按其字面复现19c78ca本身不动:它的 SHA 是两条判据 head 的证据。补丁内容改由收尾消息交付。
This commit is contained in:
@ -1,112 +0,0 @@
|
||||
ID:10 / KERNEL-REGISTRY-SETLOCK 收口补丁(CI 侧)
|
||||
================================================
|
||||
|
||||
## 这个文件是什么
|
||||
|
||||
ID:10 的收口要求里,有三条是**落在 CI 线(ci/boot-graph-tests)**上的,
|
||||
不在本分支(fix/registry-setlock,基于 f408448)的改动范围内:
|
||||
|
||||
1. 删掉 ci.yml race 门排除表里 `internal/kernelboot/modules` 那一行
|
||||
2. 删掉 evidence 步骤 ② 的内核 setter 静态断言
|
||||
3. 更新那段"整包永久排除不被接受"的警告框为收口记录
|
||||
|
||||
本分支**不许碰 ci.yml**(任务边界),所以这三步没有在本分支落地,
|
||||
而是做成下面这份可评审的补丁,交给 CI 线合入。
|
||||
|
||||
## 补丁内容(已在本机实测通过,见下)
|
||||
|
||||
patch: id10_ci_closeout.patch(相对路径 a/.github/workflows/ci.yml,
|
||||
可直接 `git apply`;对 ci/boot-graph-tests@efe0cf1 的 ci.yml)
|
||||
|
||||
改动只有三处,全部是"删排除 + 记录收口",无新增门禁逻辑:
|
||||
|
||||
① 排除表:删掉 `pkg|internal/kernelboot/modules|…|KERNEL-REGISTRY-SETLOCK` 整行
|
||||
⇒ 该包重新纳入 -race(这正是本次修复的目的:它现在跑 -race 是绿的)
|
||||
|
||||
② evidence 步骤:删掉 ② 整段(查 7 个 Set* 是否仍"单行无锁直写"的静态断言)
|
||||
⇒ 它存在的唯一目的是"修好后提醒去删排除项",排除项已删,它已完成使命
|
||||
⇒ 收尾提示语从"两个排除项…仍在"改为"webui 排除项…仍在"
|
||||
|
||||
③ 警告框:把"唯一出口是给 Set* 加锁,修好后做三步"改成"已收口"记录,
|
||||
并写清"去重不能替代加锁"的实测结论
|
||||
|
||||
## 为什么删完排除项后门禁仍然有效(实跑验证)
|
||||
|
||||
排除表删到只剩 webui 一项后:
|
||||
· `pkgs=` 为空 —— 剔除循环 `for e in $EXCL` 不执行,无断言误报
|
||||
· `tests=TestOpenAIStreamIsActuallyStreaming` —— test 级排除照常生效
|
||||
· `count=1` —— 表还在,机制没被架空
|
||||
|
||||
实测(本机 bash 跑该步骤原文):
|
||||
|
||||
════════ -race 排除表 ════════
|
||||
[1] test 级: TestOpenAIStreamIsActuallyStreaming
|
||||
包: internal/plugins/webui
|
||||
原因: gzipResponseWriter 的 mode/wroteHeader/buf 无锁;…
|
||||
修复单: WEBUI-GZIP-RACE
|
||||
════════ 共排除 1 项(不是静默跳过:每次 CI 都打印本表)════════
|
||||
EXIT=0
|
||||
--- GITHUB_OUTPUT ---
|
||||
tests=TestOpenAIStreamIsActuallyStreaming
|
||||
pkgs=
|
||||
count=1
|
||||
|
||||
## 为什么这个补丁不是"拍脑袋认为 CI 会绿"
|
||||
|
||||
按 ID:10 收口要求第 2 条「**复跑一次** -race 确认整机判据在 -race 下也稳定」,
|
||||
在**修复后**的代码上重复跑了 25 次整机判据(未删排除项条件下的同一条命令):
|
||||
|
||||
go test -race ./internal/kernelboot/modules/ -count=1 -timeout 10m
|
||||
|
||||
修复后:25/25 次 0 条 DATA RACE,全部 ok(本线 f408448 + 修复补丁实测)
|
||||
修复前(同一棵树、同一命令):2/25 次报红,累计 14 条 DATA RACE
|
||||
|
||||
修复前那次的原始栈(证明命中的正是本单缺陷,不是别的竞争):
|
||||
|
||||
WARNING: DATA RACE
|
||||
… internal/kernelmod/agent.wirePluginSDK()
|
||||
internal/kernelmod/agent/mod.go:251 (SetLuaVM)
|
||||
internal/kernelmod/agent/mod.go:252 (SetBaseAPIKey)
|
||||
… :253 :254 :255 :256 :257
|
||||
… internal/kernelmod/pluginhost.injectBaseDeps()
|
||||
internal/kernelmod/pluginhost/mod.go:289 (SetLuaVM)
|
||||
… :290 :292 :294 :295 :296 :299
|
||||
… internal/plugin/registry.go:231 (SetLuaVM 无锁直写)
|
||||
… internal/plugin/registry.go:232 (SetBaseAPIKey 无锁直写)
|
||||
… internal/plugin/registry.go:271 / :272
|
||||
|
||||
即:agent 与 plugin-host 两个 goroutine 在第 4 层并行写同一批字段,
|
||||
与 ID:10 描述完全一致。
|
||||
|
||||
## 另一个边界:去重不能替代加锁(实测)
|
||||
|
||||
本次同时做了"去掉重复注入",但**它替代不了加锁**。做了对照实验:
|
||||
回退 registry.go 到未加锁版、只保留 agent 侧去重(即 injectBaseDeps 不动),
|
||||
然后人为制造"去重后仍然存在的写-读并发":
|
||||
|
||||
写侧:agent 侧去重后**保留**的 SetStatusProvider
|
||||
读侧:pluginhost 侧加载插件时 buildSDK 读 r.status
|
||||
|
||||
结果:**1 条 DATA RACE**(SetStatusProvider vs buildSDK),即去重后竞争仍在。
|
||||
所以 registry 侧的锁才是修复本体,去重只是消除了 7 项无意义的重复写。
|
||||
|
||||
## 应用方式
|
||||
|
||||
在 ci/boot-graph-tests 分支上:
|
||||
|
||||
git checkout ci/boot-graph-tests
|
||||
git apply id10_ci_closeout.patch
|
||||
python3 .github/scripts/check-ci-gates.py # 应通过
|
||||
git commit -m "ci: ID:10 收口 —— 删掉 kernelboot/modules 的 -race 排除项"
|
||||
|
||||
## 验收清单(全部已在本机实测)
|
||||
|
||||
[x] go build ./... 0
|
||||
[x] go vet ./... 0
|
||||
[x] gofmt(改动文件) 干净
|
||||
[x] check-ci-gates.py 通过(EXIT=0)
|
||||
[x] 排除表步骤实跑 EXIT=0,pkgs 为空、tests 有值
|
||||
[x] -race 整机判据 25 次 0 条 DATA RACE
|
||||
[x] -race 内核三包全量(kernelboot/plugin/kernelmod) 全 ok,0 条 DATA RACE
|
||||
[x] 门禁脚本仍能咬住(变异 A:缺原因 ⇒ EXIT=1) ✔
|
||||
[x] 门禁脚本仍能咬住(变异 B:判空改 false + 留文案 ⇒ EXIT=1) ✔
|
||||
@ -1,84 +0,0 @@
|
||||
--- a/.github/workflows/ci.yml
|
||||
+++ b/.github/workflows/ci.yml
|
||||
@@ -220,13 +220,31 @@
|
||||
# ║ ① 让 ~4% 的偶发红进主干(长红 ⇒ 所有人学会忽略 ⇒ 整道门失效) ║
|
||||
# ║ ② 先挡住、同时派单修根因(本表选这条) ║
|
||||
# ║ ║
|
||||
- # ║ **整包永久排除不被接受。** 唯一出口是给 plugin.Registry 的 Set* ║
|
||||
- # ║ 加锁(修复单 KERNEL-REGISTRY-SETLOCK),修好后: ║
|
||||
- # ║ · 删掉本表里 kernelboot/modules 那一行 ║
|
||||
- # ║ · **复跑一次** -race 全仓确认整机判据在 -race 下也稳定 ║
|
||||
- # ║ · 删掉 evidence 步骤 ② 的静态断言 ║
|
||||
- # ║ 这三步没做完,本线不算收口。 ║
|
||||
+ # ║ **整包永久排除不被接受。** 本表目前**已经没有** pkg 级条目。 ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
+ #
|
||||
+ # ── 已收口:KERNEL-REGISTRY-SETLOCK(2026-10-24)──
|
||||
+ #
|
||||
+ # 原先这里有一条 pkg 级排除 `internal/kernelboot/modules`:
|
||||
+ # 该包把真实整机装起来 ⇒ 第 4 层 agent 与 plugin-host 并行 Init 时,
|
||||
+ # 双方都无锁直写同一 plugin.Registry 的 7 个 Set*。竞争在**内核装配**里,
|
||||
+ # 不在该包代码里,所以任何装整机的用例都会撞上(实测约 4%)。
|
||||
+ #
|
||||
+ # 已修(分支 fix/registry-setlock):plugin.Registry 的 24 个 Set* 全部取写锁,
|
||||
+ # 读侧(buildSDK)改为"一次 RLock 取整组快照后立刻放锁",读侧仍是 RLock。
|
||||
+ # 并按"必要性不对称"去掉了 agent.wirePluginSDK 与 pluginhost.injectBaseDeps
|
||||
+ # 的重复注入(保留 pluginhost 侧 —— 它不依赖 agent,是"插件不等 agent 35 秒"
|
||||
+ # 的那半边;agent 侧只留 SetStatusProvider)。
|
||||
+ #
|
||||
+ # 收口三步**已全部做完**,故本表删掉了那一行:
|
||||
+ # · 删掉 kernelboot/modules 排除行 ✔(本提交)
|
||||
+ # · 复跑 -race 确认整机判据在 -race 下稳定 ✔(25/25 无 DATA RACE;
|
||||
+ # 修前同条件 2/25 报红、累计 14 条)
|
||||
+ # · 删掉 evidence 步骤 ② 的内核 setter 静态断言 ✔(本提交)
|
||||
+ #
|
||||
+ # ★ 注意:**去重不能替代加锁**(已实测)。去重后 agent 侧仍写
|
||||
+ # SetStatusProvider,而 pluginhost 侧可能同时 buildSDK 读 status ⇒
|
||||
+ # 写-读竞争仍在(实测报 1 条 DATA RACE)。所以 registry 侧的锁才是修复。
|
||||
- name: 计算 -race 排除表并打印
|
||||
id: skip
|
||||
run: |
|
||||
@@ -234,7 +252,6 @@
|
||||
# 列名:粒度|目标|原因|修复单号 (用 | 分隔,原因内可含空格)
|
||||
read -r -d '' TABLE <<'EOF' || true
|
||||
test|internal/plugins/webui|TestOpenAIStreamIsActuallyStreaming|gzipResponseWriter 的 mode/wroteHeader/buf 无锁;handler goroutine(发 finish/[DONE])与增量写 goroutine 并发写同一 ResponseWriter(gzip.go:139 读 mode vs gzip.go:206 写 mode)|WEBUI-GZIP-RACE
|
||||
- pkg|internal/kernelboot/modules|*(整包)|该包把真实整机装起来 ⇒ 第 4 层 agent 与 plugin-host 并行 Init 时,双方都无锁直写同一 plugin.Registry 的 7 个 Set*(SetLuaVM/SetBaseAPIKey/SetSupervisor/SetTracker/SetConfig/SetStageHost/SetIndexer,registry.go:231-284)。竞争在**内核装配**里,不在本包代码里;任何装整机的用例都会撞上|KERNEL-REGISTRY-SETLOCK
|
||||
EOF
|
||||
|
||||
tests=""; pkgs=""; n=0
|
||||
@@ -359,34 +376,10 @@
|
||||
-run 'TestOpenAIStreamIsActuallyStreaming' -count=1 -timeout 5m 2>&1 || true)
|
||||
echo " (参考)本次 DATA RACE 报告数: $(echo "$out" | grep -c 'WARNING: DATA RACE')(偶发,0 不代表已修)"
|
||||
|
||||
- echo "=== ② kernel: agent↔plugin-host 无锁直写 plugin.Registry(修复单 KERNEL-REGISTRY-SETLOCK)==="
|
||||
- #
|
||||
- # ★ 这里**不跑**偶发竞争来当证据 —— 实测该竞争单步跑 6/6 次撞不到
|
||||
- # (它要 92 包并发压满才容易命中),拿它当断言必然假绿。
|
||||
- # 改成**静态断言**:直接查那 7 个 Set* 是否仍是"单行无锁直写"形态。
|
||||
- # 修好(改成取锁)后形态变化 ⇒ 本条失败 ⇒ 提醒删排除表。因果稳定。
|
||||
- SETTERS="SetLuaVM SetBaseAPIKey SetSupervisor SetTracker SetConfig SetStageHost SetIndexer"
|
||||
- REG=internal/plugin/registry.go
|
||||
- locked=0; total=0
|
||||
- for fn in $SETTERS; do
|
||||
- total=$((total + 1))
|
||||
- if grep -qE "^func \\(r \\*Registry\\) ${fn}\\([^)]*\\)[[:space:]]*\\{[^}]*\\}[[:space:]]*$" "$REG"; then
|
||||
- : # 仍是单行直写(未加锁)
|
||||
- else
|
||||
- echo " 已不再是无锁单行: $fn"
|
||||
- locked=$((locked + 1))
|
||||
- fi
|
||||
- done
|
||||
- echo " 仍为无锁直写的 Set*: $((total - locked))/$total"
|
||||
- if [ "$locked" -gt 0 ]; then
|
||||
- echo "::error title=内核 setter 已加锁::KERNEL-REGISTRY-SETLOCK 可能已被修复($locked/$total 个 Set* 形态已变)—— 请从 ci.yml 排除表删掉 kernelboot/modules 那一行"
|
||||
- fail=1
|
||||
- fi
|
||||
-
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
- echo " 证据核对完成:两个排除项对应的缺陷均仍在(排除表有效)"
|
||||
+ echo " 证据核对完成:webui 排除项对应的缺陷仍在(排除表有效)"
|
||||
|
||||
# ── 交叉编译:可在无 cgo 下构建的客户端/工具 ──
|
||||
#
|
||||
Reference in New Issue
Block a user