diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0a75968..b58d885b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,7 +236,6 @@ jobs: set -euo pipefail # 列名:粒度|目标|原因|修复单号 (用 | 分隔,原因内可含空格) 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/kernelmod/all|*(整包)|该包把真实整机装起来(bootgraph_test.go 的整机判据) ⇒ 第 4 层 agent 与 plugin-host 并行 Init 时,双方都无锁直写同一 plugin.Registry 的 7 个 Set*(SetLuaVM/SetBaseAPIKey/SetSupervisor/SetTracker/SetConfig/SetStageHost/SetIndexer,registry.go:231-284)。竞争在**内核装配**里,不在本包代码里;任何装整机的用例都会撞上。★ 目标包随 ID:13 迁到此(原 internal/kernelboot/modules 已删)|KERNEL-REGISTRY-SETLOCK EOF @@ -330,38 +329,26 @@ jobs: # ── 证据步骤:把"已知红"变成每次 CI 都可核对的数字 ── # # ★ 这里**不用 continue-on-error 混过去**(那是"假装没红")。 - # 做法相反:显式断言两件事都成立,任一不成立 ⇒ 这一步**真红**: - # ① webui 那条竞争**确实还在**(报告数 > 0)—— 证明排除表没白排除 - # ② 内核那 7 个 Set* **确实还无锁**(栈里出现 registry.go 的 Set*) - # 修好之后这两条会自然失败,提醒去删排除表 —— 这是**期望的**失败, + # 做法相反:显式断言这件事成立,不成立 ⇒ 这一步**真红**: + # 内核那 7 个 Set* **确实还无锁**(形态仍是单行直写) + # 修好之后这条会自然失败,提醒去删排除表 —— 这是**期望的**失败, # 报错信息里直接写了该做什么。 + # (webui 那条排除项已于 2026-10-24 撤除:7457b05 改成 w 单写者模型, + # 没给 gzip.go 加锁 ⇒ 原静态判据 sync_fields/lock_calls 两值恒为 0, + # 判据永不触发,该证据从此只会假绿 ⇒ 故连同排除行一并删除。) + # 撤除时本地核对(原文,不作为判据):该用例在 -race 下单跑 5 次, + # 均 0 条 WARNING: DATA RACE 报告;但用例本身未正常退出 + # (SIGQUIT: quit / signal arrived during execution,耗时 11~30s, + # 退出码非 0),故此数据不能当"已修"的证据。 + # ★ 不留"跑 5 次 0 条 DATA RACE"这类替代证据步骤:排除项已删、 + # 该用例已回到主 go test -race 门里跑,再单独留一次"跑 N 次 0 条" + # 等于拿偶发概率充判据——正是本次撤除要清掉的坏判据,换个地方 + # 再种一遍没有意义。 - name: 已知红的可核对证据(修好后本步会红,提醒删排除项) run: | set -uo pipefail fail=0 - echo "=== ① webui: gzipResponseWriter 无锁并发写(修复单 WEBUI-GZIP-RACE)===" - # - # ★ 同样**不**赌竞争必现:实测该竞争单跑 3/8 命中(偶发), - # 拿"报告数>0"当断言会在没撞上的那 5 次假绿。 - # 改成**静态断言**:struct 无 sync 字段 且 commit 不取锁 ⇒ 无锁仍在。 - # 修好(加锁)后两条件之一变化 ⇒ 本条失败 ⇒ 提醒删排除表。 - GZ=internal/plugins/webui/gzip.go - sync_fields=$(awk '/type gzipResponseWriter struct/,/^}/' "$GZ" | grep -c 'sync\.' || true) - lock_calls=$(awk '/func \(g \*gzipResponseWriter\) commit\(/,/^}/' "$GZ" \ - | grep -cE '\.Lock\(\)|\.RLock\(\)' || true) - echo " gzipResponseWriter 的 sync 字段数: $sync_fields" - echo " commit() 内的加锁调用数: $lock_calls" - if [ "$sync_fields" -ne 0 ] || [ "$lock_calls" -ne 0 ]; then - echo "::error title=webui gzip 竞争可能已修::WEBUI-GZIP-RACE 的锁已补(sync字段=$sync_fields 加锁=$lock_calls)—— 请从 ci.yml 排除表删掉该行,并删掉本证据步骤" - fail=1 - fi - - # 附:顺带跑一次,把当前是否撞上记进日志(**不作为判据**) - out=$(go test -race ./internal/plugins/webui/ \ - -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 次撞不到 @@ -389,7 +376,7 @@ jobs: if [ "$fail" -ne 0 ]; then exit 1 fi - echo " 证据核对完成:两个排除项对应的缺陷均仍在(排除表有效)" + echo " 证据核对完成:排除项对应的缺陷仍在(排除表有效)" # ── 交叉编译:可在无 cgo 下构建的客户端/工具 ── #