Skip to content

test(ci): CI 必需运行时清单显式化,bash/rm 显式标注为平台相关 - #109

Merged
ROM4n2 merged 1 commit into
masterfrom
fix/ci-required-binaries-fog4
Oct 6, 2026
Merged

ROM4n2 merged 1 commit into
masterfrom
fix/ci-required-binaries-fog4

Conversation

@ROM4n2

@ROM4n2 ROM4n2 commented Oct 6, 2026

Copy link
Copy Markdown
Owner

把「CI 必需运行时」清单显式化成守卫,并钉住一条否定式结论:bash 与 rm 都不是 CI 必需。

调研推翻了两条前提(上一轮任务书写错了)

① shutil.which("rm") 全仓 0 次。 三重交叉验证:grep -rc 'shutil.which("rm")' tests/ delector/ = 0、def test_cleanup 全仓 0 次、delector/core/database.py 内 shutil 0 次。tests/db_cleanup.py::remove_db_files 用的是跨平台 os.remove。⇒ 我上一轮 work.log 里记的"database.py:2086 的 test_cleanup 用 shutil.which("rm"),是第 8 处同类漏网"是错的,在此更正。

② bash 判为「平台相关」,不进 CI 必需清单。 依据:

  • CI 是 ubuntu-latest,bash 由镜像自带,且 GitHub Actions 的 run: 步骤本身就以 bash 为默认 shell——ci.yml 里那些 shell: bash 正是靠这个默认,不存在"缺 bash"的现实路径
  • tests/test_server.py:2591 的 skip 不是 if not shutil.which("bash"),而是 _find_bash() 五套策略的最后一招(git-bash 路径 → where bash → PATH 扫描 → shutil.which,见 :2574)。其语义是"本机找不到任何可用 bash"——Windows 无 Git-Bash/WSL 时跳过是正确行为,不是"守卫静默失效"
  • 升级为 fail 会让无 bash 的本地环境直接红,违背 fix(encounter): 降级状态与本次调用绑定,消除并发下的串味误标 #106 明确的"不做 CI 零 skip 禁令"

⇒ 本 PR 未改动 conftest.py,扩进清单的项为 0。session 检查现状已正确,硬塞 bash 只会制造一条错误的门禁。

守卫内容(tests/test_ci_hardening.py +165)

  1. 清单 ↔ 实现双向一致:conftest.py 实际强制的运行时集合 == 守卫里的显式清单(防止"代码加了但清单没记"与反向脱节)
  2. rm 显式列为"平台相关、非 CI 必需"并断言其不在清单里——防将来有人误升级为 fail
  3. bash 显式列为"平台相关",并有一条反向钉:断言它不在 CI 必需清单里
  4. local_env_still_skips:钉住 conftest 的 CI 判据仍是环境变量判定(改恒真会红)

无 RED 是诚实结果,不是跳过 TDD

新守卫首跑直接绿(21 passed)——因为核实结论就是"清单无需变更"。改用五条变异证明守卫非空转:

变异 结果
① 清单 ("node",) → () 1 failed, 19 passed, 1 skipped
② 清单加 rm 2 failed(assert 'rm' in {'node'})
③ 清单加 bash 2 failed
④ bash 同时进两个清单 3 failed,含 not_promoted_to_fail[bash]
⑤ conftest CI 判据改恒真 2 failed,含 local_env_still_skips

每条均 cp 还原 + diff 确认 RESTORED IDENTICAL(测试文件 4 次、conftest 1 次)。

门禁(两道 mypy 都跑)

项 结果
test_ci_hardening.py 21 passed(0 skip)
test_probe_wiring_guard.py 5 passed
test_server.py -k precommit 6 passed(bash hook 测试真跑,未被误判红、也未 skip)
mypy --follow-imports=skip tests 93 files 0 error
mypy --strict delector tools 70 files 0 error
ruff 通过

