From 5d9a41c3d3d9ab9ae607fd1060d29bcef2c4a02d Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 25 Sep 2026 07:01:34 +0800 Subject: [PATCH] =?UTF-8?q?=E2=98=85=20pi=20=E6=8C=87=E5=87=BA=E6=88=91"?= =?UTF-8?q?=E5=8F=AA=E4=BF=AE=E4=BA=86=E4=B8=80=E5=8D=8A":=20check-require?= =?UTF-8?q?-declaration.sh=20=E6=94=B6=E9=9B=86=E8=BF=9D=E8=A7=84=E8=A1=8C?= =?UTF-8?q?=E9=82=A3=E5=A4=84=E4=BB=8D=E6=98=AF=E7=AE=A1=E9=81=93=EF=BC=9B?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=20-n=E2=86=92-q=20=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E6=BC=8F=E6=8E=89=E5=85=A8=E9=83=A8=203=20=E4=B8=AA=E8=BF=9D?= =?UTF-8?q?=E8=A7=84=20=E2=87=92=20=E5=88=A4=E6=8D=AE=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E8=90=BD=E5=9C=A8**=E8=BE=93=E5=87=BA=E9=80=9A=E9=81=93**?= =?UTF-8?q?=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ★ pi 的实验我复现: 现行 `grep -n` 报 3 个违规/rc=1;改成 `grep -q` ⇒ 报 **0** 个/rc=**0**(3 个全漏) ⇒ 它**目前**不出事只因"恰好选了不早退的那个选项"(-n 要读完全部输入 ⇒ 无 SIGPIPE) ⇒ **那不是正确性,是运气**。与我上一版在 :78-82 修的是同一条,我却漏了 :102。 ★ 修法**三样一起做**(我做前两样后**实测仍有洞**,故补第三样): ① 去管道(<<< here-string)⇒ 生产者不再收 SIGPIPE,-n/-q 都不再有 141 ② 两条**独立通道**: "有没有违规"用 `grep -q` 的**退出码**;"哪几行"用 `grep -n` 的**输出** ③ ★ **不一致时 fail-closed**: 若"退出码说有"而"行号通道没给出行号" ⇒ 判据内部自相矛盾 ⇒ **按"有违规"计**并报出该矛盾。 实测缺 ③ 会怎样: 只做 ①② 时,把取行号那处改成 `-q` ⇒ 报 0 个、rc=**0**(又是全漏) ⇒ **"计数"与"证据"走同一条通道时,那条通道静音就等于"没有"** ⇒ 要么分通道,要么规定**静音=失败侧**(本处取后者)。 ★ 验证(全部真跑,含三个变异): · 基线 rc=0(3 个调用者,裸赋值 0 处) · [A] 注入 3 处裸赋值 ⇒ rc=1 ✓ · [B] 判"有没有"那处 -q→-n ⇒ rc=1 ✓ · [C] 取行号那处 -n→-q(pi 的变异) ⇒ rc=1 ✓ 且 **fail-closed 报出 3 次** ✓ · 每个变异后还原并复测 rc=0;`git diff --numstat` 仅剩我的文件 (同目录另有并发会话在改 check-deploy-drift.mjs —— 未 add 它的改动) · criteria-hygiene 7/7 绿、pi 的 env-guard 17/17 绿、bash -n 过;生产未动 --- deploy/check-require-declaration.sh | 43 ++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) 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