pi 通读后逐处指出,三条都实测复现:
**1. `jsonTestOnlyChange`/`testOnlyDrift`/`runtimeOnly` 没有任何自检碰过。**
他的质疑成立:我上一封说"配了六个样本",那六个样本是**开发时的内联脚本、没进文件**
(他读了全文,找不到——我核了,确实没有)。而这段逻辑是文件里**唯一一处"把红变成绿"
的代码**,也是唯一没有判据的代码,失效方向恰好是"比恒黄更坏"那个(假绿)。
已补 **4 条走真路径的样本**(真临时树 + `diffSummary(d,{repoDir,snapDir})`):
★只差 `scripts.test` ⇒ 不算运行时漂移且必须说出豁免了哪条键;
★`scripts.start` 变了 ⇒ 必须算运行时;★解析不了 ⇒ 不许豁免;★不传 ctx ⇒ 不豁免。
★ 写样本时被一对**同义不同数**的字段绊住:断言 `runtimeDrift === 0` 却得到 1 ——
`diffSummary` 报的是**原始**检测数,而 `checkHost` 自己又减了一遍豁免。
判据自己产出两个矛盾口径,与"注释里两组矛盾的写点计数"同族 ⇒ **统一**:
`runtimeDrift` = 减掉豁免后的结论,被豁免的只出现在 `testOnly` 里;
`checkHost` 删掉自算的 `runtimeOnly`。不传 ctx 时行为与旧版逐字相同。
**2. `prune-deploy-artifacts.sh` 的 `del()`:`rm` 的结果没人看。**
脚本是 `set -uo pipefail`(**无 -e**)⇒ `rm -rf` 失败(权限/只读挂载/immutable)后
照样打"删除 …(NMB)"、收尾汇总"**已删除 N 项,释放约 X MB**"
——**一次失败之后仍产出成功措辞**(与 `redeploy-plugin.sh` 里"被拒还打 [ OK ]"同族)。
已改:判失败即报错 `exit 2`;`removed`/`freed_kb` **只在成功后累加**;并加抽验
(`rm` 报成功但路径还在 ⇒ 报错),不信单一退出码。
⚠️ **这一条的失败路径我没能实测**:本机以 root 跑,权限拦不住 `rm`;
`unshare -r` 建只读挂载被拒(`/proc/self/uid_map: Permission denied`);
tmpfs 无 `chattr +i`。要覆盖得在带 CAP_LINUX_IMMUTABLE 的环境用 immutable 文件,
或给 `del()` 加 `RM` 注入点。**我没有把"改过"说成"验过"。**
**3. `check-shared-libs.sh` 的 `show_diff` 被 `set -e` 当场中止。**
`cmp` 有差异返回 1 ⇒ `pipefail` 让函数返回 1 ⇒ 独立调用触发 `set -e` ⇒ **脚本当场死**。
实测(脚本级,fixture 树里造两处分叉:pi 与 zcode):
旧版:报告 1 处分叉、收尾汇总 0 次
新版:报告 2 处分叉、收尾汇总 0 次(收尾那句本来只在成功时打,见下)
两者退出码都是 1(判定一直是对的)—— 所以**光量退出码看不见这个 bug**,
正是 pi 说的"判定对、证据被截断"。而且旧版连 `fail=1` 都执行不到:
退出码 1 是 `set -e` 给的。加 `|| true` 后遍历跑完。
136 lines
6.4 KiB
Bash
Executable File
136 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 共用模块必须逐字节相同 —— 见 docs/PLUGIN-CONTRACT.md 第六节。
|
||
#
|
||
# 一侧改了另一侧没改,几个平台的行为就会悄悄分叉:同一封邮件在 opencode 那边
|
||
# 标了已读、在 DSH 那边没标,而两处代码看起来都"对"。
|
||
#
|
||
# 比对一律以 opencode 为基准逐个对比,而不是两两对比:后者在三方都不同时
|
||
# 会打出三条互相矛盾的差异,读的人无从判断谁是对的。
|
||
#
|
||
# # 为什么每个 peer 的清单不同
|
||
#
|
||
# 四个插件共用的是**协议无关**的那几个模块(地址解析、收件箱渲染、附件 id 归一…),
|
||
# 但各自用到的子集不同:
|
||
#
|
||
# - pi / dsh / opencode 是邮件驱动的**桥**,需要会话快照、中继去重、SSE 客户端等;
|
||
# - zcode-mail-bridge 目前是 **MCP 工具服务器**(模型侧的工具面),
|
||
# 不订阅 SSE、不管会话生命周期,所以只需要那 5 个协议无关模块。
|
||
#
|
||
# 用「对等清单」会逼它拷一份用不到的 relay/session 模块进来 —— 那些文件
|
||
# 永远不会被执行,却要跟着一起同步,反而让「哪些是真的共用」变得看不清。
|
||
# 于是改成显式列举:**声明共用就必须逐字节相同**,声明之外的模块不检查
|
||
# (因为根本没拷过来,结构上就不可能分叉)。
|
||
set -euo pipefail
|
||
BASE=plugins/opencode-mail-bridge
|
||
PEERS=(plugins/dsh-mail-bridge plugins/pi-mail-bridge plugins/zcode-mail-bridge)
|
||
|
||
ALL_LIBS="relay-dedup relay-policy relay-key permission-mode bounded inbox-format session-snapshot workspace model-scope catchup addressing discovery rename-proposal permission-grants adopt sse-client user-question attachment-ids"
|
||
ALL_TESTS="relay-policy relay-key permission-mode bounded inbox-format session-snapshot workspace model-scope catchup addressing discovery rename-proposal permission-grants adopt sse-client user-question attachment-ids"
|
||
|
||
# MCP 工具服务器 + 授权钩子 + 邮件驱动用到的子集(实现与测试都同步)。
|
||
#
|
||
# 钩子与驱动这一层额外需要:
|
||
# permission-mode / relay-key / permission-grants / sse-client
|
||
# —— 档位语义、relay_key 截断、决策判定、SSE 帧解析
|
||
# catchup / relay-policy / workspace / relay-dedup
|
||
# (relay-dedup 在基准那边也没有独立测试,故只比对实现)
|
||
# —— 停机补投、主动发信去重、回信策略、工作目录解析
|
||
#
|
||
# 这些都不能各平台自己写一份:「同意」的含义、谁该收到回信、同一封邮件
|
||
# 会不会被转两次 —— 分叉的后果都是只在单平台复现的行为差异。
|
||
MCP_LIBS="addressing inbox-format bounded discovery attachment-ids permission-mode relay-key permission-grants sse-client catchup relay-dedup relay-policy workspace"
|
||
MCP_TESTS="addressing inbox-format bounded discovery attachment-ids permission-mode relay-key permission-grants sse-client catchup relay-policy workspace"
|
||
|
||
# ── 判据:用 cmp,不用 diff ─────────────────────────────────────────
|
||
#
|
||
# 本机 PATH 上的 `diff` **不是 GNU diff**,而是鸿蒙 SDK 工具链里的
|
||
# /opt/huawei/harmonyos/ohos-sdk/linux/toolchains/diff。它不认 `-q`,
|
||
# 却对**内容不同的文件照样返回 0** —— 于是 `if ! diff -q ... >/dev/null`
|
||
# 恒为假,整支脚本变成永真输出(本检查器曾长期如此,实测才发现)。
|
||
# cmp 的语义明确:相同 0、不同 1。
|
||
same() { cmp -s "$1" "$2"; }
|
||
|
||
# 判据本身必须先被验证。否则「比较永远说相同」与「真的都相同」
|
||
# 在结果上完全一样,而这正是上面那个坑的形状。
|
||
selfcheck() {
|
||
local a b
|
||
a=$(mktemp) && b=$(mktemp)
|
||
printf 'x\n' >"$a"
|
||
printf 'y\n' >"$b"
|
||
if same "$a" "$b"; then
|
||
echo "检查器自检失败:比较函数无法发现差异(别用 PATH 上的 diff)" >&2
|
||
exit 1
|
||
fi
|
||
printf 'y\n' >"$a"
|
||
if ! same "$a" "$b"; then
|
||
echo "检查器自检失败:相同内容的两个文件被判为不同" >&2
|
||
exit 1
|
||
fi
|
||
rm -f "$a" "$b"
|
||
}
|
||
selfcheck
|
||
|
||
libs_for() {
|
||
case "$1" in
|
||
*zcode-mail-bridge) echo "$MCP_LIBS" ;;
|
||
*) echo "$ALL_LIBS" ;;
|
||
esac
|
||
}
|
||
|
||
tests_for() {
|
||
case "$1" in
|
||
*zcode-mail-bridge) echo "$MCP_TESTS" ;;
|
||
*) echo "$ALL_TESTS" ;;
|
||
esac
|
||
}
|
||
|
||
# 差异明细也走 cmp,不借 diff。
|
||
#
|
||
# ★ 末尾那个 `|| true` **是判据的一部分,不是风格**(pi 评审 2026-09-14 抓到,已实测复现):
|
||
# 本脚本是 `set -euo pipefail`,而 `cmp` 在"有差异"时返回 1 ⇒ `pipefail` 让这个函数
|
||
# 也返回 1 ⇒ 调用点 `show_diff …` 是一句独立命令,`set -e` 于是**当场中止整个脚本**。
|
||
# 实测形状(造一个分叉):
|
||
# 共用模块已分叉:f ← 打印了
|
||
# <cmp 头 3 行> ← 打印了
|
||
# ② 本该继续遍历后续文件 ← **没打印**(脚本已死)
|
||
# ③ 本该收尾报"四方同源" ← **没打印**
|
||
# 也就是说:判定(红)是对的,但**证据被截成一条**,而且连 `fail=1` 都执行不到
|
||
# —— 退出码 1 是 `set -e` 给的,不是那条赋值给的。
|
||
# 一条判据红了,却只报第一个对象、不报"我比完了全部"—— 那正是这套评审反复讲的
|
||
# "证据必须足以支持结论"。加 `|| true` 后,遍历跑完、汇总照打,红仍然是红。
|
||
show_diff() {
|
||
cmp "$1" "$2" 2>&1 | head -3 || true
|
||
}
|
||
|
||
fail=0
|
||
|
||
for peer in "${PEERS[@]}"; do
|
||
for f in $(libs_for "$peer"); do
|
||
if [[ ! -f "$peer/lib/$f.js" ]]; then
|
||
echo "共用模块缺失:$peer/lib/$f.js" >&2
|
||
fail=1
|
||
continue
|
||
fi
|
||
if ! same "$BASE/lib/$f.js" "$peer/lib/$f.js"; then
|
||
echo "共用模块已分叉:lib/$f.js($BASE vs $peer)" >&2
|
||
show_diff "$BASE/lib/$f.js" "$peer/lib/$f.js" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
# 测试同样要同源:共用模块的行为约定写在测试里,
|
||
# 只同步实现不同步测试,等于允许一侧偷偷放宽约定。
|
||
for f in $(tests_for "$peer"); do
|
||
if [[ ! -f "$peer/test/$f.test.mjs" ]]; then
|
||
echo "共用测试缺失:$peer/test/$f.test.mjs" >&2
|
||
fail=1
|
||
continue
|
||
fi
|
||
if ! same "$BASE/test/$f.test.mjs" "$peer/test/$f.test.mjs"; then
|
||
echo "共用测试已分叉:test/$f.test.mjs($BASE vs $peer)" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
done
|
||
|
||
[[ $fail -eq 0 ]] && echo " 共用模块四方同源(opencode 基准 vs dsh / pi / zcode)(判据已自检)" || exit 1
|