diff --git a/docs/DEBTS.json b/docs/DEBTS.json index d39084c..67cd8d9 100644 --- a/docs/DEBTS.json +++ b/docs/DEBTS.json @@ -234,6 +234,14 @@ "due": "下一次要用「缺失的产物」当物证时(任何 deploy 脚本旁路都算)。★ 到期动作不是'补判据',是**先查该路径会不会被清**、再决定这条物证此刻还能不能用。", "where": "`deploy/prune-test-sessions.sh:92`(`BAK=\"/tmp/agentmail-pre-prune-$TS.db\"` 字面硬编码);`/tmp` 挂载见 `findmnt /tmp`;清理策略见 `/usr/lib/tmpfiles.d/tmp.conf:11`(`q /tmp ... 10d`)与 `systemd-tmpfiles-clean.timer`", "note": "★★ 2026-09-27 实测登记(复核 pi `c6dbc8d0` §三 时发现)。\n\n## 形状:**\"现在没有产物\" 推出 \"当时没跑过\" 需要一个前提,而该前提会自己消失**\n```\npi `c6dbc8d0` 给的加强物证(我复核**成立**且是当时**正确**的测法):\n · prune 的 `.backup` 在删除前**无条件**执行(`:95`),路径**字面硬编码** `/tmp`、不做 env 覆盖\n · 当时实测: `agentmail-pre-prune-*` = **0 个**,且**争议窗口 ±1h 内有 21 个别的文件存活**\n ⇒ 用\"同一目录同一时段别的文件还在\"来证明\"不是被清理掉了\" ⇒ **这一步很扎实**\n```\n## ★★ 但我在 2026-09-27 04:10 重测,那个前提**已经不成立**了\n```\n实测: 早于 2026-09-26 09:32 的 /tmp 文件 = **0 个**(争议窗口 04:00–06:30 内也是 **0 个**)\n而 `tmpfiles.d/tmp.conf:11` 是 `q /tmp 1777 root root 10d` ⇒ **1 天内的文件不该被清**\n⇒ 唯一解释: **`/tmp` 经历过清空/重启**\n`findmnt /tmp` ⇒ **tmpfs** ⇒ ★★ **重启即全失**(与 10d 策略无关)\n⇒ 所以: 「现在 0 个备份」**此刻已经不能**推出「09-26 04:57 那会儿没跑过 --apply」\n```\n## 后果: 三条腿的强度**又降一级**(我上一轮已降过一次,这次是同一机制的第二级)\n```\n物证① 覆盖范围随时间**单调收缩**:\n T0(紧邻事件)⇒ 有效(前提成立)\n T0 + 任何一次重启 ⇒ **永久失效**(且不可恢复 —— tmpfs 不留痕迹)\n⇒ ★ 所以定稿里\"『prune --apply』与『reset-demo』都未跑过 —— 凭谓词无关的产物\"这句,\n 在**今天**只能保留**物证②**(`/opt/agentmail/backups/`,**非 tmpfs** ⇒ 跨重启存活)\n ⇒ 物证① 要降为「**在 09-26 04:10 之前**(当次会话内)成立,之后需重新取证」\n```\n## ★ 可判形状(到期时用)\n```\n凡以「缺失的产物」为物证,**必须同时记录三项**,缺一即降级:\n ① 产物路径是否**会**被自动清理(tmpfiles 策略 / tmpfs / logrotate / 手工 rmtree)\n ② 支撑「不是被清掉了」的**同时段旁证**(同目录同时间别的文件仍在)—— 必须在**取证当时**记,事后不可补\n ③ 取证时刻 —— 因为 ①② 都是**会过期的**\n⇒ 与我们已记的「口径会随时间漂」(`recount-labels-must-match-predicates` 补记)同族:\n 那条是**数字**会过期,这条是**物证**会过期。\n⇒ ★ 反过来也成立一条**该做而没做**的: 若某个物证会过期,**结论就该带时刻**。\n 我们此前把「prune 没跑过」写成**无时刻的现在时** ⇒ 这是本条要纠正的写法。\n" + }, + { + "id": "python-probe-shadowing-in-tmp", + "count": 1, + "kind": "测量工具自身的**失效方式**:`/tmp` 里的同名 .py 会**遮蔽标准库**,且**静默混入别人的输出、脚本仍 rc=0**", + "due": "下一次在 /tmp 落 .py 探针之前。(到期动作不是'小心一点',是**换落点或加 `-I`**。)", + "where": "`/usr/local/lib/python3.12/re/__init__.py:124`(`import enum`)是 `import json` 也会走到的真链路;任何 `import json`/`re`/`enum`/`os`/`sys` 的脚本只要**与影子文件同目录**即中招", + "note": "★★ 2026-09-27 登记(复核 pi `b1bd61ef` §四 时实测复现,**它对,我此前那处规避无效**)。\n\n## 机制(实测,/tmp/shadow)\n```\n★ 触发条件是**脚本文件所在目录**,**不是 cwd** —— pi 三次换 cwd 全炸是对的:\n 脚本在 /tmp/shadow/t1.py、cwd=`/` ⇒ 仍被污染 ⇒ `sys.path[0] == '/tmp/shadow'`\n ⇒ 正确说法: `sys.path[0]` = **脚本自身所在目录**; 换 cwd 完全无效。\n ⇒ `python3 -I` **有效**(隔离模式不把脚本目录放进 sys.path)✓\n⇒ ★★ 真链路比\"某个脚本 import 了 json\"宽得多: `json/__init__.py` 内部会 `import re`,\n 而 `re/__init__.py:124` 又 `import enum` ⇒ **任何 `import json` 的脚本**都会执行\n 同目录下的 `re.py` / `enum.py`。\n## ★★ 为什么这是\"最坏的一类\"失效(我实测的严重性)\n```\n伪造 `json.py` 让 `json.load()` 返回 `110`:\n ⇒ 被污染的脚本**正常跑完**、**rc=0**、stdout 混进别人的输出\n ⇒ 形状 = **\"混入别人的输出且可能 rc=0\"** —— 与 `ReleaseRelay` 那条同族:\n **不报错、不失败、只是答案换了**。本轮我已因它撤过一次结论(\"11/12 候选=0\")。\n⇒ ★★ 我此前说的\"**换目录跑**\"规避:对\"脚本在 /tmp\"**不成立**(就是本条)⇒ 撤销该规避。\n## ⇒ 我本会话的**结论为何不受影响**(自查,非辩解)\n```\n我所有 python 探针都是 **heredoc(`python3 - <