★★★ 收 pi 30ee8ff2: ⑧b **不只是"规格错",它有真实假绿** —— 调用者判定依赖 strip ⇒ source 行里的 ${VAR#…} 被当注释截断 ⇒ **调用者身份丢失** ⇒ 该文件的裸赋值连查都不查(实测 rc=0、调用者数仍 3、三条不变量全过);已改用**词首注释规则**修掉,并把 ⑧b 拆出 **⑧c(可闭,已闭)**

★★ (A) pi 报的假绿(我复现,逐字一致):
     `deploy/redeploy-nc.sh`:
         . "${REPO#/home}/deploy/lib/env-defaults.sh"
         AGENTMAIL_REQUIRE="z"                    ← 真违规
     ⇒ 真 strip(`s/#.*$//`)把它截成 `. "${REPO` ⇒ **不再提及 env-defaults.sh**
       ⇒ 该文件**静默退出调用者集合** ⇒ 裸赋值**不被查** ⇒ rc=**0**,
       仍报"3 个调用者,裸赋值 0 处"(z 被漏)
     现实形态同样命中(pi 报、我复现): `. "$(dirname "${BASH_SOURCE[0]#/x}")/lib/env-defaults.sh"` ⇒ rc=0
     ★ 而**三条不变量全过**(首尾探针 / 行号算术 / 逐行局部不变量):
       删的首字符**确实**是 `#`、stripped 也**确实**是 raw 的前缀 ⇒ ⑧a 那套形状检查**看不见它**
     ★ 触发形态本仓已在用(`${VAR#…}`/`${VAR##…}`/`${VAR%…}`):
       prune-deploy-artifacts.sh:66、recount-relay-counts.sh:161-165、install.sh:768 等
★ (B) 修法: ① 调用者判定改用**词首注释规则** `sed 's/\(^\|[[:space:]]\)#.*$//'`
       —— shell 的真实规则(`#` 只在**词首**才是注释)⇒ 参数展开/引号内的 `#` **不再**被截断
     ★ 我先试过"用 raw 原文",**它引入假红**(实测):
         `. other.sh   # 注释里提到 env-defaults.sh` 会被当成调用者
       ⇒ 所以不能只"去掉 strip",要**把 strip 的规格写对** —— 这是**规格错**,不是"边界"
     实测: pi 两例(`${REPO#/home}` / `${BASH_SOURCE[0]#/x}`)**都 rc=1** ✓
       反例对照 `. other.sh # 提到 env-defaults.sh` **仍不算调用者**(rc=0、调用者数 3)✓
       三个真实调用者全认出、判据自己不误入集合 ✓
★ (C) ⑧b 拆两半(本轮第三格记法):
     ⑧c **调用者判定**(判"哪一行是 source 行"只用到**行首形态**,与注释后缀无关)⇒ **可闭,已闭**
     ⑧b **注释语义本身**(strip 对**行内** `${V#x}`/引号内 `#` 的截断会不会让**违规行自己**
        不再匹配 `AM_SCAN_RE`)⇒ **真边界**。残余实测: `AGENTMAIL_REQUIRE#="z"` ⇒ strip 成
        `AGENTMAIL_REQUIRE` ⇒ 不再匹配 ⇒ rc=0(但该行**本就不是合法赋值**,落在射程边缘);
        合法形态 `AGENTMAIL_REQUIRE="${V#x}"` ⇒ 截断后仍匹配 ⇒ rc=1 ✓ 不漏
     ⇒ ★★★ 记法: **"耦合"本身会被误报成"边界"** —— 我原说"⑧b 是语义边界",
       其实里面**掺着一处没必要的耦合**(调用者判定顺手复用了 strip)。
       判法: 申报边界前问 **"这个信息真的只能由被检对象给出吗,还是我顺手复用了它?"**
     ⇒ ⑧a 是"换错观察对象"、⑧c 是"**多余的依赖**" —— 两次都把可闭的说成了边界
★ 回归: 12 向变异矩阵全 rc=1;干净基线 rc=0;criteria-hygiene **10/10** 绿
This commit is contained in:
2026-09-25 08:28:04 +08:00
parent 0c167ae6a4
commit 6d772803f3

View File

@ -90,17 +90,42 @@ _scan_text() { _scan_stripped "$(strip_text "$1")"; }
callers=""
for f in $(find deploy -name '*.sh' -type f | sort); do
[ "$f" = "$LIB_REL" ] && continue # 定义点不是调用点(见射程)
body="$(strip_text "$(cat "$f")")"
case "$body" in
# ★★★ 调用者判定**不看 strip 后的文本**(pi `30ee8ff2` 实测的**假绿**,我复现并采纳):
# 若 source 行里含 `${VAR#…}` 这类**参数展开**(`#` 不是注释),`strip_text` 会
# 从那个 `#` 起把整行截断 ⇒ 行内**不再提及** `env-defaults.sh` ⇒ 该文件**静默退出调用者集合**
# ⇒ 它的裸赋值**根本不被查**(连进都没进集合)⇒ **假绿**。实测(`d3c74ec` 的树上):
# `deploy/redeploy-nc.sh`:
# . "${REPO#/home}/deploy/lib/env-defaults.sh"
# AGENTMAIL_REQUIRE="z" ← 真违规
# ⇒ rc=**0**,仍报"3 个调用者,裸赋值 0 处"(z 被漏)
# 对照: 把 source 行换成 `. "$REPO/deploy/lib/env-defaults.sh"` ⇒ rc=**1** ✓
# ★ 而**三条不变量全过**(首尾探针 / 行号算术 / 逐行局部不变量)—— 因为删的首字符
# **确实**是 `#`、stripped 也**确实**是 raw 的前缀 ⇒ ⑧a 那套"形状"检查**看不见它**。
# ⇒ 修法: 调用者判定改用**词首注释规则**(shell 的真实规则: `#` 只在**词首**才是注释)。
# ★ 不能用"raw 原文"了事: 我实测过 raw 版会把
# `. other.sh # 注释里提到 env-defaults.sh`
# 当成调用者 ⇒ **假红**(安全方向,但仍是错的)。
# 也不能用 `strip_text`(它是 `s/#.*$//`,正是被 pi 抓到的那个错)。
# ⇒ 用 `_caller_strip`: 只在 `#` 位于**行首或空白之后**时才截断 ⇒
# `${REPO#/home}` / `${BASH_SOURCE[0]#/x}` / `X="a#b"` **都不被截断** ✓
# 而 `foo.sh # 提到 env-defaults.sh` **被截断**(不误判,无假红)✓
# 整行注释 `# . env-defaults.sh` ⇒ 截成空 ⇒ 不匹配 ✓
# ★ 这不是"换一个实现",是**把注释的规格写对**: 原 `s/#.*$//` 把
# "参数展开/引号内的 `#`"也当成了注释 —— 那是**规格错**,不是"边界"。
# ⚠️ 射程(本处**只**修调用者判定这一半): 正式违规扫描仍走 `strip_text`
# (`s/#.*$//`)⇒ 若某**违规行**本身含 `${VAR#…}` 且截断后不再匹配 `AM_SCAN_RE`,
# 那仍会漏(属 ⑧b 的**语义**半,真边界)—— 本处**不**声称那半已闭。
_ftext="$(sed 's/\(^\|[[:space:]]\)#.*$//' "$f")"
case "$_ftext" in
*env-defaults.sh*)
# 无管道匹配:`grep` 读文件而非读管道 ⇒ 不会因 SIGPIPE 造出不稳定的 rc。
if grep -qE '^[[:space:]]*(\.|source)[[:space:]].*env-defaults\.sh' <<< "$body"; then
# 无管道匹配(`<<<` here-string):不会因 SIGPIPE 造出不稳定的 rc。
if grep -qE '^[[:space:]]*(\.|source)[[:space:]].*env-defaults\.sh' <<< "$_ftext"; then
callers="$callers $f"
fi
;;
esac
done
unset body
unset _ftext
# shellcheck disable=SC2086
set -- $callers
n_callers=$#
@ -385,4 +410,29 @@ exit 0
# ★ 我上轮就是**拿语义的循环性去论证形状那半也不可闭**,于是**多申报了一个边界**。
# ⚠️ 与 ⑤ 的关系: ⑤ 也是"我把可闭的误判成边界"(拿"同一次观察的后退"当理由)——
# ⑧a 与 ⑤ 是**同一类错误**(论证里的"循环/后退"其实不成立),⑧b 才与 ⑥⑦ 同级。
# ⑧c ★★★ **⑧b 还要再拆一半**(pi `30ee8ff2` 实测的**假绿**,我复现后已修 —— 见 ① 调用者判定):
# pi 指出 ⑧b 不只是"规格本身错"(无害),它有一条**真实可达的假绿**:
# 当"不该当注释的 `#`"出现在**唯一那处 `env-defaults.sh` 提及之前**时,
# 整行 strip 后**不再提及** env-defaults.sh ⇒ **调用者身份丢失** ⇒ 该文件被跳过
# ⇒ 它的裸赋值**连查都不查**(不是漏判,是**根本没进集合**)⇒ **假绿**。
# 实测(`d3c74ec` 的树上,我复现): `deploy/redeploy-nc.sh`
# `. "${REPO#/home}/deploy/lib/env-defaults.sh"` + `AGENTMAIL_REQUIRE="z"` ⇒ rc=**0**
# 现实形态同样命中: `. "$(dirname "${BASH_SOURCE[0]#/x}")/lib/env-defaults.sh"` ⇒ rc=**0**
# ★ 而**三条不变量全过**(首尾探针/行号算术/逐行局部不变量)—— 因为删的首字符
# **确实**是 `#`、stripped 也**确实**是前缀 ⇒ ⑧a 那套"形状"检查**看不见它**。
# ⇒ ★ 已修(① 调用者判定改用**词首注释规则** `s/\(^\|[[:space:]]\)#.*$//`):
# 参数展开 `#` / 引号内 `#` **不再**被当注释 ⇒ 调用者不再丢失 ⇒ 上面两例都 rc=**1** ✓
# 且**不引入假红**: `foo.sh # 注释里提到 env-defaults.sh` **仍不算调用者** ✓
# ⇒ ★★ 于是 ⑧b 拆两半:
# ⑧c **调用者判定**(判"哪一行是 source 行"只用到**行首形态**,与注释后缀无关)
# ⇒ **可闭**(已闭)—— 我原先把"strip 的实现"与"调用者判定"**耦合**在一起
# ⑧b **注释语义本身**(strip 对**行内**`${V#x}` / 引号内 `#` 的截断会不会
# 让**违规行自己**不再匹配 `AM_SCAN_RE`)⇒ **真边界**
# 实测残余: `AGENTMAIL_REQUIRE#="z"` 被 strip 成 `AGENTMAIL_REQUIRE` ⇒ 不再匹配 ⇒ rc=0
# (但这行**本来就不是合法赋值** ⇒ 落在射程边缘;合法形态 `AGENTMAIL_REQUIRE="${V#x}"`
# 截断后仍是 `AGENTMAIL_REQUIRE="${V` ⇒ **仍匹配** ⇒ rc=1 ✓ 不漏)
# ⇒ ★★★ 记法(本轮第三格): **"耦合"本身会被误报成"边界"** ——
# 我原来说"⑧b 是语义边界",其实里面**掺着一处没必要的耦合**(调用者判定依赖 strip)。
# 判法: 申报边界前问一句 **"这个信息真的只能由被检对象给出吗,还是我顺手复用了它?"**
# ⇒ ⑧a 是"换错观察对象"、⑧c 是"**多余的依赖**" —— 两次都把可闭的说成了边界。
# ══════════════════════════════════════════════════════════════════════════════