构建侧:release-build.yml 声明 on.workflow_call.secrets.ULL_MSA_CLIENT_ID(required: false), cargo build 步以 env 注入它,option_env! 把它烘进二进制;release.yml 的 build job 按名显式透传 (与 PUBLISH_TOKEN 同一模式,不用 inherit)。真值放仓库 Secret,不进任何 git 文件;Secret 未录入 或 Actions 之外求值为空串时,client_id.rs 的 blank_env_value_counts_as_missing 保证「空白=没配」, 不会拿空 id 去联网。 文档:README 两版 / help.rs 的 accounts topic / packaging/release-notes.md / packaging/docs/build-and-ci.md 统一成「官方构建已内置登录所需配置、开箱即用,仍可用环境变量 ULL_MSA_CLIENT_ID 覆盖;自建想自带就构建时注入」的功能性口径 —— 不出现 id 本身,也不出现归属描述。 client_id.rs 的模块注释与测试注释同步(原文写「id 不进仓库(用户定案)」,已随 Secret 方案改写), 并记下「别把 ULL_MSA_CLIENT_ID 导出到跑 cargo test 的 shell」——presenter 的 M132 入口锚会在 已烘焙 id 的构建里故意红。 实测:ULL_MSA_CLIENT_ID=<id> cargo build --bin ull 后,清空 env 跑 ull accounts add msa 打出 用户码与链接(无「未配置」提示);同二进制设一个假 env id 则 AADSTS700016 点名该假 id(env 覆盖生效)。 单测:core auth 28、unlucky-cli 全套、i18n 30、presenter 222 全绿;M132 锚在烘焙构建里按设计红、 在不带 id 的构建里绿。cargo fmt --all --check 通过。
打包与发布工程(packaging/)
单一真相源:单文件产物矩阵 + 发布契约。.github/workflows/release.yml 按本文实现,
packaging/make_artifacts.py 是本地与 CI 共用的打包脚本(同一份代码 → 同一套目录布局)。
本目录只放发布工程资产(脚本 / 说明 / 发布说明模板),不参与任何 crate 的编译。
索引:§1–§12 各在哪份文件(M145 拆分)
拆分原因:本文件与 .github/workflows/release.yml 都已是 400 行整,下一处改动必撞全仓行数红线(guards.yml 的
file-size,单文件 ≤400 行)。按主题分开后每份都留出余量,内容一字未改、只搬家;节号沿用原编号,
所以全仓那些「packaging/README.md §4 / §7.4 / §9」式引用不必改动 —— 按下表找承载文件即可。
| 节 | 主题 | 承载文件 |
|---|---|---|
| §1 | 产物矩阵 | packaging/docs/artifacts-and-version.md |
| §2 | 版本来源(唯一真相源) | packaging/docs/artifacts-and-version.md |
| §3 | 怎么构建(本地 / CI) | packaging/docs/build-and-ci.md |
| §4 | 每平台运行时依赖 | packaging/docs/runtime-deps.md |
| §5 | 软渲染兜底 | packaging/docs/runtime-deps.md |
| §6 | Cargo 构建档位 | packaging/docs/profiles-and-measurements.md |
| §7 | 实测(本机,不是估算) | packaging/docs/profiles-and-measurements.md |
| §8 | 发行合规 | packaging/docs/compliance-support-boundaries.md |
| §9 | 支持矩阵(对外口径) | packaging/docs/compliance-support-boundaries.md |
| §10 | 已知边界 / 后续 | packaging/docs/compliance-support-boundaries.md |
| §11 | CI 运行时冒烟(Linux 真渲染一帧) | 本文下方(细节在 packaging/ci-runtime-smoke.md) |
| §12 | 文件清单 | 本文下方 |
本文件仍是契约的唯一真相源入口:.github/workflows/release.yml(及拆出的 release-build.yml /
release-publish.yml)的注释、make_artifacts.py 的说明、根 README.md / README.zh-CN.md 与
packaging/release-notes.md 都按「packaging/README.md §N」引用。改契约时先改上表对应的承载文件,
再看一眼 §12 的行数预算 —— 任何一份超过 400 行都要继续按主题拆。
11. CI 运行时冒烟(Linux 真渲染一帧)
细节与依据在 packaging/ci-runtime-smoke.md(本节再增长也往那里写,两个文件都必须 ≤400 行)。
ci.yml 的 runtime-smoke job 在 ubuntu-latest 上补第一份真实图形环境证据:装 xvfb + 软渲染依赖 +
字体,用 xvfb-run 起 GUI 进程渲出一帧 PNG,再对像素本身断言(退出码 0 / 尺寸 / 非空白,artifact
runtime-smoke-screenshot)。
要点三条:
- 只看退出码不够:「合法 PNG + 退出码 0」不等于画面有内容;「完全没字体」与「非软渲染」都是硬失败(panic / 报错,不产生 PNG;review 实测)。
- 闸门下限 ≈「至少画出一条标题栏」(review 实测切片仍 pass):证明「场景被真实渲染过」,不证明界面元素齐全, 更不证明视觉正确——视觉靠人眼看 artifact。
- 只覆盖 Linux x64;macOS 是 dispatch-only 探针(无实测证据),Windows 已有本机人眼验收。
本地复跑:bash packaging/linux-smoke-docker.sh . D:/tmp/ull-smoke——脚本逐步复刻这个 job(同样的 apt 依赖、
--bin unlucky-launcher-iced、同样的 xvfb-run … --software-renderer --screenshot --data-dir);输出目录别写 /tmp,
Git Bash 下会静默落进 Docker VM(脚本内部用 cygpath -m 归一)。
M131 真跑过一次(本机 Docker / Debian 12 容器 / 2026-11-05):exit=0,截图 1180×760、[ok] 截图非空白。
12. 文件清单
| 文件 | 作用 | 行数上限 |
|---|---|---|
packaging/README.md |
本文:索引 + §11 / §12(契约入口;§1–§10 见 docs/) |
≤400 |
packaging/docs/artifacts-and-version.md |
§1 产物矩阵 + §2 版本来源 | ≤400 |
packaging/docs/build-and-ci.md |
§3 怎么构建(本地 / CI) | ≤400 |
packaging/docs/runtime-deps.md |
§4 每平台运行时依赖 + §5 软渲染兜底 | ≤400 |
packaging/docs/profiles-and-measurements.md |
§6 Cargo 构建档位 + §7 实测 | ≤400 |
packaging/docs/compliance-support-boundaries.md |
§8 发行合规 + §9 支持矩阵 + §10 已知边界 | ≤400 |
packaging/make_artifacts.py |
打包与校验(本地 + CI 共用) | ≤400 |
packaging/release-notes.md |
GitHub Release 说明模板({{VERSION}} / {{SUMS}} 占位) |
≤400 |
packaging/check_screenshot.py |
截图非空白判定(CI 门禁 + 本地手动跑,零第三方依赖) | ≤400 |
packaging/ci-runtime-smoke.md |
§11 的细节:断言口径/阈值依据/失效模式/复跑 | ≤400 |
packaging/linux-smoke-docker.sh |
本地复跑 runtime-smoke(Docker + xvfb) |
≤400 |
packaging/linux-check-docker.sh |
本地复跑 ci.yml 的两条 ubuntu 门禁(clippy / test,Docker) |
≤400 |
.github/workflows/release.yml |
tag 触发 → 选槽位(plan)→ 调下面两个可复用工作流 |
≤400 |
.github/workflows/release-build.yml |
workflow_call:单槽位构建(体检 / cargo / 打包 / 上传 artifact) |
≤400 |
.github/workflows/release-publish.yml |
workflow_call:发布(PUBLISH_SLOTS 裁剪 / SHA256SUMS / Release) |
≤400 |