零 static/ / delector/ / tools/*.mjs 改动 ⇒ 不触发发版。

Fog 4:把「哪些二进制算 CI 必需」这条判据本身钉成清单,双向防止
- 真正 CI 必需的项被悄悄摘掉(退回静默 skip);
- 平台相关的项被误升级为 fail(本地 Windows 被红)。

判定结论(附代码依据):
- node  → CI 必需(29 处 shutil.which("node") 守卫,.mjs 探针全靠它)
- bash  → 平台相关,刻意不进清单。CI(ubuntu) 上必然存在(镜像自带且
          Actions run 步骤默认即 bash),缺它不现实;test_server.py:2591
          的用法是 _find_bash() 五套策略的兜底分支,skip 语义是「本机
          找不到任何可用 bash」——Windows 无 Git-Bash/WSL 时跳过是正确
          行为,非回归守卫静默失效。升级会违背 #106「不做零 skip 禁令」。
- rm    → 调研前提经核实不成立:全仓 shutil.which("rm") 命中 0 次、
          def test_cleanup 命中 0 次、database.py 内 which 命中 0 次。
          真实实现在 tests/db_cleanup.py,用跨平台 os.remove。已加守卫
          钉住「不依赖外部 rm」,防将来引入 subprocess rm 造新 Fog。

conftest.py 无需改动:现有 session 检查已正确,扩展它反而会误伤。
仅新增守卫 + 清单常量。
@ROM4n2
ROM4n2 merged commit f74e3a7 into master Oct 6, 2026
1 check passed
ROM4n2 added a commit that referenced this pull request Oct 6, 2026
更正:上一条 log 记的'shutil.which("rm") 是第 8 处同类 skip 漏网'是错的
——全仓 0 次,tests/db_cleanup.py 用跨平台 os.remove。教训:不要把未核实的
记忆当事实写进文档。

Fog 4(#109):两条前提均被推翻(rm 不存在、bash 判为平台相关),交付
否定式守卫——rm 与 bash 均显式标注'非 CI 必需'并断言不在清单,扩进清单
0 项、未改 conftest.py。

Fog 3(#110):原论证'改用运行时 dependant 更可靠'被实测推翻(运行时只
找出 4 条,看不到函数体内调用的 16 条)。改为加固 AST 守卫:关掉三个实测
确认的漏检洞,allowlist 20 条逐字未动,delector/ 零残留。16 处形式统一
(C-F)待用户裁决。
@ROM4n2
ROM4n2 deleted the fix/ci-required-binaries-fog4 branch October 6, 2026 04:57
ROM4n2 added a commit that referenced this pull request Oct 6, 2026
版本面六处同步(test_writer_mobile.py 30 passed 钉死一致):
- static/sw.js CACHE_NAME -> delector-static-v5.16.0
- static/index.html 顶栏指示灯 -> System · v5.16.0 Online
- android/app/build.gradle fallback -> 5.16.0 / 51600
- README badge + 下载表四行 + 摘要区
- CHANGELOG 完整条目(并补上 v5.15.0 章节的版本前缀)
- PROJECT_OVERVIEW 发布面 + 测试基线

本版内容:Fog 1~4 全部收口
- #108 修掉「每次 GET 文章都重跑完整 spaCy + UPDATE articles」:惰性迁移判据
  写死 3.4.0 而写入端两条路径都写 3.5.0,判据恒真 => 惰性迁移退化成每次迁移。
  修法=PROCESSED_JSON_VERSION 单一真相源,惰性迁移语义完整保留。
- #109 CI 必需运行时清单显式化 + 两条否定守卫(rm 全仓不存在、bash 属平台相关)
- #110 localhost 守卫加固三个「将来会漏」的洞,allowlist 20 条逐字未动
- Fog 1 裁决「内网可信」;Fog 3 的 16 处形式统一裁决不做

门禁:1317 passed + 1 skipped(1053 + 264);tools/*.mjs 探针 28/28;ruff 零告警;
mypy 两道(93 + 70 files)零错误;发版守护 30 passed;五条守卫全绿。

无 static/ 改动(除 sw.js/index.html 的版本字符串)=> 桌面端刷新即生效;
Android APK 随 tag 重建(versionCode 51600,可覆盖安装)。
ROM4n2 added a commit that referenced this pull request Oct 6, 2026
如实记录:写 CHANGELOG/README/PROJECT_OVERVIEW 时抄了 #110 那轮 maker 报告里的
1048 当终值('1312 = 1048 + 264'),但 #109 又合入 5 个守卫测试,实测半 A 是
1053、全量 1317,三处全错,靠发版前全量门禁才发现。已存 memory:发版顺序
固定为「改版本点 → 跑全量门禁取实测数 → 写文档 → commit」。

同时记录 README 破坏事故未复发的做法:脚本写进系统 temp 执行(避开 8KB 命令
行限制)、列表插入一律用 .split('\n')/[text]、脚本内置破坏检测。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant