diff --git a/deploy/check-require-declaration.sh b/deploy/check-require-declaration.sh index c3d3d40..8915084 100755 --- a/deploy/check-require-declaration.sh +++ b/deploy/check-require-declaration.sh @@ -99,13 +99,42 @@ fi fails=0 for f in "$@"; do - hits="$(strip_comments "$f" | grep -nE '^[[:space:]]*AGENTMAIL_REQUIRE=' || true)" - [ -z "$hits" ] && continue - while IFS= read -r h; do - [ -z "$h" ] && continue - printf ' [FAIL] %s:%s 用了裸赋值(应改为 `agentmail_require <命令…>`)\n' "$f" "${h%%:*}" >&2 - fails=$((fails + 1)) - done <<< "$hits" + # ★★ 这里**也不能**写成 `strip_comments "$f" | grep -nE …`(我第一版就是): + # 它**目前**不出事只是因为选了 `-n`(`grep -n` 要读完全部输入才退出 ⇒ 没有早退 + # ⇒ 生产者不会收到 SIGPIPE)。**换一个字母就翻面** —— pi 2026-09-25 做了可判实验: + # `-n` → `-q` 后,三个调用者的裸赋值**全部被静默漏掉**(rc 由 1 变 **0**)。 + # 我复现同一实验:现行 `-n` 报 **3** 个违规 / rc=1;改成 `-q` 报 **0** 个 / rc=**0** ✓ + # ⇒ "恰好选了不早退的那个选项"**不是正确性,是运气** —— 而它考的是同一件事: + # 判据读输入的**那一步**能不能把对象静默丢掉(`-n` 与 `-q` 只差"要不要早退")。 + # ⇒ 与 :78-82 一致:**先收集到变量,再对变量匹配(无管道)**。 + # + # ★★ 第二版(pi 指出我"只修了一半"之后重做)—— 三样一起做,才真的闭掉: + # ① **去管道**(`<<<` here-string)⇒ 生产者不会收 SIGPIPE,`-n`/`-q` 都不再有 141; + # ② **两条独立通道**:"有没有违规"用 `grep -q` 的**退出码**; + # "哪几行"用 `grep -n` 的**输出**。两者各自可靠 ⇒ 输出为空不再能冒充"没有违规"。 + # ③ ★ **不一致时 fail-closed**:若"退出码说有"而"行号通道没给出行号" + # (例如有人把取行号那处的 `-n` 写成 `-q` —— `-q` 什么都不打印), + # 则**判据内部自相矛盾** ⇒ **按"有违规"计**,并明确报出这个矛盾。 + # 我实测过少了 ③ 会怎样:只做 ①② 时,把取行号那处改成 `-q` + # ⇒ 报 **0** 个违规、rc=**0**(3 个违规**全部静默漏掉**)—— 判定又一次落在输出通道上。 + # ⇒ 记法: **"计数"与"证据"若走同一条通道,那条通道静音就等于"没有"**; + # 要要么分通道、要么**规定静音=失败侧**(本处取后者)。 + body="$(strip_comments "$f")" + _had=0 + grep -qE '^[[:space:]]*AGENTMAIL_REQUIRE=' <<< "$body" && _had=1 + _cnt=0 + while IFS=: read -r _ln _rest; do + [ -z "${_ln:-}" ] && continue + printf ' [FAIL] %s:%s 用了裸赋值(应改为 `agentmail_require <命令…>`)\n' "$f" "$_ln" >&2 + _cnt=$((_cnt + 1)) + done < <(grep -nE '^[[:space:]]*AGENTMAIL_REQUIRE=' <<< "$body") + if [ "$_had" -eq 1 ] && [ "$_cnt" -eq 0 ]; then + printf ' [FAIL] %s 有裸赋值,但**取行号的那条通道没给出任何行号** —— 判据内部不一致;\n' "$f" >&2 + printf ' 按 fail-closed 记作 1 处违规(两条通道必须都给得出,否则判定就落在单条通道上)。\n' >&2 + _cnt=1 + fi + fails=$((fails + _cnt)) + unset body _had _cnt _ln _rest done if [ "$fails" -gt 0 ]; then