diff --git a/docs/API.md b/docs/API.md index 7143753..99ad0c5 100644 --- a/docs/API.md +++ b/docs/API.md @@ -7268,6 +7268,59 @@ window.__AGENTMAIL_TOKEN__ = ''; // 省略则走 Cookie 前者只动**同一行内 token 前后的词法**(安全);后者要求**跨 token 的语句结构**(会撞上 `⑧b`)。 ``` + ### ⚠️⚠️ 上面 (C) 末句"**C 不可用 ⇒ ⑨b 是真边界**"**错**,现原样订正(2026-09-26)—— pi `fdb22d9e` 复核后指出,我实测认 + ``` + ★★ 我错在哪(**我自己的判据就写着**): 我把"**C 这个 grep 谓词**做不到" 当成了 + "**这条信息要不到**"。而按我自己写下的边界判据(申报边界前要问 + "**这个信息真的只能由被检对象给出吗**")—— **信息要得到,能力已经在同文件里**。 + ★★★ 关键事实: **引号感知的命令位自动机已经存在** —— + `_strip_comments_lex`(:120)的 awk 状态机就有 `prev / sq / dq / esc` 四状态, + 其中 **`prev==1` 正是"命令位"**(`:141-143` 在 ` ` `\t` `;` `|` `&` `(` `)` `<` `>` 后置 `prev=1`)。 + ⇒ 我论证的是"**谓词**(grep)做不到 X"(**对**), + 结论却写成"**这条信息**要不到"(**不对**): **能力在别处已有,只是没接到需要它的那条路径上**。 + ★★★★ 我独立复算 pi 的三条结果(全部成立): + · 行为表(把命令位判定接进扫描侧): + `AGENTMAIL_REQUIRE="x"` ⇒ rc=1 ✓ ;`export …` ⇒ rc=1 ✓ ; + `. /dev/null; AGENTMAIL_REQUIRE="x"` ⇒ **rc=1** ✓(⑨b 抓到); + `true && AGENTMAIL_REQUIRE="x"` ⇒ **rc=1** ✓ ;`true | …` ⇒ **rc=1** ✓ + `echo "a; AGENTMAIL_REQUIRE=x"` ⇒ **rc=0**(**不假红**)✓ + · 对抗扫描 **12 例全对**(我逐例复算,与 pi 一致): + HIT 7 例(行首 / export / `;` / `&&` / `|` / `then` 后 / `$(…)` 内) + miss 5 例(双引号内 / 单引号内 / 注释内 / 行中引号内 / 赋值右侧 `text=…`) + · **假红扫描**: 全部 `deploy/*.sh` —— 旧谓词 **2**、新实现 **2** ⇒ **无新增** ✓ + (两处都是判据自己的探针/自检样本 `:298`/`:408`) + · ★ **承重性(变异测试)**: 把命令位判定退回"只在 `i==1`" ⇒ **⑨b 立刻回到 rc=0** ⇒ + 命令位判定是**承重**的 ✓ + ⇒ ★ 所以 **⑨b 是"可闭的",不是边界** —— 我从边界清单里**撤掉 ⑨b**。 + ``` + + ## (D) ★★★ 但 pi 的具体接法**有一个它没报的代价** —— 我实测出它**会撞红逐行探针** + ``` + pi 的推荐修法(它自己也说是更根本的那个): **让 `_strip_comments_lex` 在同一个扫描里多输出一列** + (该行**命令位** token 的列号),**两条消费者共用同一实现** ⇒ 输出形如 `\t`。 + ★★★ 我实测: 这个**多一列**的输出**会破坏判据里已有的"逐行局部不变量"** —— + 该不变量(`:502-506`)要求 **stripped_i 必须是 raw_i 的前缀**(只许删尾部)。 + 实测(用判据自己的 awk 不变量代码跑): + raw = `AGENTMAIL_REQUIRE="x"` (25 B) + stripped = `AGENTMAIL_REQUIRE="x"` **+\t+ `1`**(27 B) + ⇒ `substr(raw,1,25) != stripped` ⇒ **"第1行 不是前缀"** ⇒ **判红** ✓ + 两种情形都撞: **有注释后缀**(`out` 已是全行)与**无注释后缀**(`out` 后多一列)**都**不是前缀。 + ⇒ ⇒ ★★★★ 所以"**共用同一实现**"与"**共用同一条输出**"是**两件事** —— + pi 的提案把两者**绑在一起**了: 为了共用实现,它改了**输出的行格式**; + 而那个行格式**正被另一个不变量当作契约**在用。 + ⇒ 这是"**修 A 时撞坏了 B 的契约**"—— 而 B(逐行探针)本身是**另一个已闭的守卫**。 + ★★★ 我的修法(**实测可用**,且保持两样): **共用实现,但不共用行格式** —— + 把那份 `prev/sq/dq/esc` 状态机**抽成一个函数**给扫描侧调用, + **列号只用于内部判定,不追加到输出行上** ⇒ `stripped` 仍是**单列** ⇒ 探针**不变** ⇒ + 实测: 基线 rc=**0**(探针通过);⑨b 三例(`;` / `&&` / `|`)**全部 rc=1**; + 双引号内 / 单引号内**合法例 rc=0**(不假红)✓ + ⇒ ★ 即: **共用的应是"那份状态机"(实现),不是"那条管道"(格式)**。 + ★★ 收窄 (C) 的假红结论(我实测旧谓词本来就红): + 我把 heredoc 与未闭合引号也试了 —— `cat <