AskaEth
|
8722c5a0ab
|
fix(ci)+test(packaging): 关掉「门禁关死而自检全绿」三条路:outputs 绑定、判据步真跑、自检步指向
r2 复审:r1 那 11 条 + M3 已闭合(复审自己重放 12/12 红),但它新造的 40 条变异仍有 11 条漏网,
其中三条是「1 行改绿」:把 `probe.outputs.available` 改指向 `reason`/字面量(门永久关、每次绿);
判据步的退出码在标记表之外被吞(`|| echo 先忽略` / `; :` / `| cat` / `if !` / `true # 原行`,
复审真 bash 实测 exit 0);自检步被指向另一个脚本(自检根本不跑)。
三条 P1:
- 新判据 9:`probe.outputs.{available,log,png}` 必须逐个等于 `${{ steps.detect.outputs.<同名> }}`;
- 新判据 5:把 `id: judge` 的 `run` 原文真跑两次 —— 正例必须 exit 0、CPU 档日志必须 exit≠0,
且 `bash -e` 与**裸 bash** 各跑一遍(`; :` 只在后者现形,实测 `bash -e`=1 / 裸 bash=0)。
这一条一次封掉整类「吞码」,不依赖标记表;
- 判据 2:`id: wiring` 的 `run` 必须含 `gpu_shot_ci_selftest.py`,且 `vectors`/`wiring` 必须是**单条命令**
(不许换行/管道/`;`/`&`/反引号/`#`/`$(`)⇒ `|| echo 先忽略` 无从下手。
两条 P2:
- 新判据 10:`on:` 必须同时有 `push`(含 `main`)/`pull_request`/`workflow_call`;
- 「载体依赖」这条边界补进四处(自检 docstring / gpu-evidence.md §8 / README / workflow 头注释):
整个 workflow 被删掉就没有东西会跑自检,`guards.yml` 399/400 行塞不进去。
止步线(写进 docstring 与 §8):封闭清单 10 类 / 33 条变异向量;明确不覆盖「改判据脚本」「删掉整个
workflow」「求值器与 GitHub 语义差」「判据 4 的合法调用替换」;本文档不宣称「不可能被改成总是绿」;
**自 2026-11-11 起停止加固,扩项须由人类新开 mission**。
新增 `packaging/tests/gpu_shot_ci_expr.py`(`if:` 小求值器,判据脚本仍守 ≤400 行:377/215/64)。
|
2026-11-11 18:31:30 +08:00 |
|
AskaEth
|
2e9702790d
|
fix(ci)+test(packaging): 接线自检不再给假安全证书:19 条变异重放全红,dev 线接上
r1 复审 P1-1:上一版自检对外宣称「不可能被改成总是绿」,实测 19 条变异漏 11 条
(最要命的是把 `available` 写成恒 false —— 门禁永久关闭而每次运行都绿)。根因是三条
判据只是字符串存在性检查、自测步与自检步被整条豁免、`is True` 挡不住 `'true'`。
`packaging/tests/gpu_shot_ci_selftest.py` 重写为 6 条判据:
① 五步按 `id:` 必须在场且无条件(`vectors`/`exitcodes`/`wiring`/`detect`/`judge`,
`exitcodes` 还得真断言 `expect 0/1/2`);
② 解析 `if:` 表达式后**求值**判「判定挂门」(`available` 取 `'true'`/`'false'`/`''`
必须真/假/假,认不出一律红)—— `|| always()` 这类文本层面的门现在真红了;
③ 两种调用形态都必须在场且产物来自 `needs.probe.outputs.*`;
④ 跳过路径**实跑 7 种输入**(新增 `packaging/tests/gpu_shot_ci_probe.py`),
断言 `$GITHUB_OUTPUT` 的 `available`、summary 文案、`::warning::` 与三条红线的 exit≠0;
⑤ `continue-on-error` 按 YAML 布尔语义判(`'true'` / `${{ true }}` 也算开启);
⑥ 扫所有 `python`+`packaging/` 的 `run`(自测步、自检步都在内),`|| true` / `; true` /
`|| exit 0` / 裸 `exit 0` 全算吞。
变异向量搬到 `packaging/tests/gpu_shot_ci_vectors.json`:21 条,按解析后的结构注入。
P2-1:`gpu-evidence.yml` 加 `workflow_call:`,`dev-guards.yml` 里 `uses:` 同一份 ——
直推 dev 时 selftest 那一半现在会跑(evidence 在 dev 上照样显式跳过)。
P2-2:跳过摘要与 `gpu-evidence.md §8` 改成唯一可行的补救路径(把产物提交进被 dispatch
的 ref,`git add -f`),并写明「就地拷文件在 CI 上做不到」。
措辞:三处「不可能被改成总是绿」改成能复跑的覆盖面 + 边界。
|
2026-11-11 18:08:31 +08:00 |
|
AskaEth
|
075769c6d2
|
feat(ci)+test(packaging): GPU 证据接进 CI:自测无条件跑,无 GPU 显式跳过(跳过≠通过)
新增 `.github/workflows/gpu-evidence.yml`:`selftest` 无条件跑 `--self-test` 与三个退出码
(0 过 / 1 判据不过 / 2 用法错,用真 CLI 走一遍);`probe` 只探测可用产物与硬件适配器;
`evidence` 的 job 级 `if:` 要求 `needs.probe.outputs.available == 'true'`,所以没产物时它在
Actions 里是灰色 skipped(不是一个绿色 ✓),原因写进 job summary 并打 `::warning::`。
新开文件而不是并进 `guards.yml`:那份已 399/400 行,`release-build.yml` 正好 400。
新增 `packaging/tests/gpu_shot_ci_selftest.py`:把接线口径变成机器判据(自测步不许有 `if:`、
真判据必须挂门、跳过必须 summary+`跳过`+`::warning::`+`$GITHUB_OUTPUT`、禁 `continue-on-error`、
判据命令不许 `|| true`),并带 5 条变异向量证明每种「改绿」写法都会当场红。
`packaging/docs/gpu-evidence.md` §8 记账(含「CI 上从没真跑过」)与 `packaging/README.md` 索引更新。
|
2026-11-11 17:53:53 +08:00 |
|
worker-gpushot
|
9aefb6a5b0
|
fix(packaging): 堵两处判定假绿 + 证据账读数可复跑(M249 r1 P2-1/2/3)
P2-1 判据 2:`Selected: AdapterInfo {` 与字段不在同一行时(pretty-print Debug 漂移)
`device_type` 取不到、旧写法默认 `"?"` 而 `"?" ∉ {Cpu,Other}` ⇒ 判绿。改成取不到即判红。
P2-2 判据 1:`"wgpu" in renderers` 是「曾经出现过」,把 CPU 那次的 stderr >> 追加进来
再配 CPU 那张图会判绿。改成 `set(renderers) == {"wgpu"}`(全部 [shot] 行都声称 wgpu)。
P2-3 doc §2:A6 `--expect-refuse` 那行的「3/3」需要传 PNG 路径才成立,按表复跑是 2/2;
命令列补上 PNG,并单列「不传 PNG = 2/2」一行。
行数:判据脚本 383 → 311(自测脚手架搬到 tests/gpu_shot_selftest.py,124 行;向量
16 → 19 条,红 16 / 绿 3,新增「多行 Debug」「空体」「混入异种 renderer」三条靶子)。
|
2026-11-11 13:13:36 +08:00 |
|
worker-gpushot
|
1f7dfd7bdd
|
feat(packaging): GPU 截图证据判定 check_gpu_shot.py(M249 GPUSHOTGATE)
把 M246「这张图真是 GPU 档出来的」的人读判据固定成可复跑的门禁:
入参 = 一份 stderr 日志 + 一张 PNG(可选 --expect-refuse),逐条点名失败
的判据(不只印 FAILED),退出码 0/1/2。
判据:① `[shot] … renderer=wgpu`(不是 `[probe] renderer =`,那只是意图)
② `Selected: AdapterInfo` 的 device_type ∉ {Cpu, Other}(与 probe.rs:165-167
同口径)③ PNG 能解码且非空 ④ PNG 宽高 = 日志 [shot] 的宽高 ⑤ `[backend]
final=wgpu result=started` ⑥ 复用 check_screenshot.py 的非空白判据。
PNG 解码直接 import 同目录 check_screenshot,不复制第二份解码器。
--expect-refuse 是 A6 负例口径:via=refuse + 无出图行 + 目标 PNG 不存在。
--self-test 跑 tests/gpu_shot_vectors.json 的 16 条向量(红 13 / 绿 3),
每条给出期望的失败判据清单,变异(允许 Cpu / 删掉 renderer=wgpu 判据)
会让清单对不上而报红。
docs/gpu-evidence.md 记录能证什么(字形栅格与边缘 AA、面板 α 与玻璃、
两后端一致性)与不能证什么(首帧与帧率、整窗 α 与圆角观感 —— 走 DWM,
任何截图都拍不到),并写明历史 --diff 基线已永久不可复核。
本脚本尚未接进 CI(另一条 mission),本 mission 不改 Rust、不改 workflow。
|
2026-11-11 13:01:44 +08:00 |
|
worker-updatee2e
|
d7adbd1172
|
fix(m169): r3 四条就地修完 —— 只认同级 name:、纳入 .cargo/config.toml、登记 env 交接边界、校准两处数字
合并门禁只认 clean,r3 的 p2-4items 就地修掉(无行为改动,判据更严,不放松任何一条)。
P2-1(一行 + 三向量)`_name_of` 现在只认**同级** `name:`(`item.end() == key_indent`):更深缩进的
`- name:`(`env:`/`with:` 子列表、`run: |` 块标量里的行)不再被当成项名;同一项里出现两个**不同**
的 `name:` 返回 `None`(无法判定 ⇒ 默认拒绝,不去猜 YAML 重复键语义)。新向量:name 藏在 env 子项 /
藏在 `run: |` 里 / 两个不同 name ⇒ 必须红。
P2-2 `.cargo/config*.toml` 进扫描面(`CONFIG_GLOBS`:根与 `crates/*` 下的 `config.toml`/`config`),
新增 `scan_cargo_config`:feature 字面量(覆盖 `--cfg feature="…"`、`[env] RUSTFLAGS`)走原有判据,
`rustc-wrapper` / `rustc-workspace-wrapper` **一律判红**(wrapper 注入什么由程序决定,文本扫描看不见;
合法用途如 sccache 需要 review 明确同意,不能顺手加)。新向量:config.toml 用 `--cfg` 开该 feature
⇒ 红;设 rustc-wrapper ⇒ 红;普通 config.toml ⇒ 绿(防误杀)。
P2-3 运行期 env 交接写进守门自己的「抓不住」表(脚本头 + README §14):第一步把 feature 写进
`$GITHUB_ENV`、第二步只用 `--features "$FEAT"`——第二步没有字面量,**任何静态扫描都看不见**,这是本
守门的固有边界(引 YAML 解析器也修不了,因为这是数据流不是结构),不是漏判。
P2-4 两处过期数字:`release-guard.yml` 的「注入 14 条」→ 26 条注入 + 6 条防误杀/放行(另加基线,
条数以 `--self-test` 输出为准);README 的「26 条:21 红 + 6 绿」→「32 条向量:26 红 + 6 绿 + 基线」。
守门脚本 399 行(≤400,仍零第三方依赖);自测数据 32 条向量在 `packaging/tests/guard_vectors.json`。
验证(本机,未跑全量 cargo —— tower 已在合并态跑过 workspace 全量 EXIT=0/2648 passed):
- `--self-test`:26 条注入全红 + 7 条基线/防误杀绿,exit 0。
- **真仓注入 8 组**(改真 ci.yml / 新建真 .cargo/config.toml,改完即还原):env 子项里的 name ⇒ 红;
`run: |` 里的 name ⇒ 红;两个不同 name ⇒ 红;`--cfg feature=` ⇒ 红;`rustc-wrapper` ⇒ 红;
普通 config.toml ⇒ 绿;r2 的无名步骤 / flow 步骤回归 ⇒ 仍红;还原后基线绿。
- 正式扫描(真仓)exit 0;全仓 400 行扫描无超限;改动文件全 LF。
|
2026-11-08 11:27:21 +08:00 |
|
worker-updatee2e
|
68a1f90828
|
fix(m169): 复审 r2 —— 守门归属改成「列表项结构判定 + 默认拒绝」,堵掉无名步骤/无名 job/flow 步骤的继承放行
r2 复审(reviewer-updatee2e-r2,p2-4items;被抓出一个真洞,mission 翻回 active)逐条落地。
P2-1(本轮核心,真洞)allowlist 的归属原来按「最近一行 `- name:`」切块,于是任何不写成
`- name: <x>` 的步骤都继承上一块的名字;被放行的 `update-e2e` 恰好是 ci.yml 里最后一个
`- name:`,所以追加到文件末尾的一切都落在它的块里。复审三条真实注入(无名 `- run:`、无名步骤的
整个 job、flow 风格步骤)当时全绿。现在:
- `split_items()` 按 YAML **列表项**切块(每个 `- ` 起一项;比当前项深的行归当前项;同级或更浅的
非列表行**结束**当前项)。项名 = 该项内**同级**的 `name:` 键(键序无关;`run: |` 块里的
`name: dummy` 不算;`run: echo "name: x"` 也不算)。
- **默认拒绝**:落不到列表项上的行(`jobs:` 之前的孤儿行、job 级 `run:` 这类项外键)带 feature 即红;
没有 `name:` 的项带 feature 即红。不再有「继承上一块」这回事。
- 三条复审注入 + 本轮新增三条(`jobs:` 之前的孤儿行、`run: |` 里夹带并伪造 name、shell 变量拼接)
都进了自测向量;在**真仓库文件**上重跑也是全红。
P2-2(同族误杀):
- 键序无关:允许的那一步把 `run:` 写在 `name:` 之前仍绿(旧实现会报到上一块的名字上)。
- `cargo hack check --all-targets` 不再被误判成 `--all`(正则收紧到 `--all(?![-\w])`)。
- Cargo 的 `update-test-source = [ … ]` **跨行声明**不再被误判成「写进了别的 feature 列表」
(`scan_manifest` 增加 `in_declaration` 状态)。
P2-3 `Fixture::run` 的第二条断言比错对象:原来比夹具字段 `self.dest`,手写
`fx.run(&["apply","--dest","<测试二进制>","--json"])` 两条都过。现在从 `args` 里解析真实 `--dest`
值(含 `--dest=` 形式)再 canonicalize 比较;夹具字段那份作为额外一道保留。
P2-4 `release-guard.yml` 的步骤级注释还停在 r1 的扫描面:改成「含复合 action / packaging 递归 /
Makefile 等 + 归属按列表项判 + 唯一允许 ci.yml 的 update-e2e 一步」。
自测数据搬到 `packaging/tests/guard_vectors.json`(基线 8 个文件 + 26 条向量:21 红 / 6 绿),
脚本本身从 379 行降到 373 行(守门仍 ≤400);README §14 补上归属规则与「抓不住」清单。
验证(本机,全部 exit 0):
- 守门正式扫描绿;`--self-test` 21 条注入全红 + 6 条基线/放行绿;向量文件缺失时 exit 1(不静默)。
- **真仓注入**(在真 ci.yml / release-build.yml / cli/Cargo.toml 上改完即还原):复审三条(无名步骤 /
无名 job / flow 步骤)全红;本轮新增三条(孤儿行 / `run: |` 夹带 / shell 拼接)全红;
三条合法写法(键序、`--all-targets`、跨行声明)全绿;还原后基线绿。
- E2E:debug 6 绿、release 6 绿(`running 3 tests` ×2,0.26s / 0.23s,非 0 measured)。
- `cargo clippy -p unlucky-cli --all-targets --features update-test-source -- -D warnings` 干净;
`cargo fmt --all -- --check` 干净;全仓 400 行扫描无超限(守门 373 / 向量 194 / ci.yml 317)。
约束遵守:未 push;`PUBLISH_SLOTS` 只列 `windows-x64`(未动);release 侧仍无该 feature;跨卷 bug 未碰。
⚠ 仍未验:CI 里 E2E 真跑起来本机验不了(只证明 workflow 写对 + 守门放行,首跑要等推送后看 Actions)。
|
2026-11-08 11:12:11 +08:00 |
|
AskaEth
|
e3ee20bdcd
|
feat(packaging): M151 发布流水线生成更新清单 manifest.json(D50)
清单挂 GitHub Release 资产,固定文件名 manifest.json(D50)。字段形状的权威是 M146 的
crates/core/src/update/manifest.rs(ReleaseManifest,deny_unknown_fields + 逐字段校验),
生成器只负责把那套形状填对,不另立 schema。
同源,不双写:packaging/make_manifest.py 的每个 sha256 直接读 Release 自己的
SHA256SUMS.txt,size 取自同一批文件的 stat();产物名里的版本段必须等于 --version,
tag 与 Cargo.toml 漂了就没有产物可对,当场失败。CI 在「裁剪发布白名单后重算
SHA256SUMS」之后调它,所以清单描述的是真正要发的资产,不是构建出来的全部。
make_artifacts.py 只加 --manifest 开关,用子进程调同一份脚本(本地跑也产出
manifest.json),本文件继续是产物命名的唯一真相源。
只放启动器产物:DTO 的 Artifact 没有角色字段,Release::artifact_for() 取第一个
target 命中的产物,把 ull 并列写进去会让「覆盖哪个文件」取决于数组顺序;ull 照旧进
SHA256SUMS.txt 与 Release。
url 两种形态:默认裸文件名(DirSource 口径,本地/内网用);CI 传 --asset-base-url
拼绝对地址并钉 tag(不是 latest),清单里每条都指向与它自报版本相符的字节。
自验:--self-test 用 packaging/tests/manifest.golden.json 逐字节对拍(覆盖裸 exe 与
tar.gz 两种形态,并钉住「ull 不进清单」),再跑 14 条负例证明严格解析不是摆设;
发布步会先跑它再产文件。真 DTO 对拍已在本机用 M146 的 ReleaseManifest 实测:
golden 解析通过(2 个产物、min_supported、force 均正确落位),14 条篡改全部被拒。
未决(报告带利弊,未自行改发布默认值):releases/latest/download/* 只指向非 prerelease
的最新 Release,而发布默认 prerelease=true。
Refs: D50, M146
|
2026-11-06 22:15:58 +08:00 |
|