fix(deploy): 占位行判据改用**行的年龄**(阈值 1 会把健康并发判成泄漏)+ 后置验证补 binrev==HEAD
两件都来自 pi 2026-09-25 的实测,我逐条复跑确认。
## ① `占位行 <= 1` 是阈值版假红(pi 127746b5,我复现)
`ClaimRelay`(INSERT 占位) 与 `BindRelayMail`(UPDATE 绑定) **不在一个事务里** ⇒
"同时有 2 个请求在飞"的正常形态**就是** 2 个占位行(t1 claim、t2 claim、t1 bind、t2 bind)。
变异(/tmp/pl/t.db:清掉化石 + 插 2 个**合法在飞**占位)
旧判据: PLACE=2 ⇒ rc=**1** [FAIL] 占位行 <= 1 ← 把健康并发判成泄漏
新判据: rc=**0**,打印"最老 = 0 分钟;其中 >10 分钟 = 0"
阈值 1 是"只有 1 个请求在飞的那天"的快照,与它要防的病(泄漏)**不正交**。
⇒ 与泄漏正交的判别量是**行的年龄**(pi 给的):正常占位行只活一个请求的时长,
泄漏行活到**下一次请求之后**。年龄与并发度无关,也与"此刻是否恰好有请求"无关。
阈值 10 分钟:远大于任何单请求(HTTP 有超时),远小于真实泄漏尺度(那行活了 12.7 天)。
断言**上界**而非"==0"—— 0 是"恰好没请求在飞",不是健康的条件。
正反两面都验(只验一面会放过退化):
健康并发 2 行 → rc=0 ✓ 13 天泄漏 + 1 健康行 → rc=**1** ✓
真库 → rc=1(那行确实 18259 分钟 ⇒ **真阳性**,非假红)
并打印年龄 ⇒ 顺带答出"泄漏了多久"(旧判据只说"多了一行")。
## ② 抑制数丢了 keying(pi dd579a8e,我复核确认)
生成器键是 `(ag, prefix(k), r)`(**已含 agent**),但**序列化/打印时把 agent 丢了** ⇒
任何人引用这个数都会以为是"仅根"口径。实测两种 keying 全局差 6 封(61/37 vs 55/43,
6 组**全是跨 agent 合并**)⇒ 名字里不写,下一个人**必重犯**。
文本: `抑制数 [keying=(agent,根) scope=全局]: …`
JSON: `suppress_full_groups_keying_agent_root_scope_global`
★ 同时补 **scope**:本脚本报的是全局;session 侧同 keying 是另一个数(4/18)——
同 keying 两个 scope 两个数,少写任一个都只能靠猜。
★ 只改名字,**数的值不动**(这是防再犯,不是纠错)。
## ③ 后置验证补 `binrev == HEAD`(pi 127746b5 §一,落在脚本而非只落检查器)
§7 那几项(服务 active / `/health` 200 / 无 panic / SSE 重连)**全都与代码版本无关** ⇒
**旧二进制跑这套清单会全绿**。2026-09-25 实证:线上是 09-19 的二进制而 §7 全过。
pi 建议落在 `redeploy-gateway.sh`,我采纳 —— 因为我昨天已把同一件事实现为
`check-deploy-drift` 判据 ⑤b,但**那个检查器没有任何自动入口**(要人手跑);
落在部署脚本里才能"装完当场就判"。
三态与 ⑤b 同口径:相等→绿 / 不等→**红**(就地回滚)/ 取不到任一侧→**不判**且必须说出来
(判红会让 `-buildvcs=false`、老构建、非 git 构建恒红)。
实测逻辑: 线上 e8b260dd vs HEAD ⇒ 红 ✓;/nonexistent/binary ⇒ warn 不判 ✓
## 验证
`bash -n` 两文件通过;`recount-relay-counts.sh --json` 合法(23 键);
`criteria-hygiene.test.mjs` 7/7 通过(改名后仍满足 check-*.sh 命名约定)。
This commit is contained in:
@ -436,6 +436,32 @@ case "$_scan2" in
|
||||
esac
|
||||
unset _scan _scan2 2>/dev/null || true
|
||||
|
||||
# 部署后的**同一次**校验:装上去的那份二进制就是当前 HEAD 建的。
|
||||
#
|
||||
# ★ 为什么必须有这一条(pi 2026-09-25 提出,我这边已实现为 check-deploy-drift 判据 ⑤b):
|
||||
# §7 上面那几项(服务 active / /health 200 / 无 panic / SSE 重连)**全都与代码版本无关** ——
|
||||
# 用一个**旧二进制**跑这套清单会**全绿**。2026-09-25 实证:线上跑的是 09-19 的二进制,
|
||||
# 而 §7 当时全过、`/health` 200 ⇒ 没有任何一项能说出"装的不是当前代码"。
|
||||
# 当时唯一的发现手段是人手动跑 `go version -m` —— 一个**不在任何门禁里**的动作。
|
||||
# ⇒ 这里把那个动作自动化:`vcs.revision` 是 Go 以明文编进二进制的(默认 -buildvcs=auto)。
|
||||
#
|
||||
# 三态(与 ⑤b 同口径,别改成两态):
|
||||
# · 相等 ⇒ 绿
|
||||
# · 不等 ⇒ **红**(就地回滚)
|
||||
# · 取不到任一侧 ⇒ 不判(`-buildvcs=false`/老构建/非 git 构建是合法的;判红会恒红)
|
||||
# 不判时**必须说出来**,否则读者分不清"比过且相同"与"根本没比"。
|
||||
_binrev="$(go version -m "$TARGET" 2>/dev/null | sed -n 's/.*vcs\.revision=//p' | head -1)"
|
||||
_headrev="$(git -C "$REPO" rev-parse HEAD 2>/dev/null)"
|
||||
if [ -z "$_binrev" ] || [ -z "$_headrev" ]; then
|
||||
warn "无法比对二进制版本(二进制 revision='${_binrev}',HEAD='${_headrev}')—— **不判**,不等于一致"
|
||||
elif [ "$_binrev" = "$_headrev" ]; then
|
||||
ok "已装二进制 = 当前 HEAD(${_binrev%"${_binrev#????????}"})"
|
||||
else
|
||||
bad "已装二进制是 ${_binrev%"${_binrev#????????}"},HEAD 是 ${_headrev%"${_headrev#????????}"} —— 装的不是当前代码"
|
||||
CHECK_FAIL=$((CHECK_FAIL+1))
|
||||
fi
|
||||
unset _binrev _headrev 2>/dev/null || true
|
||||
|
||||
echo
|
||||
echo " 仍需人工确认(脚本无法代替):"
|
||||
echo " [ ] 真实发一封邮件端到端跑通(不是只看进程起来了)"
|
||||
|
||||
Reference in New Issue
Block a user